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

Quay 3.17 New UI should hide Proxy Cache, Immutability, and Auto-Prune policy when organization in Mirror State

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Critical Critical
    • None
    • quay-v3.17.0
    • quay-ui
    • None
    • False
    • Hide

      None

      Show
      None
    • False

      UI Enhancement: Hide Incompatible Policy Options for Org-Mirrored Repositories

      Related Issues: PROJQUAY-10040 (Organization Mirroring), PROJQUAY-10672 (Credential Exposure)
      Component: New UI (React)
      Priority: Major

      Problem Statement

      When a Quay organization has Organization Mirroring enabled (is in "Mirror state"), the new UI currently shows repository policy configuration options that are incompatible with organization mirroring:

      1. Proxy Cache - Mutually exclusive with org mirroring
      2. Immutability Policy - Breaks mirror sync (prevents tag updates)
      3. Auto-Prune Policy - Conflicts with mirroring (creates sync/delete cycles)

      Users can attempt to configure these policies, leading to:

      • ❌ Configuration errors and confusion
      • ❌ Broken mirror sync functionality
      • ❌ Wasted bandwidth (auto-prune deleting mirrored images)
      • ❌ Poor user experience

      Current Behavior

      New UI shows ALL repository settings regardless of org mirror state, allowing users to configure incompatible features.

      Expected Behavior

      When a repository is part of an active organization mirror:

      • ❌ HIDE: Proxy Cache settings tab
      • ❌ HIDE: Immutability Policy settings tab
      • ❌ HIDE: Auto-Prune Policy settings tab
      • ✅ SHOW: Banner indicating repository is org-mirrored
      • ✅ SHOW: "Mirroring (Managed by Org)" as read-only

      Implementation Requirements

      Frontend Changes

      New Hook: web/src/hooks/UseOrgMirror.ts

      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
      export function useIsOrgMirroredRepo(orgName: string, repoName: string) {
        const {orgMirror} = useOrgMirror(orgName);
        const {discoveredRepos} = useDiscoveredRepos(orgName);
        
        const isOrgMirrored = useMemo(() => {
          if (!orgMirror?.is_enabled) return false;
          return discoveredRepos?.some(
            repo => repo.repository_name === repoName
          ) ?? false;
        }, [orgMirror, discoveredRepos, repoName]);
        
        return {isOrgMirrored, orgMirrorConfig: orgMirror};
      }
      

      Settings Page: web/src/routes/RepositoryDetails/Settings/Settings.tsx

      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
      export function RepositorySettings() {
        const {isOrgMirrored} = useIsOrgMirroredRepo(org, repo);
        
        return (
          <SettingsNav>
            <NavItem to="general">General</NavItem>
            <NavItem to="access">Access</NavItem>
            
            {/* Hide incompatible features */}
            {!isOrgMirrored && (
              <>
                <NavItem to="proxy-cache">Proxy Cache</NavItem>
                <NavItem to="immutability">Immutability</NavItem>
                <NavItem to="auto-prune">Auto-Prune</NavItem>
              </>
            )}
          </SettingsNav>
        );
      }
      

      Route Guards: Add guards to each policy settings page to block direct URL access

      Files to Modify

      1. web/src/hooks/UseOrgMirror.ts
      2. web/src/routes/RepositoryDetails/Settings/Settings.tsx
      3. web/src/routes/RepositoryDetails/Settings/ProxyCache.tsx
      4. web/src/routes/RepositoryDetails/Settings/Immutability.tsx
      5. web/src/routes/RepositoryDetails/Settings/AutoPrune.tsx
      6. web/src/routes/OrganizationsList/Organization/Tabs/Mirroring/OrgMirroringConfig.tsx

      Acceptance Criteria

      AC1: Proxy Cache, Immutability, and Auto-Prune tabs are HIDDEN for org-mirrored repositories

      AC2: Direct URL access to hidden features shows "Feature Not Available" error page

      AC3: Repository settings shows banner: "This repository is managed by org mirror"

      AC4: Organization mirroring page shows warning about disabled features

      AC5: Mirroring tab shown as read-only: "Mirroring (Managed by Org)"

      AC6: When org mirror disabled, all policy options become available

      AC7: Non-mirrored repos in same org show all options normally

      User Flow

      Step 1: User enables org mirror
        POST /api/v1/organization/myorg/mirror
      
      Step 2: Worker discovers 50 repositories
      
      Step 3: User navigates to mirrored repo settings
        URL: /repository/myorg/discovered-app/settings
      
      Expected:
        ┌───────────────────────────────────┐
        │ 🔄 Org-Mirrored Repository        │
        │ Source: harbor.example.com/...    │
        └───────────────────────────────────┘
        
        Settings:
        ├─ General ✅
        ├─ Access ✅
        ├─ Mirroring (Managed by Org) 🔒
        └─ [Proxy/Immutability/Auto-Prune HIDDEN]
      
      Step 4: User tries direct URL
        URL: /repository/myorg/app/settings/proxy-cache
        
        Result: "Feature Not Available" error page
      

      Testing

      Unit Tests:

      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
      describe('useIsOrgMirroredRepo', () => {
        it('returns true for org-mirrored repo');
        it('returns false for non-mirrored repo');
        it('returns false when org mirror disabled');
      });
      

      E2E Tests:

      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
      it('hides policy options for mirrored repos', () => {
        cy.visit('/repository/testorg/mirrored-app/settings');
        cy.contains('Proxy Cache').should('not.exist');
        cy.contains('Immutability').should('not.exist');
        cy.contains('Auto-Prune').should('not.exist');
      });
      
      it('blocks direct URL access', () => {
        cy.visit('/repository/testorg/mirrored-app/settings/proxy-cache');
        cy.contains('Feature Not Available').should('exist');
      });
      

      Why This Matters

      • ✅ Prevents user confusion
      • ✅ Avoids misconfiguration
      • ✅ Reduces support tickets
      • ✅ Follows UX best practices
      • ✅ Low implementation effort
      • ✅ Critical for PROJQUAY-10040 usability

      Alternative Approaches

      Option 1: Show but disable (NOT recommended)

      • Creates clutter
      • Users confused why disabled

      Option 2: Show with error on save (NOT recommended)

      • Bad UX
      • Wastes user time

      Option 3: Hide completely (RECOMMENDED)

      • Clean UI
      • Prevents mistakes
      • Clear expectations

              Unassigned Unassigned
              lzha1981 luffy zhang
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated: