more tracking

pull/5051/head
bunsenstraat 4 months ago
parent dee5994aa7
commit ca2145e732
  1. 1
      apps/remix-ide/src/app/plugins/matomo.ts
  2. 4
      libs/remix-ui/clipboard/src/lib/copy-to-clipboard/copy-to-clipboard.tsx
  3. 4
      libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx
  4. 11
      libs/remix-ui/git/src/components/github/devicecode.tsx
  5. 6
      libs/remix-ui/git/src/components/github/repositoryselect.tsx
  6. 43
      libs/remix-ui/git/src/components/gitui.tsx
  7. 4
      libs/remix-ui/git/src/components/navigation/remotesdetails.tsx
  8. 8
      libs/remix-ui/git/src/components/panels/branches/localbranchdetails.tsx
  9. 4
      libs/remix-ui/git/src/components/panels/branches/remotebranchedetails.tsx
  10. 9
      libs/remix-ui/git/src/components/panels/commands/pushpull.tsx
  11. 3
      libs/remix-ui/git/src/components/panels/githubcredentials.tsx
  12. 3
      libs/remix-ui/git/src/components/panels/remotes.tsx
  13. 67
      libs/remix-ui/git/src/lib/gitactions.ts
  14. 9
      libs/remix-ui/git/src/lib/listeners.ts
  15. 7
      libs/remix-ui/git/src/lib/pluginActions.ts
  16. 138
      libs/remix-ui/git/src/types/index.ts
  17. 4
      libs/remix-ui/workspace/src/lib/actions/workspace.ts

@ -21,6 +21,7 @@ export class Matomo extends Plugin {
async track(data: string[]) { async track(data: string[]) {
if (!allowedPlugins.includes(this.currentRequest.from)) return if (!allowedPlugins.includes(this.currentRequest.from)) return
console.log('Matomo', data)
_paq.push(data) _paq.push(data)
} }
} }

@ -14,9 +14,10 @@ interface ICopyToClipboard {
title?: string title?: string
children?: JSX.Element children?: JSX.Element
getContent?: () => any getContent?: () => any
callback?: () => void
} }
export const CopyToClipboard = (props: ICopyToClipboard) => { export const CopyToClipboard = (props: ICopyToClipboard) => {
const { tip = 'Copy', icon = 'fa-copy', direction = 'right', getContent, children, ...otherProps } = props const { tip = 'Copy', icon = 'fa-copy', direction = 'right', getContent, children, callback, ...otherProps } = props
let { content } = props let { content } = props
const [message, setMessage] = useState(tip) const [message, setMessage] = useState(tip)
@ -29,6 +30,7 @@ export const CopyToClipboard = (props: ICopyToClipboard) => {
if (typeof content !== 'string') { if (typeof content !== 'string') {
content = JSON.stringify(content, null, '\t') content = JSON.stringify(content, null, '\t')
} }
callback && callback()
copy(content) copy(content)
setMessage('Copied') setMessage('Copied')
} catch (e) { } catch (e) {

@ -4,10 +4,11 @@ import { CustomTooltip } from "@remix-ui/helper"
import React, { useEffect, useState } from "react" import React, { useEffect, useState } from "react"
import { FormattedMessage } from "react-intl" import { FormattedMessage } from "react-intl"
import { gitActionsContext } from "../../state/context" import { gitActionsContext } from "../../state/context"
import { branch, remote } from "../../types" import { branch, gitMatomoEventTypes, remote } from "../../types"
import { gitPluginContext } from "../gitui" import { gitPluginContext } from "../gitui"
import GitUIButton from "./gituibutton" import GitUIButton from "./gituibutton"
import { syncStateContext } from "./sourceControlBase" import { syncStateContext } from "./sourceControlBase"
import { sendToMatomo } from "../../lib/pluginActions"
export const SourceControlButtons = () => { export const SourceControlButtons = () => {
const context = React.useContext(gitPluginContext) const context = React.useContext(gitPluginContext)
@ -51,6 +52,7 @@ export const SourceControlButtons = () => {
} }
const refresh = async() => { const refresh = async() => {
await sendToMatomo(gitMatomoEventTypes.REFRESH)
await actions.getFileStatusMatrix(null) await actions.getFileStatusMatrix(null)
await actions.gitlog() await actions.gitlog()
} }

@ -4,6 +4,8 @@ import { gitPluginContext } from "../gitui";
import axios from "axios"; import axios from "axios";
import { CopyToClipboard } from "@remix-ui/clipboard"; import { CopyToClipboard } from "@remix-ui/clipboard";
import { Card } from "react-bootstrap"; import { Card } from "react-bootstrap";
import { sendToMatomo } from "../../lib/pluginActions";
import { gitMatomoEventTypes } from "../../types";
export const GetDeviceCode = () => { export const GetDeviceCode = () => {
const context = React.useContext(gitPluginContext) const context = React.useContext(gitPluginContext)
@ -13,7 +15,7 @@ export const GetDeviceCode = () => {
const [authorized, setAuthorized] = React.useState<boolean>(false) const [authorized, setAuthorized] = React.useState<boolean>(false)
const getDeviceCodeFromGitHub = async () => { const getDeviceCodeFromGitHub = async () => {
await sendToMatomo(gitMatomoEventTypes.GETGITHUBDEVICECODE)
setAuthorized(false) setAuthorized(false)
// Send a POST request // Send a POST request
const response = await axios({ const response = await axios({
@ -36,6 +38,7 @@ export const GetDeviceCode = () => {
} }
const connectApp = async () => { const connectApp = async () => {
await sendToMatomo(gitMatomoEventTypes.CONNECTTOGITHUB)
// poll https://github.com/login/oauth/access_token // poll https://github.com/login/oauth/access_token
const accestokenresponse = await axios({ const accestokenresponse = await axios({
method: 'post', method: 'post',
@ -56,13 +59,17 @@ export const GetDeviceCode = () => {
if (response.access_token) { if (response.access_token) {
setAuthorized(true) setAuthorized(true)
await sendToMatomo(gitMatomoEventTypes.CONNECTTOGITHUBSUCCESS)
await pluginActions.saveToken(response.access_token) await pluginActions.saveToken(response.access_token)
await actions.loadGitHubUserFromToken() await actions.loadGitHubUserFromToken()
} else {
await sendToMatomo(gitMatomoEventTypes.CONNECTTOGITHUBFAIL)
} }
} }
const disconnect = async () => { const disconnect = async () => {
await sendToMatomo(gitMatomoEventTypes.DISCONNECTFROMGITHUB)
setAuthorized(false) setAuthorized(false)
setGitHubResponse(null) setGitHubResponse(null)
await pluginActions.saveToken(null) await pluginActions.saveToken(null)
@ -84,7 +91,7 @@ export const GetDeviceCode = () => {
<div className="input-group text-secondary mb-0 h6"> <div className="input-group text-secondary mb-0 h6">
<input disabled type="text" className="form-control" value={gitHubResponse.user_code} /> <input disabled type="text" className="form-control" value={gitHubResponse.user_code} />
<div className="input-group-append"> <div className="input-group-append">
<CopyToClipboard content={gitHubResponse.user_code} data-id='copyToClipboardCopyIcon' className='far fa-copy ml-1 p-2 mt-1' direction={"top"} /> <CopyToClipboard callback={() => sendToMatomo(gitMatomoEventTypes.COPYGITHUBDEVICECODE)} content={gitHubResponse.user_code} data-id='copyToClipboardCopyIcon' className='far fa-copy ml-1 p-2 mt-1' direction={"top"} />
</div> </div>
</div> </div>
<br></br> <br></br>

@ -1,11 +1,10 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Button } from 'react-bootstrap';
import Select from 'react-select'; import Select from 'react-select';
import { gitActionsContext } from '../../state/context'; import { gitActionsContext } from '../../state/context';
import { repository } from '../../types'; import { gitMatomoEventTypes, repository } from '../../types';
import { selectStyles, selectTheme } from '../../types/styles'; import { selectStyles, selectTheme } from '../../types/styles';
import { gitPluginContext } from '../gitui'; import { gitPluginContext } from '../gitui';
import { TokenWarning } from '../panels/tokenWarning'; import { sendToMatomo } from '../../lib/pluginActions';
interface RepositorySelectProps { interface RepositorySelectProps {
select: (repo: repository) => void; select: (repo: repository) => void;
@ -57,6 +56,7 @@ const RepositorySelect = (props: RepositorySelectProps) => {
} }
const fetchRepositories = async () => { const fetchRepositories = async () => {
await sendToMatomo(gitMatomoEventTypes.LOADREPOSITORIESFROMGITHUB)
try { try {
setShow(true) setShow(true)
setLoading(true) setLoading(true)

@ -1,10 +1,10 @@
import React, { useEffect, useReducer, useState } from 'react' import React, { useEffect, useReducer, useState } from 'react'
import { add, addall, checkout, checkoutfile, clone, commit, createBranch, remoteBranches, repositories, rm, getCommitChanges, diff, resolveRef, getBranchCommits, setUpstreamRemote, loadGitHubUserFromToken, getBranches, getRemotes, remoteCommits, saveGitHubCredentials, getGitHubCredentialsFromLocalStorage, fetch, pull, push, setDefaultRemote, addRemote, removeRemote, sendToGitLog, clearGitLog, getBranchDifferences, getFileStatusMatrix, init, showAlert, gitlog } from '../lib/gitactions' import { add, addall, checkout, checkoutfile, clone, commit, createBranch, remoteBranches, repositories, rm, getCommitChanges, diff, resolveRef, getBranchCommits, setUpstreamRemote, loadGitHubUserFromToken, getBranches, getRemotes, remoteCommits, saveGitHubCredentials, getGitHubCredentialsFromLocalStorage, fetch, pull, push, setDefaultRemote, addRemote, removeRemote, sendToGitLog, clearGitLog, getBranchDifferences, getFileStatusMatrix, init, showAlert, gitlog } from '../lib/gitactions'
import { loadFiles, setCallBacks } from '../lib/listeners' import { loadFiles, setCallBacks } from '../lib/listeners'
import { openDiff, openFile, saveToken, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions' import { openDiff, openFile, saveToken, sendToMatomo, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions'
import { gitActionsContext, pluginActionsContext } from '../state/context' import { gitActionsContext, pluginActionsContext } from '../state/context'
import { gitReducer } from '../state/gitreducer' import { gitReducer } from '../state/gitreducer'
import { defaultGitState, defaultLoaderState, gitState, loaderState } from '../types' import { defaultGitState, defaultLoaderState, gitMatomoEventTypes, gitState, gitUIPanels, loaderState } from '../types'
import { Accordion } from "react-bootstrap"; import { Accordion } from "react-bootstrap";
import { CommitMessage } from './buttons/commitmessage' import { CommitMessage } from './buttons/commitmessage'
import { Commits } from './panels/commits' import { Commits } from './panels/commits'
@ -118,6 +118,13 @@ export const GitUI = (props: IGitUi) => {
}, [gitState.gitHubUser, gitState.currentBranch, gitState.remotes, gitState.gitHubAccessToken, gitState.currentHead]) }, [gitState.gitHubUser, gitState.currentBranch, gitState.remotes, gitState.gitHubAccessToken, gitState.currentHead])
useEffect(() => {
const panelName = Object.keys(gitUIPanels)
.filter(k => gitUIPanels[k] === activePanel);
if(!(panelName && panelName[0])) return
sendToMatomo(gitMatomoEventTypes.OPENPANEL, [panelName && panelName[0]])
}, [activePanel])
const gitActionsProviderValue = { const gitActionsProviderValue = {
commit, commit,
addall, addall,
@ -175,51 +182,51 @@ export const GitUI = (props: IGitUi) => {
{needsInit ? <Init></Init> : null} {needsInit ? <Init></Init> : null}
{!setup && !needsInit ? {!setup && !needsInit ?
<Accordion activeKey={activePanel} defaultActiveKey="0" className=""> <Accordion activeKey={activePanel} defaultActiveKey="0" className="">
<SourceControlNavigation eventKey="0" activePanel={activePanel} callback={setActivePanel} /> <SourceControlNavigation eventKey={gitUIPanels.SOURCECONTROL} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="0"> <Accordion.Collapse className='bg-light' eventKey={gitUIPanels.SOURCECONTROL}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<SourceControlBase><CommitMessage /></SourceControlBase> <SourceControlBase><CommitMessage /></SourceControlBase>
<SourceControl /> <SourceControl />
</div> </div>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<CommandsNavigation eventKey="1" activePanel={activePanel} callback={setActivePanel} /> <CommandsNavigation eventKey={gitUIPanels.COMMANDS} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className="bg-light" eventKey="1"> <Accordion.Collapse className="bg-light" eventKey={gitUIPanels.COMMANDS}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<Commands></Commands> <Commands></Commands>
</div> </div>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<CommitsNavigation title={`COMMITS`} eventKey="3" activePanel={activePanel} callback={setActivePanel} showButtons={true} /> <CommitsNavigation title={`COMMITS`} eventKey={gitUIPanels.COMMITS} activePanel={activePanel} callback={setActivePanel} showButtons={true} />
<Accordion.Collapse className='bg-light' eventKey="3"> <Accordion.Collapse className='bg-light' eventKey={gitUIPanels.COMMITS}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<Commits /> <Commits />
</div> </div>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<BranchesNavigation eventKey="2" activePanel={activePanel} callback={setActivePanel} /> <BranchesNavigation eventKey={gitUIPanels.BRANCHES} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="2"> <Accordion.Collapse className='bg-light' eventKey={gitUIPanels.BRANCHES}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<Branches /> <Branches />
</div> </div>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<RemotesNavigation eventKey="5" activePanel={activePanel} callback={setActivePanel} /> <RemotesNavigation eventKey={gitUIPanels.REMOTES} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="5"> <Accordion.Collapse className='bg-light' eventKey={gitUIPanels.REMOTES}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<Remotes></Remotes> <Remotes></Remotes>
</div> </div>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<CloneNavigation eventKey="4" activePanel={activePanel} callback={setActivePanel} /> <CloneNavigation eventKey={gitUIPanels.CLONE} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="4"> <Accordion.Collapse className='bg-light' eventKey={gitUIPanels.CLONE}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<Clone /></div> <Clone /></div>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<GitHubNavigation eventKey="7" activePanel={activePanel} callback={setActivePanel} /> <GitHubNavigation eventKey={gitUIPanels.GITHUB} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="7"> <Accordion.Collapse className='bg-light' eventKey={gitUIPanels.GITHUB}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<GetDeviceCode></GetDeviceCode> <GetDeviceCode></GetDeviceCode>
<hr></hr> <hr></hr>
@ -227,8 +234,8 @@ export const GitUI = (props: IGitUi) => {
</div> </div>
</Accordion.Collapse> </Accordion.Collapse>
<hr></hr> <hr></hr>
<LogNavigation eventKey="6" activePanel={activePanel} callback={setActivePanel} /> <LogNavigation eventKey={gitUIPanels.LOG} activePanel={activePanel} callback={setActivePanel} />
<Accordion.Collapse className='bg-light' eventKey="6"> <Accordion.Collapse className='bg-light' eventKey={gitUIPanels.LOG}>
<div className="px-2 py-2"> <div className="px-2 py-2">
<LogViewer /> <LogViewer />
</div> </div>

@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { CustomTooltip } from "@remix-ui/helper"; import { CustomTooltip } from "@remix-ui/helper";
import React, { useContext, useEffect } from "react"; import React, { useContext, useEffect } from "react";
import { gitActionsContext } from "../../state/context"; import { gitActionsContext } from "../../state/context";
import { branch, remote } from "../../types"; import { branch, gitMatomoEventTypes, remote } from "../../types";
import GitUIButton from "../buttons/gituibutton"; import GitUIButton from "../buttons/gituibutton";
import { gitPluginContext } from "../gitui"; import { gitPluginContext } from "../gitui";
import { removeGitFromUrl } from "../../utils"; import { removeGitFromUrl } from "../../utils";
@ -33,7 +33,7 @@ export const RemotesDetailsNavigation = (props: RemotesDetailsNavigationProps) =
window.open(`${removeGitFromUrl(remote.url)}`, '_blank'); window.open(`${removeGitFromUrl(remote.url)}`, '_blank');
} }
const setAsDefault = () => { const setAsDefault = async () => {
actions.setDefaultRemote(remote) actions.setDefaultRemote(remote)
} }

@ -4,12 +4,13 @@ import { Accordion } from "react-bootstrap";
import { CommitDetailsNavigation } from "../../navigation/commitdetails"; import { CommitDetailsNavigation } from "../../navigation/commitdetails";
import { gitActionsContext } from "../../../state/context"; import { gitActionsContext } from "../../../state/context";
import { gitPluginContext } from "../../gitui"; import { gitPluginContext } from "../../gitui";
import { branch } from "../../../types"; import { branch, gitMatomoEventTypes } from "../../../types";
import { BrancheDetailsNavigation } from "../../navigation/branchedetails"; import { BrancheDetailsNavigation } from "../../navigation/branchedetails";
import { CommitDetailsItems } from "../commits/commitdetailsitem"; import { CommitDetailsItems } from "../commits/commitdetailsitem";
import { CommitDetails } from "../commits/commitdetails"; import { CommitDetails } from "../commits/commitdetails";
import { BranchDifferences } from "./branchdifferences"; import { BranchDifferences } from "./branchdifferences";
import GitUIButton from "../../buttons/gituibutton"; import GitUIButton from "../../buttons/gituibutton";
import { sendToMatomo } from "../../../lib/pluginActions";
export interface BrancheDetailsProps { export interface BrancheDetailsProps {
branch: branch; branch: branch;
@ -32,8 +33,9 @@ export const LocalBranchDetails = (props: BrancheDetailsProps) => {
} }
}, [activePanel]) }, [activePanel])
const checkout = (branch: branch) => { const checkout = async (branch: branch) => {
actions.checkout({ await sendToMatomo(gitMatomoEventTypes.CHECKOUT_LOCAL_BRANCH)
await actions.checkout({
ref: branch.name, ref: branch.name,
remote: branch.remote && branch.remote.name || null, remote: branch.remote && branch.remote.name || null,
refresh: true refresh: true

@ -4,11 +4,12 @@ import { Accordion } from "react-bootstrap";
import { CommitDetailsNavigation } from "../../navigation/commitdetails"; import { CommitDetailsNavigation } from "../../navigation/commitdetails";
import { gitActionsContext } from "../../../state/context"; import { gitActionsContext } from "../../../state/context";
import { gitPluginContext } from "../../gitui"; import { gitPluginContext } from "../../gitui";
import { branch } from "../../../types"; import { branch, gitMatomoEventTypes } from "../../../types";
import { BrancheDetailsNavigation } from "../../navigation/branchedetails"; import { BrancheDetailsNavigation } from "../../navigation/branchedetails";
import { CommitDetailsItems } from "../commits/commitdetailsitem"; import { CommitDetailsItems } from "../commits/commitdetailsitem";
import { CommitDetails } from "../commits/commitdetails"; import { CommitDetails } from "../commits/commitdetails";
import GitUIButton from "../../buttons/gituibutton"; import GitUIButton from "../../buttons/gituibutton";
import { sendToMatomo } from "../../../lib/pluginActions";
export interface BrancheDetailsProps { export interface BrancheDetailsProps {
branch: branch; branch: branch;
@ -47,6 +48,7 @@ export const RemoteBranchDetails = (props: BrancheDetailsProps) => {
}, [context.remoteBranchCommits]) }, [context.remoteBranchCommits])
const checkout = async (branch: branch) => { const checkout = async (branch: branch) => {
await sendToMatomo(gitMatomoEventTypes.CHECKOUT_REMOTE_BRANCH)
await actions.fetch({ await actions.fetch({
remote: branch.remote, remote: branch.remote,
ref: branch, ref: branch,

@ -4,8 +4,9 @@ import { gitPluginContext } from "../../gitui";
import { selectStyles, selectTheme } from "../../../types/styles"; import { selectStyles, selectTheme } from "../../../types/styles";
import Select, { Options, OptionsOrGroups } from 'react-select' import Select, { Options, OptionsOrGroups } from 'react-select'
import GitUIButton from "../../buttons/gituibutton"; import GitUIButton from "../../buttons/gituibutton";
import { remote } from "../../../types"; import { gitMatomoEventTypes, remote } from "../../../types";
import { relative } from "path"; import { relative } from "path";
import { sendToMatomo } from "../../../lib/pluginActions";
export const PushPull = () => { export const PushPull = () => {
const context = React.useContext(gitPluginContext) const context = React.useContext(gitPluginContext)
@ -45,11 +46,13 @@ export const PushPull = () => {
} }
},[context.defaultRemote]) },[context.defaultRemote])
const onRemoteBranchChange = (value: string) => { const onRemoteBranchChange = async (value: string) => {
await sendToMatomo(gitMatomoEventTypes.SETREMOTEBRANCHINCOMMANDS)
setRemoteBranch(value) setRemoteBranch(value)
} }
const onLocalBranchChange = (value: any) => { const onLocalBranchChange = async (value: any) => {
await sendToMatomo(gitMatomoEventTypes.SETLOCALBRANCHINCOMMANDS)
setLocalBranch(value) setLocalBranch(value)
} }

@ -5,6 +5,8 @@ import { CustomTooltip } from "@remix-ui/helper";
import { useIntl, FormattedMessage } from "react-intl"; import { useIntl, FormattedMessage } from "react-intl";
import { CopyToClipboard } from "@remix-ui/clipboard"; import { CopyToClipboard } from "@remix-ui/clipboard";
import { gitMatomoEventTypes } from "../../types";
import { sendToMatomo } from "../../lib/pluginActions";
export const GitHubCredentials = () => { export const GitHubCredentials = () => {
const context = React.useContext(gitPluginContext) const context = React.useContext(gitPluginContext)
@ -39,6 +41,7 @@ export const GitHubCredentials = () => {
} }
async function saveGithubToken() { async function saveGithubToken() {
await sendToMatomo(gitMatomoEventTypes.SAVEMANUALGITHUBCREDENTIALS)
await pluginactions.saveGitHubCredentials({ await pluginactions.saveGitHubCredentials({
username: githubUsername, username: githubUsername,
email: githubEmail, email: githubEmail,

@ -3,6 +3,8 @@ import { gitActionsContext } from "../../state/context"
import { gitPluginContext } from "../gitui" import { gitPluginContext } from "../gitui"
import { Remoteselect } from "./remoteselect" import { Remoteselect } from "./remoteselect"
import { RemotesImport } from "./remotesimport" import { RemotesImport } from "./remotesimport"
import { sendToMatomo } from "../../lib/pluginActions"
import { gitMatomoEventTypes } from "../../types"
export const Remotes = () => { export const Remotes = () => {
const context = React.useContext(gitPluginContext) const context = React.useContext(gitPluginContext)
@ -18,6 +20,7 @@ export const Remotes = () => {
} }
const addRemote = async () => { const addRemote = async () => {
await sendToMatomo(gitMatomoEventTypes.ADDMANUALREMOTE)
actions.addRemote({ actions.addRemote({
name: remoteName, name: remoteName,
url: url url: url

@ -1,11 +1,11 @@
import { ReadBlobResult, ReadCommitResult } from "isomorphic-git"; import { ReadBlobResult, ReadCommitResult } from "isomorphic-git";
import React from "react"; import React from "react";
import { fileStatus, fileStatusMerge, setRemoteBranchCommits, resetRemoteBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRemoteBranches, setRemotes, setRepos, setUpstream, setLocalBranchCommits, setBranchDifferences, setRemoteAsDefault, setScopes, setLog, clearLog, setUserEmails, setCurrenHead, setStoragePayload, resetBranchDifferences } from "../state/gitpayload"; import { fileStatus, fileStatusMerge, setRemoteBranchCommits, resetRemoteBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRemoteBranches, setRemotes, setRepos, setUpstream, setLocalBranchCommits, setBranchDifferences, setRemoteAsDefault, setScopes, setLog, clearLog, setUserEmails, setCurrenHead, setStoragePayload, resetBranchDifferences } from "../state/gitpayload";
import { GitHubUser, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference, remote, gitLog, fileStatusResult, customGitApi, IGitApi, cloneInputType, fetchInputType, pullInputType, pushInputType, checkoutInput, rmInput, addInput, repository, userEmails, storage } from '../types'; import { GitHubUser, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference, remote, gitLog, fileStatusResult, customGitApi, IGitApi, cloneInputType, fetchInputType, pullInputType, pushInputType, checkoutInput, rmInput, addInput, repository, userEmails, storage, gitMatomoEventTypes } from '../types';
import { removeSlash } from "../utils"; import { removeSlash } from "../utils";
import { disableCallBacks, enableCallBacks } from "./listeners"; import { disableCallBacks, enableCallBacks } from "./listeners";
import { ModalTypes } from "@remix-ui/app"; import { ModalTypes } from "@remix-ui/app";
import { setFileDecorators } from "./pluginActions"; import { sendToMatomo, setFileDecorators } from "./pluginActions";
import { Plugin } from "@remixproject/engine"; import { Plugin } from "@remixproject/engine";
import { CustomRemixApi } from "@remix-api"; import { CustomRemixApi } from "@remix-api";
@ -24,27 +24,6 @@ export const fileStatuses = [
["unstaged,modified", 1, 2, 0] ["unstaged,modified", 1, 2, 0]
]; ];
enum gitEventTypes {
INIT = 'INIT',
COMMIT = 'COMMIT',
PUSH = 'PUSH',
PULL = 'PULL',
ADDREMOTE = 'ADDREMOTE',
RMREMOTE = 'RMREMOTE',
CLONE = 'CLONE',
FETCH = 'FETCH',
ADD = 'ADD',
ADD_ALL = 'ADD_ALL',
RM = 'RM',
CHECKOUT = 'CHECKOUT',
DIFF = 'DIFF',
BRANCH = 'BRANCH',
CREATEBRANCH = 'CREATEBRANCH',
}
const statusmatrix: statusMatrixType[] = fileStatuses.map((x: any) => { const statusmatrix: statusMatrixType[] = fileStatuses.map((x: any) => {
return { return {
matrix: x.shift().split(","), matrix: x.shift().split(","),
@ -59,12 +38,8 @@ export const setPlugin = (p: Plugin, dispatcher: React.Dispatch<gitActionDispatc
dispatch = dispatcher dispatch = dispatcher
} }
const sendToMatomo = async (event: gitEventTypes) => {
plugin.call('matomo', 'track', ['trackEvent', 'git', event])
}
export const init = async () => { export const init = async () => {
sendToMatomo(gitEventTypes.INIT) await sendToMatomo(gitMatomoEventTypes.INIT)
await plugin.call('dgitApi', "init"); await plugin.call('dgitApi', "init");
await gitlog(); await gitlog();
await getBranches(); await getBranches();
@ -169,7 +144,7 @@ export const currentBranch = async () => {
} }
export const createBranch = async (name: string = "") => { export const createBranch = async (name: string = "") => {
sendToMatomo(gitEventTypes.CREATEBRANCH) await sendToMatomo(gitMatomoEventTypes.CREATEBRANCH)
dispatch(setLoading(true)) dispatch(setLoading(true))
if (name) { if (name) {
await plugin.call('dgitApi', 'branch', { ref: name, force: true, checkout: true }); await plugin.call('dgitApi', 'branch', { ref: name, force: true, checkout: true });
@ -200,7 +175,7 @@ const settingsWarning = async () => {
export const commit = async (message: string = "") => { export const commit = async (message: string = "") => {
sendToMatomo(gitEventTypes.COMMIT) await sendToMatomo(gitMatomoEventTypes.COMMIT)
try { try {
const credentials = await settingsWarning() const credentials = await settingsWarning()
if (!credentials) { if (!credentials) {
@ -228,7 +203,7 @@ export const commit = async (message: string = "") => {
} }
export const addall = async (files: fileStatusResult[]) => { export const addall = async (files: fileStatusResult[]) => {
sendToMatomo(gitEventTypes.ADD_ALL) await sendToMatomo(gitMatomoEventTypes.ADD_ALL)
try { try {
const filesToAdd = files const filesToAdd = files
.filter(f => !f.statusNames.includes('deleted')) .filter(f => !f.statusNames.includes('deleted'))
@ -254,7 +229,7 @@ export const addall = async (files: fileStatusResult[]) => {
} }
export const add = async (filepath: addInput) => { export const add = async (filepath: addInput) => {
sendToMatomo(gitEventTypes.ADD) await sendToMatomo(gitMatomoEventTypes.ADD)
try { try {
if (typeof filepath.filepath === "string") { if (typeof filepath.filepath === "string") {
filepath.filepath = removeSlash(filepath.filepath) filepath.filepath = removeSlash(filepath.filepath)
@ -281,7 +256,7 @@ const getLastCommmit = async () => {
} }
export const rm = async (args: rmInput) => { export const rm = async (args: rmInput) => {
sendToMatomo(gitEventTypes.RM) await sendToMatomo(gitMatomoEventTypes.RM)
await plugin.call('dgitApi', 'rm', { await plugin.call('dgitApi', 'rm', {
filepath: removeSlash(args.filepath), filepath: removeSlash(args.filepath),
}); });
@ -318,7 +293,7 @@ export const checkoutfile = async (filename: string) => {
} }
export const checkout = async (cmd: checkoutInput) => { export const checkout = async (cmd: checkoutInput) => {
sendToMatomo(gitMatomoEventTypes.CHECKOUT)
await disableCallBacks(); await disableCallBacks();
await plugin.call('fileManager', 'closeAllFiles') await plugin.call('fileManager', 'closeAllFiles')
try { try {
@ -332,7 +307,7 @@ export const checkout = async (cmd: checkoutInput) => {
export const clone = async (input: cloneInputType) => { export const clone = async (input: cloneInputType) => {
sendToMatomo(gitEventTypes.CLONE) await sendToMatomo(gitMatomoEventTypes.CLONE)
dispatch(setLoading(true)) dispatch(setLoading(true))
const urlParts = input.url.split("/"); const urlParts = input.url.split("/");
const lastPart = urlParts[urlParts.length - 1]; const lastPart = urlParts[urlParts.length - 1];
@ -361,7 +336,7 @@ export const clone = async (input: cloneInputType) => {
} }
export const fetch = async (input: fetchInputType) => { export const fetch = async (input: fetchInputType) => {
sendToMatomo(gitEventTypes.FETCH) await sendToMatomo(gitMatomoEventTypes.FETCH)
dispatch(setLoading(true)) dispatch(setLoading(true))
await disableCallBacks() await disableCallBacks()
try { try {
@ -379,7 +354,7 @@ export const fetch = async (input: fetchInputType) => {
} }
export const pull = async (input: pullInputType) => { export const pull = async (input: pullInputType) => {
sendToMatomo(gitEventTypes.PULL) await sendToMatomo(gitMatomoEventTypes.PULL)
dispatch(setLoading(true)) dispatch(setLoading(true))
await disableCallBacks() await disableCallBacks()
try { try {
@ -394,7 +369,7 @@ export const pull = async (input: pullInputType) => {
} }
export const push = async (input: pushInputType) => { export const push = async (input: pushInputType) => {
sendToMatomo(gitEventTypes.PUSH) await sendToMatomo(gitMatomoEventTypes.PUSH)
dispatch(setLoading(true)) dispatch(setLoading(true))
await disableCallBacks() await disableCallBacks()
try { try {
@ -420,6 +395,7 @@ const parseError = async (e: any) => {
console.trace(e) console.trace(e)
// if message conttains 401 Unauthorized, show token warning // if message conttains 401 Unauthorized, show token warning
if (e.message.includes('401')) { if (e.message.includes('401')) {
await sendToMatomo(gitMatomoEventTypes.ERROR, ['401'])
const result = await plugin.call('notification', 'modal' as any, { const result = await plugin.call('notification', 'modal' as any, {
title: 'The GitHub token may be missing or invalid', title: 'The GitHub token may be missing or invalid',
message: 'Please check the GitHub token and try again. Error: 401 Unauthorized', message: 'Please check the GitHub token and try again. Error: 401 Unauthorized',
@ -430,6 +406,7 @@ const parseError = async (e: any) => {
} }
// if message contains 404 Not Found, show repo not found // if message contains 404 Not Found, show repo not found
else if (e.message.includes('404')) { else if (e.message.includes('404')) {
await sendToMatomo(gitMatomoEventTypes.ERROR, ['404'])
await plugin.call('notification', 'modal' as any, { await plugin.call('notification', 'modal' as any, {
title: 'Repository not found', title: 'Repository not found',
message: 'Please check the URL and try again.', message: 'Please check the URL and try again.',
@ -440,6 +417,7 @@ const parseError = async (e: any) => {
} }
// if message contains 403 Forbidden // if message contains 403 Forbidden
else if (e.message.includes('403')) { else if (e.message.includes('403')) {
await sendToMatomo(gitMatomoEventTypes.ERROR, ['403'])
await plugin.call('notification', 'modal' as any, { await plugin.call('notification', 'modal' as any, {
title: 'The GitHub token may be missing or invalid', title: 'The GitHub token may be missing or invalid',
message: 'Please check the GitHub token and try again. Error: 403 Forbidden', message: 'Please check the GitHub token and try again. Error: 403 Forbidden',
@ -448,6 +426,7 @@ const parseError = async (e: any) => {
type: ModalTypes.confirm type: ModalTypes.confirm
}) })
} else if (e.toString().includes('NotFoundError') && !e.toString().includes('fetch')) { } else if (e.toString().includes('NotFoundError') && !e.toString().includes('fetch')) {
await sendToMatomo(gitMatomoEventTypes.ERROR, ['BRANCH NOT FOUND ON REMOTE'])
await plugin.call('notification', 'modal', { await plugin.call('notification', 'modal', {
title: 'Remote branch not found', title: 'Remote branch not found',
message: 'The branch you are trying to fetch does not exist on the remote. If you have forked this branch from another branch, you may need to fetch the original branch first or publish this branch on the remote.', message: 'The branch you are trying to fetch does not exist on the remote. If you have forked this branch from another branch, you may need to fetch the original branch first or publish this branch on the remote.',
@ -455,6 +434,7 @@ const parseError = async (e: any) => {
type: ModalTypes.alert type: ModalTypes.alert
}) })
} else { } else {
await sendToMatomo(gitMatomoEventTypes.ERROR, ['UKNOWN'])
await plugin.call('notification', 'alert' as any, { await plugin.call('notification', 'alert' as any, {
title: 'Error', title: 'Error',
message: e.message message: e.message
@ -482,6 +462,7 @@ export const repositories = async () => {
} }
} else { } else {
await sendToMatomo(gitMatomoEventTypes.ERROR, ['TOKEN ERROR'])
plugin.call('notification', 'alert', { plugin.call('notification', 'alert', {
id: 'github-token-error', id: 'github-token-error',
title: 'Error getting repositories', title: 'Error getting repositories',
@ -491,6 +472,7 @@ export const repositories = async () => {
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)
await sendToMatomo(gitMatomoEventTypes.ERROR, ['TOKEN ERROR'])
plugin.call('notification', 'alert', { plugin.call('notification', 'alert', {
id: 'github-token-error', id: 'github-token-error',
title: 'Error getting repositories', title: 'Error getting repositories',
@ -519,6 +501,7 @@ export const remoteBranches = async (owner: string, repo: string) => {
page++ page++
} }
} else { } else {
await sendToMatomo(gitMatomoEventTypes.ERROR, ['TOKEN ERROR'])
plugin.call('notification', 'alert', { plugin.call('notification', 'alert', {
title: 'Error getting branches', title: 'Error getting branches',
id: 'github-token-error', id: 'github-token-error',
@ -528,6 +511,7 @@ export const remoteBranches = async (owner: string, repo: string) => {
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)
await sendToMatomo(gitMatomoEventTypes.ERROR, ['TOKEN ERROR'])
plugin.call('notification', 'alert', { plugin.call('notification', 'alert', {
title: 'Error', title: 'Error',
id: 'github-error', id: 'github-error',
@ -697,7 +681,7 @@ export const resolveRef = async (ref: string) => {
} }
export const diff = async (commitChange: commitChange) => { export const diff = async (commitChange: commitChange) => {
sendToMatomo(gitEventTypes.DIFF) await sendToMatomo(gitMatomoEventTypes.DIFF)
if (!commitChange.hashModified) { if (!commitChange.hashModified) {
const newcontent = await plugin.call( const newcontent = await plugin.call(
"fileManager", "fileManager",
@ -864,11 +848,12 @@ export const getBranchCommits = async (branch: branch, page: number) => {
} }
export const setDefaultRemote = async (remote: remote) => { export const setDefaultRemote = async (remote: remote) => {
await sendToMatomo(gitMatomoEventTypes.SETDEFAULTREMOTE)
dispatch(setRemoteAsDefault(remote)) dispatch(setRemoteAsDefault(remote))
} }
export const addRemote = async (remote: remote) => { export const addRemote = async (remote: remote) => {
sendToMatomo(gitEventTypes.ADDREMOTE) await sendToMatomo(gitMatomoEventTypes.ADDREMOTE)
try { try {
await plugin.call('dgitApi', 'addremote', remote) await plugin.call('dgitApi', 'addremote', remote)
await getRemotes() await getRemotes()
@ -883,7 +868,7 @@ export const addRemote = async (remote: remote) => {
} }
export const removeRemote = async (remote: remote) => { export const removeRemote = async (remote: remote) => {
sendToMatomo(gitEventTypes.RMREMOTE) await sendToMatomo(gitMatomoEventTypes.RMREMOTE)
try { try {
await plugin.call('dgitApi', 'delremote', remote) await plugin.call('dgitApi', 'delremote', remote)
await getRemotes() await getRemotes()

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { setCanUseApp, setLoading, setRepoName, setGItHubToken, setLog, setGitHubUser, setUserEmails } from "../state/gitpayload"; import { setCanUseApp, setLoading, setRepoName, setGItHubToken, setLog, setGitHubUser, setUserEmails } from "../state/gitpayload";
import { gitActionDispatch, storage } from "../types"; import { gitActionDispatch, gitUIPanels, storage } from "../types";
import { Plugin } from "@remixproject/engine"; import { Plugin } from "@remixproject/engine";
import { getBranches, getFileStatusMatrix, loadGitHubUserFromToken, getRemotes, gitlog, setPlugin, setStorage } from "./gitactions"; import { getBranches, getFileStatusMatrix, loadGitHubUserFromToken, getRemotes, gitlog, setPlugin, setStorage } from "./gitactions";
import { Profile } from "@remixproject/plugin-utils"; import { Profile } from "@remixproject/plugin-utils";
@ -163,11 +163,8 @@ export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch<g
}) })
plugin.on('dgit' as any, 'openPanel', async (panel: string) => { plugin.on('dgit' as any, 'openPanel', async (panel: string) => {
const panels = {
'branches': '2' setAtivePanel(panel)
}
const panelNumber = panels[panel]
setAtivePanel(panelNumber)
}) })
callBackEnabled = true; callBackEnabled = true;

@ -1,5 +1,5 @@
import { commitChange, fileStatusResult, gitActionDispatch, gitState } from "../types" import { commitChange, fileStatusResult, gitActionDispatch, gitMatomoEventTypes, gitState } from "../types"
import { fileDecoration, fileDecorationType } from "@remix-ui/file-decorators" import { fileDecoration, fileDecorationType } from "@remix-ui/file-decorators"
import { removeSlash } from "../utils" import { removeSlash } from "../utils"
import { getFilesByStatus } from "./fileHelpers" import { getFilesByStatus } from "./fileHelpers"
@ -98,3 +98,8 @@ export const clearFileDecorator = async(path: string) => {
await plugin.call('fileDecorator', 'clearFileDecorators', path) await plugin.call('fileDecorator', 'clearFileDecorators', path)
} }
export const sendToMatomo = async (event: gitMatomoEventTypes, args?: string[]) => {
const trackArgs = args ? ['trackEvent', 'git', event, ...args] : ['trackEvent', 'git', event];
plugin && await plugin.call('matomo', 'track', trackArgs);
}

@ -143,8 +143,8 @@ export interface repositoriesInput { token: string, page?: number, per_page?: nu
export interface statusInput { ref: string, filepaths?: string[] } export interface statusInput { ref: string, filepaths?: string[] }
export const dGitProfile: LibraryProfile<IGitApi> = { export const dGitProfile: LibraryProfile<IGitApi> = {
name: 'dgitApi', name: 'dgitApi',
methods: ['clone', 'branches', 'remotes', 'getCommitChanges', 'log', 'remotecommits'], methods: ['clone', 'branches', 'remotes', 'getCommitChanges', 'log', 'remotecommits'],
} }
export interface customGitApi extends IRemixApi { export interface customGitApi extends IRemixApi {
@ -266,53 +266,53 @@ export type remoteBranch = {
} }
export const defaultGitState: gitState = { export const defaultGitState: gitState = {
currentBranch: { name: "", remote: { name: "", url: "" } }, currentBranch: { name: "", remote: { name: "", url: "" } },
currentHead: "", currentHead: "",
commits: [], commits: [],
branch: "", branch: "",
canCommit: true, canCommit: true,
branches: [], branches: [],
remotes: [], remotes: [],
defaultRemote: null, defaultRemote: null,
fileStatusResult: [], fileStatusResult: [],
staged: [], staged: [],
untracked: [], untracked: [],
deleted: [], deleted: [],
modified: [], modified: [],
allchangesnotstaged: [], allchangesnotstaged: [],
canUseApp: true, canUseApp: true,
loading: false, loading: false,
storage: { storage: {
used: 0, used: 0,
total: 0, total: 0,
available: 0, available: 0,
percentUsed: 0, percentUsed: 0,
enabled: false enabled: false
}, },
reponame: "", reponame: "",
repositories: [], repositories: [],
remoteBranches: [], remoteBranches: [],
commitChanges: [], commitChanges: [],
remoteBranchCommits: {}, remoteBranchCommits: {},
localBranchCommits: {}, localBranchCommits: {},
branchDifferences: {}, branchDifferences: {},
syncStatus: syncStatus.none, syncStatus: syncStatus.none,
localCommitCount: 0, localCommitCount: 0,
remoteCommitCount: 0, remoteCommitCount: 0,
upstream: null, upstream: null,
gitHubUser: {} as GitHubUser, gitHubUser: {} as GitHubUser,
userEmails: [] as userEmails, userEmails: [] as userEmails,
gitHubScopes: [], gitHubScopes: [],
gitHubAccessToken: "", gitHubAccessToken: "",
log: [] log: []
} }
export const defaultLoaderState: loaderState = { export const defaultLoaderState: loaderState = {
branches: false, branches: false,
commits: false, commits: false,
sourcecontrol: false, sourcecontrol: false,
remotes: false, remotes: false,
plugin: false plugin: false
} }
export type fileStatusResult = { export type fileStatusResult = {
@ -338,6 +338,52 @@ export type storage = {
enabled: boolean enabled: boolean
} }
export enum gitMatomoEventTypes {
INIT = 'INIT',
COMMIT = 'COMMIT',
PUSH = 'PUSH',
PULL = 'PULL',
ADDREMOTE = 'ADDREMOTE',
RMREMOTE = 'RMREMOTE',
CLONE = 'CLONE',
FETCH = 'FETCH',
ADD = 'ADD',
ADD_ALL = 'ADD_ALL',
RM = 'RM',
CHECKOUT = 'CHECKOUT',
CHECKOUT_LOCAL_BRANCH = 'CHECKOUT_LOCAL_BRANCH',
CHECKOUT_REMOTE_BRANCH = 'CHECKOUT_REMOTE_BRANCH',
DIFF = 'DIFF',
BRANCH = 'BRANCH',
CREATEBRANCH = 'CREATEBRANCH',
GETGITHUBDEVICECODE = 'GET_GITHUB_DEVICECODE',
CONNECTTOGITHUB = 'CONNECT_TO_GITHUB',
DISCONNECTFROMGITHUB = 'DISCONNECT_FROM_GITHUB',
SAVEMANUALGITHUBCREDENTIALS = 'SAVE_MANUAL_GITHUB_CREDENTIALS',
LOADREPOSITORIESFROMGITHUB = 'LOAD_REPOSITORIES_FROM_GITHUB',
COPYGITHUBDEVICECODE = 'COPY_GITHUB_DEVICE_CODE',
CONNECTTOGITHUBSUCCESS = 'CONNECT_TO_GITHUB_SUCCESS',
CONNECTTOGITHUBFAIL = 'CONNECT_TO_GITHUB_FAIL',
OPENPANEL = 'OPEN_PANEL',
ADDMANUALREMOTE = 'ADD_MANUAL_REMOTE',
SETDEFAULTREMOTE = 'SET_DEFAULT_REMOTE',
SETLOCALBRANCHINCOMMANDS = 'SET_LOCAL_BRANCH_IN_COMMANDS',
SETREMOTEBRANCHINCOMMANDS = 'SET_REMOTE_IN_COMMANDS',
REFRESH = 'REFRESH',
ERROR = 'ERROR',
}
export enum gitUIPanels {
SOURCECONTROL = '0',
COMMANDS = '1',
BRANCHES = '2',
COMMITS = '3',
CLONE = '4',
REMOTES = '5',
GITHUB = '7',
LOG = '6'
}
export interface fileStatusAction { export interface fileStatusAction {
type: string, type: string,
payload: fileStatusResult[] payload: fileStatusResult[]

@ -43,7 +43,7 @@ import { ROOT_PATH } from '../utils/constants'
import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files/filesystems/indexedDB' import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files/filesystems/indexedDB'
import { getUncommittedFiles } from '../utils/gitStatusFilter' import { getUncommittedFiles } from '../utils/gitStatusFilter'
import { AppModal, ModalTypes } from '@remix-ui/app' import { AppModal, ModalTypes } from '@remix-ui/app'
import { branch, cloneInputType, IGitApi } from '@remix-ui/git' import { branch, cloneInputType, IGitApi, gitUIPanels } from '@remix-ui/git'
import * as templates from '@remix-project/remix-ws-templates' import * as templates from '@remix-project/remix-ws-templates'
import { Plugin } from "@remixproject/engine"; import { Plugin } from "@remixproject/engine";
import { CustomRemixApi } from '@remix-api' import { CustomRemixApi } from '@remix-api'
@ -788,7 +788,7 @@ export const showAllBranches = async () => {
const isActive = await plugin.call('manager', 'isActive', 'dgit') const isActive = await plugin.call('manager', 'isActive', 'dgit')
if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit') if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit')
plugin.call('menuicons', 'select', 'dgit') plugin.call('menuicons', 'select', 'dgit')
plugin.call('dgit', 'open', 'branches') plugin.call('dgit', 'open', gitUIPanels.BRANCHES)
} }
export const getGitConfig = async () => { export const getGitConfig = async () => {

Loading…
Cancel
Save