divers fixes : bouton sauvegarde
This commit is contained in:
1 parent
f1b176ae4a
commit
cf10b9073b
96 files changed
+402
-143
No files matched your search
@@ -5,23 +5,18 @@
|
||||
import type { Agent } from '$lib/types/api'
|
||||
import type { PageProps } from './$types';
|
||||
import { agentApi } from "$lib/api/endpoints/agent"
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
//import { validateUrl } from '$lib/utilities/validators'
|
||||
import AgentForm from './AgentForm.svelte'
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
let agents = $state([] as Agent[])
|
||||
let agents = $state(data.agents)
|
||||
let addingAgent = $state(false)
|
||||
let editingAgent = $state(null as string|null)
|
||||
let agentForm = $state({} as Agent)
|
||||
let errors = new SvelteMap<string,string>()
|
||||
|
||||
onMount(async ()=>{
|
||||
agents = await agentApi.getAgents(data.space)
|
||||
})
|
||||
|
||||
const handleEnterAddAgent = () => {
|
||||
if (editingAgent) return
|
||||
errors.clear()
|
||||
@@ -38,6 +33,9 @@
|
||||
if (!a.name) {
|
||||
errors.set("name","Le nom est obligatoire !")
|
||||
}
|
||||
if (a.defaultProviderId==="" || a.defaultModelId==="") {
|
||||
errors.set("model","Le modèle est obligatoire !")
|
||||
}
|
||||
|
||||
if (errors.size === 0) {
|
||||
agentApi.createAgent(data.space, a)
|
||||
@@ -109,10 +107,10 @@
|
||||
/>
|
||||
{/key}
|
||||
{:else}
|
||||
<div class="rounded border border-dashed p-2 border-stone-500 cursor-pointer" onclick={handleEnterAddAgent} tabindex="0">
|
||||
<button class="rounded w-full border border-dashed p-2 border-stone-500 cursor-pointer" onclick={handleEnterAddAgent} tabindex="0">
|
||||
<i class="icon-plus"></i>
|
||||
Ajouter un agent
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#each agents as agent (agent.id) }
|
||||
@@ -131,10 +129,10 @@
|
||||
<div class="flex-1">
|
||||
<span>{ agent.name }</span>
|
||||
</div>
|
||||
<button class="bt small mx-1" onclick={()=>handleEditAgent(agent.id)}>
|
||||
<button class="bt small mx-1" onclick={()=>handleEditAgent(agent.id)} title="Modifier">
|
||||
<i class="icon-edit"></i>
|
||||
</button>
|
||||
<button class="bt small mx-1" onclick={()=>handleDeleteAgent(agent.id)}>
|
||||
<button class="bt small mx-1" onclick={()=>handleDeleteAgent(agent.id)} title="Supprimer">
|
||||
<i class="icon-trash-empty"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,42 +1,52 @@
|
||||
<script lang="ts">
|
||||
|
||||
import FormError from '$lib/components/FormError.svelte';
|
||||
import Select from 'svelte-select/no-styles';
|
||||
import type { Agent, ComplexItem } from "$lib/types/api"
|
||||
import FormError from '$lib/components/FormError.svelte';
|
||||
import Select from 'svelte-select/no-styles';
|
||||
import type { Agent, ComplexItem } from "$lib/types/api"
|
||||
import { untrack } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
item: Agent
|
||||
providersModels: ComplexItem[],
|
||||
errors: Map<string,string>
|
||||
onSave: (item: Agent) => void
|
||||
onCancel: () => void
|
||||
}
|
||||
let {
|
||||
item,
|
||||
providersModels,
|
||||
errors,
|
||||
onSave,
|
||||
onCancel,
|
||||
}: Props = $props();
|
||||
type Props = {
|
||||
item: Agent
|
||||
providersModels: ComplexItem[],
|
||||
errors: Map<string,string>
|
||||
onSave: (item: Agent) => void
|
||||
onCancel: () => void
|
||||
}
|
||||
let {
|
||||
item,
|
||||
providersModels,
|
||||
errors,
|
||||
onSave,
|
||||
onCancel,
|
||||
}: Props = $props();
|
||||
|
||||
let model = $state("")
|
||||
let model = $state(untrack(()=>item.defaultProviderId+"|"+item.defaultModelId))
|
||||
|
||||
const modelGroupBy = (item: Record<string, unknown>) => item.group as string;
|
||||
const modelGroupBy = (item: Record<string, unknown>) => item.group as string;
|
||||
|
||||
const autofocus = (node: HTMLElement) => {
|
||||
node.focus();
|
||||
}
|
||||
const autofocus = (node: HTMLElement) => {
|
||||
node.focus();
|
||||
}
|
||||
|
||||
const handleSave = (e: Event) => {
|
||||
e.preventDefault()
|
||||
onSave(item)
|
||||
}
|
||||
const handleSave = (e: Event) => {
|
||||
e.preventDefault()
|
||||
|
||||
const handleCancel = (e: Event) => {
|
||||
e.preventDefault()
|
||||
onCancel()
|
||||
}
|
||||
let modelSplit = model.split("|")
|
||||
if (model.length>1) {
|
||||
item.defaultProviderId = modelSplit[0]
|
||||
item.defaultModelId = modelSplit[1]
|
||||
} else {
|
||||
item.defaultProviderId = ""
|
||||
item.defaultModelId = ""
|
||||
}
|
||||
|
||||
onSave(item)
|
||||
}
|
||||
|
||||
const handleCancel = (e: Event) => {
|
||||
e.preventDefault()
|
||||
onCancel()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -75,7 +85,7 @@ const handleCancel = (e: Event) => {
|
||||
groupBy={modelGroupBy}
|
||||
bind:value={model}
|
||||
/>
|
||||
<FormError key="type" errors={errors} />
|
||||
<FormError key="model" errors={errors} />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<script lang="ts">
|
||||
|
||||
import { untrack } from 'svelte';
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
import type { PageProps } from './$types';
|
||||
import type { User, Address, Item } from '$lib/types/api'
|
||||
import { SaveState } from '$lib/types/api'
|
||||
import { userApi } from '$lib/api/endpoints/user'
|
||||
import { miscApi } from '$lib/api/endpoints/misc'
|
||||
import FormError from '$lib/components/FormError.svelte';
|
||||
@@ -10,14 +12,17 @@
|
||||
import { validateEmail } from '$lib/utilities/validators'
|
||||
import { onMount } from 'svelte';
|
||||
import Select from 'svelte-select/no-styles';
|
||||
import SaveButton from '$lib/components/SaveButton.svelte';
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
let form : User = $state(data.me.user)
|
||||
let form : User = $state(untrack(()=>data.me.user))
|
||||
let addresses : Address[] = $state([] as Address[])
|
||||
let newAddress : Address = $state({} as Address)
|
||||
let newAddress : Address = $state({type:"", address:""} as Address)
|
||||
let timezones = $state([] as Item[])
|
||||
let errors = new SvelteMap<string,string>()
|
||||
let saveState = $state(SaveState.None)
|
||||
let addressSaveState = $state(SaveState.None)
|
||||
|
||||
onMount(async ()=> {
|
||||
addresses = await userApi.listAddresses(form.id)
|
||||
@@ -31,6 +36,7 @@
|
||||
|
||||
let submitUser = (e: Event) => {
|
||||
e.preventDefault()
|
||||
saveState = SaveState.Saving
|
||||
if (!validateEmail(form.email)) {
|
||||
errors.set("email","Adresse email invalide !")
|
||||
}
|
||||
@@ -42,16 +48,25 @@
|
||||
}
|
||||
if (errors.size==0) {
|
||||
userApi.update(form.id, form)
|
||||
.then(()=>{ console.log('success')})
|
||||
.catch((err: string)=>{ console.error(err)})
|
||||
.then(()=>{
|
||||
saveState = SaveState.Saved
|
||||
//setTimeout(()=>{saveState = SaveState.None}, 2000)
|
||||
})
|
||||
.catch((err: string)=>{
|
||||
saveState = SaveState.Saving
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddAddress = () => {
|
||||
addressSaveState=SaveState.Saving
|
||||
userApi.createAddress(form.id, newAddress)
|
||||
.then((data)=>{
|
||||
addresses.push(data)
|
||||
newAddress = {} as Address
|
||||
newAddress = {type:"", address:""} as Address
|
||||
addressSaveState=SaveState.Saved
|
||||
//setTimeout(()=>{addressSaveState = SaveState.None}, 2000)
|
||||
})
|
||||
.catch((error)=>{ console.log(error) })
|
||||
}
|
||||
@@ -62,12 +77,21 @@
|
||||
}).catch((error)=>{console.log(error)})
|
||||
}
|
||||
|
||||
const handleFormChange = () => {
|
||||
errors.clear()
|
||||
saveState = SaveState.Changed
|
||||
}
|
||||
|
||||
const autofocus = (node: HTMLElement) => {
|
||||
node.focus();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="mb-4 formgroup container">
|
||||
<h2>Mon compte</h2>
|
||||
|
||||
<form onsubmit={submitUser} onchange={()=>{errors.clear()}}>
|
||||
<form onsubmit={submitUser} onchange={handleFormChange}>
|
||||
|
||||
<div class="formelement">
|
||||
<label for="email" class="my-1 flex-1">Email</label>
|
||||
@@ -76,7 +100,7 @@
|
||||
type="text"
|
||||
bind:value={form.email}
|
||||
class="textinput"
|
||||
autofocus
|
||||
use:autofocus
|
||||
/>
|
||||
<FormError key="email" errors={errors} />
|
||||
</div>
|
||||
@@ -133,7 +157,10 @@
|
||||
<FormError key="theme" errors={errors} />
|
||||
</div>
|
||||
|
||||
<button class="bt w-full">Enregistrer</button>
|
||||
<SaveButton
|
||||
label="Enregistrer"
|
||||
state={saveState}
|
||||
/>
|
||||
|
||||
</form>
|
||||
|
||||
@@ -147,7 +174,11 @@
|
||||
<div class="dark:bg-stone-700 bg-stone-300 rounded inline px-2 py-1 text-sm">
|
||||
<span class="inline-block w-20">{address.type} : </span>
|
||||
<span class="">{address.address}</span>
|
||||
<button class="ml-4 pointer" onclick={()=>{handleDeleteAddress(address.id)}}>
|
||||
<button
|
||||
class="ml-4 pointer"
|
||||
onclick={()=>{handleDeleteAddress(address.id)}}
|
||||
title="Annuler"
|
||||
>
|
||||
<i class="icon-cancel"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -156,6 +187,7 @@
|
||||
<div class="flex gap-2 mt-6">
|
||||
<div>
|
||||
<select bind:value={newAddress.type} class="textinput">
|
||||
<option value=""></option>
|
||||
<option value="email">Email</option>
|
||||
<option value="signal">Signal</option>
|
||||
<option value="telegram">Telegram</option>
|
||||
@@ -163,10 +195,18 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<input type="text" bind:value={newAddress.address} class="textinput" />
|
||||
<input type="text"
|
||||
bind:value={newAddress.address}
|
||||
onchange={()=>addressSaveState=SaveState.Changed}
|
||||
class="textinput" />
|
||||
</div>
|
||||
<div>
|
||||
<button class="bt" onclick={handleAddAddress}>Ajouter</button>
|
||||
<SaveButton
|
||||
disabled={newAddress.type==="" || newAddress.address===""}
|
||||
label="Ajouter"
|
||||
handleClick={handleAddAddress}
|
||||
state={addressSaveState}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -30,9 +30,22 @@ h2 {
|
||||
}
|
||||
.bt {
|
||||
appearance: button;
|
||||
@apply cursor-pointer rounded bg-stone-300 px-4 py-1 font-bold hover:bg-stone-200 dark:bg-stone-800 dark:hover:bg-stone-700;
|
||||
@apply min-w-40 cursor-pointer rounded bg-stone-300 px-4 py-1 font-bold transition-all duration-300 hover:bg-stone-200 dark:bg-stone-800 dark:hover:bg-stone-700;
|
||||
&.small {
|
||||
@apply px-2 py-1;
|
||||
@apply min-w-0 px-2 py-1;
|
||||
}
|
||||
&.changed,
|
||||
&.saving {
|
||||
@apply bg-sky-300 dark:bg-sky-700;
|
||||
}
|
||||
&.saved {
|
||||
@apply bg-green-300 dark:bg-green-700;
|
||||
}
|
||||
&.error {
|
||||
@apply bg-red-300 dark:bg-red-700;
|
||||
}
|
||||
&.disabled {
|
||||
@apply text-stone-400 hover:bg-stone-200 dark:hover:bg-stone-800;
|
||||
}
|
||||
}
|
||||
.menuitem {
|
||||
@@ -48,7 +61,7 @@ h2 {
|
||||
}
|
||||
.profile a,
|
||||
.public a {
|
||||
@apply text-sky-500;
|
||||
@apply bg-sky-300 dark:bg-sky-700;
|
||||
}
|
||||
|
||||
#outer {
|
||||
|
||||
Reference in new issue
Block a user