Skip to content

Commit 032cff0

Browse files
feat: enhanced byot ux.
1 parent 0d57885 commit 032cff0

4 files changed

Lines changed: 206 additions & 25 deletions

File tree

src/app.js

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const appGrid = document.querySelector('.app-grid')
2121
const githubAiControls = document.getElementById('github-ai-controls')
2222
const githubTokenInput = document.getElementById('github-token-input')
2323
const githubTokenInfo = document.getElementById('github-token-info')
24+
const githubTokenInfoPanel = document.getElementById('github-token-info-panel')
2425
const githubTokenAdd = document.getElementById('github-token-add')
2526
const githubTokenDelete = document.getElementById('github-token-delete')
2627
const githubRepoWrap = document.getElementById('github-repo-wrap')
@@ -110,6 +111,7 @@ const compactViewportMediaQuery = window.matchMedia('(max-width: 900px)')
110111
const stackedRailMediaQuery = window.matchMedia('(max-width: 1090px)')
111112
let stackedRailViewControlsOpen = false
112113
let compactAiControlsOpen = false
114+
let githubTokenInfoOpen = false
113115

114116
const isStackedRailViewport = () => stackedRailMediaQuery.matches
115117

@@ -139,13 +141,30 @@ const setStackedRailViewControlsOpen = isOpen => {
139141
viewControlsDrawer.setAttribute('hidden', '')
140142
}
141143

144+
const setGitHubTokenInfoOpen = isOpen => {
145+
if (!(githubTokenInfo instanceof HTMLButtonElement) || !githubTokenInfoPanel) {
146+
return
147+
}
148+
149+
githubTokenInfoOpen = Boolean(isOpen)
150+
githubTokenInfo.setAttribute('aria-expanded', githubTokenInfoOpen ? 'true' : 'false')
151+
152+
if (githubTokenInfoOpen) {
153+
githubTokenInfoPanel.removeAttribute('hidden')
154+
return
155+
}
156+
157+
githubTokenInfoPanel.setAttribute('hidden', '')
158+
}
159+
142160
const setCompactAiControlsOpen = isOpen => {
143161
if (!(aiControlsToggle instanceof HTMLButtonElement) || !githubAiControls) {
144162
return
145163
}
146164

147165
if (!aiAssistantFeatureEnabled) {
148166
compactAiControlsOpen = false
167+
setGitHubTokenInfoOpen(false)
149168
aiControlsToggle.setAttribute('hidden', '')
150169
aiControlsToggle.setAttribute('aria-expanded', 'false')
151170
githubAiControls.removeAttribute('data-compact-open')
@@ -157,6 +176,7 @@ const setCompactAiControlsOpen = isOpen => {
157176

158177
if (!isCompactViewport()) {
159178
compactAiControlsOpen = false
179+
setGitHubTokenInfoOpen(false)
160180
aiControlsToggle.setAttribute('aria-expanded', 'false')
161181
githubAiControls.removeAttribute('data-compact-open')
162182
githubAiControls.removeAttribute('hidden')
@@ -166,6 +186,10 @@ const setCompactAiControlsOpen = isOpen => {
166186
compactAiControlsOpen = Boolean(isOpen)
167187
aiControlsToggle.setAttribute('aria-expanded', compactAiControlsOpen ? 'true' : 'false')
168188
githubAiControls.dataset.compactOpen = compactAiControlsOpen ? 'true' : 'false'
189+
190+
if (!compactAiControlsOpen) {
191+
setGitHubTokenInfoOpen(false)
192+
}
169193
}
170194

171195
const getCurrentLayout = () => {
@@ -508,6 +532,15 @@ const byotControls = createGitHubByotControls({
508532
githubAiContextState.selectedRepository = repository
509533
chatDrawerController.setSelectedRepository(repository)
510534
},
535+
onTokenDeleteRequest: onConfirm => {
536+
confirmAction({
537+
title: 'Remove saved GitHub token?',
538+
copy: 'This action removes the token from browser storage. You can add another token at any time.',
539+
fallbackConfirmText:
540+
'Remove saved GitHub token? This action removes the token from browser storage.',
541+
onConfirm,
542+
})
543+
},
511544
onTokenChange: token => {
512545
githubAiContextState.token = token
513546
syncAiChatTokenVisibility(token)
@@ -943,17 +976,13 @@ const clearStylesSource = () => {
943976
maybeRender()
944977
}
945978

946-
const confirmClearSource = ({ label, onConfirm }) => {
979+
const confirmAction = ({ title, copy, fallbackConfirmText, onConfirm }) => {
947980
const supportsModalDialog =
948981
clearConfirmDialog instanceof HTMLDialogElement &&
949982
typeof clearConfirmDialog.showModal === 'function'
950983

951984
if (!supportsModalDialog) {
952-
if (
953-
window.confirm(
954-
`Clear ${label.toLowerCase()} source? This action will remove all text from the editor.`,
955-
)
956-
) {
985+
if (window.confirm(fallbackConfirmText)) {
957986
onConfirm()
958987
}
959988
return
@@ -964,18 +993,26 @@ const confirmClearSource = ({ label, onConfirm }) => {
964993
}
965994

966995
if (clearConfirmTitle) {
967-
clearConfirmTitle.textContent = `Clear ${label} source?`
996+
clearConfirmTitle.textContent = title
968997
}
969998

970999
if (clearConfirmCopy) {
971-
clearConfirmCopy.textContent =
972-
'This action will remove all text from the editor. This cannot be undone.'
1000+
clearConfirmCopy.textContent = copy
9731001
}
9741002

9751003
pendingClearAction = onConfirm
9761004
clearConfirmDialog.showModal()
9771005
}
9781006

1007+
const confirmClearSource = ({ label, onConfirm }) => {
1008+
confirmAction({
1009+
title: `Clear ${label} source?`,
1010+
copy: 'This action will remove all text from the editor. This cannot be undone.',
1011+
fallbackConfirmText: `Clear ${label.toLowerCase()} source? This action will remove all text from the editor.`,
1012+
onConfirm,
1013+
})
1014+
}
1015+
9791016
const copyTextToClipboard = async text => {
9801017
if (!clipboardSupported) {
9811018
throw new Error('Clipboard API is not available in this browser context.')
@@ -1186,6 +1223,13 @@ if (aiControlsToggle instanceof HTMLButtonElement) {
11861223
})
11871224
}
11881225

1226+
if (githubTokenInfo instanceof HTMLButtonElement && githubTokenInfoPanel) {
1227+
githubTokenInfo.addEventListener('click', event => {
1228+
event.preventDefault()
1229+
setGitHubTokenInfoOpen(!githubTokenInfoOpen)
1230+
})
1231+
}
1232+
11891233
document.addEventListener('click', event => {
11901234
const clickTarget = event.target
11911235
if (!(clickTarget instanceof Node)) {
@@ -1209,6 +1253,15 @@ document.addEventListener('click', event => {
12091253
setCompactAiControlsOpen(false)
12101254
}
12111255
}
1256+
1257+
if (githubTokenInfoOpen) {
1258+
if (
1259+
!githubTokenInfo?.contains(clickTarget) &&
1260+
!githubTokenInfoPanel?.contains(clickTarget)
1261+
) {
1262+
setGitHubTokenInfoOpen(false)
1263+
}
1264+
}
12121265
})
12131266

12141267
document.addEventListener('keydown', event => {
@@ -1218,6 +1271,7 @@ document.addEventListener('keydown', event => {
12181271

12191272
setStackedRailViewControlsOpen(false)
12201273
setCompactAiControlsOpen(false)
1274+
setGitHubTokenInfoOpen(false)
12211275
})
12221276

12231277
for (const button of editorToolsButtons) {
@@ -1277,6 +1331,7 @@ applyEditorToolsVisibility()
12771331
applyPanelCollapseState()
12781332
setStackedRailViewControlsOpen(false)
12791333
setCompactAiControlsOpen(false)
1334+
setGitHubTokenInfoOpen(false)
12801335
syncAiChatTokenVisibility(githubAiContextState.token)
12811336

12821337
updateRenderButtonVisibility()

src/index.html

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,33 @@ <h1>
4242
>
4343
<div class="github-token-control-wrap">
4444
<button
45-
class="hint-icon shadow-hint github-token-info"
45+
class="github-token-info"
4646
id="github-token-info"
4747
type="button"
48-
aria-label="About GitHub token"
49-
aria-describedby="github-token-privacy-note"
50-
data-tooltip="This token is stored only in your browser and is sent only to GitHub APIs you invoke."
48+
aria-label="About GitHub token features and privacy"
49+
aria-expanded="false"
50+
aria-controls="github-token-info-panel"
5151
>
5252
i
5353
</button>
54+
<div class="github-token-info-panel" id="github-token-info-panel" hidden>
55+
<p
56+
class="github-token-info-message github-token-info-message--missing-token"
57+
>
58+
Provide a GitHub PAT to open pull requests against your repos or chat with
59+
GitHub models. Read more about it in the
60+
<a
61+
href="https://github.com/knightedcodemonkey/develop/blob/main/docs/byot.md"
62+
target="_blank"
63+
rel="noreferrer noopener"
64+
>docs</a
65+
>.
66+
</p>
67+
<p class="github-token-info-message github-token-info-message--has-token">
68+
This token is stored only in your browser and is sent only to GitHub APIs
69+
you invoke. Use the trash icon to remove it from storage.
70+
</p>
71+
</div>
5472
<label class="sr-only" for="github-token-input">GitHub token</label>
5573
<input
5674
class="github-token-input"

src/modules/github-byot-controls.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const createGitHubByotControls = ({
5656
repoSelect,
5757
repoWrap,
5858
onRepositoryChange,
59+
onTokenDeleteRequest,
5960
onTokenChange,
6061
setStatus,
6162
}) => {
@@ -114,6 +115,22 @@ export const createGitHubByotControls = ({
114115
const hasProvidedToken =
115116
typeof savedToken === 'string' && savedToken.trim().length > 0
116117

118+
if (tokenInfoButton instanceof HTMLButtonElement) {
119+
tokenInfoButton.dataset.tokenState = hasProvidedToken ? 'present' : 'missing'
120+
tokenInfoButton.textContent = hasProvidedToken ? 'i' : '?'
121+
tokenInfoButton.setAttribute(
122+
'aria-label',
123+
hasProvidedToken
124+
? 'About GitHub token privacy'
125+
: 'About GitHub token features and privacy',
126+
)
127+
128+
const tokenControlWrap = tokenInfoButton.closest('.github-token-control-wrap')
129+
if (tokenControlWrap instanceof HTMLElement) {
130+
tokenControlWrap.dataset.tokenState = hasProvidedToken ? 'present' : 'missing'
131+
}
132+
}
133+
117134
if (tokenAddButton instanceof HTMLButtonElement) {
118135
tokenAddButton.hidden = hasProvidedToken
119136
}
@@ -413,7 +430,7 @@ export const createGitHubByotControls = ({
413430
void persistAndLoadToken(tokenInput.value)
414431
})
415432

416-
tokenDeleteButton?.addEventListener('click', () => {
433+
const removeSavedToken = () => {
417434
abortInFlightRepoRequest()
418435
clearAddButtonResetTimer()
419436
setTokenAddButtonState('idle')
@@ -426,6 +443,15 @@ export const createGitHubByotControls = ({
426443
onRepositoryChange?.(null)
427444
syncSavedTokenUi()
428445
setStatus('GitHub token removed', 'neutral')
446+
}
447+
448+
tokenDeleteButton?.addEventListener('click', () => {
449+
if (typeof onTokenDeleteRequest === 'function') {
450+
onTokenDeleteRequest(removeSavedToken)
451+
return
452+
}
453+
454+
removeSavedToken()
429455
})
430456

431457
tokenInfoButton?.setAttribute('aria-expanded', 'false')

0 commit comments

Comments
 (0)