diff --git a/source/components/Rule.css b/source/components/Rule.css index 1702828ea..15a2db395 100644 --- a/source/components/Rule.css +++ b/source/components/Rule.css @@ -166,13 +166,29 @@ align-items: center; } .dictionaryPanel { - width: 35%; + width: 33%; border: 1px dashed #aaa; margin: 1em; - padding: .6em 1em; + padding: 0em 1.5em; min-height: 6em; border-radius: .3em; - +} +.dictionaryPanel h3 { + color: #333350 +} +.dictionaryPanel blockquote { + font-style: italic; + border-left: 4px solid #eee; + padding-left: 1em; + margin-left: 0; +} +.dictionaryPanel blockquote p { + color: #666; +} +.dictionaryPanel code { + border: 1px solid #aaa; + padding: .05em .3em; + border-radius: .3em; } #rule-rules section { @@ -200,6 +216,12 @@ font-weight: 600; border-radius: .4em; } +[data-term-definition] { + cursor: pointer; +} +[data-term-definition]:hover { + opacity: .8 +} .ruleProp > .nodeHead .name { background: #df5320 } @@ -275,6 +297,7 @@ font-weight: 600; font-size: 90%; border: 1px solid rgba(51, 51, 80, 0.25); + white-space: nowrap } diff --git a/source/components/Rule.js b/source/components/Rule.js index ef8cbe149..36b7d27db 100644 --- a/source/components/Rule.js +++ b/source/components/Rule.js @@ -13,6 +13,7 @@ import destinataires from '../../règles/destinataires/destinataires.yaml' import references from '../../règles/références/références.yaml' import {capitalise0} from '../utils' import knownMecanisms from '../engine/known-mecanisms.yaml' +import marked from '../engine/marked' // situationGate function useful for testing : let testingSituationGate = v => // eslint-disable-line no-unused-vars @@ -128,24 +129,27 @@ export default class Rule extends Component { let AttachDictionary = dictionary => Decorated => class extends React.Component { state = { + term: null, explanation: null } - explain = explanation => - this.setState({explanation}) componentDidMount() { let decoratedNode = ReactDOM.findDOMNode(this.decorated) decoratedNode.addEventListener('click', e => { - let term = e.target.dataset['termDefinition'] - this.explain(R.path([term, 'description'], dictionary)) + let term = e.target.dataset['termDefinition'], + explanation = R.path([term, 'description'], dictionary) + this.setState({explanation, term}) }) } + renderExplanationMarkdown(explanation, term) { + return marked(`### Mécanisme: ${term}\n\n${explanation}`) + } render(){ + let {explanation, term} = this.state return (
this.decorated = decorated} {...this.props} explain={this.explain}/> - {this.state.explanation && -
- {this.state.explanation} + {explanation && +
}
diff --git a/source/engine/known-mecanisms.yaml b/source/engine/known-mecanisms.yaml index 0274d5018..5e02afc9e 100644 --- a/source/engine/known-mecanisms.yaml +++ b/source/engine/known-mecanisms.yaml @@ -1,20 +1,30 @@ +# Liste et description des différents mécanismes compris par le moteur. +# La description peut être rédigée en markdown :-) + l'une de ces conditions: description: | - C'est un 'ou' logique. + C'est un `ou` logique. + Contient une liste de conditions. - Renvoie vrai si l'une des conditions sont vraies. + + Renvoie vrai si l'une des conditions est vraie. toutes ces conditions: description: | - C'est un 'et' logique. + C'est un `et` logique. + Contient une liste de conditions. + Renvoie vrai si toutes les conditions vraies. logique numérique: description: | Contient une liste de couples condition-conséquence. - Un par un, si la condition est vraie, alors on choisit la conséquence. - Cette conséquence peut elle-même être un mécanisme "logique numérique" ou plus simplement un taux. - Si aucune condition n'est vraie, alors ce mécanisme renvoie implilcitement 'non applicable' (ce qui peut se traduire par la valeur 0 si nous sommes dans un contexte numérique). + + Couple par couple, si la condition est vraie, alors on choisit la conséquence. + + Cette conséquence peut elle-même être un mécanisme `logique numérique` ou plus simplement un `taux`. + + Si aucune condition n'est vraie, alors ce mécanisme renvoie implicitement `non applicable` (ce qui peut se traduire par la valeur `0` si nous sommes dans un contexte numérique). taux: description: | @@ -23,22 +33,51 @@ taux: multiplication: description: | C'est une multiplication un peu améliorée, très utile pour exprimer les cotisations, souvent linéaires. - Sa propriété 'assiette' est multipliée par un pourcentage, 'taux', ou par un 'facteur' quand ce nom est plus approprié. - La multiplication peut être plafonnée : ce plafond sépare l'assiette en deux, et la partie au-dessus du plafond est tout simplement ignorée. - Dans ce cas, elle se comporte comme une barème en taux marginaux à deux tranches, la deuxième au taux nul et allant de 'plafond' à l'infini. + Sa propriété `assiette` est multipliée par un pourcentage, `taux`, ou par un `facteur` quand ce nom est plus approprié. + + La multiplication peut être plafonnée : ce plafond sépare l'assiette en deux, et la partie au-dessus du plafond est tout simplement ignorée. Dans ce cas, elle se comporte comme une barème en taux marginaux à deux tranches, la deuxième au taux nul et allant de `plafond` à l'infini. le maximum de: description: | - Calcule le maximum de la liste de propositions fournie. + Renvoie l'élément de la liste de propositions fournie qui la la plus grande valeur. + Ces propositions doivent avoir un mécanisme de calcul ou être une valeur numérique. - Il est conseillé de renseigner une description de chaque propositions par exemple quand elles représentent des méthodes de calcul alternatives parmi lesquelles il faut en choisir une. + + Il est conseillé de renseigner une description de chaque proposition par exemple quand elles représentent des méthodes de calcul alternatives parmi lesquelles il faut en choisir une. somme: description: | C'est tout simplement la somme de chaque terme de la liste. +########################################## +# Ce qu'on appelle aujourd'hui des RuleProp +# Et qui deviendront des mécanismes classiques normalement par la suite #TODO + +formule: + description: | + C'est la formule de calcul d'une variable. Elle renvoie une valeur numérique ou un 'non', exprimant le fait que la variable n'est pas applicable, ce qui vaut implicitement 0. + + Cette doit faire appel à fera appel à des mécanismes de calcul : par exemple `multiplication`, le plus commun pour les variables de type `Cotisation`. + + +non applicable si: + description: | + Si cette variable est vraie, c'est que la variable n'est pas applicable pour la situation saisie. + + > Pour une cotisation sociale, cela signifie qu'elle ne me concerne pas, que je n'ai pas à la verser. + + La formule est donc à ignorer. + + + + + + + + + # à venir # barème: # description: | diff --git a/source/engine/marked.js b/source/engine/marked.js new file mode 100644 index 000000000..972e7aa5f --- /dev/null +++ b/source/engine/marked.js @@ -0,0 +1,10 @@ +import marked from 'marked' + +let customMarked = new marked.Renderer() +customMarked.link = ( href, title, text ) => + `${ text }` +marked.setOptions({ + renderer: customMarked +}) + +export default marked diff --git a/source/engine/rules.js b/source/engine/rules.js index 57ccab637..c8b9edcb3 100644 --- a/source/engine/rules.js +++ b/source/engine/rules.js @@ -2,15 +2,7 @@ import rawRules from './load-rules' import R from 'ramda' import possibleVariableTypes from './possibleVariableTypes.yaml' -import marked from 'marked' - - -let customMarked = new marked.Renderer() -customMarked.link = ( href, title, text ) => - `${ text }` -marked.setOptions({ - renderer: customMarked -}) +import marked from './marked' /*********************************** Méthodes agissant sur une règle */ diff --git a/source/engine/traverse-common-jsx.js b/source/engine/traverse-common-jsx.js index 57134e4df..81fc34b56 100644 --- a/source/engine/traverse-common-jsx.js +++ b/source/engine/traverse-common-jsx.js @@ -3,42 +3,44 @@ import R from 'ramda' import classNames from 'classnames' let treatValue = data => - data == null - ? '?' - : R.is(Number)(data) ? Math.round(data) : data ? 'oui' : 'non' + data == null + ? '?' + : R.is(Number)(data) ? Math.round(data) : data ? 'oui' : 'non' let NodeValue = ({data}) => ( - - ←  - {treatValue(data)} - + + ←  + {treatValue(data)} + ) // Un élément du graphe de calcul qui a une valeur interprétée (à afficher) export class Node extends React.Component { render() { - let {classes, name, value, child, termDefinition} = this.props + let + {classes, name, value, child} = this.props, + termDefinition = R.contains('mecanism', classes) && name return ( -
- {name && - - {name} - - } - {child} - {!name && } -
+
+ {name && + + {name} + + } + {child} + {!name && } +
) } } // Un élément du graphe de calcul qui a une valeur interprétée (à afficher) export let Leaf = ({classes, name, value}) => ( - - {name && - - {name} - } - + + {name && + + {name} + } + ) diff --git a/source/engine/traverse.js b/source/engine/traverse.js index d1ba3b0ce..ce94cb398 100644 --- a/source/engine/traverse.js +++ b/source/engine/traverse.js @@ -248,7 +248,6 @@ let treat = (situationGate, rule) => rawNode => { )(v) return {...result, jsx: