feat: add target organization to Add Repository dialog (#202)

* feat: add target organization field to Add Repository dialog

Allow users to specify a destination Gitea organization when adding a
single repository, instead of relying solely on the default mirror
strategy. The field is optional — when left empty, the existing strategy
logic applies as before.

Closes #200

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add screenshot of target organization field in Add Repository dialog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ARUNAVO RAY
2026-03-01 07:55:27 +05:30
committed by GitHub
parent 2e00a610cb
commit be46cfdffa
5 changed files with 37 additions and 3 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -18,10 +18,12 @@ interface AddRepositoryDialogProps {
repo,
owner,
force,
destinationOrg,
}: {
repo: string;
owner: string;
force?: boolean;
destinationOrg?: string;
}) => Promise<void>;
}
@@ -32,6 +34,7 @@ export default function AddRepositoryDialog({
}: AddRepositoryDialogProps) {
const [repo, setRepo] = useState<string>("");
const [owner, setOwner] = useState<string>("");
const [destinationOrg, setDestinationOrg] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string>("");
@@ -40,6 +43,7 @@ export default function AddRepositoryDialog({
setError("");
setRepo("");
setOwner("");
setDestinationOrg("");
}
}, [isDialogOpen]);
@@ -54,11 +58,16 @@ export default function AddRepositoryDialog({
try {
setIsLoading(true);
await onAddRepository({ repo, owner });
await onAddRepository({
repo,
owner,
destinationOrg: destinationOrg.trim() || undefined,
});
setError("");
setRepo("");
setOwner("");
setDestinationOrg("");
setIsDialogOpen(false);
} catch (err: any) {
setError(err?.message || "Failed to add repository.");
@@ -124,6 +133,27 @@ export default function AddRepositoryDialog({
/>
</div>
<div>
<label
htmlFor="destinationOrg"
className="block text-sm font-medium mb-1.5"
>
Target Organization{" "}
<span className="text-muted-foreground font-normal">
(optional)
</span>
</label>
<input
id="destinationOrg"
type="text"
value={destinationOrg}
onChange={(e) => setDestinationOrg(e.target.value)}
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
placeholder="Gitea org or user (uses default strategy if empty)"
autoComplete="off"
/>
</div>
{error && <p className="text-sm text-red-500 mt-1">{error}</p>}
</div>

View File

@@ -698,10 +698,12 @@ export default function Repository() {
repo,
owner,
force = false,
destinationOrg,
}: {
repo: string;
owner: string;
force?: boolean;
destinationOrg?: string;
}) => {
if (!user || !user.id) {
return;
@@ -736,6 +738,7 @@ export default function Repository() {
repo: trimmedRepo,
owner: trimmedOwner,
force,
...(destinationOrg ? { destinationOrg } : {}),
};
const response = await apiRequest<AddRepositoriesApiResponse>(

View File

@@ -20,7 +20,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
const userId = authResult.userId;
const body: AddRepositoriesApiRequest = await request.json();
const { owner, repo, force = false } = body;
const { owner, repo, force = false, destinationOrg } = body;
if (!owner || !repo) {
return new Response(
@@ -122,7 +122,7 @@ export const POST: APIRoute = async ({ request, locals }) => {
lastMirrored: existingRepo?.lastMirrored ?? null,
errorMessage: existingRepo?.errorMessage ?? null,
mirroredLocation: existingRepo?.mirroredLocation ?? "",
destinationOrg: existingRepo?.destinationOrg ?? null,
destinationOrg: destinationOrg?.trim() || existingRepo?.destinationOrg || null,
updatedAt: repoData.updated_at
? new Date(repoData.updated_at)
: new Date(),

View File

@@ -83,6 +83,7 @@ export interface AddRepositoriesApiRequest {
repo: string;
owner: string;
force?: boolean;
destinationOrg?: string;
}
export interface AddRepositoriesApiResponse {