Uploaded image for project: 'Project Quay'
  1. Project Quay
  2. PROJQUAY-10242

"Update Mirror" button should remain disabled when only toggle the "Enabled" checkbox

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Normal Normal
    • None
    • quay-v3.16.1
    • quay-ui
    • Security & Compliance
    • False
    • Hide

      None

      Show
      None
    • False

      Bug Summary

      The "Enabled" checkbox in Repository Mirroring applies changes immediately via API, but also incorrectly marks the form as dirty, causing the "Update Mirror" button to enable unnecessarily.

      Current Behavior (BUG)

      When toggling the "Enabled" checkbox:

      1. ✅ API call happens immediately (toggleMirroring called)
      2. ✅ Success message appears: "Mirror enabled/disabled successfully"
      3. BUG: "Update Mirror" button becomes enabled (form marked as dirty)
      4. ❌ User might click "Update Mirror" button again (re-applying same change unnecessarily)

      Expected Behavior

      When toggling the "Enabled" checkbox:

      1. ✅ API call happens immediately
      2. ✅ Success message appears
      3. ✅ Checkbox visual state updates
      4. ✅ "Update Mirror" button remains disabled (no pending changes - already applied!)

      The Problem

      Since the "Enabled" toggle already applies immediately via API:

      • There is nothing pending to update
      • The "Update Mirror" button should not enable
      • Clicking "Update Mirror" would re-submit the same enabled/disabled state (redundant)
      • This creates confusion: "The change already happened, why is the button enabled?"

      Steps to Reproduce

      1. Create repository with existing mirror configuration
      2. Navigate to Mirroring tab
      3. Observe "Update Mirror" button is disabled
      4. Uncheck the "Enabled" checkbox
      5. Observe:
        • ✅ Success message: "Mirror disabled successfully"
        • BUG: "Update Mirror" button becomes enabled
      6. Click "Update Mirror" button
      7. Observe: Another API call is made, re-applying the same disabled state (redundant)

      Expected Result (Step 5)

      • ✅ Success message appears
      • ✅ "Update Mirror" button remains disabled (no pending changes)

      Root Cause

      Code Location: /web/src/routes/RepositoryDetails/Mirroring/MirroringConfiguration.tsx:87-96

      Unable to find source-code formatter for language: typescript. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yamlcustomOnChange={async (checked, onChange) => {
        try {
          await toggleMirroring(namespace, repoName, checked);  // ← Immediate API call ✓
          onChange(checked);  // ← BUG: This marks form as dirty! ✗
          addAlert({
            variant: AlertVariant.Success,
            title: `Mirror ${checked ? 'enabled' : 'disabled'} successfully`,
          });
        } catch (err) {
          // ...
        }
      }}
      

      The Bug:

      • Line 90: onChange(checked) updates the form field value
      • React Hook Form sees this as a field change
      • Form is marked as "dirty" (isDirty: true)
      • "Update Mirror" button enables per the !formHook.isDirty check

      Code Location: /web/src/routes/RepositoryDetails/Mirroring/Mirroring.tsx:200-211

      Unable to find source-code formatter for language: typescript. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml<Button
        isDisabled={
          (configHook.config && !formHook.isDirty) ||  // ← Becomes false when form dirty
          // ... other validations
        }
      >
        Update Mirror
      </Button>
      

      Impact

      • Redundant API Calls: Users might click "Update Mirror" after toggling "Enabled", sending duplicate requests
      • User Confusion: "The change already applied, why is the button enabled?"
      • Inconsistent State: Form shows pending changes when nothing is actually pending
      • Poor UX: Users unsure if they need to click "Update Mirror" or not

      Proposed Fix

      Option 1: Don't call onChange (Recommended)

      Unable to find source-code formatter for language: typescript. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yamlcustomOnChange={async (checked, onChange) => {
        try {
          await toggleMirroring(namespace, repoName, checked);
          // DON'T call onChange(checked) - it marks form as dirty
          // Just update the checkbox visual state directly if needed
          addAlert({
            variant: AlertVariant.Success,
            title: `Mirror ${checked ? 'enabled' : 'disabled'} successfully`,
          });
        } catch (err) {
          // ...
        }
      }}
      

      Option 2: Reset form dirty state after immediate action

      Unable to find source-code formatter for language: typescript. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yamlcustomOnChange={async (checked, onChange) => {
        try {
          await toggleMirroring(namespace, repoName, checked);
          onChange(checked);
          formHook.reset(formHook.formValues);  // Reset dirty state
          addAlert({ ... });
        } catch (err) {
          // ...
        }
      }}
      

      Option 3: Separate immediate controls from form

      Move "Enabled" toggle outside the form as a standalone control, not part of the form submission flow.

      Additional Context

      • This creates confusion about when "Update Mirror" button should be used
      • Makes testing difficult (unclear what the expected button state should be)

      Acceptance Criteria

      • [ ] Toggling "Enabled" checkbox applies change immediately via API
      • [ ] "Update Mirror" button remains disabled after toggling "Enabled"
      • [ ] Form is NOT marked as dirty after toggling "Enabled"
      • [ ] Clicking "Update Mirror" does not re-submit the same enabled/disabled state
      • [ ] Test cases verify button stays disabled after immediate actions

              Unassigned Unassigned
              szhao@redhat.com Sean Zhao
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated: