Studio : Support des exemples et menu déroulant
parent
205b441634
commit
9278244e7e
|
@ -21,8 +21,8 @@
|
|||
"dependencies": {
|
||||
"@babel/polyfill": "^7.4.0",
|
||||
"@babel/runtime": "^7.3.4",
|
||||
"@monaco-editor/react": "^3.1.1",
|
||||
"@rehooks/local-storage": "^2.1.1",
|
||||
"@monaco-editor/react": "^2.3.0",
|
||||
"classnames": "^2.2.5",
|
||||
"color-convert": "^1.9.2",
|
||||
"core-js": "^3.2.1",
|
||||
|
@ -31,6 +31,7 @@
|
|||
"i18next": "^18.0.1",
|
||||
"iframe-resizer": "^4.1.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"monaco-editor": "^0.20.0",
|
||||
"moo": "^0.5.0",
|
||||
"nearley": "^2.19.0",
|
||||
"ramda": "^0.25.0",
|
||||
|
@ -63,6 +64,9 @@
|
|||
"swr": "^0.1.16",
|
||||
"whatwg-fetch": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"monaco-editor": "^0.20.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "node source/scripts/prepare.js",
|
||||
"compile": "yarn run webpack --config source/webpack.prod.js && yarn run webpack --config source/webpack.prod.legacyBrowser.js",
|
||||
|
|
|
@ -42,7 +42,7 @@ if (
|
|||
}
|
||||
|
||||
type ProviderProps = {
|
||||
tracker: Tracker
|
||||
tracker?: Tracker
|
||||
basename: string
|
||||
sitePaths: SitePaths
|
||||
language: AvailableLangs
|
||||
|
@ -92,7 +92,7 @@ export default class Provider extends PureComponent<ProviderProps> {
|
|||
document.body.appendChild(css)
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.props.tracker.disconnectFromHistory()
|
||||
this.props.tracker?.disconnectFromHistory()
|
||||
}
|
||||
render() {
|
||||
const iframeCouleur =
|
||||
|
@ -105,7 +105,7 @@ export default class Provider extends PureComponent<ProviderProps> {
|
|||
<ThemeColorsProvider
|
||||
color={iframeCouleur && decodeURIComponent(iframeCouleur)}
|
||||
>
|
||||
<TrackerProvider value={this.props.tracker}>
|
||||
<TrackerProvider value={this.props.tracker as Tracker}>
|
||||
<SitePathProvider value={this.props.sitePaths}>
|
||||
<I18nextProvider i18n={i18next}>
|
||||
<Router history={this.history}>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import exemple1 from '!!raw-loader!./exemple1.yaml'
|
||||
import exemple2 from '!!raw-loader!./exemple2.yaml'
|
||||
import exemple1 from '!!raw-loader!./exemples/bareme-ir.yaml'
|
||||
import exemple2 from '!!raw-loader!./exemples/douche.yaml'
|
||||
import ColoredYaml from 'Components/rule/ColoredYaml'
|
||||
import React, { useEffect } from 'react'
|
||||
import emoji from 'react-easy-emoji'
|
||||
|
@ -61,7 +61,9 @@ export default function Landing() {
|
|||
<div className="ui__ card">
|
||||
<ColoredYaml source={exemple1} />
|
||||
</div>
|
||||
<button className="ui__ button small">Lancer le calcul ⚡</button>
|
||||
<Link to="/studio?exemple=bareme-ir" className="ui__ button small">
|
||||
Lancer le calcul ⚡
|
||||
</Link>
|
||||
<p>
|
||||
En plus du site Web, Mon-entreprise est disponible comme une{' '}
|
||||
<a href="https://mon-entreprise.fr/intégration/bibliothèque-de-calcul">
|
||||
|
@ -76,7 +78,9 @@ export default function Landing() {
|
|||
<div className="ui__ card">
|
||||
<ColoredYaml source={exemple2} />
|
||||
</div>
|
||||
<button className="ui__ button small ">Lancer le calcul ⚡</button>
|
||||
<Link to="/studio?exemple=douche" className="ui__ button small">
|
||||
Lancer le calcul ⚡
|
||||
</Link>
|
||||
<br />
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
import baremeIr from '!!raw-loader!./exemples/bareme-ir.yaml'
|
||||
import douche from '!!raw-loader!./exemples/douche.yaml'
|
||||
import { ControlledEditor } from '@monaco-editor/react'
|
||||
import Engine from 'Engine/index'
|
||||
import { buildFlatRules } from 'Engine/rules'
|
||||
import { serializeUnit } from 'Engine/units'
|
||||
import { safeLoad } from 'js-yaml'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import React, { useRef, useState } from 'react'
|
||||
import emoji from 'react-easy-emoji'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { analysisWithDefaultsSelector } from 'Selectors/analyseSelectors'
|
||||
import { setSimulationConfig } from '../../actions/actions'
|
||||
import { useLocation } from 'react-router'
|
||||
import { Header } from './Header'
|
||||
|
||||
let initialInput = `
|
||||
a:
|
||||
let examples = {
|
||||
'bareme-ir': baremeIr,
|
||||
douche
|
||||
}
|
||||
|
||||
let initialInput = `a:
|
||||
formule: 10
|
||||
b:
|
||||
b:
|
||||
formule: a + 18
|
||||
c:
|
||||
formule:
|
||||
|
@ -34,34 +39,29 @@ export default function SafeStudio() {
|
|||
)
|
||||
}
|
||||
export function Studio() {
|
||||
const defaultTarget = 'b'
|
||||
const [ready, setReady] = useState(false)
|
||||
const [value, setValue] = useState(initialInput)
|
||||
const [target, setTarget] = useState(defaultTarget)
|
||||
const { search } = useLocation()
|
||||
const currentExample = new URLSearchParams(search ?? '').get('exemple')
|
||||
const [editorValue, setEditorValue] = useState(
|
||||
currentExample && Object.keys(examples).includes(currentExample)
|
||||
? examples[currentExample]
|
||||
: initialInput
|
||||
)
|
||||
const [targets, setTargets] = useState<string[]>([])
|
||||
const [currentTarget, setCurrentTarget] = useState('')
|
||||
const [analysis, setAnalysis] = useState()
|
||||
const engine = useRef<any>(null)
|
||||
|
||||
const dispatch = useDispatch()
|
||||
try {
|
||||
setTargets(Object.keys(safeLoad(editorValue) ?? {}))
|
||||
} catch {}
|
||||
|
||||
const setRules = rulesString =>
|
||||
dispatch({
|
||||
type: 'SET_RULES',
|
||||
rules: buildFlatRules(safeLoad(rulesString))
|
||||
})
|
||||
const setTargets = targets =>
|
||||
dispatch(setSimulationConfig({ objectifs: targets }))
|
||||
|
||||
useEffect(() => {
|
||||
setRules(initialInput)
|
||||
setTargets([defaultTarget])
|
||||
setReady(true)
|
||||
}, [])
|
||||
|
||||
function onChange(ev, newValue) {
|
||||
setValue(newValue)
|
||||
}
|
||||
|
||||
function updateRules() {
|
||||
setTargets([target])
|
||||
setRules(value)
|
||||
function updateResult() {
|
||||
engine.current = new Engine.Engine(buildFlatRules(safeLoad(editorValue)))
|
||||
engine.current.evaluate(
|
||||
[targets.includes(currentTarget) ? currentTarget : targets[0]],
|
||||
{ defaultUnits: [], situation: {} }
|
||||
)
|
||||
setAnalysis(engine.current.getLastEvaluationExplanations()?.targets?.[0])
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -70,34 +70,37 @@ export function Studio() {
|
|||
<ControlledEditor
|
||||
height="40vh"
|
||||
language="yaml"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
value={editorValue}
|
||||
onChange={(ev, newValue) => setEditorValue(newValue ?? '')}
|
||||
options={{ minimap: { enabled: false } }}
|
||||
/>
|
||||
<div>
|
||||
<label htmlFor="objectif">Que voulez-vous calculer ? </label>
|
||||
<input
|
||||
id="objectif"
|
||||
value={target}
|
||||
onChange={e => setTarget(e.target.value)}
|
||||
/>
|
||||
<select
|
||||
onChange={e => {
|
||||
setCurrentTarget(e.target.value)
|
||||
}}
|
||||
>
|
||||
{targets.map(target => (
|
||||
<option key={target} value={target}>
|
||||
{target}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
css="display: block; margin-top: 1rem"
|
||||
className="ui__ button small"
|
||||
onClick={() => updateRules()}
|
||||
onClick={() => updateResult()}
|
||||
>
|
||||
{emoji('▶️')} Mettre à jour
|
||||
</button>
|
||||
{ready && <Results />}
|
||||
<Results analysis={analysis} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export const Results = () => {
|
||||
const analysis = useSelector(state => analysisWithDefaultsSelector(state))
|
||||
?.targets[0]
|
||||
console.log(analysis)
|
||||
return (
|
||||
export const Results = ({ analysis }) => {
|
||||
return analysis ? (
|
||||
<div>
|
||||
<h2>Résultats</h2>
|
||||
<ul>
|
||||
|
@ -108,12 +111,12 @@ export const Results = () => {
|
|||
<li>Applicable : {analysis.isApplicable ? '✅' : '❌'}</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
) : null
|
||||
}
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
state = {
|
||||
error: false
|
||||
error: false as false | { message: string }
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
// Mettez à jour l'état, de façon à montrer l'UI de repli au prochain rendu.
|
||||
|
@ -123,7 +126,7 @@ class ErrorBoundary extends React.Component {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
{this.state.error && (
|
||||
{this.state.error ? (
|
||||
<p css="max-height: 4rem; overflow: hidden; border: 3px solid red;">
|
||||
Erreur :{' '}
|
||||
{
|
||||
|
@ -132,8 +135,9 @@ class ErrorBoundary extends React.Component {
|
|||
)[0]
|
||||
}
|
||||
</p>
|
||||
) : (
|
||||
this.props.children
|
||||
)}
|
||||
{this.props.children}
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
douche:
|
||||
icônes: 🚿
|
||||
|
||||
douche . impact par douche:
|
||||
titre: Une douche
|
||||
icônes: 🚿
|
||||
formule: impact par litre * litres d'eau
|
||||
|
||||
douche . impact par litre:
|
||||
|
@ -75,6 +77,9 @@ chauffage . impact par litre:
|
|||
titre: impact par litre chauffé
|
||||
formule: impact par kWh * énergie consommée par litre
|
||||
|
||||
eau:
|
||||
icônes: 🌊
|
||||
|
||||
eau . impact par litre froid:
|
||||
unité: kgCO₂e/l
|
||||
formule: eau potable + traitement eau usée
|
|
@ -98,3 +98,13 @@ Multiplication complète:
|
|||
# valeur attendue: 0
|
||||
# variables manquantes: []
|
||||
|
||||
a:
|
||||
formule:
|
||||
multiplication:
|
||||
assiette: 1000
|
||||
taux: 3%
|
||||
|
||||
b:
|
||||
formule: a
|
||||
exemples:
|
||||
- valeur attendue: 30
|
||||
|
|
13
yarn.lock
13
yarn.lock
|
@ -1039,10 +1039,10 @@
|
|||
"@types/istanbul-reports" "^1.1.1"
|
||||
"@types/yargs" "^13.0.0"
|
||||
|
||||
"@monaco-editor/react@^2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-2.3.0.tgz#ef1e09c408bb3119e2dc0d369b132e82b2d3ade7"
|
||||
integrity sha512-jmmZCQ4iSMfwelWGRV4HWUOJchkN4MOx9vhx1DWvC6ERpvK5DXrcwJBBzuayVtiK7cyCVOGKB7mgjT7KOdUkJw==
|
||||
"@monaco-editor/react@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-3.1.1.tgz#35338643f8350d37f508596b02970bcc2ecf8ea9"
|
||||
integrity sha512-c2XMTEu5SxOahcmvZ6AorDZLWrl3Q6Cax4G2fr5rC55jCYN2b8hpjXu8BlH/Q3blKHEk8e/bahF/i2GeQukLzA==
|
||||
|
||||
"@prerenderer/prerenderer@^0.7.2":
|
||||
version "0.7.2"
|
||||
|
@ -7366,6 +7366,11 @@ moment@2.24.0:
|
|||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
|
||||
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
|
||||
|
||||
monaco-editor@^0.20.0:
|
||||
version "0.20.0"
|
||||
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
|
||||
integrity sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ==
|
||||
|
||||
moo@^0.4.3:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/moo/-/moo-0.4.3.tgz#3f847a26f31cf625a956a87f2b10fbc013bfd10e"
|
||||
|
|
Loading…
Reference in New Issue