@@ -282,12 +282,14 @@ export function OAuthConsentModal() {
282282
283283 /**
284284 * Create or pick a machine, link it to the client, then approve OAuth consent.
285+ * Machine assignment is optional: leaving the picker on "No machine" (and not
286+ * mid-way through creating a new one) just approves without tagging a machine.
285287 */
286288 const handleNameAndAllow = async ( ) => {
287289 if ( modalState . type !== 'name-machine' ) return ;
288290 const { details, machines } = modalState ;
289291
290- let machineId = selectedMachineId ;
292+ let machineId : string | null = selectedMachineId || null ;
291293 if ( creatingMachine ) {
292294 const missingField = getMissingMachineProfileField ( {
293295 name : machineName ,
@@ -298,10 +300,7 @@ export function OAuthConsentModal() {
298300 setProcessError ( t ( `oauthConsent.nameMachine.${ missingField } Required` ) ) ;
299301 return ;
300302 }
301- } else if ( ! machineId ) {
302- setProcessError ( t ( 'oauthConsent.nameMachine.nameRequired' ) ) ;
303- return ;
304- } else {
303+ } else if ( machineId ) {
305304 const selected = machines . find ( ( machine ) => machine . id === machineId ) ;
306305 if ( selected && ! isMachineRowComplete ( selected ) ) {
307306 setProcessError ( t ( 'oauthConsent.nameMachine.profileIncomplete' ) ) ;
@@ -324,7 +323,9 @@ export function OAuthConsentModal() {
324323 machineId = created . id ;
325324 }
326325
327- await setClientMachineId ( details . clientId , machineId ) ;
326+ if ( machineId ) {
327+ await setClientMachineId ( details . clientId , machineId ) ;
328+ }
328329 await finishApproval ( details ) ;
329330 } catch ( err ) {
330331 console . error ( '[OAuth] Failed to name machine and approve:' , err ) ;
@@ -334,6 +335,28 @@ export function OAuthConsentModal() {
334335 }
335336 } ;
336337
338+ /**
339+ * Skip machine assignment entirely and approve, regardless of whatever the
340+ * picker/create sub-form currently holds. The one-tap escape hatch for
341+ * "I don't care which machine this is" or getting unstuck mid-create.
342+ */
343+ const handleSkipMachine = async ( ) => {
344+ if ( modalState . type !== 'name-machine' ) return ;
345+ const { details } = modalState ;
346+
347+ setIsProcessing ( true ) ;
348+ setProcessError ( null ) ;
349+
350+ try {
351+ await finishApproval ( details ) ;
352+ } catch ( err ) {
353+ console . error ( '[OAuth] Failed to skip machine and approve:' , err ) ;
354+ setProcessError ( String ( err ) ) ;
355+ } finally {
356+ setIsProcessing ( false ) ;
357+ }
358+ } ;
359+
337360 const handleDeny = async ( ) => {
338361 if ( modalState . type !== 'consent' && modalState . type !== 'name-machine' ) return ;
339362 const { details } = modalState ;
@@ -438,9 +461,13 @@ export function OAuthConsentModal() {
438461 const { details, machines } = modalState ;
439462 const createDraft = { name : machineName , icon : machineIcon , hostname : machineHostname } ;
440463 const selectedMachine = machines . find ( ( machine ) => machine . id === selectedMachineId ) ;
464+ // Machine assignment is optional — picking nothing is valid (approves
465+ // untagged). Only an in-progress "create new machine" sub-form or an
466+ // incomplete existing machine profile blocks submission.
441467 const canSubmit = creatingMachine
442468 ? isMachineProfileComplete ( createDraft )
443- : selectedMachineId . length > 0 && selectedMachine != null && isMachineRowComplete ( selectedMachine ) ;
469+ : selectedMachineId . length === 0 ||
470+ ( selectedMachine != null && isMachineRowComplete ( selectedMachine ) ) ;
444471
445472 return (
446473 < div className = "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm" >
@@ -559,6 +586,14 @@ export function OAuthConsentModal() {
559586 < X className = "mr-2 h-4 w-4" />
560587 { t ( 'oauthConsent.deny' ) }
561588 </ Button >
589+ < button
590+ type = "button"
591+ onClick = { ( ) => void handleSkipMachine ( ) }
592+ disabled = { isProcessing || ! approveReady }
593+ className = "text-center text-xs text-[rgb(var(--muted))] transition-colors hover:text-[rgb(var(--foreground))] disabled:opacity-50"
594+ >
595+ { t ( 'oauthConsent.nameMachine.skipBtn' ) }
596+ </ button >
562597 </ div >
563598 </ CardContent >
564599 </ Card >
0 commit comments