L'exemple activé est gardé de /regle en /regle

Incontournable pour trouver pourquoi un exemple est rouge
pull/171/head
Mael 2018-02-22 17:23:47 +01:00
parent 94b31ac3e4
commit 054bb02873
5 changed files with 109 additions and 80 deletions

View File

@ -6,6 +6,10 @@ export function stepAction(name, step, source) {
return { type: STEP_ACTION, name, step, source }
}
export function setExample(name, situation) {
return { type: 'SET_EXAMPLE', situation, name }
}
export const START_CONVERSATION = 'START_CONVERSATION'
// Reset the form

View File

@ -6,6 +6,9 @@ import knownMecanisms from 'Engine/known-mecanisms.yaml'
import { makeJsx } from 'Engine/evaluation'
import './Algorithm.css'
import { humanFigure } from '../../utils'
import { head } from 'ramda'
import { analyse } from 'Engine/traverse'
import { exampleSituationGateWithDefaults } from './Examples'
let RuleWithoutFormula = () => (
<p>
@ -16,14 +19,21 @@ let RuleWithoutFormula = () => (
@AttachDictionary(knownMecanisms)
export default class Algorithm extends React.Component {
state = {
showValues: true
}
render() {
let { rule, showValues } = this.props,
let { rule: displayedRule, showValues, currentExample, rules } = this.props,
ruleWithoutFormula =
!rule['formule'] ||
path(['formule', 'explanation', 'une possibilité'], rule)
!displayedRule['formule'] ||
path(['formule', 'explanation', 'une possibilité'], displayedRule)
let rule = currentExample
? head(
analyse(rules, displayedRule.dottedName)(
exampleSituationGateWithDefaults(currentExample.situation, rules)
).targets
)
: displayedRule
console.log('didcomp')
return (
<div id="algorithm">

View File

@ -1,11 +1,15 @@
import React, { Component } from 'react'
import { evolve, path, isEmpty } from 'ramda'
import { evolve, path, isEmpty, compose } from 'ramda'
import classNames from 'classnames'
import { connect } from 'react-redux'
import { disambiguateExampleSituation, collectDefaults } from 'Engine/rules.js'
import { analyse } from 'Engine/traverse'
import './Examples.css'
import { assume } from '../../reducers'
import { setExample } from '../../actions'
export let exampleSituationGateWithDefaults = (situationObject, rules) =>
assume(() => name => situationObject[name], collectDefaults(rules))()
// By luck this works as expected for both null and undefined, * but with different branches failing :O *
export let isFloat = n => Number(n) === n && n % 1 !== 0
@ -16,10 +20,8 @@ export let runExamples = (examples, rule, parsedRules) =>
examples
.map(evolve({ situation: disambiguateExampleSituation(parsedRules, rule) }))
.map(ex => {
let exampleSituationGate = () => name => ex.situation[name]
let runExample = analyse(parsedRules, rule.dottedName)(
assume(exampleSituationGate, collectDefaults(parsedRules))()
exampleSituationGateWithDefaults(ex.situation, parsedRules)
),
exampleValue = runExample.targets[0].nodeValue,
goal = ex['valeur attendue'],
@ -37,21 +39,25 @@ export let runExamples = (examples, rule, parsedRules) =>
}
})
@connect(state => ({
situationGate: state.situationGate,
parsedRules: state.parsedRules,
colour: state.themeColours.colour
}))
@connect(
state => ({
situationGate: state.situationGate,
parsedRules: state.parsedRules,
colour: state.themeColours.colour
}),
dispatch => ({
setExample: compose(dispatch, setExample)
})
)
export default class Examples extends Component {
render() {
let focusedExample = path(['focusedExample', 'nom'])(this.props),
{
inject,
let {
situationExists,
showValues,
rule,
parsedRules,
colour
colour,
setExample,
currentExample
} = this.props,
{ exemples = [] } = rule,
examples = runExamples(exemples, rule, parsedRules)
@ -70,46 +76,51 @@ export default class Examples extends Component {
</p>
) : (
<ul>
{examples.map(({ nom, ok, rule, 'valeur attendue': expected }) => (
<li
key={nom}
className={classNames('example', {
ok,
selected: focusedExample == nom
})}
onClick={() => inject({ nom, ok, rule })}
>
<span>
{' '}
{ok ? (
<i className="fa fa-check-circle" aria-hidden="true" />
) : (
<i className="fa fa-times" aria-hidden="true" />
)}
</span>
<span className="name">{nom}</span>
{!ok &&
focusedExample == nom && (
<div className="ko">
Ce test ne passe pas
{showValues && (
{examples.map(
({ nom, ok, rule, 'valeur attendue': expected, situation }) => (
<li
key={nom}
className={classNames('example', {
ok,
selected: currentExample && currentExample.name == nom
})}
onClick={() =>
currentExample
? setExample(null)
: setExample(nom, situation)
}
>
<span>
{' '}
{ok ? (
<i className="fa fa-check-circle" aria-hidden="true" />
) : (
<i className="fa fa-times" aria-hidden="true" />
)}
</span>
<span className="name">{nom}</span>
{!ok &&
currentExample &&
currentExample.name == nom && (
<div className="ko">
Ce test ne passe pas
<span>
: le résultat attendu était{' '}
<span className="expected">{expected}</span>
</span>
)}
</div>
)}
</li>
))}
</div>
)}
</li>
)
)}
</ul>
)}
{situationExists &&
focusedExample && (
currentExample && (
<div>
<button
id="injectSituation"
onClick={() => inject()}
onClick={() => setExample(null)}
style={{ background: colour }}
>
Revenir à votre situation

View File

@ -17,28 +17,16 @@ import SearchButton from 'Components/SearchButton'
@connect(state => ({
form: state.form,
rules: state.parsedRules
rules: state.parsedRules,
currentExample: state.currentExample
}))
export default class Rule extends Component {
state = {
example: null,
showValues: true
}
componentWillReceiveProps(nextProps) {
let dn = path(['rule', 'dottedName'])
if (dn(this.props) !== dn(this.nextProps)) {
this.setState({ example: null })
}
}
render() {
let { form, rule } = this.props,
conversationStarted = !isEmpty(form),
situationExists = conversationStarted || this.state.example != null
let { form, rule, currentExample, rules } = this.props,
conversationStarted = !isEmpty(form)
let { type, name, title, description, question, ns } = rule,
situationOrExampleRule = path(['example', 'rule'])(this.state) || rule,
namespaceRules = findRuleByNamespace(this.props.rules, rule.dottedName)
namespaceRules = findRuleByNamespace(rules, rule.dottedName)
return (
<div id="rule">
@ -60,8 +48,10 @@ export default class Rule extends Component {
<section id="rule-content">
<Algorithm
rule={situationOrExampleRule}
showValues={situationExists}
rules={rules}
currentExample={currentExample}
rule={rule}
showValues={conversationStarted || currentExample}
/>
{rule.note && (
<section id="notes">
@ -70,15 +60,9 @@ export default class Rule extends Component {
</section>
)}
<Examples
currentExample={currentExample}
situationExists={conversationStarted}
rule={rule}
focusedExample={this.state.example}
showValues={this.state.showValues}
inject={example =>
this.state.example != null
? this.setState({ example: null })
: this.setState({ example, showValues: true })
}
/>
{!isEmpty(namespaceRules) && (
<NamespaceRulesList {...{ rule, namespaceRules }} />

View File

@ -1,4 +1,13 @@
import { head, isEmpty, pathOr, reject, contains, without, concat, length } from 'ramda'
import {
head,
isEmpty,
pathOr,
reject,
contains,
without,
concat,
length
} from 'ramda'
import { combineReducers } from 'redux'
import reduceReducers from 'reduce-reducers'
import { reducer as formReducer, formValueSelector } from 'redux-form'
@ -116,7 +125,7 @@ export let reduceSteps = (tracker, flatRules, answerSource) => (
if (action.type == STEP_ACTION && action.name == 'fold') {
tracker.push([
'trackEvent',
'answer:'+action.source,
'answer:' + action.source,
action.step + ': ' + situationWithDefaults(state)(action.step)
])
@ -124,7 +133,7 @@ export let reduceSteps = (tracker, flatRules, answerSource) => (
tracker.push([
'trackEvent',
'done',
'after'+length(newState.foldedSteps)+'questions'
'after' + length(newState.foldedSteps) + 'questions'
])
}
@ -166,6 +175,15 @@ function explainedVariable(state = null, { type, variableName = null }) {
}
}
function currentExample(state = null, { type, situation, name }) {
switch (type) {
case 'SET_EXAMPLE':
return name != null ? { name, situation } : null
default:
return state
}
}
export default reduceReducers(
combineReducers({
sessionId: (id = Math.floor(Math.random() * 1000000000000) + '') => id,
@ -191,7 +209,9 @@ export default reduceReducers(
themeColours,
explainedVariable
explainedVariable,
currentExample
}),
// cross-cutting concerns because here `state` is the whole state tree
reduceSteps(ReactPiwik, rules, formatInputs(rules, formValueSelector))