CI / changes (push) Successful in 10s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 27s
CI / web (push) Successful in 38s
CI / go (push) Successful in 2m36s
CI / bird2 (push) Successful in 15s
CI / release (push) Failing after 3m7s
Refactored the project structure to support a monorepo setup, moving the web application to `apps/web/` and updating related configurations. Adjusted pre-commit hooks to use `pnpm` for linting and formatting. Updated CI workflows to reflect the new directory structure and dependencies. Removed legacy files and configurations from the previous `web/` directory, streamlining the project for better maintainability and clarity.
126 lines
3.4 KiB
Svelte
126 lines
3.4 KiB
Svelte
<script lang="ts">
|
|
import { apiMutate } from '$lib/api/client.js';
|
|
import type { BgpCommunity, DomainEntry, DomainEntryCreate } from '$lib/api/types.js';
|
|
import {
|
|
communityLabel,
|
|
communityOptionLabel,
|
|
fromNullableSelect,
|
|
NONE_OPTION,
|
|
nullableSelectValue
|
|
} from '$lib/components/modules/module-helpers.js';
|
|
import { Button } from '@evobgp/ui/components/button/index.js';
|
|
import { Input } from '@evobgp/ui/components/input/index.js';
|
|
import { Label } from '@evobgp/ui/components/label/index.js';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogFooter
|
|
} from '@evobgp/ui/components/dialog/index.js';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger
|
|
} from '@evobgp/ui/components/select/index.js';
|
|
import { notify, notifyApiError } from '$lib/ui/app/toast.js';
|
|
|
|
type Props = {
|
|
open: boolean;
|
|
moduleId: string;
|
|
edit: DomainEntry | null;
|
|
communities: BgpCommunity[];
|
|
onSaved: () => void | Promise<void>;
|
|
onClose: () => void;
|
|
};
|
|
|
|
let { open = $bindable(), moduleId, edit, communities, onSaved, onClose }: Props = $props();
|
|
|
|
let saving = $state(false);
|
|
let form = $state<DomainEntryCreate>({ fqdn: '', community_id: null });
|
|
let initKey = $state('');
|
|
|
|
function resetForm() {
|
|
form = edit
|
|
? { fqdn: edit.fqdn, community_id: edit.community_id }
|
|
: { fqdn: '', community_id: null };
|
|
}
|
|
|
|
$effect(() => {
|
|
if (!open) {
|
|
initKey = '';
|
|
return;
|
|
}
|
|
const nextKey = edit?.id ?? 'new';
|
|
if (nextKey !== initKey) {
|
|
initKey = nextKey;
|
|
resetForm();
|
|
}
|
|
});
|
|
|
|
async function save() {
|
|
saving = true;
|
|
try {
|
|
if (edit) {
|
|
await apiMutate(`/v1/modules/${moduleId}/domain-entries/${edit.id}`, 'PATCH', form);
|
|
notify.success('Домен обновлён');
|
|
} else {
|
|
await apiMutate(`/v1/modules/${moduleId}/domain-entries`, 'POST', form);
|
|
notify.success('Домен добавлен');
|
|
}
|
|
open = false;
|
|
await onSaved();
|
|
} catch (e) {
|
|
notifyApiError(e);
|
|
} finally {
|
|
saving = false;
|
|
}
|
|
}
|
|
|
|
function handleOpenChange(next: boolean) {
|
|
open = next;
|
|
if (!next) onClose();
|
|
}
|
|
</script>
|
|
|
|
<Dialog bind:open onOpenChange={handleOpenChange}>
|
|
<DialogContent class="sm:max-w-sm">
|
|
<DialogHeader>
|
|
<DialogTitle>{edit ? 'Редактировать домен' : 'Новый домен'}</DialogTitle>
|
|
</DialogHeader>
|
|
<div class="space-y-4 py-2">
|
|
<div class="space-y-1.5">
|
|
<Label for="dom-fqdn">FQDN</Label>
|
|
<Input id="dom-fqdn" placeholder="example.com" bind:value={form.fqdn} />
|
|
</div>
|
|
<div class="space-y-1.5">
|
|
<Label for="dom-comm">Community</Label>
|
|
<Select
|
|
type="single"
|
|
value={nullableSelectValue(form.community_id)}
|
|
onValueChange={(v) => {
|
|
form.community_id = fromNullableSelect(v);
|
|
}}
|
|
>
|
|
<SelectTrigger id="dom-comm" class="w-full">
|
|
{form.community_id ? communityLabel(form.community_id, communities) : 'Не выбрано'}
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value={NONE_OPTION}>Не выбрано</SelectItem>
|
|
{#each communities as c (c.id)}
|
|
<SelectItem value={c.id}>{communityOptionLabel(c)}</SelectItem>
|
|
{/each}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
<DialogFooter>
|
|
<Button variant="outline" onclick={() => handleOpenChange(false)}>Отмена</Button>
|
|
<Button onclick={save} disabled={saving}>
|
|
{saving ? 'Сохранение…' : edit ? 'Сохранить' : 'Добавить'}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|