diff --git a/example.env b/example.env index 95716af6bfba336605a7b7b2c8ad63cf63278d0d..0bbb1f7dd69fa28736c9ed795759c460f527c782 100644 --- a/example.env +++ b/example.env @@ -54,6 +54,10 @@ PORTAL_URL="https://leximpact.an.fr/" # Set to true when application is behind a proxy PROXY=false +# Optional name of default reform to use +# Reform name must belong to a name of an OpenFisca reform in metadata.json +# REFORM=universal_basic_income + # Directory containing JSON of simulations saved by users SIMULATIONS_DIR="../simulations" diff --git a/package-lock.json b/package-lock.json index 7bbd0f3028180c592ddd484e141a86000dd2b802..28e021cbca1a13aecae22ea242bc142dcc8fc7e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,9 +16,9 @@ "@auditors/core": "^0.1.7", "@fontsource/lato": "^4.3.0", "@fontsource/lora": "^4.3.0", - "@openfisca/json-model": "^0.15.1", - "@sveltejs/adapter-node": "^1.0.0-next.48", - "@sveltejs/kit": "^1.0.0-next.168", + "@openfisca/json-model": "^0.15.2", + "@sveltejs/adapter-node": "^1.0.0-next.49", + "@sveltejs/kit": "^1.0.0-next.169", "@tailwindcss/forms": "^0.3.2", "@types/cookie": "^0.4.0", "@types/fs-extra": "^9.0.11", @@ -327,19 +327,19 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" }, "engines": { "node": ">=6.9.0" @@ -432,9 +432,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "engines": { "node": ">=6.9.0" } @@ -491,9 +491,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", "peer": true, "bin": { "parser": "bin/babel-parser.js" @@ -1911,9 +1911,9 @@ } }, "node_modules/@openfisca/json-model": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@openfisca/json-model/-/json-model-0.15.1.tgz", - "integrity": "sha512-Q1gsZAIhKDBu6Wu/LUBnboyRWHyduCuVdwpRCNG+tyeDWrGzdb4NoHA4Zi5rdvwvPLUNQ5htFDkMHLc5x8LSkw==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@openfisca/json-model/-/json-model-0.15.2.tgz", + "integrity": "sha512-tVfzvwTz2bQbl9CowSxTcdlcXW/s9LDcpbPkCqD8b4W8uI5bBzfAqpQe63ijhNDS9bIVI0oVufIZ9aFmMo6nGA==", "dev": true, "dependencies": { "@auditors/core": "^0.1.11", @@ -1938,22 +1938,22 @@ } }, "node_modules/@sveltejs/adapter-node": { - "version": "1.0.0-next.48", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.48.tgz", - "integrity": "sha512-j50GruX7OPVhtDRikTqGbQVZ5+jmF0kxr32EkMjXxdG1MU//37ChYsxps06/L1hLvULXEVZwRs0WUQE0VYZ7IQ==", + "version": "1.0.0-next.49", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.49.tgz", + "integrity": "sha512-0v70tnoWOJoYql9g+P92aF+rfhqJ+y9wAyuAV62F7+kSgTBqzTCohuwQwRzLDXKfvxou7G9hfWo7RV1zo7tNKw==", "dev": true, "dependencies": { - "esbuild": "^0.12.5", + "esbuild": "^0.12.28", "tiny-glob": "^0.2.9" } }, "node_modules/@sveltejs/kit": { - "version": "1.0.0-next.168", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.168.tgz", - "integrity": "sha512-BHVqLp3d8BCPD0kuNueoV5YxyfLfgAC9wU6PCbOGIhn1gw4mvpiVbeEn7NKeVkTkl88bu/QtAITLsIx1+4flTA==", + "version": "1.0.0-next.169", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.169.tgz", + "integrity": "sha512-MtYsQIIB35qVHrEDD7yzZejga/0mOHnvS6qy0zkcpyZxbbDu9/BUTBAGHrCiL2qvajI94eUPSzjWaCbRap809g==", "dependencies": { "@sveltejs/vite-plugin-svelte": "^1.0.0-next.24", - "cheap-watch": "^1.0.3", + "cheap-watch": "^1.0.4", "sade": "^1.7.4", "vite": "^2.5.7" }, @@ -3341,9 +3341,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.842", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.842.tgz", - "integrity": "sha512-P/nDMPIYdb2PyqCQwhTXNi5JFjX1AsDVR0y6FrHw752izJIAJ+Pn5lugqyBq4tXeRSZBMBb2ZGvRGB1djtELEQ==" + "version": "1.3.843", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.843.tgz", + "integrity": "sha512-OWEwAbzaVd1Lk9MohVw8LxMXFlnYd9oYTYxfX8KS++kLLjDfbovLOcEEXwRhG612dqGQ6+44SZvim0GXuBRiKg==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -7252,19 +7252,19 @@ } }, "@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "peer": true, "requires": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" } }, "@babel/helper-optimise-call-expression": { @@ -7333,9 +7333,9 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==" + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" }, "@babel/helper-validator-option": { "version": "7.14.5", @@ -7377,9 +7377,9 @@ } }, "@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", "peer": true }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { @@ -8348,9 +8348,9 @@ } }, "@openfisca/json-model": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@openfisca/json-model/-/json-model-0.15.1.tgz", - "integrity": "sha512-Q1gsZAIhKDBu6Wu/LUBnboyRWHyduCuVdwpRCNG+tyeDWrGzdb4NoHA4Zi5rdvwvPLUNQ5htFDkMHLc5x8LSkw==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@openfisca/json-model/-/json-model-0.15.2.tgz", + "integrity": "sha512-tVfzvwTz2bQbl9CowSxTcdlcXW/s9LDcpbPkCqD8b4W8uI5bBzfAqpQe63ijhNDS9bIVI0oVufIZ9aFmMo6nGA==", "dev": true, "requires": { "@auditors/core": "^0.1.11", @@ -8369,22 +8369,22 @@ } }, "@sveltejs/adapter-node": { - "version": "1.0.0-next.48", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.48.tgz", - "integrity": "sha512-j50GruX7OPVhtDRikTqGbQVZ5+jmF0kxr32EkMjXxdG1MU//37ChYsxps06/L1hLvULXEVZwRs0WUQE0VYZ7IQ==", + "version": "1.0.0-next.49", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.49.tgz", + "integrity": "sha512-0v70tnoWOJoYql9g+P92aF+rfhqJ+y9wAyuAV62F7+kSgTBqzTCohuwQwRzLDXKfvxou7G9hfWo7RV1zo7tNKw==", "dev": true, "requires": { - "esbuild": "^0.12.5", + "esbuild": "^0.12.28", "tiny-glob": "^0.2.9" } }, "@sveltejs/kit": { - "version": "1.0.0-next.168", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.168.tgz", - "integrity": "sha512-BHVqLp3d8BCPD0kuNueoV5YxyfLfgAC9wU6PCbOGIhn1gw4mvpiVbeEn7NKeVkTkl88bu/QtAITLsIx1+4flTA==", + "version": "1.0.0-next.169", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.169.tgz", + "integrity": "sha512-MtYsQIIB35qVHrEDD7yzZejga/0mOHnvS6qy0zkcpyZxbbDu9/BUTBAGHrCiL2qvajI94eUPSzjWaCbRap809g==", "requires": { "@sveltejs/vite-plugin-svelte": "^1.0.0-next.24", - "cheap-watch": "^1.0.3", + "cheap-watch": "^1.0.4", "sade": "^1.7.4", "vite": "^2.5.7" } @@ -9413,9 +9413,9 @@ } }, "electron-to-chromium": { - "version": "1.3.842", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.842.tgz", - "integrity": "sha512-P/nDMPIYdb2PyqCQwhTXNi5JFjX1AsDVR0y6FrHw752izJIAJ+Pn5lugqyBq4tXeRSZBMBb2ZGvRGB1djtELEQ==" + "version": "1.3.843", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.843.tgz", + "integrity": "sha512-OWEwAbzaVd1Lk9MohVw8LxMXFlnYd9oYTYxfX8KS++kLLjDfbovLOcEEXwRhG612dqGQ6+44SZvim0GXuBRiKg==" }, "emoji-regex": { "version": "8.0.0", diff --git a/package.json b/package.json index e57934baa3fe39befb792a78c99d4570c00a752a..75ae887de45e96ad14e97bd4395a7584d81bc95a 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,9 @@ "@auditors/core": "^0.1.7", "@fontsource/lato": "^4.3.0", "@fontsource/lora": "^4.3.0", - "@openfisca/json-model": "^0.15.1", - "@sveltejs/adapter-node": "^1.0.0-next.48", - "@sveltejs/kit": "^1.0.0-next.168", + "@openfisca/json-model": "^0.15.2", + "@sveltejs/adapter-node": "^1.0.0-next.49", + "@sveltejs/kit": "^1.0.0-next.169", "@tailwindcss/forms": "^0.3.2", "@types/cookie": "^0.4.0", "@types/fs-extra": "^9.0.11", diff --git a/src/hooks.ts b/src/hooks.ts index 54357d651f1f37abd1ca8cb8edf769ce7b221541..1cfdaf957d946f2ff2567a827fe14fcc894f823c 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -54,6 +54,7 @@ export const getSession: GetSession<{}, Session> = async (request) => { urlTemplate: openfiscaRepository.urlTemplate, }, portalUrl: config.portalUrl, + reformName: config.reformName, title: config.title, user, } diff --git a/src/lib/auditors/config.ts b/src/lib/auditors/config.ts index b2fc30b85e14c9ad675e4f996b614fb51d4ca0bc..0568bf67bc1e5806d307f6471c7eb5ab83adbf2c 100644 --- a/src/lib/auditors/config.ts +++ b/src/lib/auditors/config.ts @@ -82,14 +82,9 @@ export function auditConfig( auditRequire, ) } - audit.attribute( - data, - "githubPersonalAccessToken", - true, - errors, - remainingKeys, - auditTrimString, - ) + for (const key of ["githubPersonalAccessToken", "reformName"]) { + audit.attribute(data, key, true, errors, remainingKeys, auditTrimString) + } audit.attribute( data, "hiddenEntitiesKeyPlural", diff --git a/src/lib/components/parameters/ParameterPane.svelte b/src/lib/components/parameters/ParameterPane.svelte index 9bf2a8be2a36ed9dbd8021e65c093648a0c015ed..9edf42392fdbd9198c90fe72f152eef60bc1556b 100644 --- a/src/lib/components/parameters/ParameterPane.svelte +++ b/src/lib/components/parameters/ParameterPane.svelte @@ -1,11 +1,11 @@ <script lang="ts"> import ParameterView from "$lib/components/parameters/ParameterView.svelte" - import { getParameter } from "$lib/parameters" + import { getParameter, rootParameter } from "$lib/parameters" export let name: string // export let pane: string - $: parameter = getParameter(name) + $: parameter = getParameter(rootParameter, name) $: if (parameter === undefined) { console.error(`Parameter "${name}" not found`) diff --git a/src/lib/components/test_cases/TestCaseView.svelte b/src/lib/components/test_cases/TestCaseView.svelte index f82373aa520d4a1ed9d357fd8c24fc171da17682..f8656d8a3777a68741bce65d44af2f6ac6fb4764 100644 --- a/src/lib/components/test_cases/TestCaseView.svelte +++ b/src/lib/components/test_cases/TestCaseView.svelte @@ -55,7 +55,9 @@ ) as Writable<EvaluationByNameArrayByCalculationName> const familyEntity = entityByKey[$session.familyEntityKey] const personEntity = entityByKey[personEntityKey] - const reform = getContext("reform") as Writable<ParametricReform> + const parametricReform = getContext( + "parametricReform", + ) as Writable<ParametricReform> const variableDefinitionByName = { age: { allowSlider: true, @@ -149,6 +151,7 @@ variableName: string, populationId: string, ): number | undefined { + console.log("getVariableValue", variableName, populationId) const variable = variableSummaryByName[variableName] if (variable === undefined) { return undefined @@ -449,7 +452,7 @@ title="⚠️ Les dispositifs n'étant pas tous à jour, ce montant est à considérer avec prudence." > <ValueChange - amendmentValue={Object.keys($reform).length === 0 + amendmentValue={Object.keys($parametricReform).length === 0 ? undefined : calculateTotal( $evaluationByNameArrayByCalculationName.amendment[ diff --git a/src/lib/components/variables/VariableReferredNodeParameter.svelte b/src/lib/components/variables/VariableReferredNodeParameter.svelte index c1cf1ec899c1a448896c227b9641d9ea3d59c1c3..b93c60f04cd87184cab66586073a269a76c75200 100644 --- a/src/lib/components/variables/VariableReferredNodeParameter.svelte +++ b/src/lib/components/variables/VariableReferredNodeParameter.svelte @@ -1,5 +1,10 @@ <script lang="ts"> - import type { NodeParameter } from "@openfisca/json-model" + import type { + NodeParameter, + Parameter, + ScaleParameter, + ValueParameter, + } from "@openfisca/json-model" import { ParameterClass } from "@openfisca/json-model" import VariableReferredParameterHeader from "./VariableReferredParameterHeader.svelte" @@ -8,29 +13,71 @@ export let date: string export let depth: number - export let parameter: NodeParameter + export let parameter: NodeParameter | undefined + export let reformParameter: NodeParameter + + function asScaleParameter( + parameter: Parameter | undefined, + ): ScaleParameter | undefined { + return parameter as ScaleParameter | undefined + } + + function asValueParameter( + parameter: Parameter | undefined, + ): ValueParameter | undefined { + return parameter as ValueParameter | undefined + } + + function* iterChildren( + parameter: NodeParameter | undefined, + reformParameter: NodeParameter, + ): Generator<[Parameter | undefined, Parameter], void, unknown> { + // Notes: + // A reformParameter is always more complete than a parameter before reform. + // A reform never changes the class of a parameter + for (const reformChild of Object.values(reformParameter.children).sort( + (reformChild1, reformChild2) => + reformChild1.class === reformChild2.class || + (reformChild1.class !== ParameterClass.Node && + reformChild2.class !== ParameterClass.Node) + ? reformChild1.title.localeCompare(reformChild2.title) + : reformChild1.class === ParameterClass.Node + ? 1 + : -1, + )) { + const child = parameter?.children[reformChild.id] + yield [child, reformChild] + } + } </script> <section> - <VariableReferredParameterHeader {depth} {parameter} /> + <VariableReferredParameterHeader {depth} parameter={reformParameter} /> - {#if parameter.children !== undefined} + {#if reformParameter.children !== undefined} <ul> - {#each Object.values(parameter.children).sort( (child1, child2) => (child1.class === child2.class || (child1.class !== ParameterClass.Node && child2.class !== ParameterClass.Node) ? child1.title.localeCompare(child2.title) : child1.class === ParameterClass.Node ? 1 : -1), ) as child} + {#each [...iterChildren(parameter, reformParameter)] as [child, reformChild]} <li> - {#if child.class === ParameterClass.Node} - <svelte:self {date} depth={depth + 1} parameter={child} /> - {:else if child.class === ParameterClass.Value} - <VariableReferredValueParameter + {#if reformChild.class === ParameterClass.Node} + <svelte:self {date} depth={depth + 1} parameter={child} + reformParameter={reformChild} /> - {:else if child.class === ParameterClass.Scale} + {:else if reformChild.class === ParameterClass.Value} + <VariableReferredValueParameter + {date} + depth={depth + 1} + parameter={asValueParameter(child)} + reformParameter={reformChild} + /> + {:else if reformChild.class === ParameterClass.Scale} <VariableReferredScaleParameter {date} depth={depth + 1} - parameter={child} + parameter={asScaleParameter(child)} + reformParameter={reformChild} /> {/if} </li> diff --git a/src/lib/components/variables/VariableReferredParameters.svelte b/src/lib/components/variables/VariableReferredParameters.svelte index b48b4b612ae12aac64c518b94668c1622e6b5611..397a7b8210628fa75e1cb60a3593885ca9abcb92 100644 --- a/src/lib/components/variables/VariableReferredParameters.svelte +++ b/src/lib/components/variables/VariableReferredParameters.svelte @@ -1,137 +1,278 @@ <script lang="ts"> - import type { Parameter, Variable } from "@openfisca/json-model" + import type { + NodeParameter, + Parameter, + ScaleParameter, + ValueParameter, + } from "@openfisca/json-model" import { getVariableFormula, mergeParameters, ParameterClass, } from "@openfisca/json-model" + import { getContext } from "svelte" + import type { Writable } from "svelte/store" + + import { + decompositionCoreByName, + decompositionCoreByNameByReformName, + } from "$lib/decompositions" + import { + getParameter, + rootParameter, + rootParameterByReformName, + } from "$lib/parameters" + import { + iterVariableParametersName, + variableSummaryByName, + variableSummaryByNameByReformName, + } from "$lib/variables" import VariableHeader from "./VariableHeader.svelte" import VariableReferredNodeParameter from "./VariableReferredNodeParameter.svelte" import VariableReferredScaleParameter from "./VariableReferredScaleParameter.svelte" import VariableReferredValueParameter from "./VariableReferredValueParameter.svelte" - import type { Decomposition } from "$lib/decompositions" export let date: string - export let decomposition: Decomposition | undefined - export let parameters: Parameter[] - export let variable: Variable | undefined + export let name: string + const billName = getContext("billName") as Writable<string | undefined> let openDirectParameters = true - $: directParametersName = new Set( - variable === undefined + // Note: A reform decomposition is always more complete than a decomposition before reform. + // And the children of a reform decomposition always contain the children of the decomposition + // before reform. + // => Non reform decomposition is not needed. + $: reformDecompositionCoreByName = + decompositionCoreByNameByReformName[$billName] ?? decompositionCoreByName + $: reformDecompositionCore = reformDecompositionCoreByName[name] + $: reformDecomposition = + reformDecompositionCore === undefined + ? undefined + : { + ...reformDecompositionCore, + name, + } + + // Note: A reform variable is always more complete than a variable before reform. + // But it may contain different formulas, with different parameters & variables. + $: reformVariableSummaryByName = + variableSummaryByNameByReformName[$billName] ?? variableSummaryByName + $: reformVariable = reformVariableSummaryByName[name] + $: variable = variableSummaryByName[name] + + $: if (reformDecomposition === undefined && reformVariable === undefined) { + console.error(`Variable "${name}" not found`) + } + + // Note: A reform parameters tree is always more complete than a parameters tree before reform. + // And the children of a reform node parameter always contain the children of the node parameter + // before reform (albeit with some different value parameters). + $: reformRootParameter = rootParameterByReformName[$billName] ?? rootParameter + + $: bothParametersName = new Set([ + ...(variable === undefined + ? [] + : iterVariableParametersName(variable, date)), + ...(reformVariable === undefined + ? [] + : iterVariableParametersName(reformVariable, date)), + ]) + + $: bothDirectParametersName = new Set([ + ...(variable === undefined + ? [] + : getVariableFormula(variable, date)?.parameters ?? []), + ...(reformVariable === undefined ? [] - : getVariableFormula(variable, date)?.parameters ?? [], + : getVariableFormula(reformVariable, date)?.parameters ?? []), + ]) + + $: bothRootParameterById = mergeParameters( + [...bothParametersName].map((name) => + getParameter(reformRootParameter, name), + ), ) - $: directParameters = parameters.filter((parameter) => - directParametersName.has(parameter.name), + $: bothRootDirectParameterById = mergeParameters( + [...bothDirectParametersName].map((name) => + getParameter(reformRootParameter, name), + ), ) - $: openAllParameters = directParameters.length === 0 + $: openAllParameters = bothDirectParametersName.size === 0 + + function asNodeParameter( + parameter: Parameter | undefined, + ): NodeParameter | undefined { + return parameter as NodeParameter | undefined + } - $: rootDirectParameterById = mergeParameters(directParameters) + function asScaleParameter( + parameter: Parameter | undefined, + ): ScaleParameter | undefined { + return parameter as ScaleParameter | undefined + } - $: rootParameterById = mergeParameters(parameters) + function asValueParameter( + parameter: Parameter | undefined, + ): ValueParameter | undefined { + return parameter as ValueParameter | undefined + } + + function* iterVariableRootParameters( + bothRootParameterById: { [id: string]: Parameter }, + rootParameter: NodeParameter, + reformRootParameter: NodeParameter, + ): Generator<[Parameter | undefined, Parameter], void, unknown> { + for (const bothChild of Object.values(bothRootParameterById).sort( + (bothChild1, bothChild2) => + bothChild1.class === bothChild2.class || + (bothChild1.class !== ParameterClass.Node && + bothChild2.class !== ParameterClass.Node) + ? bothChild1.title.localeCompare(bothChild2.title) + : bothChild1.class === ParameterClass.Node + ? 1 + : -1, + )) { + const child = rootParameter.children[bothChild.id] // Sometimes undefined + const reformChild = reformRootParameter.children[bothChild.id] // Never undefined + yield [child, reformChild] + } + } </script> -<VariableHeader {decomposition} {variable} /> - -{#if decomposition?.children === undefined} - {#if Object.keys(rootDirectParameterById).length > 0} - <h2 - class="bg-le-gris-dispositif-ultralight text-black flex justify-between py-2 text-lg px-5 rounded-r shadow-inner" - > - <span>Principaux paramètres de la loi</span> - <button on:click={() => (openDirectParameters = !openDirectParameters)}> - {#if openDirectParameters} - <!-- Material Icons name: Expand Less --> - <svg - aria-hidden="true" - class="block h-6 stroke-current w-6" - fill="black" - viewBox="0 0 24 24" - xmlns="http://www.w3.org/2000/svg" - ><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" /></svg - > - {:else} - <!-- Material Icons name: Expand More --> - <svg - aria-hidden="true" - class="block h-6 stroke-current w-6" - fill="black" - viewBox="0 0 24 24" - xmlns="http://www.w3.org/2000/svg" - ><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" /></svg - > - {/if} - </button> - </h2> - - {#if openDirectParameters} - <section class="pl-5 mb-3"> - <ul> - {#each Object.values(rootDirectParameterById) as parameter} - <li> - {#if parameter.class === ParameterClass.Node} - <VariableReferredNodeParameter {date} depth={0} {parameter} /> - {:else if parameter.class === ParameterClass.Value} - <VariableReferredValueParameter {date} depth={0} {parameter} /> - {:else if parameter.class === ParameterClass.Scale} - <VariableReferredScaleParameter {date} depth={0} {parameter} /> - {/if} - </li> - {/each} - </ul> - </section> +{#if reformDecomposition !== undefined || reformVariable !== undefined} + <VariableHeader + decomposition={reformDecomposition} + variable={reformVariable} + /> + + {#if reformDecomposition?.children === undefined} + {#if Object.keys(bothRootDirectParameterById).length > 0} + <h2 + class="bg-le-gris-dispositif-ultralight text-black flex justify-between py-2 text-lg px-5 rounded-r shadow-inner" + > + <span>Principaux paramètres de la loi</span> + <button on:click={() => (openDirectParameters = !openDirectParameters)}> + {#if openDirectParameters} + <!-- Material Icons name: Expand Less --> + <svg + aria-hidden="true" + class="block h-6 stroke-current w-6" + fill="black" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + ><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" /></svg + > + {:else} + <!-- Material Icons name: Expand More --> + <svg + aria-hidden="true" + class="block h-6 stroke-current w-6" + fill="black" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + ><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" /></svg + > + {/if} + </button> + </h2> + + {#if openDirectParameters} + <section class="pl-5 mb-3"> + <ul> + {#each [...iterVariableRootParameters(bothRootDirectParameterById, rootParameter, reformRootParameter)] as [parameter, reformParameter]} + <li> + {#if parameter.class === ParameterClass.Node} + <VariableReferredNodeParameter + {date} + depth={0} + {parameter} + reformParameter={asNodeParameter(reformParameter)} + /> + {:else if parameter.class === ParameterClass.Value} + <VariableReferredValueParameter + {date} + depth={0} + {parameter} + reformParameter={asValueParameter(reformParameter)} + /> + {:else if parameter.class === ParameterClass.Scale} + <VariableReferredScaleParameter + {date} + depth={0} + {parameter} + reformParameter={asScaleParameter(reformParameter)} + /> + {/if} + </li> + {/each} + </ul> + </section> + {/if} {/if} - {/if} - {#if Object.keys(rootParameterById).length > 0} - <h2 - class="bg-le-gris-dispositif-ultralight text-black flex justify-between py-2 text-lg px-5 rounded-r shadow-inner" - > - <span>Autres paramètres affectant le dispositif</span> - <button on:click={() => (openAllParameters = !openAllParameters)}> - {#if openAllParameters} - <!-- Material Icons name: Expand Less --> - <svg - aria-hidden="true" - class="block h-6 fill-current stroke-current text-gray-500 w-6" - viewBox="0 0 24 24" - xmlns="http://www.w3.org/2000/svg" - ><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" /></svg - > - {:else} - <!-- Material Icons name: Expand More --> - <svg - aria-hidden="true" - class="block h-6 fill-current stroke-current text-gray-500 w-6" - viewBox="0 0 24 24" - xmlns="http://www.w3.org/2000/svg" - ><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" /></svg - > - {/if} - </button> - </h2> - - {#if openAllParameters} - <section class="pb-3 mb-3 px-5"> - <ul> - {#each Object.values(rootParameterById).sort( (parameter1, parameter2) => (parameter1.class === parameter2.class || (parameter1.class !== ParameterClass.Node && parameter2.class !== ParameterClass.Node) ? parameter1.title.localeCompare(parameter2.title) : parameter1.class === ParameterClass.Node ? 1 : -1), ) as parameter} - <li> - {#if parameter.class === ParameterClass.Node} - <VariableReferredNodeParameter {date} depth={0} {parameter} /> - {:else if parameter.class === ParameterClass.Value} - <VariableReferredValueParameter {date} depth={0} {parameter} /> - {:else if parameter.class === ParameterClass.Scale} - <VariableReferredScaleParameter {date} depth={0} {parameter} /> - {/if} - </li> - {/each} - </ul> - </section> + {#if Object.keys(bothRootParameterById).length > 0} + <h2 + class="bg-le-gris-dispositif-ultralight text-black flex justify-between py-2 text-lg px-5 rounded-r shadow-inner" + > + <span>Autres paramètres affectant le dispositif</span> + <button on:click={() => (openAllParameters = !openAllParameters)}> + {#if openAllParameters} + <!-- Material Icons name: Expand Less --> + <svg + aria-hidden="true" + class="block h-6 fill-current stroke-current text-gray-500 w-6" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + ><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z" /></svg + > + {:else} + <!-- Material Icons name: Expand More --> + <svg + aria-hidden="true" + class="block h-6 fill-current stroke-current text-gray-500 w-6" + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + ><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" /></svg + > + {/if} + </button> + </h2> + + {#if openAllParameters} + <section class="pb-3 mb-3 px-5"> + <ul> + {#each [...iterVariableRootParameters(bothRootParameterById, rootParameter, reformRootParameter)] as [parameter, reformParameter]} + <li> + {#if parameter.class === ParameterClass.Node} + <VariableReferredNodeParameter + {date} + depth={0} + {parameter} + reformParameter={asNodeParameter(reformParameter)} + /> + {:else if parameter.class === ParameterClass.Value} + <VariableReferredValueParameter + {date} + depth={0} + {parameter} + reformParameter={asValueParameter(reformParameter)} + /> + {:else if parameter.class === ParameterClass.Scale} + <VariableReferredScaleParameter + {date} + depth={0} + {parameter} + reformParameter={asScaleParameter(reformParameter)} + /> + {/if} + </li> + {/each} + </ul> + </section> + {/if} {/if} {/if} {/if} diff --git a/src/lib/components/variables/VariableReferredParametersPane.svelte b/src/lib/components/variables/VariableReferredParametersPane.svelte deleted file mode 100644 index 5ca00677fef66cb953584a25712ed34318b9338b..0000000000000000000000000000000000000000 --- a/src/lib/components/variables/VariableReferredParametersPane.svelte +++ /dev/null @@ -1,33 +0,0 @@ -<script lang="ts"> - import { decompositionCoreByName } from "$lib/decompositions" - import { iterVariableParameters, variableSummaryByName } from "$lib/variables" - - import VariableReferredParameters from "./VariableReferredParameters.svelte" - - export let date: string - export let name: string - // export let pane: string - - $: decompositionCore = decompositionCoreByName[name] - - $: decomposition = - decompositionCore === undefined - ? undefined - : { - ...decompositionCore, - name, - } - - $: variable = variableSummaryByName[name] - - $: if (decomposition === undefined && variable === undefined) { - console.error(`Variable "${name}" not found`) - } - - $: parameters = - variable === undefined ? [] : [...iterVariableParameters(variable, date)] -</script> - -{#if decomposition !== undefined || variable !== undefined} - <VariableReferredParameters {date} {decomposition} {parameters} {variable} /> -{/if} diff --git a/src/lib/components/variables/VariableReferredScaleAtInstant.svelte b/src/lib/components/variables/VariableReferredScaleAtInstant.svelte new file mode 100644 index 0000000000000000000000000000000000000000..09505d2dba4f62e3464fb3af6ed401a7c8e966f1 --- /dev/null +++ b/src/lib/components/variables/VariableReferredScaleAtInstant.svelte @@ -0,0 +1,293 @@ +<script lang="ts"> + import { auditStringToNumber, laxAudit } from "@auditors/core" + import type { + AmountBracketAtInstant, + BracketAtInstant, + MaybeNumberValue, + NumberValue, + RateBracketAtInstant, + ScaleAtInstant, + ScaleParameter, + } from "@openfisca/json-model" + import { + isAmountScaleParameter, + scaleParameterUsesBase, + ScaleType, + } from "@openfisca/json-model" + import { createEventDispatcher } from "svelte" + + import { errorAsKeyValueDictionary, iterArrayWithErrors } from "$lib/errors" + + let globalErrors: { [key: string]: unknown } + export { globalErrors as errors } + export let parameter: ScaleParameter | undefined + export let reformParameter: ScaleParameter | undefined + export let scaleAtInstant: ScaleAtInstant | undefined | null + export let showErrors: boolean + + const dispatch = createEventDispatcher() + let errors = globalErrors + + $: isAmountScale = isAmountScaleParameter(reformParameter) + + $: usesBase = scaleParameterUsesBase(reformParameter) + + function appendBracket() { + const bracket: BracketAtInstant = [ + ScaleType.MarginalAmount, + ScaleType.SingleAmount, + ].includes(reformParameter.type) + ? { + amount: { value: null } as NumberValue, + threshold: { value: null } as MaybeNumberValue, + } + : { + // base: { value: null } as NumberValue, + rate: { value: null } as MaybeNumberValue, + threshold: { value: null } as MaybeNumberValue, + } + scaleAtInstant = [...scaleAtInstant, bracket] + } + + function asAmountBracketAtInstant( + bracket: BracketAtInstant, + ): AmountBracketAtInstant { + return bracket as AmountBracketAtInstant + } + + function asMaybeNumberValue( + value: MaybeNumberValue | "expected", + ): MaybeNumberValue { + return value as MaybeNumberValue + } + + function asNumberValue(value: NumberValue | "expected"): NumberValue { + return value as NumberValue + } + + function asRateBracketAtInstant( + bracket: BracketAtInstant, + ): RateBracketAtInstant { + return bracket as RateBracketAtInstant + } + + function changeValue( + index: number, + key: keyof AmountBracketAtInstant | keyof RateBracketAtInstant, + { target }: Event, + ) { + const { value } = target as HTMLInputElement + const [validValue, error] = auditStringToNumber(laxAudit, value) + let errorsAtIndex = errors[index] as { [key: string]: unknown } | undefined + if (error === null) { + if (errorsAtIndex?.[key] !== undefined) { + errorsAtIndex = { ...errorsAtIndex } + delete errorsAtIndex[key] + errors = { ...errors } + if (Object.keys(errorsAtIndex).length === 0) { + delete errors[index] + } + } + } else { + if (error !== errorsAtIndex?.[key]) { + errors = { + ...errors, + [index]: { ...(errorsAtIndex ?? {}), amount: error }, + } + } + } + scaleAtInstant = [...scaleAtInstant] + const bracket = (scaleAtInstant[index] = { + ...scaleAtInstant[index], + }) as BracketAtInstant + bracket[key] = + bracket[key] === "expected" + ? { value: validValue } + : { + ...(bracket[key] as { [key: string]: unknown }), + value: validValue, + } + dispatch("change", scaleAtInstant) + } + + function deleteBracket(index: number) { + scaleAtInstant = [...scaleAtInstant] + scaleAtInstant.splice(index, 1) + dispatch("change", scaleAtInstant) + } +</script> + +<div class="flex-col"> + <div> + <table class="table-auto border-collapse "> + <thead> + <tr> + <th /> + <th class="font-light text-center bg-gray-100">Seuil</th> + {#if isAmountScale} + <th class="font-light text-center bg-gray-100">Montant</th> + {:else} + {#if usesBase} + <th class="font-light text-center bg-gray-100">Base</th> + {/if} + <th class="font-light text-center bg-gray-100">Taux</th> + {/if} + </tr> + </thead> + <tbody> + {#each [...iterArrayWithErrors(scaleAtInstant, errors)] as [bracketAtInstant, errorsAtIndex], index} + <tr> + <td> + <button + class="pr-1 rounded" + on:click={() => deleteBracket(index)} + title="Supprimer" + type="button" + > + <!-- Material ui icon : delete --> + <svg + class="fill-current h-5 w-5 text-gray-500 hover:text-le-gris-dispositif" + xmlns="http://www.w3.org/2000/svg" + height="24px" + viewBox="0 0 24 24" + width="24px" + ><path d="M0 0h24v24H0z" fill="none" /><path + d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" + /></svg + > + </button> + </td> + <td class="p-1"> + <div class="flex items-center"> + <input + class="bg-white text-black hover:bg-le-gris-dispositif-light font-serif text-lg border-b border-l-0 border-r-0 border-t-0 py-0 w-24" + step="any" + type="number" + on:change={(event) => changeValue(index, "threshold", event)} + value={bracketAtInstant.threshold === "expected" + ? null + : bracketAtInstant.threshold?.value ?? null} + /> + {#if showErrors && errorAsKeyValueDictionary(errorAsKeyValueDictionary(errorsAtIndex).threshold).value !== undefined} + <p> + {errorAsKeyValueDictionary( + errorAsKeyValueDictionary(errorsAtIndex).threshold, + ).value} + </p> + {/if} + <!--UNITE A CHANGER + <p class="font-serif text-base">€</p> + --> + </div> + </td> + {#if isAmountScale} + <td class="border-l-2 p-1"> + <div class="flex items-center"> + <input + class="bg-white text-black hover:bg-le-gris-dispositif-light font-serif text-lg border-b border-l-0 border-r-0 border-t-0 py-0 w-24" + step="any" + type="number" + on:change={(event) => changeValue(index, "amount", event)} + value={asAmountBracketAtInstant(bracketAtInstant).amount === + "expected" + ? null + : asNumberValue( + asAmountBracketAtInstant(bracketAtInstant).amount, + ).value ?? null} + /> + {#if showErrors && errorAsKeyValueDictionary(errorAsKeyValueDictionary(errorsAtIndex).amount).value !== undefined} + <p> + {errorAsKeyValueDictionary( + errorAsKeyValueDictionary(errorsAtIndex).amount, + ).value} + </p> + {/if} + <!--UNITE A CHANGER + <p class="font-serif text-base">€</p> + --> + </div> + </td> + {:else} + {#if usesBase} + <td class="border-l-2 p-1"> + <div class="flex items-center"> + <input + class="bg-white text-black font-serif text-lg border-b border-l-0 border-r-0 border-t-0 py-0 w-24" + step="any" + type="number" + on:change={(event) => changeValue(index, "base", event)} + value={asRateBracketAtInstant(bracketAtInstant).base === + "expected" + ? null + : asNumberValue( + asRateBracketAtInstant(bracketAtInstant).base, + )?.value ?? null} + /> + {#if showErrors && errorAsKeyValueDictionary(errorAsKeyValueDictionary(errorsAtIndex).base).value !== undefined} + <p> + {errorAsKeyValueDictionary( + errorAsKeyValueDictionary(errorsAtIndex).base, + ).value} + </p> + {/if} + <!--UNITE A CHANGER + <p class="font-serif text-base">€</p> + --> + </div> + </td> + {/if} + <td class="border-l-2 p-1"> + <div class="flex items-center"> + <input + class="bg-white text-black font-serif text-lg border-b border-l-0 border-r-0 border-t-0 py-0 w-24 hover:bg-le-gris-dispositif-light" + step="any" + type="number" + on:change={(event) => changeValue(index, "rate", event)} + value={asRateBracketAtInstant(bracketAtInstant).rate === + "expected" + ? null + : asMaybeNumberValue( + asRateBracketAtInstant(bracketAtInstant).rate, + ).value ?? null} + /> + {#if showErrors && errorAsKeyValueDictionary(errorAsKeyValueDictionary(errorsAtIndex).rate).value !== undefined} + <p> + {errorAsKeyValueDictionary( + errorAsKeyValueDictionary(errorsAtIndex).rate, + ).value} + </p> + {/if} + <!--UNITE A CHANGER + <p class="font-serif text-base">€</p> + --> + </div> + </td> + {/if} + </tr> + {/each} + </tbody> + </table> + </div> + + <div> + <button + class="text-gray-500 hover:text-le-gris-dispositif w-64 " + on:click={appendBracket} + type="button" + > + <div class="mt-4 text-sm pl-1 flex items-center"> + <svg + class="fill-current inline mr-1" + xmlns="http://www.w3.org/2000/svg" + height="18px" + viewBox="0 0 24 24" + width="18px" + fill="#000000" + ><path d="M0 0h24v24H0z" fill="none" /><path + d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" + /></svg + >Ajouter un seuil + </div></button + > + </div> +</div> diff --git a/src/lib/components/variables/VariableReferredScaleParameter.svelte b/src/lib/components/variables/VariableReferredScaleParameter.svelte index e14bcc275bfe14d58f88abbad1d3d3cee30595d3..c103a7d2d17700d4badc448bf0b5e1869516859a 100644 --- a/src/lib/components/variables/VariableReferredScaleParameter.svelte +++ b/src/lib/components/variables/VariableReferredScaleParameter.svelte @@ -4,23 +4,26 @@ import { getContext } from "svelte" import type { Writable } from "svelte/store" - import ScaleAtInstantEdit from "$lib/components/parameters/ScaleAtInstantEdit.svelte" import type { CalculationName } from "$lib/decompositions" import type { ParametricReform } from "$lib/reforms" - import { ReformChangeType } from "$lib/reforms" + import { ParameterReformChangeType } from "$lib/reforms" import VariableReferredParameterHeader from "./VariableReferredParameterHeader.svelte" + import VariableReferredScaleAtInstant from "./VariableReferredScaleAtInstant.svelte" export let date: string export let depth: number - export let parameter: ScaleParameter + export let parameter: ScaleParameter | undefined + export let reformParameter: ScaleParameter - const reform = getContext("reform") as Writable<ParametricReform> + const parametricReform = getContext( + "parametricReform", + ) as Writable<ParametricReform> const requestedCalculationsName = getContext( "requestedCalculationsName", ) as Writable<Set<CalculationName>> - $: scaleByInstant = scaleByInstantFromBrackets(parameter.brackets) + $: scaleByInstant = scaleByInstantFromBrackets(reformParameter.brackets) $: instantScaleCouplesArray = Object.entries(scaleByInstant).sort( ([instant1], [instant2]) => instant2.localeCompare(instant1), @@ -44,12 +47,12 @@ scale !== undefined && Object.keys(scale).length > 0 ) { - $reform = { - ...$reform, - [parameter.name]: { + $parametricReform = { + ...$parametricReform, + [reformParameter.name]: { scale, start, - type: ReformChangeType.Scale, + type: ParameterReformChangeType.Scale, }, } @@ -64,13 +67,14 @@ </script> <section class="ml-14 pl-4 pb-4 border-l-2 border-le-gris-dispositif-light"> - <VariableReferredParameterHeader {depth} {parameter} /> + <VariableReferredParameterHeader {depth} parameter={reformParameter} /> <div class="flex bg-gray-100 rounded-t pl-1 py-2 mt-1"> - <ScaleAtInstantEdit + <VariableReferredScaleAtInstant errors={{}} {parameter} on:change={changeScale} + {reformParameter} scaleAtInstant={latestScaleAtInstant} showErrors={true} /> @@ -139,7 +143,7 @@ <div> <a class="text-sm ml-1 underline text-gray-600 hover:text-gray-700" - href="/parameters/{parameter.name}" + href="/parameters/{reformParameter.name}" target="_blank" > <svg diff --git a/src/lib/components/variables/VariableReferredValueParameter.svelte b/src/lib/components/variables/VariableReferredValueParameter.svelte index fe9b83e3caa152234f2d2f8dc2a52725ec5b8f5a..51400870beb517248147bc5aa9902484eb396c04 100644 --- a/src/lib/components/variables/VariableReferredValueParameter.svelte +++ b/src/lib/components/variables/VariableReferredValueParameter.svelte @@ -5,25 +5,30 @@ import type { CalculationName } from "$lib/decompositions" import type { ParametricReform, ValueParameterReform } from "$lib/reforms" - import { ReformChangeType } from "$lib/reforms" + import { ParameterReformChangeType } from "$lib/reforms" import VariableReferredParameterHeader from "./VariableReferredParameterHeader.svelte" export let date: string export let depth: number - export let parameter: ValueParameter + export let parameter: ValueParameter | undefined + export let reformParameter: ValueParameter let instantValueCouplesArray: [string, ValueAtInstant][] - const reform = getContext("reform") as Writable<ParametricReform> + const parametricReform = getContext( + "parametricReform", + ) as Writable<ParametricReform> const requestedCalculationsName = getContext( "requestedCalculationsName", ) as Writable<Set<CalculationName>> let validValue = undefined let valueError = null - $: change = $reform[parameter.name] as ValueParameterReform | undefined + $: change = $parametricReform[reformParameter.name] as + | ValueParameterReform + | undefined - $: instantValueCouplesArray = Object.entries(parameter.values).sort( + $: instantValueCouplesArray = Object.entries(reformParameter.values).sort( ([instant1], [instant2]) => instant2.localeCompare(instant1), ) @@ -53,11 +58,11 @@ function updateReform(start: string, value) { if (start !== undefined && value !== undefined) { - $reform = { - ...$reform, - [parameter.name]: { + $parametricReform = { + ...$parametricReform, + [reformParameter.name]: { start, - type: ReformChangeType.Parameter, + type: ParameterReformChangeType.Parameter, value, }, } @@ -72,7 +77,7 @@ </script> <section class="ml-14 pl-4 pb-4 border-l-2 border-le-gris-dispositif-light"> - <VariableReferredParameterHeader {depth} {parameter} /> + <VariableReferredParameterHeader {depth} parameter={reformParameter} /> <div class="bg-gray-100 p-2 pb-2 items-center flex justify-start rounded"> <div> @@ -172,7 +177,7 @@ <div> <a class="text-sm ml-1 underline text-gray-600 hover:text-gray-700" - href="/parameters/{parameter.name}" + href="/parameters/{reformParameter.name}" target="_blank" > <svg diff --git a/src/lib/decompositions.ts b/src/lib/decompositions.ts index 0b50ac0b35bad8d80cdeeed544498c3462ca9c42..7b8820d80abc857a2146254bc319f42242859f36 100644 --- a/src/lib/decompositions.ts +++ b/src/lib/decompositions.ts @@ -15,6 +15,7 @@ import type { import decompositionCoreByNameUnknown from "$lib/openfisca/decompositions.json" import waterfallsUnknown from "$lib/openfisca/waterfalls.json" +import { reformChangesByName } from "$lib/reforms" import type { Situation } from "$lib/situations" export type CalculationName = "amendment" | "bill" | "law" @@ -64,6 +65,18 @@ export const calculationNames: CalculationName[] = ["law", "bill", "amendment"] export const decompositionCoreByName: DecompositionCoreByName = decompositionCoreByNameUnknown +export const decompositionCoreByNameByReformName: { + [name: string]: DecompositionCoreByName +} = Object.fromEntries( + Object.entries(reformChangesByName).map(([reformName, reformChanges]) => [ + reformName, + patchDecompositionCoreByName( + decompositionCoreByName, + reformChanges.decompositions, + ), + ]), +) + export const waterfalls: Waterfall[] = waterfallsUnknown export const decompositionsOptionsVariablesName = new Set<string>() @@ -369,6 +382,26 @@ export function labelFromCalculationName( ) } +function patchDecompositionCoreByName( + decompositionCoreByName: DecompositionCoreByName, + patch: { [name: string]: DecompositionCore | null }, +): DecompositionCoreByName { + if (Object.keys(patch).length === 0) { + return decompositionCoreByName + } + const patchedDecompositionCoreByName = { ...decompositionCoreByName } + for (const [name, decompositionCorePatch] of Object.entries(patch)) { + if (decompositionCorePatch === null) { + // This case should not occur, because a reform should always + // have all the decompositions of the original tax-benefit system. + delete patchedDecompositionCoreByName[name] + } else { + patchedDecompositionCoreByName[name] = decompositionCorePatch + } + } + return patchedDecompositionCoreByName +} + export function updateEvaluations( decompositionByName: DecompositionByName, evaluationByName: EvaluationByName, diff --git a/src/lib/parameters.ts b/src/lib/parameters.ts index 90f35b40b7a82603ac9664d5aa28ee281555185a..eda32956b5b66c1afeed228d96f4ccb2c2b0b900 100644 --- a/src/lib/parameters.ts +++ b/src/lib/parameters.ts @@ -21,6 +21,7 @@ import { } from "@openfisca/json-model" import rootParameterUnknown from "$lib/openfisca/editable_processed_parameters.json" +import { reformChangesByName } from "$lib/reforms" export interface InstantReferencesAndScale { instant: string @@ -37,6 +38,17 @@ export interface InstantReferencesAndValue { improveParameter(null, rootParameterUnknown as NodeParameter) export const rootParameter = rootParameterUnknown as NodeParameter +export const rootParameterByReformName: { [name: string]: NodeParameter } = + Object.fromEntries( + Object.entries(reformChangesByName).map(([reformName, reformChanges]) => [ + reformName, + patchParameter( + rootParameter, + reformChanges.editable_processed_parameters, + ), + ]), + ) + export const leafParametersName = new Set<string>() for (const parameter of walkParameters(rootParameter)) { leafParametersName.add(parameter.name!) @@ -99,8 +111,11 @@ export function buildInstantReferencesAndValueArray( .map(([, instantReferencesAndValue]) => instantReferencesAndValue) } -export function getParameter(name: string): Parameter | undefined { - let parameter = rootParameter as Parameter +export function getParameter( + rootParameter: Parameter, + name: string, +): Parameter | undefined { + let parameter = rootParameter for (const id of name.split(".")) { const children = parameter.class === ParameterClass.Node ? parameter.children : undefined @@ -168,3 +183,41 @@ export function labelFromValueType(type: ValueType | string): string { }[type] ?? type ) } + +function patchParameter<ParameterType extends Parameter>( + parameter: ParameterType, + patch: { [key: string]: unknown }, +): ParameterType { + if (Object.keys(patch).length === 0) { + return parameter + } + const patchedParameter = { ...parameter } + for (const [key, value] of Object.entries(patch)) { + if (value === null) { + delete patchedParameter[key] + } else if (patchedParameter[key] === undefined) { + patchedParameter[key] = value + } else if (key === "children") { + const patchedChildren = ((patchedParameter as NodeParameter).children = { + ...(patchedParameter as NodeParameter).children, + }) + for (const [childId, childPatch] of Object.entries( + value as { [childId: string]: unknown }, + )) { + if (childPatch === null) { + delete patchedChildren[childId] + } else if (patchedChildren[childId] === undefined) { + patchedChildren[childId] = childPatch as Parameter + } else { + patchedChildren[childId] = patchParameter( + patchedChildren[childId], + childPatch as { [key: string]: unknown }, + ) + } + } + } else { + patchedParameter[key] = value + } + } + return patchedParameter +} diff --git a/src/lib/reforms.ts b/src/lib/reforms.ts index 83106e13de59b3811fb6d548509d40cd97bcf45c..c63ba642cb1d225e3b377e223e1b9f06386972d4 100644 --- a/src/lib/reforms.ts +++ b/src/lib/reforms.ts @@ -1,28 +1,45 @@ -import type { ScaleAtInstant } from "@openfisca/json-model" +import type { + Decomposition as DecompositionCore, + ScaleAtInstant, + Variable, +} from "@openfisca/json-model" + +import reformChangesByNameUnknown from "$lib/openfisca/reforms_changes.json" export type ParameterReform = ValueParameterReform | ScaleParameterReform export interface ParameterReformBase { start: string stop?: string - type: ReformChangeType + type: ParameterReformChangeType +} + +export enum ParameterReformChangeType { + Parameter = "parameter", + Scale = "scale", } export interface ParametricReform { [parameterName: string]: ParameterReform } +export interface ReformChanges { + decompositions: { [name: string]: DecompositionCore | null } + editable_processed_parameters: { [key: string]: unknown } + variables_summaries: { [name: string]: Variable | null } +} + +export type ReformChangesByName = { [name: string]: ReformChanges } + export interface ScaleParameterReform extends ParameterReformBase { - type: ReformChangeType.Scale + type: ParameterReformChangeType.Scale scale: ScaleAtInstant } export interface ValueParameterReform extends ParameterReformBase { - type: ReformChangeType.Parameter + type: ParameterReformChangeType.Parameter value: number } -export enum ReformChangeType { - Parameter = "parameter", - Scale = "scale", -} +export const reformChangesByName = + reformChangesByNameUnknown as ReformChangesByName diff --git a/src/lib/server/config.ts b/src/lib/server/config.ts index 8ae023cc65d7bed03766df681e84dfdd56bbb29f..323a8ac1cb020aae19e6463c9aa480b39120865f 100644 --- a/src/lib/server/config.ts +++ b/src/lib/server/config.ts @@ -35,6 +35,7 @@ export interface Config { } portalUrl: string proxy: boolean + reformName?: string simulationsDir: string title: string } @@ -76,6 +77,7 @@ const [validConfig, error] = validateConfig({ }, portalUrl: process.env["PORTAL_URL"], proxy: process.env["PROXY"], + reformName: process.env["REFORM"], simulationsDir: process.env["SIMULATIONS_DIR"], title: process.env["TITLE"], }) diff --git a/src/lib/sessions.ts b/src/lib/sessions.ts index f4afccf6bf09d46f78ffeb8741f30fa311a02d16..2bb4e797891312c2c55f54bd5be9d596f4394508 100644 --- a/src/lib/sessions.ts +++ b/src/lib/sessions.ts @@ -18,6 +18,7 @@ export interface Session { } openfiscaRepository: SessionOpenFiscaRepository portalUrl: string + reformName?: string title: string user?: User } diff --git a/src/lib/variables.ts b/src/lib/variables.ts index 65249710cf3f581e3a07ee269b24ee3d77032c41..0922e36ac69750a7b36f78b4178cc6496108a634 100644 --- a/src/lib/variables.ts +++ b/src/lib/variables.ts @@ -1,13 +1,12 @@ import type { Formula, - Parameter, Reference, Variable, VariableByName, } from "@openfisca/json-model" import variableSummaryByNameUnknown from "$lib/openfisca/variables_summaries.json" -import { getParameter } from "$lib/parameters" +import { reformChangesByName } from "$lib/reforms" export type VariableValues = boolean[] | number[] | string[] @@ -20,6 +19,18 @@ export interface InstantFormulaAndReferences { export const variableSummaryByName = variableSummaryByNameUnknown as VariableByName +export const variableSummaryByNameByReformName: { + [name: string]: VariableByName +} = Object.fromEntries( + Object.entries(reformChangesByName).map(([reformName, reformChanges]) => [ + reformName, + patchVariableSummaryByName( + variableSummaryByName, + reformChanges.variables_summaries, + ), + ]), +) + export function buildInstantFormulaAndReferencesArray( variable: Variable, ): InstantFormulaAndReferences[] { @@ -119,12 +130,12 @@ export function* iterVariableInputVariables( } } -export function* iterVariableParameters( +export function* iterVariableParametersName( variable: Variable, date: string, encounteredParametersName: Set<string> = new Set(), encounteredVariablesName: Set<string> = new Set(), -): Generator<Parameter, void> { +): Generator<string, void> { const name = variable.name if (encounteredVariablesName.has(name)) { return @@ -152,7 +163,7 @@ export function* iterVariableParameters( if (referredVariablesName !== undefined) { for (const referredVariableName of referredVariablesName) { const referredVariable = variableSummaryByName[referredVariableName] - yield* iterVariableParameters( + yield* iterVariableParametersName( referredVariable, date, encounteredParametersName, @@ -168,12 +179,27 @@ export function* iterVariableParameters( continue } encounteredParametersName.add(referredParameterName) + yield referredParameterName + } + } +} - const referredParameter = getParameter(referredParameterName) - if (referredParameter === undefined) { - continue - } - yield referredParameter +function patchVariableSummaryByName( + variableSummaryByName: VariableByName, + patch: { [name: string]: Variable | null }, +): VariableByName { + if (Object.keys(patch).length === 0) { + return variableSummaryByName + } + const patchedVariableSummaryByName = { ...variableSummaryByName } + for (const [name, variableSummaryPatch] of Object.entries(patch)) { + if (variableSummaryPatch === null) { + // This case should not occur, because a reform should always + // have all the variables of the original tax-benefit system. + delete patchedVariableSummaryByName[name] + } else { + patchedVariableSummaryByName[name] = variableSummaryPatch } } + return patchedVariableSummaryByName } diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte index a13227f800e7de1635c51e011b47c1543591e15d..05cbfe6e92b5944c24f45f7a7a81b13af90ac426 100644 --- a/src/routes/__layout.svelte +++ b/src/routes/__layout.svelte @@ -25,6 +25,7 @@ waterfalls, } from "$lib/decompositions" import { entityByKey } from "$lib/entities" + import { metadata } from "$lib/metadata" import type { ParametricReform } from "$lib/reforms" import type { Situation } from "$lib/situations" import { @@ -37,7 +38,12 @@ import { variableSummaryByName } from "$lib/variables" import type { WebSocketByName, WebSocketOpenByName } from "$lib/websockets" - const billName: Writable<string | undefined> = writable("PLF LFI") + const billName: Writable<string | undefined> = writable( + metadata.reforms.find(({ name }) => name === $session.reformName) === + undefined + ? undefined + : $session.reformName, + ) setContext("billName", billName) const calculationName: Writable<CalculationName> = writable("law") @@ -110,23 +116,23 @@ ) setContext("nonVirtualDecompositionsName", nonVirtualDecompositionsName) - let reformValue: ParametricReform + let parametricReformValue: ParametricReform if (browser) { - const reformJson = localStorage.getItem("reform") - if (reformJson !== null) { + const parametricReformJson = localStorage.getItem("parametricReform") + if (parametricReformJson !== null) { try { - reformValue = JSON.parse(reformJson) + parametricReformValue = JSON.parse(parametricReformJson) } catch { - reformValue = {} + parametricReformValue = {} } } else { - reformValue = {} + parametricReformValue = {} } } else { - reformValue = {} + parametricReformValue = {} } - const reform = writable(reformValue) - setContext("reform", reform) + const parametricReform = writable(parametricReformValue) + setContext("parametricReform", parametricReform) const requestedCalculationsName = writable(new Set<CalculationName>()) setContext("requestedCalculationsName", requestedCalculationsName) @@ -175,7 +181,7 @@ } $: if (browser) { - localStorage.setItem("reform", JSON.stringify($reform)) + localStorage.setItem("parametricReform", JSON.stringify($parametricReform)) } $: if (browser) { diff --git a/src/routes/index.svelte b/src/routes/index.svelte index 4d13e488d9d6fe30231a1528ff04ff9f4eb30274..510ae6aee2355cd585730a7299a39f5d0c961ba0 100644 --- a/src/routes/index.svelte +++ b/src/routes/index.svelte @@ -17,7 +17,7 @@ import TestCasesPane from "$lib/components/test_cases/TestCasesPane.svelte" import VariableReferredInputsPane from "$lib/components/variables/VariableReferredInputsPane.svelte" import StartTutorial from "$lib/components/tutorial/StartTutorial.svelte" - import VariableReferredParametersPane from "$lib/components/variables/VariableReferredParametersPane.svelte" + import VariableReferredParameters from "$lib/components/variables/VariableReferredParameters.svelte" import type { CalculationName, DecompositionByName, @@ -32,6 +32,7 @@ } from "$lib/decompositions" import type { EditionMode } from "$lib/editions" import { entityByKey } from "$lib/entities" + import { metadata } from "$lib/metadata" import type { ParametricReform } from "$lib/reforms" import type { Axis, @@ -89,7 +90,9 @@ }> > setContext("newSelfTargetAProps", newSelfTargetAProps) - const reform = getContext("reform") as Writable<ParametricReform> + const parametricReform = getContext( + "parametricReform", + ) as Writable<ParametricReform> const requestedCalculationsName = getContext( "requestedCalculationsName", ) as Writable<Set<CalculationName>> @@ -222,6 +225,17 @@ } } + function changeBillName({ target }: Event) { + const { value } = target as HTMLSelectElement + $billName = value === "undefined" ? undefined : value + if (!$requestedCalculationsName.has("bill")) { + $requestedCalculationsName = new Set([ + ...$requestedCalculationsName, + "bill", + ]) + } + } + function changeInputInstantsByVariableName( situationIndex: number, inputInstantsByVariableName: { @@ -424,7 +438,7 @@ } function reset(): void { - $reform = {} + $parametricReform = {} $testCases = testCasesCore if ( calculationNames.some( @@ -439,7 +453,7 @@ const url = "/simulations.json" const res = await fetch(url, { body: JSON.stringify({ - reform: $reform, + parametricReform: $parametricReform, testCases: buildTestCasesWithoutNonInputVariables( entityByKey, $inputInstantsByVariableNameArray, @@ -464,6 +478,7 @@ } function submit(requestedCalculationsName: Set<CalculationName>) { + console.log("submit called") // Aggregate every situations into a single one without calculated variables. const aggregatedSituation: SituationWithAxes = {} const entities = Object.values(entityByKey as EntityByKey) @@ -553,19 +568,25 @@ ) { const token = ($calculationTokenByName.bill = uuidv4()) $webSocketByName.bill.send( - JSON.stringify({ ...message, reform: $billName, title: "bill", token }), + JSON.stringify({ + ...message, + reform_name: $billName, + title: "bill", + token, + }), ) } if ( requestedCalculationsName.has("amendment") && - Object.keys($reform).length > 0 && + Object.keys($parametricReform).length > 0 && $webSocketOpenByName.amendment ) { const token = ($calculationTokenByName.amendment = uuidv4()) $webSocketByName.amendment.send( JSON.stringify({ ...message, - reform: $reform, + parametric_reform: $parametricReform, + reform_name: $billName, // Will be removed when $billName is undefined. title: "amendment", token, }), @@ -766,7 +787,7 @@ --> <div class="lg:h-[calc(100vh-13rem)] lg:overflow-y-auto"> <div class="bg-white mr-4"> - <VariableReferredParametersPane + <VariableReferredParameters date={$date} name={editionMode.variableName} /> @@ -793,6 +814,18 @@ Échelle unique </span></label > --> + <select + class=" rounded border-1 text-xs " + on:blur={changeBillName} + on:change={changeBillName} + value={$billName} + > + <option value={undefined}>Pas de projet/proposition de loi</option> + {#each metadata.reforms as { label, name }} + <option value={name}>{label}</option> + {/each} + </select> + <select class=" rounded border-1 text-xs " required diff --git a/src/routes/parameters/[parameter]/edit.svelte b/src/routes/parameters/[parameter]/edit.svelte index 20fbeb898b10b29e07f8bab5aee7f1db4ea7ecab..c771b23089bf96e3290c731a0d19711a8a08669c 100644 --- a/src/routes/parameters/[parameter]/edit.svelte +++ b/src/routes/parameters/[parameter]/edit.svelte @@ -9,7 +9,11 @@ import yaml from "js-yaml" import { metadata } from "$lib/metadata" - import { getParameter, labelFromParameterClass } from "$lib/parameters" + import { + getParameter, + labelFromParameterClass, + rootParameter, + } from "$lib/parameters" import type { SessionOpenFiscaRepository } from "$lib/sessions" export async function load({ @@ -18,7 +22,7 @@ session, }: LoadInput): Promise<LoadOutput> { const { parameter: name } = page.params - const processedParameter = getParameter(name) + const processedParameter = getParameter(rootParameter, name) if (processedParameter === undefined) { return { status: 404, @@ -160,6 +164,7 @@ return } showErrors = false + return const url = `/parameters/${processedParameter.name}.json` const res = await fetch(url, { body: JSON.stringify(validParameter), diff --git a/src/routes/parameters/[parameter]/index.json.ts b/src/routes/parameters/[parameter]/index.json.ts index 349dd610654f9ffe3f403e459779b7c628dd43ee..464ac539f600b00b353435dca5fbd30051ce0f54 100644 --- a/src/routes/parameters/[parameter]/index.json.ts +++ b/src/routes/parameters/[parameter]/index.json.ts @@ -10,7 +10,7 @@ import type { RequestHandler } from "@sveltejs/kit" import { randomBytes } from "crypto" import { metadata } from "$lib/metadata" -import { getParameter } from "$lib/parameters" +import { getParameter, rootParameter } from "$lib/parameters" import config from "$lib/server/config" const { githubPersonalAccessToken, openfiscaRepository } = config @@ -29,7 +29,7 @@ export const put: RequestHandler = async ({ body, params }) => { } const { parameter: name } = params - const parameter = getParameter(name) + const parameter = getParameter(rootParameter, name) if (parameter === undefined) { return { body: null, status: 404 } } diff --git a/src/routes/parameters/[parameter]/index.svelte b/src/routes/parameters/[parameter]/index.svelte index 3ff458179c25266f1c7dec1c819e4cb3d89a3a7f..6083a40c0d5b0f67f5b3e406d2a29240c4ca917c 100644 --- a/src/routes/parameters/[parameter]/index.svelte +++ b/src/routes/parameters/[parameter]/index.svelte @@ -1,11 +1,11 @@ <script context="module" lang="ts"> import type { LoadInput, LoadOutput } from "@sveltejs/kit" - import { getParameter } from "$lib/parameters" + import { getParameter, rootParameter } from "$lib/parameters" export function load({ page }: LoadInput): LoadOutput { const { parameter: name } = page.params - const parameter = getParameter(name) + const parameter = getParameter(rootParameter, name) if (parameter === undefined) { return { status: 404, diff --git a/src/routes/simulations/[simulation].svelte b/src/routes/simulations/[simulation].svelte index 41d85c84e4254291517831c5247631060bd210e2..fdf419dde680b13be9ca40b04cd87c7d66b3c651 100644 --- a/src/routes/simulations/[simulation].svelte +++ b/src/routes/simulations/[simulation].svelte @@ -28,13 +28,18 @@ import type { ParametricReform } from "$lib/reforms" import type { Situation } from "$lib/situations" - export let simulation: { reform: ParametricReform; testCases: Situation[] } + export let simulation: { + parametricReform: ParametricReform + testCases: Situation[] + } - const reform = getContext("reform") as Writable<ParametricReform> + const parametricReform = getContext( + "parametricReform", + ) as Writable<ParametricReform> const testCases = getContext("testCases") as Writable<Situation[]> onMount(() => { - $reform = simulation.reform + $parametricReform = simulation.parametricReform $testCases = simulation.testCases goto("/") }) diff --git a/src/routes/simulations/index.json.ts b/src/routes/simulations/index.json.ts index f2b820385614bc1c7c2d06c8c1cdc2cb309747eb..f76294b35a47c926ca7f9b93e603c18699c4ff91 100644 --- a/src/routes/simulations/index.json.ts +++ b/src/routes/simulations/index.json.ts @@ -24,7 +24,7 @@ function auditBody(audit: Audit, dataUnknown: unknown): [unknown, unknown] { audit.attribute( data, - "reform", + "parametricReform", true, errors, remainingKeys, diff --git a/src/routes/variables/[variable]/parameters/[date].svelte b/src/routes/variables/[variable]/parameters/[date].svelte index 33907ed486d90c94fd4aab79cf1c6da57a806e45..73506c36a0b0f3dde4c494791ba36798664b5be8 100644 --- a/src/routes/variables/[variable]/parameters/[date].svelte +++ b/src/routes/variables/[variable]/parameters/[date].svelte @@ -1,52 +1,10 @@ -<script context="module" lang="ts"> - import type { LoadInput, LoadOutput } from "@sveltejs/kit" - - import type { Decomposition } from "$lib/decompositions" - import { decompositionCoreByName } from "$lib/decompositions" - import { iterVariableParameters, variableSummaryByName } from "$lib/variables" - - export function load({ page }: LoadInput): LoadOutput { - const { date, variable: name } = page.params - const decompositionCore = decompositionCoreByName[name] - const decomposition: Decomposition = - decompositionCore === undefined - ? undefined - : { - ...decompositionCore, - name, - } - const variable = variableSummaryByName[name] - if (decomposition === undefined && variable === undefined) { - return { - status: 404, - error: new Error(`Variable "${name}" not found`), - } - } - const parameters = - variable === undefined ? [] : [...iterVariableParameters(variable, date)] - - return { - props: { - decomposition, - variable, - parameters, - }, - } - } -</script> - <script lang="ts"> - import type { Parameter, Variable } from "@openfisca/json-model" import { setContext } from "svelte" import { page, session } from "$app/stores" import VariableReferredParameters from "$lib/components/variables/VariableReferredParameters.svelte" import { newSelfTargetAProps } from "$lib/urls" - export let decomposition: Decomposition | undefined - export let parameters: Parameter[] - export let variable: Variable | undefined - setContext("newSelfTargetAProps", newSelfTargetAProps) $: params = $page.params @@ -63,5 +21,5 @@ </svelte:head> <main> - <VariableReferredParameters {date} {decomposition} {parameters} {variable} /> + <VariableReferredParameters {date} {name} /> </main>