From 96b9ef2f89ca53d84dadd71b086dea9deb1090a3 Mon Sep 17 00:00:00 2001 From: agent-company Date: Fri, 27 Mar 2026 16:04:07 +0000 Subject: [PATCH] feat: make repo selector searchable on create issue form Replace the plain + pair so users can type to filter repositories. Add debounced input handler for label loading, change event for direct datalist selection, and client-side validation that the entered value is a known repository. Closes leeworks-agents/gitea-mobile#87 Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/templates/create_issue.html | 46 +++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/internal/templates/create_issue.html b/internal/templates/create_issue.html index 6668a00..550aa6b 100644 --- a/internal/templates/create_issue.html +++ b/internal/templates/create_issue.html @@ -6,16 +6,15 @@
- + {{range $org, $repos := .Repos}} - {{range $repos}} {{end}} - {{end}} - +
@@ -45,9 +44,16 @@ var repoInput = document.getElementById('repo-input'); var formError = document.getElementById('form-error'); + // Build a set of valid repo values for validation. + var validRepos = {}; + var options = document.getElementById('repo-options').options; + for (var i = 0; i < options.length; i++) { + validRepos[options[i].value] = true; + } + function splitOwnerRepo() { var val = repoSelect.value; - if (val) { + if (val && val.indexOf('/') !== -1) { var parts = val.split('/'); ownerInput.value = parts[0] || ''; repoInput.value = parts[1] || ''; @@ -57,11 +63,31 @@ } } + var debounceTimer = null; + repoSelect.addEventListener('input', function() { + clearTimeout(debounceTimer); + debounceTimer = setTimeout(function() { + splitOwnerRepo(); + var labelSection = document.getElementById('label-section'); + var labelList = document.getElementById('label-list'); + if (ownerInput.value && repoInput.value && validRepos[repoSelect.value]) { + labelList.innerHTML = 'Loading labels...'; + labelSection.style.display = 'block'; + htmx.ajax('GET', '/issues/new/labels?owner=' + encodeURIComponent(ownerInput.value) + '&repo=' + encodeURIComponent(repoInput.value), {target: '#label-list', swap: 'innerHTML'}); + } else { + labelSection.style.display = 'none'; + labelList.innerHTML = ''; + } + }, 300); + }); + + // Also handle the change event for when a datalist option is selected directly. repoSelect.addEventListener('change', function() { + clearTimeout(debounceTimer); splitOwnerRepo(); var labelSection = document.getElementById('label-section'); var labelList = document.getElementById('label-list'); - if (ownerInput.value && repoInput.value) { + if (ownerInput.value && repoInput.value && validRepos[repoSelect.value]) { labelList.innerHTML = 'Loading labels...'; labelSection.style.display = 'block'; htmx.ajax('GET', '/issues/new/labels?owner=' + encodeURIComponent(ownerInput.value) + '&repo=' + encodeURIComponent(repoInput.value), {target: '#label-list', swap: 'innerHTML'}); @@ -80,6 +106,12 @@ formError.style.display = 'block'; return false; } + if (!validRepos[repoSelect.value]) { + evt.preventDefault(); + formError.textContent = 'Please select a valid repository from the list.'; + formError.style.display = 'block'; + return false; + } formError.style.display = 'none'; });