feat(KAN-38): rebuild personal Git connection settings
This commit is contained in:
@@ -731,4 +731,43 @@ export const en = {
|
||||
'ticketForm.saved': 'All changes saved',
|
||||
'ticketForm.authorRestricted': 'Only project admins can change the author.',
|
||||
'ticketForm.blocker': 'Blocker',
|
||||
'gitConnections.description':
|
||||
'Connect your personal Git account to browse repositories, branches, and pull requests you can access.',
|
||||
'gitConnections.privacy':
|
||||
'Connections belong to your account. Saved tokens stay hidden. Without a matching connection, only repository names are available.',
|
||||
'gitConnections.add': 'Add connection',
|
||||
'gitConnections.editAction': 'Edit',
|
||||
'gitConnections.edit': 'Edit connection',
|
||||
'gitConnections.remove': 'Remove',
|
||||
'gitConnections.removeTitle': 'Remove connection',
|
||||
'gitConnections.saved': 'Saved connections',
|
||||
'gitConnections.empty': 'No Git connections yet',
|
||||
'gitConnections.emptyDescription':
|
||||
'Add a Gitea connection to access your repositories and their Git activity.',
|
||||
'gitConnections.unnamedAccount': 'Unnamed remote account',
|
||||
'gitConnections.remoteId': 'Remote user ID: {id}',
|
||||
'gitConnections.editAccount': 'Edit {account} at {server}',
|
||||
'gitConnections.removeAccount': 'Remove {account} at {server}',
|
||||
'gitConnections.addDescription':
|
||||
'Connect a Gitea account using its server URL and a personal application token.',
|
||||
'gitConnections.editDescription':
|
||||
'Update the server URL and enter a fresh token to verify this connection.',
|
||||
'gitConnections.removeDescription':
|
||||
'Remove this personal connection? Repository links remain, but Git activity will require another matching connection.',
|
||||
'gitConnections.gitea': 'Gitea',
|
||||
'gitConnections.baseUrl': 'Gitea base URL',
|
||||
'gitConnections.token': 'Application token',
|
||||
'gitConnections.newToken': 'New application token',
|
||||
'gitConnections.tokenPlaceholder': 'Paste your Gitea application token',
|
||||
'gitConnections.tokenHelp':
|
||||
'Your token is verified with Gitea before saving. It is never shown in the saved connection.',
|
||||
'gitConnections.verifying': 'Verifying connection…',
|
||||
'gitConnections.save': 'Save changes',
|
||||
'gitConnections.removing': 'Removing connection…',
|
||||
'gitConnections.forbidden': 'Connection access denied',
|
||||
'gitConnections.forbiddenDescription':
|
||||
'You can only manage connections belonging to your account. Close this dialog and refresh the page.',
|
||||
'gitConnections.added': 'Git connection added.',
|
||||
'gitConnections.updated': 'Git connection updated.',
|
||||
'gitConnections.removed': 'Git connection removed.',
|
||||
} as const;
|
||||
|
||||
@@ -1,267 +1,493 @@
|
||||
<script setup lang="ts">
|
||||
import { Form, Head, usePage } from '@inertiajs/vue3';
|
||||
import GitConnectionController from '@/actions/App/Http/Controllers/Settings/GitConnectionController';
|
||||
import Heading from '@/components/Heading.vue';
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import {
|
||||
GitBranch,
|
||||
LockKeyhole,
|
||||
Pencil,
|
||||
Plus,
|
||||
Server,
|
||||
Trash2,
|
||||
} from 'lucide-vue-next';
|
||||
import { computed, ref } from 'vue';
|
||||
import {
|
||||
destroy,
|
||||
store,
|
||||
update,
|
||||
} from '@/actions/App/Http/Controllers/Settings/GitConnectionController';
|
||||
import FeedbackState from '@/components/FeedbackState.vue';
|
||||
import FormFeedback from '@/components/FormFeedback.vue';
|
||||
import InputError from '@/components/InputError.vue';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@/components/ui/card';
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useFormProtection } from '@/composables/useFormProtection';
|
||||
import { useLocalization } from '@/composables/useLocalization';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import SettingsLayout from '@/layouts/settings/Layout.vue';
|
||||
import { edit as editGitConnections } from '@/routes/git-connections/index';
|
||||
import { edit } from '@/routes/git-connections/index';
|
||||
import type { BreadcrumbItem, SettingsGitConnectionsPageProps } from '@/types';
|
||||
import type { UserGitConnectionModel } from '@/types/models/user-git-connection-model';
|
||||
|
||||
defineProps<SettingsGitConnectionsPageProps>();
|
||||
const props = defineProps<SettingsGitConnectionsPageProps>();
|
||||
const { t } = useLocalization();
|
||||
const breadcrumbItems = computed<BreadcrumbItem[]>(() => [
|
||||
{ title: t('navigation.gitConnections'), href: edit() },
|
||||
]);
|
||||
const mode = ref<'create' | 'edit' | 'remove'>('create');
|
||||
const dialogOpen = ref(false);
|
||||
const selectedConnection = ref<UserGitConnectionModel | null>(null);
|
||||
// Keep provider credentials out of Inertia's remembered browser history.
|
||||
const connectionForm = useForm({
|
||||
provider: 'gitea',
|
||||
base_url: '',
|
||||
api_token: '',
|
||||
});
|
||||
const connectionProtection = useFormProtection(connectionForm);
|
||||
const removalForm = useForm({});
|
||||
const removalProtection = useFormProtection(removalForm);
|
||||
const processing = computed(
|
||||
() => connectionForm.processing || removalForm.processing,
|
||||
);
|
||||
const dialogTitle = computed(() =>
|
||||
t(
|
||||
mode.value === 'create'
|
||||
? 'gitConnections.add'
|
||||
: mode.value === 'edit'
|
||||
? 'gitConnections.edit'
|
||||
: 'gitConnections.removeTitle',
|
||||
),
|
||||
);
|
||||
const successTitle = computed(() =>
|
||||
props.status === 'Git connection was added.'
|
||||
? t('gitConnections.added')
|
||||
: props.status === 'Git connection was updated.'
|
||||
? t('gitConnections.updated')
|
||||
: t('gitConnections.removed'),
|
||||
);
|
||||
|
||||
const page = usePage();
|
||||
const appName = String(page.props.name);
|
||||
function resetForms(): void {
|
||||
connectionForm.defaults({ provider: 'gitea', base_url: '', api_token: '' });
|
||||
connectionForm.resetAndClearErrors();
|
||||
connectionProtection.clearFeedback();
|
||||
removalForm.resetAndClearErrors();
|
||||
removalProtection.clearFeedback();
|
||||
}
|
||||
|
||||
const breadcrumbItems: BreadcrumbItem[] = [
|
||||
{
|
||||
title: 'Git connections',
|
||||
href: editGitConnections(),
|
||||
},
|
||||
];
|
||||
function openDialog(
|
||||
nextMode: typeof mode.value,
|
||||
connection: UserGitConnectionModel | null = null,
|
||||
): void {
|
||||
resetForms();
|
||||
mode.value = nextMode;
|
||||
selectedConnection.value = connection;
|
||||
connectionForm.defaults({
|
||||
provider: connection?.provider ?? 'gitea',
|
||||
base_url: connection?.base_url ?? '',
|
||||
api_token: '',
|
||||
});
|
||||
connectionForm.reset();
|
||||
dialogOpen.value = true;
|
||||
}
|
||||
|
||||
function closeDialog(open: boolean): void {
|
||||
if (open || processing.value || !connectionProtection.confirmLeave()) {
|
||||
return;
|
||||
}
|
||||
dialogOpen.value = false;
|
||||
resetForms();
|
||||
}
|
||||
|
||||
function finish(): void {
|
||||
resetForms();
|
||||
dialogOpen.value = false;
|
||||
}
|
||||
|
||||
function saveConnection(): void {
|
||||
const target =
|
||||
mode.value === 'edit' && selectedConnection.value
|
||||
? update(selectedConnection.value.id)
|
||||
: store();
|
||||
connectionProtection.submit(target, {
|
||||
preserveScroll: true,
|
||||
onSuccess: finish,
|
||||
});
|
||||
}
|
||||
|
||||
function removeConnection(): void {
|
||||
if (!selectedConnection.value) {
|
||||
return;
|
||||
}
|
||||
removalProtection.submit(destroy(selectedConnection.value.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: finish,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout :breadcrumbs="breadcrumbItems">
|
||||
<Head title="Git connections" />
|
||||
|
||||
<Head :title="t('navigation.gitConnections')" />
|
||||
<SettingsLayout>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="space-y-2">
|
||||
<Heading
|
||||
variant="small"
|
||||
title="Git connections"
|
||||
description="Add your personal Git provider credentials here. Project repository links will use these connections to fetch repositories, branches, and pull requests you can access."
|
||||
/>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
Each user needs their own application key. Without a
|
||||
matching personal connection, {{ appName }} can only
|
||||
show repository names and will link you back to this
|
||||
page.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="status"
|
||||
class="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-900 dark:border-emerald-900/70 dark:bg-emerald-950/40 dark:text-emerald-100"
|
||||
<Card
|
||||
class="min-w-0 gap-0 overflow-hidden rounded-xl py-0 shadow-none"
|
||||
>
|
||||
<CardHeader
|
||||
class="gap-column min-w-0 grid-cols-1 border-b p-5 sm:p-6"
|
||||
>
|
||||
{{ status }}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 xl:grid-cols-[24rem_minmax(0,1fr)]">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Add Gitea connection</CardTitle>
|
||||
<CardDescription>
|
||||
Connect a Gitea account by storing the instance
|
||||
base URL and a personal application token.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<Form
|
||||
v-bind="GitConnectionController.store.form()"
|
||||
class="space-y-4"
|
||||
v-slot="{ errors, processing }"
|
||||
>
|
||||
<input
|
||||
name="provider"
|
||||
type="hidden"
|
||||
value="gitea"
|
||||
/>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="base_url">Gitea base URL</Label>
|
||||
<Input
|
||||
id="base_url"
|
||||
name="base_url"
|
||||
type="url"
|
||||
required
|
||||
autofocus
|
||||
placeholder="https://git.example.com"
|
||||
/>
|
||||
<InputError :message="errors.base_url" />
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="api_token"
|
||||
>Application token</Label
|
||||
>
|
||||
<Input
|
||||
id="api_token"
|
||||
name="api_token"
|
||||
type="password"
|
||||
required
|
||||
placeholder="Paste your Gitea application key"
|
||||
/>
|
||||
<InputError :message="errors.api_token" />
|
||||
</div>
|
||||
|
||||
<Button type="submit" :disabled="processing">
|
||||
Add connection
|
||||
</Button>
|
||||
</Form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card class="gap-0 overflow-hidden">
|
||||
<CardHeader class="border-b">
|
||||
<CardTitle>Saved connections</CardTitle>
|
||||
<CardDescription>
|
||||
Tokens stay hidden after save. Updating a
|
||||
connection requires entering a fresh token.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent class="space-y-4 p-6">
|
||||
<div
|
||||
v-if="gitConnections.length === 0"
|
||||
class="border-border text-muted-foreground rounded-xl border border-dashed px-4 py-6 text-sm"
|
||||
>
|
||||
No Git connections have been added yet.
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="gitConnection in gitConnections"
|
||||
:key="gitConnection.id"
|
||||
class="border-border rounded-xl border p-4"
|
||||
>
|
||||
<div
|
||||
class="flex min-w-0 flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"
|
||||
>
|
||||
<div class="gap-stack grid min-w-0">
|
||||
<h2 class="text-title">
|
||||
{{ t('navigation.gitConnections') }}
|
||||
</h2>
|
||||
<p class="text-muted-foreground">
|
||||
{{ t('gitConnections.description') }}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
class="shrink-0 self-start"
|
||||
@click="openDialog('create')"
|
||||
>
|
||||
<Plus aria-hidden="true" />{{
|
||||
t('gitConnections.add')
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
class="bg-muted/45 text-caption text-muted-foreground flex items-start gap-2 rounded-lg border p-3"
|
||||
>
|
||||
<LockKeyhole
|
||||
class="text-primary mt-0.5 size-4 shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p>{{ t('gitConnections.privacy') }}</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent class="gap-column grid min-w-0 p-5 sm:p-6">
|
||||
<FeedbackState
|
||||
v-if="status"
|
||||
state="success"
|
||||
:title="successTitle"
|
||||
/>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<h3 class="font-semibold">
|
||||
{{ t('gitConnections.saved') }}
|
||||
</h3>
|
||||
<Badge variant="secondary">{{
|
||||
gitConnections.length
|
||||
}}</Badge>
|
||||
</div>
|
||||
<FeedbackState
|
||||
v-if="gitConnections.length === 0"
|
||||
state="empty"
|
||||
:title="t('gitConnections.empty')"
|
||||
:description="t('gitConnections.emptyDescription')"
|
||||
/>
|
||||
<ul
|
||||
v-else
|
||||
class="gap-column grid min-w-0"
|
||||
:aria-label="t('gitConnections.saved')"
|
||||
>
|
||||
<li
|
||||
v-for="connection in gitConnections"
|
||||
:key="connection.id"
|
||||
class="gap-column grid min-w-0 rounded-lg border p-4"
|
||||
>
|
||||
<div class="flex min-w-0 items-start gap-3">
|
||||
<div
|
||||
class="mb-4 flex flex-wrap items-start justify-between gap-3"
|
||||
class="bg-accent text-primary flex size-10 shrink-0 items-center justify-center rounded-lg"
|
||||
>
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
class="flex flex-wrap items-center gap-2"
|
||||
<GitBranch
|
||||
class="size-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="gap-stack grid min-w-0 flex-1">
|
||||
<div
|
||||
class="flex min-w-0 flex-wrap items-center gap-2"
|
||||
>
|
||||
<h4
|
||||
class="min-w-0 break-all font-semibold"
|
||||
>
|
||||
<Badge>{{
|
||||
gitConnection.provider_label
|
||||
}}</Badge>
|
||||
<span class="text-sm font-medium">
|
||||
{{
|
||||
gitConnection.account_login
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<p
|
||||
class="text-muted-foreground text-sm"
|
||||
>
|
||||
{{
|
||||
gitConnection.account_name ??
|
||||
'Unnamed remote account'
|
||||
}}
|
||||
</p>
|
||||
<p
|
||||
class="text-muted-foreground text-xs"
|
||||
>
|
||||
{{ gitConnection.base_url }}
|
||||
</p>
|
||||
{{ connection.account_login }}
|
||||
</h4>
|
||||
<Badge variant="secondary">{{
|
||||
connection.provider_label
|
||||
}}</Badge>
|
||||
</div>
|
||||
|
||||
<p class="text-muted-foreground text-xs">
|
||||
Remote user ID:
|
||||
{{ gitConnection.provider_user_id }}
|
||||
<p
|
||||
class="text-caption text-muted-foreground break-words"
|
||||
>
|
||||
{{
|
||||
connection.account_name ??
|
||||
t('gitConnections.unnamedAccount')
|
||||
}}
|
||||
</p>
|
||||
<div
|
||||
class="text-caption text-muted-foreground flex min-w-0 items-start gap-2"
|
||||
>
|
||||
<Server
|
||||
class="mt-0.5 size-4 shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span class="min-w-0 break-all">{{
|
||||
connection.base_url
|
||||
}}</span>
|
||||
</div>
|
||||
<p
|
||||
class="text-caption text-muted-foreground break-all"
|
||||
>
|
||||
{{
|
||||
t('gitConnections.remoteId', {
|
||||
id: connection.provider_user_id,
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Form
|
||||
v-bind="
|
||||
GitConnectionController.update.form(
|
||||
gitConnection.id,
|
||||
)
|
||||
"
|
||||
class="grid gap-4"
|
||||
v-slot="{ errors, processing }"
|
||||
>
|
||||
<input
|
||||
name="provider"
|
||||
type="hidden"
|
||||
:value="gitConnection.provider"
|
||||
/>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label
|
||||
:for="`base-url-${gitConnection.id}`"
|
||||
>
|
||||
Gitea base URL
|
||||
</Label>
|
||||
<Input
|
||||
:id="`base-url-${gitConnection.id}`"
|
||||
name="base_url"
|
||||
type="url"
|
||||
:default-value="
|
||||
gitConnection.base_url
|
||||
"
|
||||
required
|
||||
/>
|
||||
<InputError
|
||||
:message="errors.base_url"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label
|
||||
:for="`token-${gitConnection.id}`"
|
||||
>
|
||||
New application token
|
||||
</Label>
|
||||
<Input
|
||||
:id="`token-${gitConnection.id}`"
|
||||
name="api_token"
|
||||
type="password"
|
||||
required
|
||||
placeholder="Paste a new token to verify and save"
|
||||
/>
|
||||
<InputError
|
||||
:message="errors.api_token"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-wrap justify-between gap-3"
|
||||
>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
:disabled="processing"
|
||||
>
|
||||
Save changes
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
<Form
|
||||
v-bind="
|
||||
GitConnectionController.destroy.form(
|
||||
gitConnection.id,
|
||||
)
|
||||
"
|
||||
class="mt-3 flex justify-end"
|
||||
v-slot="{ processing }"
|
||||
>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="destructive"
|
||||
:disabled="processing"
|
||||
>
|
||||
Remove connection
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-wrap gap-2 border-t pt-3 sm:justify-end"
|
||||
>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
:aria-label="
|
||||
t('gitConnections.editAccount', {
|
||||
account: connection.account_login,
|
||||
server: connection.base_url,
|
||||
})
|
||||
"
|
||||
@click="openDialog('edit', connection)"
|
||||
>
|
||||
<Pencil aria-hidden="true" />{{
|
||||
t('gitConnections.editAction')
|
||||
}}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
:aria-label="
|
||||
t('gitConnections.removeAccount', {
|
||||
account: connection.account_login,
|
||||
server: connection.base_url,
|
||||
})
|
||||
"
|
||||
@click="openDialog('remove', connection)"
|
||||
>
|
||||
<Trash2 aria-hidden="true" />{{
|
||||
t('gitConnections.remove')
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Dialog :open="dialogOpen" @update:open="closeDialog">
|
||||
<DialogContent
|
||||
:show-close-button="!processing"
|
||||
@escape-key-down="processing && $event.preventDefault()"
|
||||
@interact-outside="processing && $event.preventDefault()"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ dialogTitle }}</DialogTitle>
|
||||
<DialogDescription>{{
|
||||
t(
|
||||
mode === 'remove'
|
||||
? 'gitConnections.removeDescription'
|
||||
: mode === 'edit'
|
||||
? 'gitConnections.editDescription'
|
||||
: 'gitConnections.addDescription',
|
||||
)
|
||||
}}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form
|
||||
v-if="mode !== 'remove'"
|
||||
class="gap-column grid min-w-0"
|
||||
:aria-busy="connectionForm.processing"
|
||||
@submit.prevent="saveConnection"
|
||||
>
|
||||
<FormFeedback
|
||||
:state="connectionProtection.state.value"
|
||||
:title="
|
||||
connectionProtection.responseStatus.value ===
|
||||
403
|
||||
? t('gitConnections.forbidden')
|
||||
: connectionForm.processing
|
||||
? t('gitConnections.verifying')
|
||||
: undefined
|
||||
"
|
||||
:description="
|
||||
connectionProtection.responseStatus.value ===
|
||||
403
|
||||
? t('gitConnections.forbiddenDescription')
|
||||
: undefined
|
||||
"
|
||||
:retryable="
|
||||
connectionProtection.responseStatus.value !==
|
||||
403
|
||||
"
|
||||
@retry="saveConnection"
|
||||
/>
|
||||
<fieldset
|
||||
class="gap-column grid min-w-0"
|
||||
:disabled="connectionForm.processing"
|
||||
>
|
||||
<legend class="sr-only">{{ dialogTitle }}</legend>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
class="justify-self-start"
|
||||
>{{ t('gitConnections.gitea') }}</Badge
|
||||
>
|
||||
<InputError
|
||||
:message="connectionForm.errors.provider"
|
||||
/>
|
||||
<div class="grid gap-2">
|
||||
<Label for="git-base-url">{{
|
||||
t('gitConnections.baseUrl')
|
||||
}}</Label>
|
||||
<Input
|
||||
id="git-base-url"
|
||||
v-model="connectionForm.base_url"
|
||||
name="base_url"
|
||||
type="url"
|
||||
required
|
||||
placeholder="https://git.example.com"
|
||||
autocomplete="url"
|
||||
:aria-invalid="
|
||||
!!connectionForm.errors.base_url
|
||||
"
|
||||
aria-describedby="git-base-url-error"
|
||||
/>
|
||||
<InputError
|
||||
id="git-base-url-error"
|
||||
:message="connectionForm.errors.base_url"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="git-token">{{
|
||||
t(
|
||||
mode === 'edit'
|
||||
? 'gitConnections.newToken'
|
||||
: 'gitConnections.token',
|
||||
)
|
||||
}}</Label>
|
||||
<Input
|
||||
id="git-token"
|
||||
v-model="connectionForm.api_token"
|
||||
name="api_token"
|
||||
type="password"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
:placeholder="
|
||||
t('gitConnections.tokenPlaceholder')
|
||||
"
|
||||
:aria-invalid="
|
||||
!!connectionForm.errors.api_token
|
||||
"
|
||||
aria-describedby="git-token-help git-token-error"
|
||||
/>
|
||||
<p
|
||||
id="git-token-help"
|
||||
class="text-caption text-muted-foreground"
|
||||
>
|
||||
{{ t('gitConnections.tokenHelp') }}
|
||||
</p>
|
||||
<InputError
|
||||
id="git-token-error"
|
||||
:message="connectionForm.errors.api_token"
|
||||
/>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
@click="closeDialog(false)"
|
||||
>{{ t('common.cancel') }}</Button
|
||||
>
|
||||
<Button type="submit">{{
|
||||
t(
|
||||
connectionForm.processing
|
||||
? 'gitConnections.verifying'
|
||||
: mode === 'edit'
|
||||
? 'gitConnections.save'
|
||||
: 'gitConnections.add',
|
||||
)
|
||||
}}</Button>
|
||||
</DialogFooter>
|
||||
</fieldset>
|
||||
</form>
|
||||
<form
|
||||
v-else
|
||||
class="gap-column grid min-w-0"
|
||||
:aria-busy="removalForm.processing"
|
||||
@submit.prevent="removeConnection"
|
||||
>
|
||||
<div
|
||||
class="bg-destructive/8 border-destructive/25 text-body grid min-w-0 gap-2 rounded-lg border p-4"
|
||||
>
|
||||
<p class="break-all font-semibold">
|
||||
{{ selectedConnection?.account_login }}
|
||||
</p>
|
||||
<p class="text-muted-foreground break-all">
|
||||
{{ selectedConnection?.base_url }}
|
||||
</p>
|
||||
</div>
|
||||
<FormFeedback
|
||||
:state="removalProtection.state.value"
|
||||
:title="
|
||||
removalProtection.responseStatus.value === 403
|
||||
? t('gitConnections.forbidden')
|
||||
: removalForm.processing
|
||||
? t('gitConnections.removing')
|
||||
: undefined
|
||||
"
|
||||
:description="
|
||||
removalProtection.responseStatus.value === 403
|
||||
? t('gitConnections.forbiddenDescription')
|
||||
: undefined
|
||||
"
|
||||
:retryable="
|
||||
removalProtection.responseStatus.value !== 403
|
||||
"
|
||||
@retry="removeConnection"
|
||||
/>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
:disabled="removalForm.processing"
|
||||
@click="closeDialog(false)"
|
||||
>{{ t('common.cancel') }}</Button
|
||||
>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="destructive"
|
||||
:disabled="removalForm.processing"
|
||||
>{{
|
||||
t(
|
||||
removalForm.processing
|
||||
? 'gitConnections.removing'
|
||||
: 'gitConnections.removeTitle',
|
||||
)
|
||||
}}</Button
|
||||
>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</SettingsLayout>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user