Compare commits

...

3 Commits

Author SHA1 Message Date
agent-company 937da1962b fix: remove go.sum from Dockerfile COPY since project has no external dependencies
The project uses only Go stdlib with zero external dependencies, so go.sum
does not exist. The Dockerfile COPY instruction fails when go.sum is missing.

Closes leeworks-agents/gitea-mobile#89

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:03:03 +00:00
AI-Manager 42a61b4428 Merge pull request 'feat: make repo selector searchable on create issue form' (#88) from feature/searchable-repo-selector-87 into master
Build and Push / test (push) Has been cancelled
Build and Push / build (push) Has been cancelled
2026-03-27 16:43:35 +00:00
agent-company 96b9ef2f89 feat: make repo selector searchable on create issue form
Replace the plain <select> with an HTML5 <input> + <datalist> 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) <noreply@anthropic.com>
2026-03-27 16:04:07 +00:00
2 changed files with 40 additions and 8 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
# Stage 1: Build # Stage 1: Build
FROM golang:1.22-alpine AS builder FROM golang:1.22-alpine AS builder
WORKDIR /app WORKDIR /app
COPY go.mod go.sum ./ COPY go.mod ./
RUN go mod download RUN go mod download
COPY . . COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /gitea-mobile ./cmd/server RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /gitea-mobile ./cmd/server
+39 -7
View File
@@ -6,16 +6,15 @@
<form id="create-issue-form" hx-post="/issues" hx-swap="innerHTML" hx-target="#main-content"> <form id="create-issue-form" hx-post="/issues" hx-swap="innerHTML" hx-target="#main-content">
<div class="form-group"> <div class="form-group">
<label for="repo-select">Repository</label> <label for="repo-select">Repository</label>
<select id="repo-select" name="owner_repo" required> <input list="repo-options" id="repo-select" name="owner_repo"
<option value="">Select a repository...</option> placeholder="Type to search repositories..." required autocomplete="off">
<datalist id="repo-options">
{{range $org, $repos := .Repos}} {{range $org, $repos := .Repos}}
<optgroup label="{{$org}}">
{{range $repos}} {{range $repos}}
<option value="{{.Owner.Login}}/{{.Name}}">{{.FullName}}</option> <option value="{{.Owner.Login}}/{{.Name}}">{{.FullName}}</option>
{{end}} {{end}}
</optgroup>
{{end}} {{end}}
</select> </datalist>
<input type="hidden" name="owner" id="owner-input"> <input type="hidden" name="owner" id="owner-input">
<input type="hidden" name="repo" id="repo-input"> <input type="hidden" name="repo" id="repo-input">
</div> </div>
@@ -45,9 +44,16 @@
var repoInput = document.getElementById('repo-input'); var repoInput = document.getElementById('repo-input');
var formError = document.getElementById('form-error'); 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() { function splitOwnerRepo() {
var val = repoSelect.value; var val = repoSelect.value;
if (val) { if (val && val.indexOf('/') !== -1) {
var parts = val.split('/'); var parts = val.split('/');
ownerInput.value = parts[0] || ''; ownerInput.value = parts[0] || '';
repoInput.value = parts[1] || ''; 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 = '<span class="empty">Loading labels...</span>';
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() { repoSelect.addEventListener('change', function() {
clearTimeout(debounceTimer);
splitOwnerRepo(); splitOwnerRepo();
var labelSection = document.getElementById('label-section'); var labelSection = document.getElementById('label-section');
var labelList = document.getElementById('label-list'); var labelList = document.getElementById('label-list');
if (ownerInput.value && repoInput.value) { if (ownerInput.value && repoInput.value && validRepos[repoSelect.value]) {
labelList.innerHTML = '<span class="empty">Loading labels...</span>'; labelList.innerHTML = '<span class="empty">Loading labels...</span>';
labelSection.style.display = 'block'; labelSection.style.display = 'block';
htmx.ajax('GET', '/issues/new/labels?owner=' + encodeURIComponent(ownerInput.value) + '&repo=' + encodeURIComponent(repoInput.value), {target: '#label-list', swap: 'innerHTML'}); 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'; formError.style.display = 'block';
return false; 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'; formError.style.display = 'none';
}); });