Implement GitConfig Setting section within Repository Settings

This commit is contained in:
say25pp 2020-04-10 00:19:51 -05:00 committed by Sergio Padrino
parent 1a414d0797
commit 6516c35121
3 changed files with 236 additions and 1 deletions

View file

@ -111,6 +111,18 @@ export async function getGlobalConfigPath(env?: {
return normalize(path[1])
}
/** Set the local config value by name. */
export async function setConfigValue(
repository: Repository,
name: string,
value: string,
env?: {
HOME: string
}
): Promise<void> {
setConfigValueInPath(name, value, repository.path, env)
}
/** Set the global config value by name. */
export async function setGlobalConfigValue(
name: string,

View file

@ -0,0 +1,107 @@
import * as React from 'react'
import { DialogContent } from '../dialog'
import { TextBox } from '../lib/text-box'
import { Row } from '../lib/row'
interface IGitConfigProps {
readonly gitConfigLocation: GitConfigLocation
readonly name: string
readonly email: string
readonly globalName: string
readonly globalEmail: string
readonly onGitConfigLocationChanged: (value: GitConfigLocation) => void
readonly onNameChanged: (name: string) => void
readonly onEmailChanged: (email: string) => void
}
interface IGitConfigState {
readonly gitConfigLocation: GitConfigLocation
}
export enum GitConfigLocation {
Global = 'Global',
Local = 'Local',
}
/** A view for creating or modifying the repository's gitignore file */
export class GitConfig extends React.Component<
IGitConfigProps,
IGitConfigState
> {
public constructor(props: IGitConfigProps) {
super(props)
this.state = {
gitConfigLocation: this.props.gitConfigLocation,
}
}
private onGitConfigLocationChanged = (
event: React.FormEvent<HTMLInputElement>
) => {
const value = event.currentTarget.value as GitConfigLocation
this.setState({ gitConfigLocation: value })
this.props.onGitConfigLocationChanged(value)
}
public render() {
return (
<DialogContent>
<div className="advanced-section">
<h2>For this repository I wish to</h2>
<div className="radio-component">
<input
type="radio"
id={GitConfigLocation.Global}
value={GitConfigLocation.Global}
checked={
this.state.gitConfigLocation === GitConfigLocation.Global
}
onChange={this.onGitConfigLocationChanged}
/>
<label htmlFor={GitConfigLocation.Global}>
Use my global Git config
</label>
</div>
<div className="radio-component">
<input
type="radio"
id={GitConfigLocation.Local}
value={GitConfigLocation.Local}
checked={this.state.gitConfigLocation === GitConfigLocation.Local}
onChange={this.onGitConfigLocationChanged}
/>
<label htmlFor={GitConfigLocation.Local}>
Use a local Git config
</label>
</div>
</div>
<Row>
<TextBox
label="Name"
value={
this.state.gitConfigLocation === GitConfigLocation.Global
? this.props.globalName
: this.props.name
}
onValueChanged={this.props.onNameChanged}
disabled={this.state.gitConfigLocation === GitConfigLocation.Global}
/>
</Row>
<Row>
<TextBox
label="Email"
value={
this.state.gitConfigLocation === GitConfigLocation.Global
? this.props.globalEmail
: this.props.email
}
onValueChanged={this.props.onEmailChanged}
disabled={this.state.gitConfigLocation === GitConfigLocation.Global}
/>
</Row>
</DialogContent>
)
}
}

View file

@ -18,6 +18,16 @@ import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
import { ForkSettings } from './fork-settings'
import { ForkContributionTarget } from '../../models/workflow-preferences'
import { enableForkSettings } from '../../lib/feature-flag'
import { GitConfigLocation, GitConfig } from './git-config'
import {
getConfigValue,
getGlobalConfigValue,
setConfigValue,
} from '../../lib/git/config'
import {
gitAuthorNameIsValid,
invalidGitAuthorNameMessage,
} from '../lib/identifier-rules'
interface IRepositorySettingsProps {
readonly dispatcher: Dispatcher
@ -30,6 +40,7 @@ enum RepositorySettingsTab {
Remote = 0,
IgnoredFiles,
ForkSettings,
GitConfig,
}
interface IRepositorySettingsState {
@ -38,6 +49,14 @@ interface IRepositorySettingsState {
readonly ignoreText: string | null
readonly ignoreTextHasChanged: boolean
readonly disabled: boolean
readonly saveDisabled: boolean
readonly gitConfigLocation: GitConfigLocation
readonly committerName: string
readonly committerEmail: string
readonly globalCommitterName: string
readonly globalCommitterEmail: string
readonly initialCommitterName: string | null
readonly initialCommitterEmail: string | null
readonly errors?: ReadonlyArray<JSX.Element | string>
readonly forkContributionTarget: ForkContributionTarget
}
@ -56,6 +75,14 @@ export class RepositorySettings extends React.Component<
ignoreTextHasChanged: false,
disabled: false,
forkContributionTarget: getForkContributionTarget(props.repository),
saveDisabled: false,
gitConfigLocation: GitConfigLocation.Global,
committerName: '',
committerEmail: '',
globalCommitterName: '',
globalCommitterEmail: '',
initialCommitterName: null,
initialCommitterEmail: null,
}
}
@ -70,6 +97,38 @@ export class RepositorySettings extends React.Component<
)
this.setState({ errors: [`Could not read root .gitignore: ${e}`] })
}
const initialCommitterName = await getConfigValue(
this.props.repository,
'user.name'
)
const initialCommitterEmail = await getConfigValue(
this.props.repository,
'user.email'
)
const globalCommitterName = (await getGlobalConfigValue('user.name')) || ''
const globalCommitterEmail =
(await getGlobalConfigValue('user.email')) || ''
let gitConfigLocation =
initialCommitterName === globalCommitterName &&
initialCommitterEmail === globalCommitterEmail
? GitConfigLocation.Global
: GitConfigLocation.Local
let committerName = initialCommitterName || ''
let committerEmail = initialCommitterEmail || ''
this.setState({
gitConfigLocation,
committerName,
committerEmail,
globalCommitterName,
globalCommitterEmail,
initialCommitterName,
initialCommitterEmail,
})
}
private renderErrors(): JSX.Element[] | null {
@ -111,6 +170,7 @@ export class RepositorySettings extends React.Component<
{showForkSettings && (
<span>{__DARWIN__ ? 'Fork Behavior' : 'Fork behavior'}</span>
)}
<span>{__DARWIN__ ? 'Git Config' : 'Git config'}</span>
</TabBar>
<div className="active-tab">{this.renderActiveTab()}</div>
@ -129,7 +189,10 @@ export class RepositorySettings extends React.Component<
return (
<DialogFooter>
<OkCancelButtonGroup okButtonText="Save" />
<OkCancelButtonGroup
okButtonText="Save"
okButtonDisabled={this.state.saveDisabled}
/>
</DialogFooter>
)
}
@ -174,6 +237,22 @@ export class RepositorySettings extends React.Component<
/>
)
}
case RepositorySettingsTab.GitConfig: {
return (
<GitConfig
gitConfigLocation={this.state.gitConfigLocation}
onGitConfigLocationChanged={this.onGitConfigLocationChanged}
name={this.state.committerName}
email={this.state.committerEmail}
globalName={this.state.globalCommitterName}
globalEmail={this.state.globalCommitterEmail}
onNameChanged={this.onCommitterNameChanged}
onEmailChanged={this.onCommitterEmailChanged}
/>
)
}
}
default:
return assertNever(tab, `Unknown tab type: ${tab}`)
}
@ -238,6 +317,23 @@ export class RepositorySettings extends React.Component<
...this.props.repository.workflowPreferences,
forkContributionTarget: this.state.forkContributionTarget,
}
if (this.state.committerName !== this.state.initialCommitterName) {
await setConfigValue(
this.props.repository,
'user.name',
this.state.gitConfigLocation === GitConfigLocation.Global
? this.state.globalCommitterName
: this.state.committerName
)
}
if (this.state.committerEmail !== this.state.initialCommitterEmail) {
await setConfigValue(
this.props.repository,
'user.email',
this.state.gitConfigLocation === GitConfigLocation.Global
? this.state.globalCommitterEmail
: this.state.committerEmail
)
}
@ -273,5 +369,25 @@ export class RepositorySettings extends React.Component<
this.setState({
forkContributionTarget,
})
private onGitConfigLocationChanged = (value: GitConfigLocation) => {
this.setState({ gitConfigLocation: value })
}
private onCommitterNameChanged = (committerName: string) => {
const errors = new Array<JSX.Element | string>()
if (gitAuthorNameIsValid(committerName)) {
this.setState({ saveDisabled: false })
} else {
this.setState({ saveDisabled: true })
errors.push(invalidGitAuthorNameMessage)
}
this.setState({ committerName, errors })
}
private onCommitterEmailChanged = (committerEmail: string) => {
this.setState({ committerEmail })
}
}