Simplified Git Trigger Picker & Dev Mock
Version: 3.1.0 Date: 2026-06-12
Goal: The Git step of the workflow editor exposed too much complexity at once (Push/Tag radio, branch/tag pattern with wildcards, no business explanation), confusing users who just wanted to "protect every release". Replace it with a one-click default, an explicit live preview, and coherent add/remove semantics.
Solution: New TriggerSelector component with two modes — simple (default, "Every tagged release") and advanced (Customize: Tag / Push toggle + wildcard pattern field with three concrete live examples). The ProjectFormatter add/remove semantics were reworked to emit a backend-clean shape and stay backward-compatible with every historical config shape.
Features:
- Default trigger is "Every tagged release" — one click on Add registers
{ name: 'tag' }(match all tags) - Customize link reveals the advanced picker (Tag / Push toggle + wildcard pattern); Use simple mode returns to default
- Pattern input supports Enter to submit
- Reserved-space preview block (no layout shift): 3 concrete examples that change with the wildcard
- Helper text "Select a repository first." next to the Add button when no repo is picked
- Repository-events table keeps a one-line layout with tag/branch icon + label, pattern chips, and an info tooltip (480 px) with summary + 3 examples
- The
ALLchip (every-tag mode) exposes a delete button
Implementation Details:
ProjectFormatterrefactored:addEvents(params, type, pattern?),removeEvent(key, type, index)(drops the event entry when the last pattern is removed),removeEventEntry(key, type), and.cleanalways emits{ name: 'tag' }for ALL or{ name: 'tag', pattern: [...] }for specifics- Backward-compatible hydrate (
ProjectFormatter.for) tolerates{ name: 'tag' },{ pattern: [] }, legacy{ pattern: [''] }, and mixed{ pattern: ['v*', ''] } - New helpers:
eventSummary.ts(summarize) andtriggerExamples.ts(triggerExamples, regex-safe wildcard substitution) ProjectFormattertest coverage grew from 15 to 21 cases
Dev-only mock for "Test connection": a surgical mock for discoverProjects only, active by default in vite dev, persisted per-developer in localStorage, with a "Use mock data (dev only)" switch. Tree-shaken from production builds.
Files Modified:
ui/src/utils/format.ts- optionalpatternparam, strict add/remove semantics, legacy-tolerant hydrate,removeEventEntryui/src/utils/format.test.ts- expanded coverage (legacy shapes, ALL-overwrite, drop-on-empty)ui/src/utils/eventSummary.ts(new) +eventSummary.test.ts(new)ui/src/utils/triggerExamples.ts(new) +triggerExamples.test.ts(new)ui/src/pages/workflows/stepForms/TriggerSelector.tsx(new)ui/src/pages/workflows/stepForms/StepGitForm.tsx- useTriggerSelectorui/src/pages/workflows/stepForms/StepStorageForm.tsx- drop "Remove empty patterns" workaroundui/src/pages/workflows/display.tsx- tag/branch icons, info tooltip, ALL chip deleteui/src/protocol/dev-mocks/devMocks.ts(new) +discoverMock.ts(new)ui/src/protocol/tower.api.ts-discoverProjectsdev-mock short-circuitui/src/pages/workflows/stepForms/StepInitForm.tsx- dev-mock switch + "(mock data)" suffixui/e2e/workflow-creation.spec.ts- adapted to advanced-mode entry path