diff --git a/.gitignore b/.gitignore index 5cddf8a0151ec4aeef30a3fb98431f461f3b0cf2..594419fe31fa5fa2385854a3fef6b2e117557b93 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,6 @@ node_modules /*.env !/example.env -/.svelte +/.svelte-kit /build /functions diff --git a/package-lock.json b/package-lock.json index 5f09b3de198f8aa1963ba13dd99e80258447dbfc..7c367893b11f9c794701d99402e0a822f23dfe1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3626,15 +3626,15 @@ } }, "node_modules/@sveltejs/adapter-node": { - "version": "1.0.0-next.17", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.17.tgz", - "integrity": "sha512-kRGW9S0yf9X5kxFdW2sYF3s/bgME3Xyu/rnFEf121bSv0q7NhWktuuRWH3WbS5wQnFRoN+0s/1PaRK3ErNHsVQ==", + "version": "1.0.0-next.18", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.18.tgz", + "integrity": "sha512-w0w9KKo2p/Aq68JIQyWjNVBg/OuNqaYbVNFf9TVgXcdlPJcY1NncwujqUqejBATTm+ZhQzyQqXoosgqYtTI5tA==", "dev": true }, "node_modules/@sveltejs/kit": { - "version": "1.0.0-next.96", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.96.tgz", - "integrity": "sha512-SKJCqA80YFz9n/uY/w8XJPd+ADTHO3n3iy8jshI3uCpkGjjyWpu1aaLcVlmCpIYdSq+OxpT9WJuTXqmKx0St9w==", + "version": "1.0.0-next.98", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.98.tgz", + "integrity": "sha512-WAbxMLAmgJ1dwtmRm46dXSYewIIs8ykjl3yWwdqdPrOBY420HQyrvBjMmh9OVyBaCRy/He5blnMWRFDKUqNQng==", "dev": true, "dependencies": { "@sveltejs/vite-plugin-svelte": "^1.0.0-next.9", @@ -23108,15 +23108,15 @@ } }, "@sveltejs/adapter-node": { - "version": "1.0.0-next.17", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.17.tgz", - "integrity": "sha512-kRGW9S0yf9X5kxFdW2sYF3s/bgME3Xyu/rnFEf121bSv0q7NhWktuuRWH3WbS5wQnFRoN+0s/1PaRK3ErNHsVQ==", + "version": "1.0.0-next.18", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.18.tgz", + "integrity": "sha512-w0w9KKo2p/Aq68JIQyWjNVBg/OuNqaYbVNFf9TVgXcdlPJcY1NncwujqUqejBATTm+ZhQzyQqXoosgqYtTI5tA==", "dev": true }, "@sveltejs/kit": { - "version": "1.0.0-next.96", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.96.tgz", - "integrity": "sha512-SKJCqA80YFz9n/uY/w8XJPd+ADTHO3n3iy8jshI3uCpkGjjyWpu1aaLcVlmCpIYdSq+OxpT9WJuTXqmKx0St9w==", + "version": "1.0.0-next.98", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.98.tgz", + "integrity": "sha512-WAbxMLAmgJ1dwtmRm46dXSYewIIs8ykjl3yWwdqdPrOBY420HQyrvBjMmh9OVyBaCRy/He5blnMWRFDKUqNQng==", "dev": true, "requires": { "@sveltejs/vite-plugin-svelte": "^1.0.0-next.9", diff --git a/src/lib/components/parameters/ParameterPane.svelte b/src/lib/components/parameters/ParameterPane.svelte index a396738be2852fb83d1e942e30288a7891de83e1..6971d46a2165a4bd09f076e93c786bb854e09ea2 100644 --- a/src/lib/components/parameters/ParameterPane.svelte +++ b/src/lib/components/parameters/ParameterPane.svelte @@ -1,15 +1,14 @@ <script lang="ts"> import { session } from "$app/stores" import ParameterView from "$lib/components/parameters/ParameterView.svelte" - import type { Parameter, ParameterNode } from "$lib/parameters" - import { improveParameter } from "$lib/parameters" + import type { AnyParameter } from "$lib/parameters" + import { improveParameterWithAncestors } from "$lib/parameters" export let name: string export let newSelfTargetUrl: (urlPath: string) => string // export let pane: string - let ancestors: ParameterNode[] | undefined = undefined - let parameter: Parameter | undefined = undefined + let parameter: AnyParameter | undefined = undefined $: retrieveParameter(name) @@ -17,27 +16,19 @@ const url = new URL(`parameters/${name}`, $session.apiBaseUrl).toString() const res = await fetch(url) if (res.ok) { - const result = await res.json() - let parent = null - for (const ancestor of result.ancestors) { - improveParameter(parent, ancestor) - parent = ancestor - } - improveParameter(parent, result.parameter) - ancestors = result.ancestors - parameter = result.parameter + const parameterWithAncestors = await res.json() + parameter = improveParameterWithAncestors(parameterWithAncestors) } else { console.error( `Error ${ res.status } while retrieving parameter "${name}" at ${url}\n\n${await res.text()}`, ) - ancestors = undefined parameter = undefined } } </script> {#if parameter !== undefined} - <ParameterView {ancestors} editable={true} {newSelfTargetUrl} {parameter} /> + <ParameterView editable={true} {newSelfTargetUrl} {parameter} /> {/if} diff --git a/src/lib/components/parameters/ParameterView.svelte b/src/lib/components/parameters/ParameterView.svelte index 012a99080c9a87dc595202a2fcffce83d81909b4..27d3c01ce8fb4d866e591e8344ac4b7081e76e12 100644 --- a/src/lib/components/parameters/ParameterView.svelte +++ b/src/lib/components/parameters/ParameterView.svelte @@ -2,11 +2,10 @@ import { getContext } from "svelte" import type { Writable } from "svelte/store" - import type { AnyParameter, ParameterNode } from "$lib/parameters" - import { ParameterClass } from "$lib/parameters" + import type { AnyParameter } from "$lib/parameters" + import { ParameterClass, iterParameterAncestors } from "$lib/parameters" import type { Reform } from "$lib/reforms" - export let ancestors: ParameterNode[] export let editable: boolean export let newSelfTargetUrl: (urlPath: string) => string export let parameter: AnyParameter @@ -53,7 +52,7 @@ <h1> Paramètre - {#each ancestors as ancestor} + {#each [...iterParameterAncestors(parameter.parent)] as ancestor} <a class="link" href={newSelfTargetUrl(`/parameters/${ancestor.name}`)}> {ancestor.title} </a> @@ -99,16 +98,18 @@ Source : <a class="link" href={parameter.source}>{parameter.source}</a> </div> {/if} -{#if parameter.class === ParameterClass.Node && parameter.children !== undefined} - <ul class="ml-4"> - {#each Object.entries(parameter.children) as [childId, child]} - <li class="my-2"> - <a class="link" href={newSelfTargetUrl(`/parameters/${child.name}`)}> - {child.title} - </a> - </li> - {/each} - </ul> +{#if parameter.class === ParameterClass.Node} + {#if parameter.children !== undefined} + <ul class="ml-4"> + {#each Object.entries(parameter.children) as [childId, child]} + <li class="my-2"> + <a class="link" href={newSelfTargetUrl(`/parameters/${child.name}`)}> + {child.title} + </a> + </li> + {/each} + </ul> + {/if} {:else if parameter.class === ParameterClass.Parameter} {#if parameter.values !== undefined} <div> diff --git a/src/lib/components/parameters/ParametersSearch.svelte b/src/lib/components/parameters/ParametersSearch.svelte index 556a004e0bd90bdc7116ea9d0e6409d557767ea2..85390d007d8014b4d7e9f9a342dc87de3dfae042 100644 --- a/src/lib/components/parameters/ParametersSearch.svelte +++ b/src/lib/components/parameters/ParametersSearch.svelte @@ -3,7 +3,7 @@ import { createEventDispatcher } from "svelte" import type { AnyParameter, ParameterNode } from "$lib/parameters" - import { iterParameterAncestors, ParameterClass } from "$lib/parameters" + import { iterParameterAncestors, walkParameters } from "$lib/parameters" export let dispatchItemClick: boolean export let rootParameter: ParameterNode @@ -31,26 +31,6 @@ dispatch("itemClick", parameter) } } - - function* walkParameters( - parameter: AnyParameter, - depthFirst = false, - ): Generator<AnyParameter, void, unknown> { - if (!depthFirst && parameter.class !== ParameterClass.Node) { - yield parameter - } - switch (parameter.class) { - case ParameterClass.Node: - for (const child of Object.values(parameter.children)) { - yield* walkParameters(child, depthFirst) - } - break - default: - } - if (depthFirst && parameter.class !== ParameterClass.Node) { - yield parameter - } - } </script> <input autocomplete="off" on:input={onInput} type="search" value={term} /> diff --git a/src/lib/components/variables/VariableReferredInputs.svelte b/src/lib/components/variables/VariableReferredInputs.svelte index d4800522a13734c004f2cbd0cbab965465f0873b..8a0d903d6043be0b08a378c20a911178e8ec64fa 100644 --- a/src/lib/components/variables/VariableReferredInputs.svelte +++ b/src/lib/components/variables/VariableReferredInputs.svelte @@ -2,15 +2,28 @@ import type { Variable } from "$lib/variables" export let newSelfTargetUrl: (urlPath: string) => string - export let variables: Variable[] + export let inputs: Variable[] + export let variable: Variable </script> -{#if variables.length > 0} +<h1 class="bg-blue-500 text-white"> + Variables d'entrée de + <var>{variable.name}</var> + {#if variable.label !== undefined} + : <em>{variable.label}</em> + {/if} + <a + href="/variables/{variable.name}" + title="Plus d'informations sur cette variable">🛈</a + > +</h1> + +{#if inputs.length > 0} <ul> - {#each variables as variable} + {#each inputs as input} <li> - <a class="link" href={newSelfTargetUrl(`/variables/${variable.name}`)} - >{variable.name}</a + <a class="link" href={newSelfTargetUrl(`/variables/${input.name}`)} + >{input.name}</a > </li> {/each} diff --git a/src/lib/components/variables/VariableReferredInputsPane.svelte b/src/lib/components/variables/VariableReferredInputsPane.svelte index 9eb1ff41a61be482967d00cbd4c482cd46fe3370..99f12328d7be605b00edf5249514fe80e9c7d62e 100644 --- a/src/lib/components/variables/VariableReferredInputsPane.svelte +++ b/src/lib/components/variables/VariableReferredInputsPane.svelte @@ -8,11 +8,29 @@ export let newSelfTargetUrl: (urlPath: string) => string // export let pane: string - let variables: Variable[] | undefined = undefined + let inputs: Variable[] | undefined = undefined + let variable: Variable | undefined = undefined - $: retrieveVariableReferredVariable(name, date) + $: retrieveVariable(name) - async function retrieveVariableReferredVariable( + $: retrieveVariableReferredInputs(name, date) + + async function retrieveVariable(name: string): Promise<void> { + const url = new URL(`variables/${name}`, $session.apiBaseUrl).toString() + const res = await fetch(url) + if (res.ok) { + variable = await res.json() + } else { + console.error( + `Error ${ + res.status + } while retrieving referred input variables of variable "${name}" at ${url}\n\n${await res.text()}`, + ) + variable = undefined + } + } + + async function retrieveVariableReferredInputs( name: string, date: string, ): Promise<void> { @@ -22,18 +40,18 @@ ).toString() const res = await fetch(url) if (res.ok) { - variables = await res.json() + inputs = await res.json() } else { console.error( `Error ${ res.status - } while retrieving referred variables of variable "${name}" at ${url}\n\n${await res.text()}`, + } while retrieving referred input variables of variable "${name}" at ${url}\n\n${await res.text()}`, ) - variables = undefined + inputs = undefined } } </script> -{#if variables !== undefined} - <VariableReferredInputs {newSelfTargetUrl} {variables} /> +{#if inputs !== undefined && variable !== undefined} + <VariableReferredInputs {inputs} {newSelfTargetUrl} {variable} /> {/if} diff --git a/src/lib/components/variables/VariableReferredNode.svelte b/src/lib/components/variables/VariableReferredNode.svelte new file mode 100644 index 0000000000000000000000000000000000000000..35c7150b707bdaed687463f78b9505433670f77c --- /dev/null +++ b/src/lib/components/variables/VariableReferredNode.svelte @@ -0,0 +1,44 @@ +<script lang="ts"> + import type { ParameterNode } from "$lib/parameters" + import { ParameterClass } from "$lib/parameters" + + import VariableReferredParameter from "./VariableReferredParameter.svelte" + import VariableReferredParameterHeader from "./VariableReferredParameterHeader.svelte" + import VariableReferredScale from "./VariableReferredScale.svelte" + + export let depth: number + export let newSelfTargetUrl: (urlPath: string) => string + export let parameter: ParameterNode +</script> + +<section> + <VariableReferredParameterHeader {depth} {newSelfTargetUrl} {parameter} /> + + {#if parameter.children !== undefined} + <ul> + {#each Object.values(parameter.children) as child} + <li> + {#if child.class === ParameterClass.Node} + <svelte:self + depth={depth + 1} + {newSelfTargetUrl} + parameter={child} + /> + {:else if child.class === ParameterClass.Parameter} + <VariableReferredParameter + depth={depth + 1} + {newSelfTargetUrl} + parameter={child} + /> + {:else if child.class === ParameterClass.Scale} + <VariableReferredScale + depth={depth + 1} + {newSelfTargetUrl} + parameter={child} + /> + {/if} + </li> + {/each} + </ul> + {/if} +</section> diff --git a/src/lib/components/variables/VariableReferredParameter.svelte b/src/lib/components/variables/VariableReferredParameter.svelte new file mode 100644 index 0000000000000000000000000000000000000000..7f6b752a025f7596a99adbcf0b8edf35c696ac90 --- /dev/null +++ b/src/lib/components/variables/VariableReferredParameter.svelte @@ -0,0 +1,110 @@ +<script lang="ts"> + import { getContext } from "svelte" + import type { Writable } from "svelte/store" + + import type { Parameter } from "$lib/parameters" + import type { Reform } from "$lib/reforms" + + import VariableReferredParameterHeader from "./VariableReferredParameterHeader.svelte" + + export let depth: number + export let newSelfTargetUrl: (urlPath: string) => string + export let parameter: Parameter + + const editable = true + const reform = getContext("reform") as Writable<Reform> + const simulationRequested = getContext( + "simulationRequested", + ) as Writable<boolean> + let validStart = undefined + let validValue = undefined + + $: change = $reform[parameter.name] + + $: start = change?.start + + $: value = change?.value + + function changeStart(start) { + validStart = start + updateReform(validStart, validValue) + } + + function changeValue(value) { + validValue = parseFloat(value) + if (validValue == null || Number.isNaN(validValue)) { + validValue = undefined + } + updateReform(validStart, validValue) + } + + function updateReform(start: string, value) { + if (start !== undefined && value !== undefined) { + $reform = { + ...$reform, + [parameter.name]: { + start, + value: validValue, + }, + } + $simulationRequested = true + } + } +</script> + +<section> + <VariableReferredParameterHeader {depth} {newSelfTargetUrl} {parameter} /> + + {#if parameter.values !== undefined} + <div> + <div>Valeurs :</div> + <table class="border border-collapse table-auto"> + <thead> + <tr> + <th class="border p-1 text-center">Date</th> + <!-- <th class="border p-1 text-center">Nom</th> --> + <th class="border p-1 text-center">Valeur</th> + <th class="border p-1 text-center">Unité</th> + <th class="border p-1 text-center">Source</th> + </tr> + </thead> + <tbody> + {#if editable} + <tr> + <td class="border p-1 text-center" + ><input + on:change={({ target }) => changeStart(target.value)} + type="date" + value={start} + /></td + > + <!-- <td class= "border p-1 text-center">{name}</td> --> + <td class="border p-1 text-center" + ><input + type="number" + on:change={({ target }) => changeValue(target.value)} + {value} + /></td + > + <td class="border p-1 text-center" /> + <td class="border p-1 text-center" /> + </tr> + {/if} + {#each parameter.values as { instant, /* name, */ source, unit, value }} + <tr> + <td class="border p-1 text-center">{instant}</td> + <!-- <td class= "border p-1 text-center">{name}</td> --> + <td class="border p-1 text-center">{value ?? ""}</td> + <td class="border p-1 text-center">{unit ?? ""}</td> + <td class="border p-1 text-center" + >{#if source !== undefined}<a class="link" href={source} + >source</a + >{/if}</td + > + </tr> + {/each} + </tbody> + </table> + </div> + {/if} +</section> diff --git a/src/lib/components/variables/VariableReferredParameterHeader.svelte b/src/lib/components/variables/VariableReferredParameterHeader.svelte new file mode 100644 index 0000000000000000000000000000000000000000..f514427345dfdced59b3956136c73b893a9d2ee4 --- /dev/null +++ b/src/lib/components/variables/VariableReferredParameterHeader.svelte @@ -0,0 +1,36 @@ +<script lang="ts"> + import type { AnyParameter } from "$lib/parameters" + import { iterParameterAncestors } from "$lib/parameters" + + export let depth: number + export let newSelfTargetUrl: (urlPath: string) => string + export let parameter: AnyParameter +</script> + +<h1 + class:font-semibold={depth <= 2} + class:text-2xl={depth === 0} + class:text-xl={depth === 1} + class:text-lg={depth === 2} +> + {#if depth === 0} + {#each [...iterParameterAncestors(parameter.parent)] as ancestor} + <a class="link" href={newSelfTargetUrl(`/parameters/${ancestor.name}`)}> + {ancestor.title} + </a> + > + {/each} + {/if} + {parameter.title} + <a + class="link" + href="/parameters/{parameter.name}" + title="Plus d'informations sur ce paramètre">🛈</a + > +</h1> +{#if parameter.documentation !== undefined} + <div>{parameter.documentation}</div> +{/if} +{#if depth === 1} + <hr /> +{/if} diff --git a/src/lib/components/variables/VariableReferredParameters.svelte b/src/lib/components/variables/VariableReferredParameters.svelte index 9234825f2abde1b5dd63dbd253dc9851d302b04f..d1ea1dfdc13fc3910c88c8ad212cae9193cc5f96 100644 --- a/src/lib/components/variables/VariableReferredParameters.svelte +++ b/src/lib/components/variables/VariableReferredParameters.svelte @@ -1,17 +1,42 @@ <script lang="ts"> import type { AnyParameter } from "$lib/parameters" + import { mergeParameters, ParameterClass } from "$lib/parameters" + import type { Variable } from "$lib/variables" + + import VariableReferredNode from "./VariableReferredNode.svelte" + import VariableReferredParameter from "./VariableReferredParameter.svelte" + import VariableReferredScale from "./VariableReferredScale.svelte" export let newSelfTargetUrl: (urlPath: string) => string export let parameters: AnyParameter[] + export let variable: Variable + + $: rootParameterById = mergeParameters(parameters) </script> -{#if parameters.length > 0} +<h1 class="bg-blue-500 text-white"> + Paramètres de + <var>{variable.name}</var> + {#if variable.label !== undefined} + : <em>{variable.label}</em> + {/if} + <a + href="/variables/{variable.name}" + title="Plus d'informations sur cette variable">🛈</a + > +</h1> + +{#if Object.keys(rootParameterById).length > 0} <ul> - {#each parameters as parameter} + {#each Object.values(rootParameterById) as parameter} <li> - <a class="link" href={newSelfTargetUrl(`/parameters/${parameter.name}`)} - >{parameter.name}</a - > + {#if parameter.class === ParameterClass.Node} + <VariableReferredNode depth={0} {newSelfTargetUrl} {parameter} /> + {:else if parameter.class === ParameterClass.Parameter} + <VariableReferredParameter depth={0} {newSelfTargetUrl} {parameter} /> + {:else if parameter.class === ParameterClass.Scale} + <VariableReferredScale depth={0} {newSelfTargetUrl} {parameter} /> + {/if} </li> {/each} </ul> diff --git a/src/lib/components/variables/VariableReferredParametersPane.svelte b/src/lib/components/variables/VariableReferredParametersPane.svelte index 1e1a3c878f0c72c73626db0060b245e82ff4262e..e8bf3e7867162203b03e90b231dd7360c861e505 100644 --- a/src/lib/components/variables/VariableReferredParametersPane.svelte +++ b/src/lib/components/variables/VariableReferredParametersPane.svelte @@ -2,17 +2,37 @@ import { session } from "$app/stores" import VariableReferredParameters from "$lib/components/variables/VariableReferredParameters.svelte" import type { AnyParameter } from "$lib/parameters" + import { improveParameterWithAncestors } from "$lib/parameters" + import type { Variable } from "$lib/variables" export let date: string export let name: string export let newSelfTargetUrl: (urlPath: string) => string // export let pane: string + let variable: Variable | undefined = undefined let parameters: AnyParameter[] | undefined = undefined - $: retrieveVariableReferredParameter(name, date) + $: retrieveVariable(name) - async function retrieveVariableReferredParameter( + $: retrieveVariableReferredParameters(name, date) + + async function retrieveVariable(name: string): Promise<void> { + const url = new URL(`variables/${name}`, $session.apiBaseUrl).toString() + const res = await fetch(url) + if (res.ok) { + variable = await res.json() + } else { + console.error( + `Error ${ + res.status + } while retrieving referred input variables of variable "${name}" at ${url}\n\n${await res.text()}`, + ) + variable = undefined + } + } + + async function retrieveVariableReferredParameters( name: string, date: string, ): Promise<void> { @@ -22,7 +42,8 @@ ).toString() const res = await fetch(url) if (res.ok) { - parameters = await res.json() + const parametersWithAncestors = await res.json() + parameters = parametersWithAncestors.map(improveParameterWithAncestors) } else { console.error( `Error ${ @@ -34,6 +55,6 @@ } </script> -{#if parameters !== undefined} - <VariableReferredParameters {newSelfTargetUrl} {parameters} /> +{#if parameters !== undefined && variable !== undefined} + <VariableReferredParameters {newSelfTargetUrl} {parameters} {variable} /> {/if} diff --git a/src/lib/components/variables/VariableReferredScale.svelte b/src/lib/components/variables/VariableReferredScale.svelte new file mode 100644 index 0000000000000000000000000000000000000000..f3625149d5de0ae68c0907ddf650460195f67e1e --- /dev/null +++ b/src/lib/components/variables/VariableReferredScale.svelte @@ -0,0 +1,53 @@ +<script lang="ts"> + import type { Scale } from "$lib/parameters" + + import VariableReferredParameterHeader from "./VariableReferredParameterHeader.svelte" + + export let depth: number + export let newSelfTargetUrl: (urlPath: string) => string + export let parameter: Scale +</script> + +<section> + <VariableReferredParameterHeader {depth} {newSelfTargetUrl} {parameter} /> + + <div> + <div>Barème de type {parameter.type}:</div> + <table class="border border-collapse table-auto"> + <thead> + <tr> + <th class="border p-1 text-center">Date</th> + <th class="border p-1 text-center">Seuil</th> + <th class="border p-1 text-center">Unité de seuil</th> + <th class="border p-1 text-center">Value</th> + </tr> + </thead> + <tbody> + {#each Object.entries(parameter.brackets) as [instant, bracket]} + {#if bracket === null} + <tr> + <td class="border p-1 text-center">{instant}</td> + <td class="border p-1 text-center" colspan="3" /> + </tr> + {:else} + {#each Object.entries(bracket) as [threshold, value], index} + <tr> + {#if index === 0} + <td + class="border p-1 text-center" + rowspan={Object.keys(bracket).length}>{instant}</td + > + {/if} + <td class="border p-1 text-center">{threshold}</td> + <td class="border p-1 text-center" + >{parameter.rate_unit ?? parameter.threshold_unit ?? ""}</td + > + <td class="border p-1 text-center">{value ?? ""}</td> + </tr> + {/each} + {/if} + {/each} + </tbody> + </table> + </div> +</section> diff --git a/src/lib/parameters.ts b/src/lib/parameters.ts index 591392bffbe221f38401f5c2ab93c981517298e2..ad6318389dff7caeda365d323a29dc7fac7edd12 100644 --- a/src/lib/parameters.ts +++ b/src/lib/parameters.ts @@ -39,6 +39,11 @@ export interface ParameterNode extends ParameterBase { class: ParameterClass.Node } +export interface ParameterWithAncestors { + parameter: AnyParameter + ancestors: ParameterNode[] +} + export interface Scale extends ParameterBase { brackets: { [instant: string]: { [threshold: string]: number | null } | null } class: ParameterClass.Scale @@ -70,6 +75,12 @@ export function improveParameter( parameter.id = id if (parent != null) { parameter.parent = parent + if (parent.children === undefined) { + parent.children = {} + } + if (parent.children[id] === undefined) { + parent.children[id] = parameter + } } const title = parameter.description === undefined @@ -90,6 +101,19 @@ export function improveParameter( } } +export function improveParameterWithAncestors({ + ancestors, + parameter, +}: ParameterWithAncestors): AnyParameter { + let parent = null + for (const ancestor of ancestors) { + improveParameter(parent, ancestor) + parent = ancestor + } + improveParameter(parent, parameter) + return parameter +} + export function* iterParameterAncestors( parameter?: AnyParameter | undefined | null, ): Generator<AnyParameter, void, unknown> { @@ -99,3 +123,62 @@ export function* iterParameterAncestors( yield* iterParameterAncestors(parameter.parent) yield parameter } + +function mergeDuplicateParameters( + existingParameter: AnyParameter, + parameter: AnyParameter, +): void { + if (existingParameter.class === ParameterClass.Node) { + const existingChidren = existingParameter.children as { + [id: string]: AnyParameter + } + for (const child of Object.values( + (parameter as ParameterNode).children as { [id: string]: AnyParameter }, + )) { + const existingChild = existingChidren[child.id] + if (existingChild === undefined) { + existingChidren[child.id] = child + child.parent = existingParameter + } else { + mergeDuplicateParameters(existingChild, child) + } + } + } +} + +export function mergeParameters( + parameters: AnyParameter[], +): { [id: string]: AnyParameter } { + const rootParameterById: { [id: string]: AnyParameter } = {} + for (const parameter of parameters) { + const rootParameter = iterParameterAncestors(parameter).next() + .value as AnyParameter + const existingRootParameter = rootParameterById[parameter.id] + if (existingRootParameter === undefined) { + rootParameterById[rootParameter.id] = rootParameter + } else { + mergeDuplicateParameters(existingRootParameter, rootParameter) + } + } + return rootParameterById +} + +export function* walkParameters( + parameter: AnyParameter, + depthFirst = false, +): Generator<AnyParameter, void, unknown> { + if (!depthFirst && parameter.class !== ParameterClass.Node) { + yield parameter + } + switch (parameter.class) { + case ParameterClass.Node: + for (const child of Object.values(parameter.children)) { + yield* walkParameters(child, depthFirst) + } + break + default: + } + if (depthFirst && parameter.class !== ParameterClass.Node) { + yield parameter + } +} diff --git a/src/routes/parameters/[parameter].svelte b/src/routes/parameters/[parameter].svelte index 12bee41406b08fb364eff4771c39d9718af8f4b4..31bf2ddc269f57fac99b7cbea5363fec334916b5 100644 --- a/src/routes/parameters/[parameter].svelte +++ b/src/routes/parameters/[parameter].svelte @@ -1,7 +1,7 @@ <script context="module" lang="ts"> import type { LoadInput, LoadOutput } from "@sveltejs/kit/types/page" - import { improveParameter } from "$lib/parameters" + import { improveParameterWithAncestors } from "$lib/parameters" export async function load({ fetch, @@ -17,18 +17,10 @@ error: new Error(`Could not load ${url}`), } } - const { ancestors, parameter } = await res.json() - let parent = null - for (const ancestor of ancestors) { - improveParameter(parent, ancestor) - parent = ancestor - } - improveParameter(parent, parameter) - + const parameterWithAncestors = await res.json() return { props: { - ancestors, - parameter, + parameter: improveParameterWithAncestors(parameterWithAncestors), }, } } @@ -37,9 +29,8 @@ <script lang="ts"> import { session } from "$app/stores" import ParameterView from "$lib/components/parameters/ParameterView.svelte" - import type { AnyParameter, ParameterNode } from "$lib/parameters" + import type { AnyParameter } from "$lib/parameters" - export let ancestors: ParameterNode[] export let parameter: AnyParameter </script> @@ -48,10 +39,5 @@ </svelte:head> <main> - <ParameterView - {ancestors} - editable={true} - newSelfTargetUrl={(url) => url} - {parameter} - /> + <ParameterView editable={true} newSelfTargetUrl={(url) => url} {parameter} /> </main> diff --git a/src/routes/variables/[variable]/inputs/[date].svelte b/src/routes/variables/[variable]/inputs/[date].svelte index dde966d506d0ea3555e1b024f44f16f92b3cc8a5..154b5bef0754da709499b57c576dc6c1041dc8fd 100644 --- a/src/routes/variables/[variable]/inputs/[date].svelte +++ b/src/routes/variables/[variable]/inputs/[date].svelte @@ -7,20 +7,52 @@ session, }: LoadInput): Promise<LoadOutput> { const { date, variable: name } = page.params - const url = new URL( - `variables/${name}/inputs/${date}`, - session.apiBaseUrl, - ).toString() - const res = await fetch(url) - if (!res.ok) { - return { - status: res.status, - error: new Error(`Could not load ${url}`), - } + const results = await Promise.all([ + (async () => { + const url = new URL(`variables/${name}`, session.apiBaseUrl).toString() + const res = await fetch(url) + if (!res.ok) { + return { + status: res.status, + error: new Error(`Could not load ${url}`), + } + } + return { + props: { + variable: await res.json(), + }, + } + })(), + (async () => { + const url = new URL( + `variables/${name}/inputs/${date}`, + session.apiBaseUrl, + ).toString() + const res = await fetch(url) + if (!res.ok) { + return { + status: res.status, + error: new Error(`Could not load ${url}`), + } + } + return { + props: { + inputs: await res.json(), + }, + } + })(), + ]) + const firstResultWithError = results.find( + ({ error }) => error !== undefined, + ) + if (firstResultWithError !== undefined) { + return firstResultWithError } return { props: { - variables: await res.json(), + ...Object.fromEntries( + [].concat(...results.map(({ props }) => Object.entries(props))), + ), }, } } @@ -31,7 +63,8 @@ import VariableReferredInputs from "$lib/components/variables/VariableReferredInputs.svelte" import type { Variable } from "$lib/variables" - export let variables: Variable[] + export let variable: Variable + export let inputs: Variable[] $: params = $page.params @@ -47,5 +80,5 @@ </svelte:head> <main> - <VariableReferredInputs newSelfTargetUrl={(url) => url} {variables} /> + <VariableReferredInputs {inputs} newSelfTargetUrl={(url) => url} {variable} /> </main> diff --git a/src/routes/variables/[variable]/parameters/[date].svelte b/src/routes/variables/[variable]/parameters/[date].svelte index 2e7beed0dc1574db83fdeea5c64c3eaabaed8313..8a3f5a4351355c9a87328f6b48e2d55ce9966667 100644 --- a/src/routes/variables/[variable]/parameters/[date].svelte +++ b/src/routes/variables/[variable]/parameters/[date].svelte @@ -1,26 +1,63 @@ <script context="module" lang="ts"> import type { LoadInput, LoadOutput } from "@sveltejs/kit/types/page" + import { improveParameterWithAncestors } from "$lib/parameters" + export async function load({ fetch, page, session, }: LoadInput): Promise<LoadOutput> { const { date, variable: name } = page.params - const url = new URL( - `variables/${name}/parameters/${date}`, - session.apiBaseUrl, - ).toString() - const res = await fetch(url) - if (!res.ok) { - return { - status: res.status, - error: new Error(`Could not load ${url}`), - } + const results = await Promise.all([ + (async () => { + const url = new URL(`variables/${name}`, session.apiBaseUrl).toString() + const res = await fetch(url) + if (!res.ok) { + return { + status: res.status, + error: new Error(`Could not load ${url}`), + } + } + return { + props: { + variable: await res.json(), + }, + } + })(), + (async () => { + const url = new URL( + `variables/${name}/parameters/${date}`, + session.apiBaseUrl, + ).toString() + const res = await fetch(url) + if (!res.ok) { + return { + status: res.status, + error: new Error(`Could not load ${url}`), + } + } + const parametersWithAncestors = await res.json() + return { + props: { + parameters: parametersWithAncestors.map( + improveParameterWithAncestors, + ), + }, + } + })(), + ]) + const firstResultWithError = results.find( + ({ error }) => error !== undefined, + ) + if (firstResultWithError !== undefined) { + return firstResultWithError } return { props: { - parameters: await res.json(), + ...Object.fromEntries( + [].concat(...results.map(({ props }) => Object.entries(props))), + ), }, } } @@ -30,8 +67,10 @@ import { page, session } from "$app/stores" import VariableReferredParameters from "$lib/components/variables/VariableReferredParameters.svelte" import type { AnyParameter } from "$lib/parameters" + import type { Variable } from "$lib/variables" export let parameters: AnyParameter[] + export let variable: Variable $: params = $page.params @@ -47,5 +86,9 @@ </svelte:head> <main> - <VariableReferredParameters newSelfTargetUrl={(url) => url} {parameters} /> + <VariableReferredParameters + newSelfTargetUrl={(url) => url} + {parameters} + {variable} + /> </main> diff --git a/svelte.config.cjs b/svelte.config.js similarity index 81% rename from svelte.config.cjs rename to svelte.config.js index 037e780360fc8653f8664db032cf6e628760ae81..85eeb2bba537b5b63d0bccbc2065911075e5ed8c 100644 --- a/svelte.config.cjs +++ b/svelte.config.js @@ -1,8 +1,18 @@ -const sveltePreprocess = require("svelte-preprocess") -const node = require("@sveltejs/adapter-node") +import node from "@sveltejs/adapter-node" +import sveltePreprocess from "svelte-preprocess" /** @type {import('@sveltejs/kit').Config} */ -module.exports = { +const config = { + kit: { + // By default, `npm run build` will create a standard Node app. + // You can create optimized builds for different platforms by + // specifying a different adapter + adapter: node(), + + // hydrate the <div id="svelte"> element in src/app.html + target: "#svelte", + }, + // Consult https://github.com/sveltejs/svelte-preprocess // for more information about preprocessors preprocess: [ @@ -13,13 +23,6 @@ module.exports = { postcss: true, }), ], - kit: { - // By default, `npm run build` will create a standard Node app. - // You can create optimized builds for different platforms by - // specifying a different adapter - adapter: node(), - - // hydrate the <div id="svelte"> element in src/app.html - target: "#svelte", - }, } + +export default config