Skip to content

UX: Add bulk operations interface and operation queue #77

@sfloess

Description

@sfloess

Overview

Add a comprehensive bulk operations UI for selecting, reviewing, and executing operations on multiple components at once.

Current State

  • ✅ Regex-based bulk delete
  • ✅ Multi-select in Swing GUI
  • ❌ No operation queue
  • ❌ No saved selections
  • ❌ No bulk move/copy/tag

UX Score Impact

Current: UX A (94/100)
With #75 + this + #77: UX A+ (99/100)

Proposed Features

1. Bulk Selection Interface

Swing GUI Enhancement:

// New "Selection" menu
JMenu selectionMenu = new JMenu("Selection");

JMenuItem selectAllItem = new JMenuItem("Select All");
JMenuItem selectByFilterItem = new JMenuItem("Select by Filter...");
JMenuItem invertSelectionItem = new JMenuItem("Invert Selection");
JMenuItem saveSelectionItem = new JMenuItem("Save Selection...");
JMenuItem loadSelectionItem = new JMenuItem("Load Selection...");

Select by Filter Dialog:

┌─ Select Components by Criteria ────────────────┐
│                                                 │
│  Size Range:                                    │
│    Min: [1000000      ] bytes (1 MB)            │
│    Max: [100000000    ] bytes (100 MB)          │
│                                                 │
│  Date Range:                                    │
│    Created After:  [2024-01-01        ]         │
│    Created Before: [2025-01-01        ]         │
│                                                 │
│  File Type:                                     │
│    Extension: [.jar              ]              │
│                                                 │
│  Content Type:                                  │
│    [application/java-archive      ]             │
│                                                 │
│  Results: Will select 1,234 components          │
│                                                 │
│  [Cancel]                 [Select]              │
└─────────────────────────────────────────────────┘

2. Saved Selections

Storage Format (JSON):

{
  "name": "Large JARs",
  "description": "JAR files over 10 MB",
  "repository": "maven-releases",
  "filters": {
    "minSize": 10485760,
    "extension": ".jar"
  },
  "savedAt": "2026-05-28T10:30:00Z",
  "componentCount": 1234
}

Location:

Load Saved Selection:

  1. File → Load Selection
  2. Choose from list of saved selections
  3. Apply filters automatically
  4. Components selected in table

3. Operation Queue

Concept: Queue multiple operations, review, execute all at once.

┌─ Operation Queue ──────────────────────────────┐
│                                                 │
│  Queued Operations:                             │
│                                                 │
│  1. [Delete] 150 components from maven-releases │
│     → Filter: .*SNAPSHOT.*                      │
│     → Size: <1 MB                               │
│                                                 │
│  2. [Delete] 45 components from npm-public      │
│     → Created before: 2025-01-01                │
│                                                 │
│  3. [Export] Statistics for maven-releases      │
│     → Format: JSON                              │
│                                                 │
│  Total Impact:                                  │
│    - Components to delete: 195                  │
│    - Disk space to free: 12.3 MB                │
│                                                 │
│  [Clear Queue]  [Execute All]  [Export Queue]   │
└─────────────────────────────────────────────────┘

Implementation:

public class OperationQueue {
    private final List<QueuedOperation> operations = new ArrayList<>();
    
    public interface QueuedOperation {
        String describe();  // "Delete 150 components from maven-releases"
        void execute() throws IOException, InterruptedException;
        void undo();  // If possible
    }
    
    public void add(QueuedOperation op) {
        operations.add(op);
    }
    
    public void executeAll(ProgressCallback callback) {
        int total = operations.size();
        for (int i = 0; i < operations.size(); i++) {
            callback.onProgress(i + 1, total, operations.get(i).describe());
            operations.get(i).execute();
        }
        operations.clear();
    }
}

4. Bulk Operations (Beyond Delete)

Bulk Move (Future Nexus API Support):

jnexus move --from maven-snapshots --to maven-releases --regex '.*-RELEASE\.jar'
# Move release artifacts that were mistakenly uploaded to snapshots

Bulk Tag/Label (If Nexus Supports):

jnexus tag my-repo --regex '.*security.*' --tag security-critical
# Add tag to security-related artifacts

Bulk Export:

jnexus export my-repo --regex '.*\.jar' --to /backup/jars/
# Export all JARs to local directory

Note: These operations depend on Nexus API capabilities. Document as "Future Enhancements" if API doesn't support.

5. CLI Bulk File Support

Concept: Read component IDs from file for bulk operations.

# Create file with component IDs (one per line)
cat > to-delete.txt <<EOF
component-id-1
component-id-2
component-id-3
EOF

# Delete from file
jnexus delete --from-file to-delete.txt

# Or use previous export
jnexus delete --from-export deleted-2026-05-28.json

Implementation:

@Option(names = "--from-file", description = "Read component IDs from file")
private Path inputFile;

@Option(names = "--from-export", description = "Use components from export file")
private Path exportFile;

void execute() {
    List<String> componentIds;
    
    if (inputFile != null) {
        componentIds = Files.readAllLines(inputFile);
    } else if (exportFile != null) {
        ExportedDeletion export = objectMapper.readValue(exportFile.toFile(), ExportedDeletion.class);
        componentIds = export.components().stream()
            .map(Component::id)
            .toList();
    } else {
        // Use regex/filter as before
    }
    
    for (String id : componentIds) {
        client.deleteComponent(id);
    }
}

6. Selection Templates

Predefined Filters for Common Tasks:

enum SelectionTemplate {
    LARGE_FILES("Large Files (>100 MB)", 
        SearchCriteria.builder().minSize(100_000_000L).build()),
    
    OLD_SNAPSHOTS("Old SNAPSHOTs (>90 days)",
        SearchCriteria.builder()
            .regexFilter(".*SNAPSHOT.*")
            .createdBefore(Instant.now().minus(Duration.ofDays(90)))
            .build()),
    
    ORPHANED_POMS("Orphaned POMs (no matching JAR)",
        SearchCriteria.builder()
            .fileExtension(".pom")
            .build()),  // Would need additional logic to check for matching JAR
    
    RECENT_UPLOADS("Recent Uploads (<7 days)",
        SearchCriteria.builder()
            .createdAfter(Instant.now().minus(Duration.ofDays(7)))
            .build());
    
    private final String displayName;
    private final SearchCriteria criteria;
    
    // Apply template
    public void apply(NexusService service, String repository) {
        return service.searchComponents(criteria.toBuilder().repository(repository).build());
    }
}

GUI Usage:

Selection → Templates → Old SNAPSHOTs (>90 days)
# Auto-populates filters and selects matching components

Example Workflows

Workflow 1: Clean Old SNAPSHOTs Across Multiple Repos

1. Selection → Templates → Old SNAPSHOTs (>90 days)
2. Select repository: maven-snapshots
3. Review: 450 components selected
4. Operations → Add to Queue → Delete
5. Switch repository: npm-snapshots
6. Review: 120 components selected
7. Operations → Add to Queue → Delete
8. Operations → View Queue (570 total)
9. Operations → Execute All

Workflow 2: Export Large Files for Analysis

1. Selection → Select by Filter
2. Min Size: 100 MB
3. Select: 1,234 components
4. Operations → Export List → large-files.json
5. Analyze large-files.json externally
6. Create custom deletion list
7. CLI: jnexus delete --from-file custom-list.txt

Workflow 3: Scheduled Cleanup Script

#!/bin/bash
# cleanup-old-snapshots.sh

# Export components to delete (for audit trail)
jnexus list maven-snapshots --regex '.*SNAPSHOT.*' \
    --created-before 2025-01-01 \
    --export snapshot-cleanup-2026-05-28.json

# Delete (with dry-run first)
jnexus delete maven-snapshots \
    --from-export snapshot-cleanup-2026-05-28.json \
    --dry-run

# Review dry-run output, then:
jnexus delete maven-snapshots \
    --from-export snapshot-cleanup-2026-05-28.json \
    --yes

Configuration

# Max operations in queue (default: 100)
nexus.operations.queue.max=100

# Selections directory
nexus.selections.directory=~/.flossware/nexus/selections/

# Enable operation templates (default: true)
nexus.operations.templates.enabled=true

Testing

@Test
void testOperationQueue() {
    OperationQueue queue = new OperationQueue();
    
    queue.add(new DeleteOperation("id1", client));
    queue.add(new DeleteOperation("id2", client));
    
    assertEquals(2, queue.size());
    
    queue.executeAll((current, total, desc) -> 
        System.out.println(current + "/" + total + ": " + desc));
    
    assertEquals(0, queue.size());  // Cleared after execution
}

@Test
void testSelectionTemplates() {
    SearchCriteria criteria = SelectionTemplate.OLD_SNAPSHOTS.getCriteria();
    assertTrue(criteria.regexFilter().contains("SNAPSHOT"));
    assertNotNull(criteria.createdBefore());
}

Acceptance Criteria

  • Selection menu added to Swing GUI
  • Select by filter dialog implemented
  • Save/load selection functionality
  • Operation queue UI created
  • CLI --from-file support added
  • CLI --from-export support added
  • Selection templates implemented (5+ templates)
  • Queue execution with progress callback
  • Tests for queue and selections
  • User guide section added

Priority

Low - Power user feature, not essential

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions