Skip to content

Commit 3500596

Browse files
authored
Merge pull request desktop#17787 from desktop/settings-radio-button-announcments
Grouping our settings radio and checkbox groups.
2 parents d5968ff + 9fdbde2 commit 3500596

File tree

7 files changed

+206
-158
lines changed

7 files changed

+206
-158
lines changed

app/src/ui/lib/radio-group.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ interface IRadioGroupProps<T> {
2828
readonly onSelectionChanged: (key: T) => void
2929

3030
/** Render radio button label contents */
31-
readonly renderRadioButtonLabelContents: (key: T) => JSX.Element
31+
readonly renderRadioButtonLabelContents: (key: T) => JSX.Element | string
3232
}
3333

3434
/**

app/src/ui/lib/ref-name-text-box.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ interface IRefNameProps {
1919
*/
2020
readonly label?: string | JSX.Element
2121

22+
/**
23+
* The aria-labelledBy attribute for the text box.
24+
*/
25+
readonly ariaLabelledBy?: string
26+
2227
/**
2328
* The aria-describedby attribute for the text box.
2429
*/
@@ -89,6 +94,7 @@ export class RefNameTextBox extends React.Component<
8994
label={this.props.label}
9095
value={this.state.proposedValue}
9196
ref={this.textBoxRef}
97+
ariaLabelledBy={this.props.ariaLabelledBy}
9298
ariaDescribedBy={this.props.ariaDescribedBy}
9399
onValueChanged={this.onValueChange}
94100
onBlur={this.onBlur}

app/src/ui/lib/text-box.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ export interface ITextBoxProps {
9393
/** Optional aria-label attribute */
9494
readonly ariaLabel?: string
9595

96+
/** Optional aria-labelledby attribute */
97+
readonly ariaLabelledBy?: string
98+
9699
/** Optional aria-describedby attribute - usually for associating a descriptive
97100
* message to the input such as a validation error, warning, or caption */
98101
readonly ariaDescribedBy?: string
@@ -312,6 +315,7 @@ export class TextBox extends React.Component<ITextBoxProps, ITextBoxState> {
312315
onContextMenu={this.onContextMenu}
313316
spellCheck={this.props.spellcheck === true}
314317
aria-label={this.props.ariaLabel}
318+
aria-labelledby={this.props.ariaLabelledBy}
315319
aria-controls={this.props.ariaControls}
316320
aria-describedby={this.props.ariaDescribedBy}
317321
required={this.props.required}

app/src/ui/preferences/git.tsx

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import { DialogContent } from '../dialog'
33
import { SuggestedBranchNames } from '../../lib/helpers/default-branch'
44
import { RefNameTextBox } from '../lib/ref-name-text-box'
55
import { Ref } from '../lib/ref'
6-
import { RadioButton } from '../lib/radio-button'
76
import { LinkButton } from '../lib/link-button'
87
import { Account } from '../../models/account'
98
import { GitConfigUserForm } from '../lib/git-config-user-form'
9+
import { RadioGroup } from '../lib/radio-group'
10+
11+
const otherOption = 'Other…'
1012

1113
interface IGitProps {
1214
readonly name: string
@@ -118,32 +120,36 @@ export class Git extends React.Component<IGitProps, IGitState> {
118120
)
119121
}
120122

123+
private renderBranchNameOption = (branchName: string) => {
124+
return branchName === otherOption ? (
125+
<span id="other-branch-name-label">{branchName}</span>
126+
) : (
127+
branchName
128+
)
129+
}
130+
121131
private renderDefaultBranchSetting() {
122132
const { defaultBranchIsOther } = this.state
123133

134+
const branchNameOptions = [...SuggestedBranchNames, otherOption]
135+
const selectedKey = defaultBranchIsOther
136+
? otherOption
137+
: SuggestedBranchNames.find(n => n === this.props.defaultBranch) ??
138+
SuggestedBranchNames.at(0) ??
139+
otherOption // Should never happen, but TypeScript doesn't know that.
140+
124141
return (
125142
<div className="default-branch-component">
126-
<h2>Default branch name for new repositories</h2>
127-
128-
{SuggestedBranchNames.map((branchName: string, i: number) => (
129-
<RadioButton
130-
key={branchName}
131-
checked={
132-
(!defaultBranchIsOther &&
133-
this.props.defaultBranch === branchName) ||
134-
(this.props.isLoadingGitConfig && i === 0)
135-
}
136-
value={branchName}
137-
label={branchName}
138-
onSelected={this.onDefaultBranchChanged}
139-
/>
140-
))}
141-
<RadioButton
142-
key={OtherNameForDefaultBranch}
143-
checked={defaultBranchIsOther}
144-
value={OtherNameForDefaultBranch}
145-
label="Other…"
146-
onSelected={this.onDefaultBranchChanged}
143+
<h2 id="default-branch-heading">
144+
Default branch name for new repositories
145+
</h2>
146+
147+
<RadioGroup<string>
148+
ariaLabelledBy="default-branch-heading"
149+
selectedKey={selectedKey}
150+
radioButtonKeys={branchNameOptions}
151+
onSelectionChanged={this.onDefaultBranchChanged}
152+
renderRadioButtonLabelContents={this.renderBranchNameOption}
147153
/>
148154

149155
{defaultBranchIsOther && (
@@ -152,6 +158,7 @@ export class Git extends React.Component<IGitProps, IGitState> {
152158
renderWarningMessage={this.renderWarningMessage}
153159
onValueChange={this.props.onDefaultBranchChanged}
154160
ref={this.defaultBranchInputRef}
161+
ariaLabelledBy={'other-branch-name-label'}
155162
/>
156163
)}
157164

@@ -186,7 +193,9 @@ export class Git extends React.Component<IGitProps, IGitState> {
186193
defaultBranchIsOther: !SuggestedBranchNames.includes(defaultBranch),
187194
})
188195

189-
this.props.onDefaultBranchChanged(defaultBranch)
196+
this.props.onDefaultBranchChanged(
197+
defaultBranch === otherOption ? '' : defaultBranch
198+
)
190199
}
191200

192201
// This function is called to open the global git config file in the

app/src/ui/preferences/prompts.tsx

Lines changed: 112 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import * as React from 'react'
22
import { UncommittedChangesStrategy } from '../../models/uncommitted-changes-strategy'
33
import { DialogContent } from '../dialog'
44
import { Checkbox, CheckboxValue } from '../lib/checkbox'
5-
import { RadioButton } from '../lib/radio-button'
5+
import { RadioGroup } from '../lib/radio-group'
6+
import { assertNever } from '../../lib/fatal-error'
67

78
interface IPromptsPreferencesProps {
89
readonly confirmRepositoryRemoval: boolean
@@ -134,106 +135,121 @@ export class Prompts extends React.Component<
134135
this.props.onShowCommitLengthWarningChanged(event.currentTarget.checked)
135136
}
136137

138+
private renderSwitchBranchOptionLabel = (key: UncommittedChangesStrategy) => {
139+
switch (key) {
140+
case UncommittedChangesStrategy.AskForConfirmation:
141+
return 'Ask me where I want the changes to go'
142+
case UncommittedChangesStrategy.MoveToNewBranch:
143+
return 'Always bring my changes to my new branch'
144+
case UncommittedChangesStrategy.StashOnCurrentBranch:
145+
return 'Always stash and leave my changes on the current branch'
146+
default:
147+
return assertNever(key, `Unknown uncommitted changes strategy: ${key}`)
148+
}
149+
}
150+
151+
private renderSwitchBranchOptions = () => {
152+
const options = [
153+
UncommittedChangesStrategy.AskForConfirmation,
154+
UncommittedChangesStrategy.MoveToNewBranch,
155+
UncommittedChangesStrategy.StashOnCurrentBranch,
156+
]
157+
158+
const selectedKey =
159+
options.find(o => o === this.state.uncommittedChangesStrategy) ??
160+
UncommittedChangesStrategy.AskForConfirmation
161+
162+
return (
163+
<div className="advanced-section">
164+
<h2 id="switch-branch-heading">
165+
If I have changes and I switch branches...
166+
</h2>
167+
168+
<RadioGroup<UncommittedChangesStrategy>
169+
ariaLabelledBy="switch-branch-heading"
170+
selectedKey={selectedKey}
171+
radioButtonKeys={options}
172+
onSelectionChanged={this.onUncommittedChangesStrategyChanged}
173+
renderRadioButtonLabelContents={this.renderSwitchBranchOptionLabel}
174+
/>
175+
</div>
176+
)
177+
}
178+
137179
public render() {
138180
return (
139181
<DialogContent>
140182
<div className="advanced-section">
141-
<h2>Show a confirmation dialog before...</h2>
142-
<Checkbox
143-
label="Removing repositories"
144-
value={
145-
this.state.confirmRepositoryRemoval
146-
? CheckboxValue.On
147-
: CheckboxValue.Off
148-
}
149-
onChange={this.onConfirmRepositoryRemovalChanged}
150-
/>
151-
<Checkbox
152-
label="Discarding changes"
153-
value={
154-
this.state.confirmDiscardChanges
155-
? CheckboxValue.On
156-
: CheckboxValue.Off
157-
}
158-
onChange={this.onConfirmDiscardChangesChanged}
159-
/>
160-
<Checkbox
161-
label="Discarding changes permanently"
162-
value={
163-
this.state.confirmDiscardChangesPermanently
164-
? CheckboxValue.On
165-
: CheckboxValue.Off
166-
}
167-
onChange={this.onConfirmDiscardChangesPermanentlyChanged}
168-
/>
169-
<Checkbox
170-
label="Discarding stash"
171-
value={
172-
this.state.confirmDiscardStash
173-
? CheckboxValue.On
174-
: CheckboxValue.Off
175-
}
176-
onChange={this.onConfirmDiscardStashChanged}
177-
/>
178-
<Checkbox
179-
label="Checking out a commit"
180-
value={
181-
this.state.confirmCheckoutCommit
182-
? CheckboxValue.On
183-
: CheckboxValue.Off
184-
}
185-
onChange={this.onConfirmCheckoutCommitChanged}
186-
/>
187-
<Checkbox
188-
label="Force pushing"
189-
value={
190-
this.state.confirmForcePush ? CheckboxValue.On : CheckboxValue.Off
191-
}
192-
onChange={this.onConfirmForcePushChanged}
193-
/>
194-
<Checkbox
195-
label="Undo commit"
196-
value={
197-
this.state.confirmUndoCommit
198-
? CheckboxValue.On
199-
: CheckboxValue.Off
200-
}
201-
onChange={this.onConfirmUndoCommitChanged}
202-
/>
203-
</div>
204-
<div className="advanced-section">
205-
<h2>If I have changes and I switch branches...</h2>
206-
207-
<RadioButton
208-
value={UncommittedChangesStrategy.AskForConfirmation}
209-
checked={
210-
this.state.uncommittedChangesStrategy ===
211-
UncommittedChangesStrategy.AskForConfirmation
212-
}
213-
label="Ask me where I want the changes to go"
214-
onSelected={this.onUncommittedChangesStrategyChanged}
215-
/>
216-
217-
<RadioButton
218-
value={UncommittedChangesStrategy.MoveToNewBranch}
219-
checked={
220-
this.state.uncommittedChangesStrategy ===
221-
UncommittedChangesStrategy.MoveToNewBranch
222-
}
223-
label="Always bring my changes to my new branch"
224-
onSelected={this.onUncommittedChangesStrategyChanged}
225-
/>
226-
227-
<RadioButton
228-
value={UncommittedChangesStrategy.StashOnCurrentBranch}
229-
checked={
230-
this.state.uncommittedChangesStrategy ===
231-
UncommittedChangesStrategy.StashOnCurrentBranch
232-
}
233-
label="Always stash and leave my changes on the current branch"
234-
onSelected={this.onUncommittedChangesStrategyChanged}
235-
/>
183+
<h2 id="show-confirm-dialog-heading">
184+
Show a confirmation dialog before...
185+
</h2>
186+
<div role="group" aria-labelledby="show-confirm-dialog-heading">
187+
<Checkbox
188+
label="Removing repositories"
189+
value={
190+
this.state.confirmRepositoryRemoval
191+
? CheckboxValue.On
192+
: CheckboxValue.Off
193+
}
194+
onChange={this.onConfirmRepositoryRemovalChanged}
195+
/>
196+
<Checkbox
197+
label="Discarding changes"
198+
value={
199+
this.state.confirmDiscardChanges
200+
? CheckboxValue.On
201+
: CheckboxValue.Off
202+
}
203+
onChange={this.onConfirmDiscardChangesChanged}
204+
/>
205+
<Checkbox
206+
label="Discarding changes permanently"
207+
value={
208+
this.state.confirmDiscardChangesPermanently
209+
? CheckboxValue.On
210+
: CheckboxValue.Off
211+
}
212+
onChange={this.onConfirmDiscardChangesPermanentlyChanged}
213+
/>
214+
<Checkbox
215+
label="Discarding stash"
216+
value={
217+
this.state.confirmDiscardStash
218+
? CheckboxValue.On
219+
: CheckboxValue.Off
220+
}
221+
onChange={this.onConfirmDiscardStashChanged}
222+
/>
223+
<Checkbox
224+
label="Checking out a commit"
225+
value={
226+
this.state.confirmCheckoutCommit
227+
? CheckboxValue.On
228+
: CheckboxValue.Off
229+
}
230+
onChange={this.onConfirmCheckoutCommitChanged}
231+
/>
232+
<Checkbox
233+
label="Force pushing"
234+
value={
235+
this.state.confirmForcePush
236+
? CheckboxValue.On
237+
: CheckboxValue.Off
238+
}
239+
onChange={this.onConfirmForcePushChanged}
240+
/>
241+
<Checkbox
242+
label="Undo commit"
243+
value={
244+
this.state.confirmUndoCommit
245+
? CheckboxValue.On
246+
: CheckboxValue.Off
247+
}
248+
onChange={this.onConfirmUndoCommitChanged}
249+
/>
250+
</div>
236251
</div>
252+
{this.renderSwitchBranchOptions()}
237253
<div className="advanced-section">
238254
<h2>Commit Length</h2>
239255
<Checkbox

0 commit comments

Comments
 (0)