Continue to work on Svelte migration
This commit is contained in:
parent
8a779e914c
commit
90754b3050
18
ui/src/lib/api/provider_specs.ts
Normal file
18
ui/src/lib/api/provider_specs.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { handleApiResponse } from '$lib/errors';
|
||||
import type { Provider, ProviderList } from '$lib/model/provider';
|
||||
|
||||
export async function listProviders(): Promise<ProviderList> {
|
||||
const res = await fetch('/api/providers/_specs', {
|
||||
method: 'GET',
|
||||
headers: {'Accept': 'application/json'},
|
||||
});
|
||||
return await handleApiResponse(res);
|
||||
}
|
||||
|
||||
export async function getProviderSpec(psid: string): Promise<Provider> {
|
||||
const res = await fetch(`/api/providers/_specs/` + psid, {
|
||||
method: 'GET',
|
||||
headers: {'Accept': 'application/json'},
|
||||
});
|
||||
return new Provider(await handleApiResponse(res));
|
||||
}
|
@ -2,7 +2,7 @@ import { handleApiResponse } from '$lib/errors';
|
||||
import type { SignUpForm, LoginForm } from '$lib/model/user';
|
||||
|
||||
export async function registerUser(form: SignUpForm): Promise<any> {
|
||||
const res = await fetch('api/users', {
|
||||
const res = await fetch('/api/users', {
|
||||
method: 'POST',
|
||||
headers: {'Accept': 'application/json'},
|
||||
body: JSON.stringify(form),
|
||||
@ -11,7 +11,7 @@ export async function registerUser(form: SignUpForm): Promise<any> {
|
||||
}
|
||||
|
||||
export async function authUser(form: LoginForm): Promise<any> {
|
||||
const res = await fetch('api/auth', {
|
||||
const res = await fetch('/api/auth', {
|
||||
method: 'POST',
|
||||
headers: {'Accept': 'application/json'},
|
||||
body: JSON.stringify(form),
|
||||
@ -20,7 +20,7 @@ export async function authUser(form: LoginForm): Promise<any> {
|
||||
}
|
||||
|
||||
export async function logout(): Promise<any> {
|
||||
const res = await fetch('api/auth/logout', {
|
||||
const res = await fetch('/api/auth/logout', {
|
||||
method: 'POST',
|
||||
headers: {'Accept': 'application/json'},
|
||||
});
|
||||
@ -28,7 +28,7 @@ export async function logout(): Promise<any> {
|
||||
}
|
||||
|
||||
export async function specialUserOperations(email: string, kind: "recovery"|"validation"): Promise<any> {
|
||||
const res = await fetch('api/users', {
|
||||
const res = await fetch('/api/users', {
|
||||
method: 'PATCH',
|
||||
headers: {'Accept': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
@ -49,7 +49,7 @@ export async function resendValidationEmail(email: string): Promise<any> {
|
||||
|
||||
export async function recoverAccount(userid: string, key: string, password: string): Promise<any> {
|
||||
userid = encodeURIComponent(userid);
|
||||
const res = await fetch(`api/users/${userid}/recovery`, {
|
||||
const res = await fetch(`/api/users/${userid}/recovery`, {
|
||||
method: 'POST',
|
||||
headers: {'Accept': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
@ -62,7 +62,7 @@ export async function recoverAccount(userid: string, key: string, password: stri
|
||||
|
||||
export async function validateEmail(userid: string, key: string): Promise<any> {
|
||||
userid = encodeURIComponent(userid);
|
||||
const res = await fetch(`api/users/${userid}/email`, {
|
||||
const res = await fetch(`/api/users/${userid}/email`, {
|
||||
method: 'POST',
|
||||
headers: {'Accept': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
|
79
ui/src/lib/components/Home.svelte
Normal file
79
ui/src/lib/components/Home.svelte
Normal file
@ -0,0 +1,79 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
Badge,
|
||||
CardHeader,
|
||||
Col,
|
||||
Container,
|
||||
Row,
|
||||
} from 'sveltestrap';
|
||||
|
||||
import Logo from '$lib/components/Logo.svelte';
|
||||
import ZoneList from '$lib/components/ZoneList.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
export let domains: Array<Domain>|undefined;
|
||||
|
||||
if (domains === undefined) {
|
||||
|
||||
}
|
||||
|
||||
export let filteredDomains = [];
|
||||
export let filteredProvider = null;
|
||||
|
||||
function showDomain(dn) {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container class="pt-4 pb-5">
|
||||
<h1 class="text-center mb-4">
|
||||
{$t('common.welcome.start')}
|
||||
<Logo height="40" />
|
||||
{$t('common.welcome.end')}
|
||||
</h1>
|
||||
|
||||
<Row>
|
||||
<Col md="8" class="order-1 order-md-0">
|
||||
<ZoneList
|
||||
button
|
||||
display-by-groups
|
||||
domains={filteredDomains}
|
||||
on:click={showDomain}
|
||||
>
|
||||
<Badge slot="badges" color="success">
|
||||
OK
|
||||
</Badge>
|
||||
</ZoneList>
|
||||
{#if filteredProvider}
|
||||
<div class="card" class:mt-4={filteredDomains.length > 0}>
|
||||
{#if !noDomainsList}
|
||||
<CardHeader class="d-flex justify-content-between">
|
||||
{$t("provider.provider")}
|
||||
<em>{filteredProvider._comment}</em>
|
||||
<Button
|
||||
type="button"
|
||||
color="secondary"
|
||||
size="sm"
|
||||
>
|
||||
{$t('provider.import-domains')}
|
||||
</Button>
|
||||
</CardHeader>
|
||||
{/if}
|
||||
<h-provider-list-domains
|
||||
ref="newDomains"
|
||||
provider={filteredProvider}
|
||||
show-domains-with-actions
|
||||
on:no-domains-list-change={noDomainsList = $event}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if !filteredProvider || noDomainsList}
|
||||
<h-list-group-input-new-domain
|
||||
autofocus
|
||||
class="mt-2"
|
||||
my-provider={filteredProvider}
|
||||
/>
|
||||
{/if}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
52
ui/src/lib/components/ZoneList.svelte
Normal file
52
ui/src/lib/components/ZoneList.svelte
Normal file
@ -0,0 +1,52 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
import hList from '$lib/components/hList.svelte';
|
||||
import { t } from '$lib/translations';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let button = false;
|
||||
export let display_by_groups = false;
|
||||
export let domains = [];
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if domains.length === 0}
|
||||
<slot name="no-domain" />
|
||||
{:else}
|
||||
{#each Objects.keys(groups) as gname}
|
||||
{@const gdomains = groups[gname]}
|
||||
<div
|
||||
class:border-top={Object.keys(groups).length != 1}
|
||||
style="margin-top: 1.4em"
|
||||
>
|
||||
{#if Object.keys(groups).length != 1}
|
||||
<div class="text-center" style="height: 1em">
|
||||
<h3 class="d-inline-block px-1" style="background: white; position: relative; top: -.65em">
|
||||
{#if group === undefined}
|
||||
{$t("domaingroups.no-group")}
|
||||
{:else}
|
||||
{gname}
|
||||
{/if}
|
||||
</h3>
|
||||
</div>
|
||||
{/if}
|
||||
<hList
|
||||
items={gdomains}
|
||||
{button}
|
||||
on:click={(event) => dispatch('click', event.details)}
|
||||
let:item={item}
|
||||
>
|
||||
<div class="text-monospace">
|
||||
<div class="d-inline-block text-center" style="width: 50px;">
|
||||
<ImgProvider id_provider={item.id_provider} />
|
||||
</div>
|
||||
{item.domain}
|
||||
</div>
|
||||
<slot name="badges" domain={item} />
|
||||
</hList>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
12
ui/src/lib/components/providers/ImgProvider.svelte
Normal file
12
ui/src/lib/components/providers/ImgProvider.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script lang="ts">
|
||||
export let id_provider;
|
||||
</script>
|
||||
|
||||
{#if providers_getAll[id_provider]}
|
||||
<img
|
||||
src="'/api/providers/_specs/' + providers_getAll[id_provider]._srctype + '/icon.png'"
|
||||
alt={providers_getAll[id_provider]._srctype}
|
||||
title={providers_getAll[id_provider]._srctype}
|
||||
style="max-width: 100%; max-height: 2.5em; margin: -.6em .4em -.6em -.6em"
|
||||
>
|
||||
{/if}
|
50
ui/src/lib/components/providers/Selector.svelte
Normal file
50
ui/src/lib/components/providers/Selector.svelte
Normal file
@ -0,0 +1,50 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
ListGroup,
|
||||
ListGroupItem,
|
||||
Spinner,
|
||||
} from 'sveltestrap';
|
||||
|
||||
import ImgProvider from '$lib/components/providers/ImgProvider.svelte';
|
||||
import { listProviders } from '$lib/api/provider_specs';
|
||||
|
||||
export let value = null;
|
||||
let isLoading = false;
|
||||
let providers = [];
|
||||
|
||||
listProviders().then((res) => providers = res)
|
||||
</script>
|
||||
|
||||
<ListGroup>
|
||||
{#if isLoading}
|
||||
<ListGroupItem class="d-flex justify-content-center align-items-center">
|
||||
<Spinner variant="primary" label="Spinning" class="mr-3" /> Retrieving usable providers...
|
||||
</ListGroupItem>
|
||||
{/if}
|
||||
{#each Object.keys(providers) as ptype (ptype)}
|
||||
{@const provider = providers[ptype]}
|
||||
<ListGroupItem
|
||||
active={value === provider.id}
|
||||
button
|
||||
class="d-flex"
|
||||
on:click={() => value = provider.id}
|
||||
>
|
||||
<div
|
||||
class="align-self-center text-center"
|
||||
style="min-width:50px;width:50px;"
|
||||
>
|
||||
<ImgProvider
|
||||
{provider}
|
||||
style="max-width: 100%; max-height: 2.5em; margin: -.6em .4em -.6em -.6em"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="align-self-center"
|
||||
style="line-height: 1.1"
|
||||
>
|
||||
<strong>{provider.name}</strong> –
|
||||
<small class="text-muted" title={provider.description}>{provider.description}</small>
|
||||
</div>
|
||||
</ListGroupItem>
|
||||
{/each}
|
||||
</ListGroup>
|
@ -44,7 +44,10 @@
|
||||
"run": "Run the request!",
|
||||
"survey": "A remark? a comment to share? Don't hesitate to write us!",
|
||||
"spinning": "Spinning",
|
||||
"welcome": "Welcome to {{0}}!",
|
||||
"welcome": {
|
||||
"start": "Welcome to ",
|
||||
"end": "!"
|
||||
},
|
||||
"help": "Help!",
|
||||
"records": "{{number:eq; 0:no {{type}} record; 1:{{type}} record; default:{{type}} records}}"
|
||||
},
|
||||
|
@ -43,7 +43,10 @@
|
||||
"resolver": "Résolveur",
|
||||
"run": "Lancer l'opération !",
|
||||
"spinning": "Chargement",
|
||||
"welcome": "Bienvenue sur {{0}} !",
|
||||
"welcome": {
|
||||
"start": "Bienvenue sur ",
|
||||
"end": " !"
|
||||
},
|
||||
"help": "Besoin d'aide ?",
|
||||
"records": "{{number:eq; 0:aucun enregistrement {{type}}; 1:enregistrement {{type}}; default:enregistrements {{type}}}}",
|
||||
"survey": "Une remarque ? un commentaire à partager ? N'hésitez pas à nous écrire !"
|
||||
|
8
ui/src/lib/model/domain.ts
Normal file
8
ui/src/lib/model/domain.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface Domain {
|
||||
id: string;
|
||||
id_owner: string;
|
||||
id_provider: string;
|
||||
domain: string;
|
||||
group: string;
|
||||
zone_history: Array<string>;
|
||||
};
|
3
ui/src/lib/model/golang.ts
Normal file
3
ui/src/lib/model/golang.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface Map<T1, T2> {
|
||||
[key: T1]: T2;
|
||||
};
|
26
ui/src/lib/model/provider.ts
Normal file
26
ui/src/lib/model/provider.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import type Map from '$lib/model/golang';
|
||||
|
||||
export class ProviderInfos {
|
||||
name: string;
|
||||
description: string;
|
||||
capabilites: Array<string>;
|
||||
|
||||
constructor({ name, description, capabilites }: ProviderInfos) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.capabilites = capabilites;
|
||||
}
|
||||
};
|
||||
|
||||
export type ProviderList = Map<string, ProviderInfos>;
|
||||
|
||||
export interface ProviderMeta {
|
||||
_srctype: string;
|
||||
_id: string;
|
||||
_ownerid: string;
|
||||
_comment: string;
|
||||
};
|
||||
|
||||
export interface Provider extends ProviderMeta {
|
||||
|
||||
};
|
11
ui/src/lib/model/service.ts
Normal file
11
ui/src/lib/model/service.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export interface ServiceMeta {
|
||||
_svctype: string;
|
||||
_id: string;
|
||||
_ownerid: string;
|
||||
_domain: string;
|
||||
_ttl: number;
|
||||
_comment: string;
|
||||
_mycomment: string;
|
||||
_aliases: Array<string>;
|
||||
_tmp_hint_nb: number;
|
||||
};
|
6
ui/src/lib/model/source.ts
Normal file
6
ui/src/lib/model/source.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface SourceMeta {
|
||||
_srctype: string;
|
||||
_id: string;
|
||||
_ownerid: string;
|
||||
_comment: string;
|
||||
};
|
9
ui/src/lib/model/zone.ts
Normal file
9
ui/src/lib/model/zone.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export interface ZoneMeta {
|
||||
id: string;
|
||||
id_author: string;
|
||||
default_ttl: Number;
|
||||
last_modified: Date;
|
||||
commit_message?: string;
|
||||
commit_date?: Date;
|
||||
published?: Date;
|
||||
};
|
16
ui/src/lib/stores/providers.ts
Normal file
16
ui/src/lib/stores/providers.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
import type { User } from '$lib/model/user';
|
||||
|
||||
export const userSession: Writable<null | User> = writable(null);
|
||||
|
||||
export async function refreshUserSession() {
|
||||
const res = await fetch('/api/auth', {headers: {'Accept': 'application/json'}})
|
||||
if (res.status == 200) {
|
||||
const user = new User(await res.json());
|
||||
userSession.set(user);
|
||||
return user
|
||||
} else {
|
||||
userSession.set(null);
|
||||
throw new Error((await res.json()).errmsg);
|
||||
}
|
||||
}
|
5
ui/src/routes/+page.svelte
Normal file
5
ui/src/routes/+page.svelte
Normal file
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
import Home from '$lib/components/Home.svelte';
|
||||
</script>
|
||||
|
||||
<Home />
|
@ -5,7 +5,9 @@ import { get_store_value } from 'svelte/internal';
|
||||
import { userSession } from '$lib/stores/usersession';
|
||||
import { config as tsConfig, locale } from '$lib/translations';
|
||||
|
||||
export const load: Load = async() => {
|
||||
export const load: Load = async({ parent }) => {
|
||||
await parent();
|
||||
|
||||
// If not connected, redirect to main website in the right language
|
||||
if (!get_store_value(userSession)) {
|
||||
const initLocale = locale.get() || window.navigator.language || window.navigator.languages[0] || tsConfig.fallbackLocale;
|
||||
|
25
ui/src/routes/providers/new/+layout.svelte
Normal file
25
ui/src/routes/providers/new/+layout.svelte
Normal file
@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
Button,
|
||||
Container,
|
||||
Icon,
|
||||
} from 'sveltestrap';
|
||||
|
||||
import { t } from '$lib/translations';
|
||||
</script>
|
||||
|
||||
<Container class="d-flex flex-column mt-4" fluid>
|
||||
<h1 class="text-center mb-3">
|
||||
<Button
|
||||
type="button"
|
||||
class="fw-bolder"
|
||||
color="link"
|
||||
on:click={() => history.go(-1)}
|
||||
>
|
||||
<Icon name="chevron-left" />
|
||||
</Button>
|
||||
{$t("provider.select-provider")}
|
||||
</h1>
|
||||
<hr class="mt-0 mb-0">
|
||||
<slot class="flex-grow-1"></slot>
|
||||
</Container>
|
18
ui/src/routes/providers/new/+page.svelte
Normal file
18
ui/src/routes/providers/new/+page.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
Col,
|
||||
Row,
|
||||
} from 'sveltestrap';
|
||||
|
||||
import ProviderSelector from '$lib/components/providers/Selector.svelte';
|
||||
|
||||
function selectNewProvider() {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<Row class="my-3">
|
||||
<Col offset-md="2" md="8">
|
||||
<ProviderSelector on:provider-selected={selectNewProvider} />
|
||||
</Col>
|
||||
</Row>
|
Loading…
Reference in New Issue
Block a user