correction des pb de space : le spaceId est maintenant dans l'url uniquement

This commit is contained in:
fabien committed 2026-09-02 21:50:26 +02:00
1 parent c52460bac0
commit 0bb8d1cb46
41 files changed
+1463 -121

No files matched your search

@@ -42,7 +42,6 @@
if (data.me) {
auth.user = data.me.user
space.spaces = data.me.teams
space.id = data.me.teams[0].id
themeToLocalStorage(auth.user.theme)
applyTheme()
auth.status = 'authenticated'
@@ -63,7 +62,7 @@
<div id="outer" class={[uiState.sidebarDesktopOpen ? "desktopMenuOpen" : "desktopMenuClosed", uiState.sidebarMobileOpen ? "mobileMenuOpen" : "mobileMenuClosed" ]}>
<div id="sidebar" class="flex flex-col">
<Sidebar {handleMenuDesktop} {handleMenuMobile}/>
<Sidebar spaceid={data.spaceid} {handleMenuDesktop} {handleMenuMobile}/>
</div>
<div id="main">
<div class="flex flex-col h-screen ">
@@ -1,8 +1,9 @@
import { userApi } from "$lib/api/endpoints/user"
import type { LayoutLoad } from './$types';
export const load: LayoutLoad = async () => {
export const load: LayoutLoad = async ({params}) => {
return {
spaceid: params.space,
me: await userApi.me()
}
}
@@ -1 +1,144 @@
<div>Modèles</div>
<script lang="ts">
import { SvelteMap } from 'svelte/reactivity';
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 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()
agentForm = {} as Agent
addingAgent= true
}
const handleCancelAddAgent = () => {
addingAgent= false
}
const handleSubmitAddAgent = (a: Agent) => {
if (!a.name) {
errors.set("name","Le nom est obligatoire !")
}
if (errors.size === 0) {
agentApi.createAgent(data.space, a)
.then((p)=>{
agents.push(p)
addingAgent= false
agentForm = {} as Agent
})
.catch((err)=>{
console.log(err)
})
}
}
const handleCancelEditAgent = () => {
editingAgent = null
agentForm = {} as Agent
}
const handleSubmitEditAgent = (a: Agent) => {
if (!a.name) {
errors.set("name","Le nom est obligatoire !")
}
if (errors.size === 0) {
agentApi.updateAgent(data.space,a)
.then((p)=>{
agents = agents.map((it: Agent)=>{return p.id===it.id ? p : it})
editingAgent = null
agentForm = {} as Agent
})
.catch((err)=>{
console.log(err)
})
}
}
const handleEditAgent = async (id: string) => {
errors.clear()
if (addingAgent) return
agentApi.getAgent(data.space,id)
.then((a)=>{
agents = agents.filter((it)=>it.id===a.id ? a : it)
editingAgent = id
})
.catch((err)=> console.log(err))
}
const handleDeleteAgent = (id: string) => {
agentApi.deleteAgent(data.space,id)
.then(() => {
agents = agents.filter((it: Agent)=>it.id!==id)
})
.catch((err) => {console.log(err)})
}
</script>
<div class="container">
{#if addingAgent}
{#key "new"}
<AgentForm
item={agentForm}
errors={errors}
onSave={handleSubmitAddAgent}
onCancel={handleCancelAddAgent}
providersModels={data.providersModels}
/>
{/key}
{:else}
<div class="rounded border border-dashed p-2 border-stone-500 cursor-pointer" onclick={handleEnterAddAgent} tabindex="0">
<i class="icon-plus"></i>
Ajouter un agent
</div>
{/if}
{#each agents as agent (agent.id) }
{#if editingAgent===agent.id}
{#key agent.id}
<AgentForm
item={agent}
errors={errors}
onSave={handleSubmitEditAgent}
onCancel={handleCancelEditAgent}
providersModels={data.providersModels}
/>
{/key}
{:else}
<div class="rounded border p-2 my-2 border-stone-500 flex">
<div class="flex-1">
<span>{ agent.name }</span>
</div>
<button class="bt small mx-1" onclick={()=>handleEditAgent(agent.id)}>
<i class="icon-edit"></i>
</button>
<button class="bt small mx-1" onclick={()=>handleDeleteAgent(agent.id)}>
<i class="icon-trash-empty"></i>
</button>
</div>
{/if}
{/each}
</div>
@@ -1,7 +1,14 @@
export function load() {
import { agentApi } from "$lib/api/endpoints/agent"
import {providerApi} from "$lib/api/endpoints/provider"
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
return {
title: 'Paramétrage : Agents',
back: "/settings",
theme: "settings"
back: "../settings",
theme: "settings",
space: params.space,
agents: await agentApi.getAgents(params.space),
providersModels: await providerApi.getProvidersModels(params.space),
};
}
@@ -0,0 +1,88 @@
<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"
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("")
const modelGroupBy = (item: Record<string, unknown>) => item.group as string;
const autofocus = (node: HTMLElement) => {
node.focus();
}
const handleSave = (e: Event) => {
e.preventDefault()
onSave(item)
}
const handleCancel = (e: Event) => {
e.preventDefault()
onCancel()
}
</script>
<div>
<div class="formgroup my-2">
<form onsubmit={handleSave} onchange={()=>{errors.clear()}}>
<div class="formelement">
<label for="name">Nom</label>
<input
id="name"
type="text"
bind:value={item.name}
class="textinput"
placeholder="nom affiché"
use:autofocus
/>
<FormError key="name" errors={errors} />
</div>
<div class="formelement">
<label for="systemPrompt">Prompt système</label>
<textarea
id="systemPrompt"
bind:value={item.systemPrompt}
class="textinput"
placeholder="prompt système"
></textarea>
<FormError key="baseUrl" errors={errors} />
</div>
<div class="formelement">
<label for="type" class="block my-1 flex-1">Type</label>
<Select items={providersModels}
valueMode="id"
groupBy={modelGroupBy}
bind:value={model}
/>
<FormError key="type" errors={errors} />
</div>
<div class="text-right">
<span>{item._version}</span>
<button type="button" class="bt" onclick={handleCancel}>Annuler</button>
<button type="submit" class="bt mx-4">Enregistrer</button>
</div>
</form>
</div>
</div>
@@ -20,7 +20,7 @@
onMount(async ()=>{
providers = await providerApi.getProviders()
providers = await providerApi.getProviders(data.space)
})
const enterAddProviderHandler = () => {
@@ -47,7 +47,7 @@
errors.set("baseUrl","Mauvaise URL !")
}
if (errors.size === 0) {
providerApi.createProvider(p)
providerApi.createProvider(data.space,p)
.then((p)=>{
providers.push(p)
addingProvider= false
@@ -76,7 +76,7 @@
errors.set("baseUrl","Mauvaise URL !")
}
if (errors.size === 0) {
providerApi.updateProvider(p)
providerApi.updateProvider(data.space,p)
.then((p)=>{
providers = providers.map((it)=>{return p.id===it.id ? p : it})
editingProvider = null
@@ -91,7 +91,7 @@
const handleEditProvider = async (id: string) => {
errors.clear()
if (addingProvider) return
providerApi.getProvider(id)
providerApi.getProvider(data.space,id)
.then((data)=>{
providers = providers.map((it)=>it.id===id ? data : it)
editingProvider = id
@@ -99,7 +99,7 @@
}
const handleDeleteProvider = (id: string) => {
providerApi.deleteProvider(id)
providerApi.deleteProvider(data.space,id)
.then(() => {
providers = providers.filter((it)=>it.id!==id)
})
@@ -1,11 +1,12 @@
import { providerApi } from "$lib/api/endpoints/provider"
import type { PageLoad } from './$types';
export const load: PageLoad = async () => {
export const load: PageLoad = async ({params}) => {
return {
title: 'Paramétrage : Modèles',
back: "/settings",
back: "../settings",
theme: "settings",
space: params.space,
providerTypes: await providerApi.providerTypes(),
};
}
@@ -25,8 +25,8 @@ type Selectable = {
value: string
selected: boolean
}
let selectedModels = $state(item.models.split(";"))
let availableModels : Selectable[]= $state(item.models.split(";").map((it)=> {return {value:it, selected:true}}))
let selectedModels = $state(item.models.split("|"))
let availableModels : Selectable[]= $state(item.models.split("|").map((it)=> {return {value:it, selected:true}}))
let modelsErrors = new SvelteMap<string,string>()
const autofocus = (node: HTMLElement) => {
@@ -35,7 +35,7 @@ const autofocus = (node: HTMLElement) => {
const handleSave = (e: Event) => {
e.preventDefault()
item.models = selectedModels.join(";")
item.models = selectedModels.join("|")
onSave(item)
}
@@ -47,7 +47,7 @@ const handleCancel = (e: Event) => {
const fetchModels = (e: Event) => {
e.preventDefault()
modelsErrors.clear()
providerApi.getAvailableModels(item)
providerApi.getAvailableModels(item.teamId, item)
.then((data) => {
availableModels = data.map((it)=>{
return { value: it, selected: selectedModels.includes(it)}
@@ -81,7 +81,7 @@ const handleModelChange = () => {
<div class="formelement">
<label for="type" class="block my-1 flex-1">Type</label>
<Select items={providerTypes}
valueMode="id" itemId="id" label="text"
valueMode="id"
bind:value={item.type}
/>
<FormError key="type" errors={errors} />
@@ -114,7 +114,7 @@ const handleModelChange = () => {
</div>
<div class="formelement">
<label for="apiKey">Models</label>
<label for="models">Models</label>
<button class="bt small" onclick={fetchModels}>
Afficher les modèles disponibles
</button>
@@ -21,7 +21,7 @@
onMount(async ()=> {
addresses = await userApi.listAddresses(form.id)
timezones = (await miscApi.listTimezones()).map((it)=>{return {id:it, text:it}})
timezones = (await miscApi.listTimezones()).map((it)=>{return {value:it, label:it}})
})
$effect(()=>{
@@ -118,7 +118,7 @@
<div class="formelement">
<label for="timezone" class="block my-1 flex-1">Timezone</label>
<Select items={timezones} bind:value={form.timezone} valueMode="id" itemId="id" label="text"/>
<Select items={timezones} bind:value={form.timezone} valueMode="id" />
<FormError key="timezone" errors={errors} />
</div>
</div>
+3 -3
View File
@@ -199,11 +199,11 @@ h2 {
}
.svelte-select-list {
@apply absolute right-0 left-0 z-10 max-h-64 w-full overflow-y-auto rounded-sm border-none bg-stone-50 px-4 shadow-md dark:bg-stone-800;
@apply absolute right-0 left-0 z-10 max-h-64 w-full overflow-y-auto rounded-sm border-none bg-stone-50 shadow-md dark:bg-stone-800;
}
.svelte-select-list .list-group-title {
@apply h-8 cursor-default px-5 text-sm leading-10 font-medium text-ellipsis whitespace-nowrap text-gray-400 uppercase;
@apply h-8 cursor-default px-2 text-sm leading-10 font-medium text-ellipsis whitespace-nowrap text-gray-400 uppercase;
}
.svelte-select-list .empty {
@@ -215,7 +215,7 @@ h2 {
}
.item.group-item {
@apply px-10;
@apply px-4;
}
.item.active {