From 1b0c19a68f544a0c74bb58f667cdaa320774e872 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 18 Oct 2021 15:47:57 +0200 Subject: [PATCH 001/135] prepare vue_visgraph component, with store, dataset and display basic graph --- .../Controller/HouseholdController.php | 17 +++- .../Resources/public/page/vis/index.js | 32 -------- .../Resources/public/page/vis/scss/vis.scss | 5 -- .../Resources/public/vuejs/VisGraph/App.vue | 51 ++++++++++++ .../Resources/public/vuejs/VisGraph/api.js | 79 +++++++++++++++++++ .../Resources/public/vuejs/VisGraph/i18n.js | 15 ++++ .../Resources/public/vuejs/VisGraph/index.js | 27 +++++++ .../Resources/public/vuejs/VisGraph/store.js | 47 +++++++++++ .../views/Household/relationship.html.twig | 30 ++++--- .../ChillPersonBundle/chill.webpack.config.js | 2 +- .../translations/messages+intl-icu.fr.yaml | 4 +- 11 files changed, 250 insertions(+), 59 deletions(-) delete mode 100644 src/Bundle/ChillPersonBundle/Resources/public/page/vis/index.js delete mode 100644 src/Bundle/ChillPersonBundle/Resources/public/page/vis/scss/vis.scss create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js create mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php index 1b9824184..bd3bf7889 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php @@ -9,6 +9,8 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Translation\TranslatorInterface; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Chill\PersonBundle\Entity\Household\Household; @@ -24,11 +26,16 @@ class HouseholdController extends AbstractController private PositionRepository $positionRepository; - public function __construct(TranslatorInterface $translator, PositionRepository $positionRepository) + private SerializerInterface $serializer; - { + public function __construct( + TranslatorInterface $translator, + PositionRepository $positionRepository, + SerializerInterface $serializer + ) { $this->translator = $translator; $this->positionRepository = $positionRepository; + $this->serializer = $serializer; } /** @@ -177,9 +184,13 @@ class HouseholdController extends AbstractController */ public function showRelationship(Request $request, Household $household) { + $jsonString = $this->serializer->serialize($household->getCurrentPersons(), + 'json', [ AbstractNormalizer::GROUPS => ['read']]); + return $this->render('@ChillPerson/Household/relationship.html.twig', [ - 'household' => $household + 'household' => $household, + 'persons' => $jsonString ] ); } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/page/vis/index.js b/src/Bundle/ChillPersonBundle/Resources/public/page/vis/index.js deleted file mode 100644 index f11e930c0..000000000 --- a/src/Bundle/ChillPersonBundle/Resources/public/page/vis/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import vis from 'vis-network/dist/vis-network.min'; - -require('./scss/vis.scss'); - -// create an array with nodes -let nodes = new vis.DataSet([ - { id: 1, label: "Node 1" }, - { id: 2, label: "Node 2" }, - { id: 3, label: "Node 3" }, - { id: 4, label: "Node 4" }, - { id: 5, label: "Node 5", cid: 1 }, -]); - -// create an array with edges -let edges = new vis.DataSet([ - { from: 1, to: 3 }, - { from: 1, to: 2 }, - { from: 2, to: 4 }, - { from: 2, to: 5 }, - { from: 3, to: 3 }, -]); - -// create a network -let container = document.getElementById("graph-relationship"); -let data = { - nodes: nodes, - edges: edges, -}; -let options = {}; - -// -let network = new vis.Network(container, data, options); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/page/vis/scss/vis.scss b/src/Bundle/ChillPersonBundle/Resources/public/page/vis/scss/vis.scss deleted file mode 100644 index 3d29c47ce..000000000 --- a/src/Bundle/ChillPersonBundle/Resources/public/page/vis/scss/vis.scss +++ /dev/null @@ -1,5 +0,0 @@ -div#graph-relationship { - margin: 2em auto; - height: 500px; - border: 1px solid lightgray; -} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue new file mode 100644 index 000000000..bbaebf670 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js new file mode 100644 index 000000000..009d1309d --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -0,0 +1,79 @@ +/** + * @var makeFetch + */ +const makeFetch = (method, url, body) => { + + return fetch(url, { + method: method, + headers: { + 'Content-Type': 'application/json;charset=utf-8' + }, + body: JSON.stringify(body) + }) + .then(response => { + + if (response.ok) { + return response.json(); + } + + if (response.status === 422) { + return response.json(); + } + + throw { + msg: 'Error while updating AccompanyingPeriod Course.', + sta: response.status, + txt: response.statusText, + err: new Error(), + body: response.body + }; + }); +} + +/** + * @var getHousehold +*/ +const getHousehold = (person) => { + console.log('getHousehold', person.id) + makeFetch( + 'GET', + `/api/1.0/person/household/by-person/${person.id}.json`, + { + type: 'person', + id: person.id + }) +} + +/** + * @var getCourse +*/ +const getCourse = (person) => { + console.log('getCourse', person.id) + makeFetch( + 'GET', + `/api/1.0/person/accompanying-course/by-person/${person.id}.json`, + { + type: 'person', + id: person.id + }) +} + +/** + * @var getRelationship +*/ +const getRelationship = (person) => { + console.log('getRelationship', person.id) + makeFetch( + 'GET', + `/api/1.0/relations/relationship/by-person/${person.id}.json`, + { + type: 'person', + id: person.id + }) +} + +export { + getHousehold, + getCourse, + getRelationship +} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js new file mode 100644 index 000000000..950f5533c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -0,0 +1,15 @@ +//import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n' + +const visMessages = { + fr: { + visgraph: { + + } + } +} + +//Object.assign(visMessages.fr, personMessages.fr); + +export { + visMessages +} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js new file mode 100644 index 000000000..e70e3bb18 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js @@ -0,0 +1,27 @@ +import { createApp } from "vue" +import { store } from "./store.js" +import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n' +import { visMessages } from './i18n' +import App from './App.vue' + +const i18n = _createI18n(visMessages) + +const container = document.getElementById('relationship-graph') + +const persons = JSON.parse(container.dataset.persons) + +persons.forEach(person => { + store.dispatch('addPerson', person) + store.dispatch('fetchInfoForPerson', person) +}) + +const app = createApp({ + template: `` +}) +.use(store) +.use(i18n) +.component('app', App) +.mount('#relationship-graph') + + +//console.log('container dataset', container.dataset.persons) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js new file mode 100644 index 000000000..ecb79c16e --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -0,0 +1,47 @@ +import { createStore } from 'vuex' +import { getHousehold, getCourse, getRelationship } from './api' + +const debug = process.env.NODE_ENV !== 'production' + +const store = createStore({ + strict: debug, + state: { + persons: [], + households: [], + courses: [], + relationships: [], + }, + getters: { + getNodes() { + let nodes = []; + state.households.forEach(h => { + nodes.push(h) + }); + return nodes + }, + getEdges() { + } + }, + mutations: { + addPerson(state, person) { + person.label = person.text // vis need label + state.persons.push(person) + } + }, + actions: { + addPerson({ commit }, person) { + //console.log('addPerson', person) + commit('addPerson', person) + }, + fetchInfoForPerson({ commit }, person) { + console.log('fetchInfoForPerson', person) + + getHousehold(person) + getCourse(person) + getRelationship(person) + + }, + } +}); + +export { store } diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig index 5d5fc77af..db143e39f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig @@ -4,24 +4,22 @@ {% block content %}

{{ block('title') }}

-
- {% for m in household.members %} - {% if m.endDate is null %} - {{ dump(m) }} - {% endif %} - {% endfor %} +
+
+ {# + {{ dump() }} + #} {% endblock %} -{% block js %} - {{ parent() }} - {{ encore_entry_script_tags('page_vis') }} -{% endblock %} - -{% block css %} - {{ parent() }} - {{ encore_entry_link_tags('page_vis') }} -{% endblock %} - {% block block_post_menu %}{% endblock %} + +{% block js %} + {{ encore_entry_script_tags('vue_visgraph') }} +{% endblock %} + +{% block css %} + {{ encore_entry_link_tags('vue_visgraph') }} +{% endblock %} diff --git a/src/Bundle/ChillPersonBundle/chill.webpack.config.js b/src/Bundle/ChillPersonBundle/chill.webpack.config.js index 925a5ccf8..e033fc89d 100644 --- a/src/Bundle/ChillPersonBundle/chill.webpack.config.js +++ b/src/Bundle/ChillPersonBundle/chill.webpack.config.js @@ -12,9 +12,9 @@ module.exports = function(encore, entries) encore.addEntry('vue_accourse', __dirname + '/Resources/public/vuejs/AccompanyingCourse/index.js'); encore.addEntry('vue_accourse_work_create', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkCreate/index.js'); encore.addEntry('vue_accourse_work_edit', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js'); + encore.addEntry('vue_visgraph', __dirname + '/Resources/public/vuejs/VisGraph/index.js'); encore.addEntry('page_household_edit_metadata', __dirname + '/Resources/public/page/household_edit_metadata/index.js'); encore.addEntry('page_person', __dirname + '/Resources/public/page/person/index.js'); encore.addEntry('page_accompanying_course_index_person_locate', __dirname + '/Resources/public/page/accompanying_course_index/person_locate.js'); - encore.addEntry('page_vis', __dirname + '/Resources/public/page/vis/index.js'); }; diff --git a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml index c92dc6a31..ba7133b2a 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml +++ b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml @@ -51,8 +51,8 @@ household: Household summary: Résumé du ménage Accompanying period: Parcours d'accompagnement Addresses: Historique adresse - Relationship: Composition familiale - Household relationships: Composition du ménage + Relationship: Filiation + Household relationships: Filiations dans le ménage Current address: Adresse actuelle Household does not have any address currently: Le ménage n'a pas d'adresse renseignée actuellement Edit household members: Modifier l'appartenance au ménage From 902c45f0cd012a63768dfa375c95fc8febad1e89 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 20 Oct 2021 13:11:58 +0200 Subject: [PATCH 002/135] endpoint created for acc periods by-person --- .../AccompanyingCourseApiController.php | 25 ++++++++++++++++++- .../ChillPersonExtension.php | 8 ++++++ .../ChillPersonBundle/chill.api.specs.yaml | 23 +++++++++++++++++ .../config/services/controller.yaml | 10 +++++--- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index 8201752af..e7243fba1 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -18,7 +18,11 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\MainBundle\Entity\Scope; +use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository; +use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Symfony\Component\Workflow\Registry; +use Symfony\Component\Routing\Annotation\Route; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; class AccompanyingCourseApiController extends ApiController { @@ -28,14 +32,18 @@ class AccompanyingCourseApiController extends ApiController private Registry $registry; + private AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository; + public function __construct( EventDispatcherInterface $eventDispatcher, ValidatorInterface $validator, - Registry $registry + Registry $registry, + AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository ) { $this->eventDispatcher = $eventDispatcher; $this->validator = $validator; $this->registry = $registry; + $this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository; } public function confirmApi($id, Request $request, $_format): Response @@ -187,4 +195,19 @@ $workflow = $this->registry->get($accompanyingPeriod); return null; } + + /** + * @Route("/api/1.0/person/accompanying-course/by-person/{person_id}.{_format}", + * name="chill_person_accompanyingperiod_by_person", + * requirements={ + * "_format"="json" + * }) + * + * @ParamConverter("person", options={"id" = "person_id"}) + */ + public function getAccompanyingPeriodsByPerson(Person $person){ + $accompanyingPeriods = $person->getAccompanyingPeriods(); + return $this->json(\array_values($accompanyingPeriods), Response::HTTP_OK, [], ['groups' => [ 'read']]); + } + } diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index bc3b798fa..1dd1a7979 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -585,6 +585,14 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, ] ], + 'findAccompanyingPeriodsByPerson' => [ + 'path' => '/by-person/{person_id}.{_format}', + 'controller_action' => 'findAccompanyingPeriodsByPerson', + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ] + ] ] ], [ diff --git a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml index 4041c52b7..5d3f07259 100644 --- a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml +++ b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml @@ -1058,6 +1058,29 @@ paths: description: "OK" 400: description: "transition cannot be applyed" + + /1.0/person/accompanying-course/by-person/{person_id}.json: + get: + tags: + - accompanying period + summary: get a list of accompanying periods for a person + description: Returns a list of the current accompanying periods for a person + parameters: + - name: person_id + in: path + required: true + description: The person id + schema: + type: integer + format: integer + minimum: 1 + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" /1.0/person/accompanying-period/origin.json: get: diff --git a/src/Bundle/ChillPersonBundle/config/services/controller.yaml b/src/Bundle/ChillPersonBundle/config/services/controller.yaml index 489168425..c61362583 100644 --- a/src/Bundle/ChillPersonBundle/config/services/controller.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/controller.yaml @@ -41,10 +41,12 @@ services: tags: ['controller.service_arguments'] Chill\PersonBundle\Controller\AccompanyingCourseApiController: - arguments: - $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' - $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface' - $registry: '@Symfony\Component\Workflow\Registry' + autowire: true + autoconfigure: true + # arguments: + # $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' + # $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface' + # $registry: '@Symfony\Component\Workflow\Registry' tags: ['controller.service_arguments'] Chill\PersonBundle\Controller\PersonApiController: From 8d947ea81b8489b2a7d6b38aa2df8f651f73bb1d Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 20 Oct 2021 13:37:27 +0200 Subject: [PATCH 003/135] viewing permission checked for returned accompanying periods by-person --- .../Controller/AccompanyingCourseApiController.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index e7243fba1..891a0f461 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -207,7 +207,11 @@ $workflow = $this->registry->get($accompanyingPeriod); */ public function getAccompanyingPeriodsByPerson(Person $person){ $accompanyingPeriods = $person->getAccompanyingPeriods(); - return $this->json(\array_values($accompanyingPeriods), Response::HTTP_OK, [], ['groups' => [ 'read']]); + $accompanyingPeriodsChecked = array_filter($accompanyingPeriods, + function(AccompanyingPeriod $period){ + return $this->isGranted(AccompanyingPeriodVoter::SEE, $period); + }); + return $this->json(\array_values($accompanyingPeriodsChecked), Response::HTTP_OK, [], ['groups' => [ 'read']]); } } From d7cf45885e7fcff61f9f88852f85af2108cee7bf Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 20 Oct 2021 10:15:33 +0200 Subject: [PATCH 004/135] vue_visgraph: vuex get household and update nodes array --- .../Resources/public/vuejs/VisGraph/App.vue | 58 +++++---- .../Resources/public/vuejs/VisGraph/api.js | 120 ++++++++++++------ .../Resources/public/vuejs/VisGraph/index.js | 5 +- .../Resources/public/vuejs/VisGraph/store.js | 65 ++++++++-- 4 files changed, 171 insertions(+), 77 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index bbaebf670..f78b9fb62 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -4,40 +4,52 @@ diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js index 009d1309d..50aafc04b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -1,14 +1,17 @@ /** - * @var makeFetch + * @function makeFetch + * @param method + * @param url + * @param body + * @returns {Promise} */ const makeFetch = (method, url, body) => { - return fetch(url, { method: method, headers: { 'Content-Type': 'application/json;charset=utf-8' }, - body: JSON.stringify(body) + body: (body !== null) ? JSON.stringify(body) : null }) .then(response => { @@ -31,49 +34,92 @@ const makeFetch = (method, url, body) => { } /** - * @var getHousehold -*/ -const getHousehold = (person) => { - console.log('getHousehold', person.id) - makeFetch( - 'GET', - `/api/1.0/person/household/by-person/${person.id}.json`, - { - type: 'person', - id: person.id - }) + * @function getFetch + * @param url + * @returns {Promise} + */ +const getFetch = (url) => { + return makeFetch('GET', url, null); } /** - * @var getCourse -*/ -const getCourse = (person) => { - console.log('getCourse', person.id) - makeFetch( - 'GET', - `/api/1.0/person/accompanying-course/by-person/${person.id}.json`, - { - type: 'person', - id: person.id - }) + * @function postFetch + * @param url + * @param body + * @returns {Promise} + */ +const postFetch = (url, body) => { + return makeFetch('POST', url, body); } /** - * @var getRelationship -*/ + * @function patchFetch + * @param url + * @param body + * @returns {Promise} + */ +const patchFetch = (url, body) => { + return makeFetch('PATCH', url, body); +} + + +/** + * @function getHouseholdByPerson + * @param person + * @returns {Promise} + */ +const getHouseholdByPerson = (person) => { + //console.log('getHouseholdByPerson', person.id) + if (person.current_household_id === null) { + throw 'Currently the person has not household!' + } + return getFetch( + `/api/1.0/person/household/${person.current_household_id}.json`) +} + +/** + * @function getCourseByPerson + * @param person + * @returns {Promise} + */ +const getCourseByPerson = (person) => { + //console.log('getCourseByPerson', person.id) + return getFetch( + `/api/1.0/person/accompanying-course/by-person/${person.id}.json`) +} + +/** + * @function getRelationship + * @param person + * @returns {Promise} + */ const getRelationship = (person) => { - console.log('getRelationship', person.id) - makeFetch( - 'GET', - `/api/1.0/relations/relationship/by-person/${person.id}.json`, + //console.log('getRelationship', person.id) + return getFetch( + `/api/1.0/relations/relationship/by-person/${person.id}.json`) +} + +/** + * @function postRelationship + * @param person + * @returns {Promise} + */ +const postRelationship = (person) => { + //console.log('postRelationship', person.id) + return postFetch( + `/api/1.0/relations/relationship.json`, { - type: 'person', - id: person.id - }) + from: { type: 'person', id: 0 }, + to: { type: 'person', id: 0 }, + relation: { type: 'relation', id: 0 }, + reverse: bool + } + ) } export { - getHousehold, - getCourse, - getRelationship + getHouseholdByPerson, + getCourseByPerson, + getRelationship, + postRelationship } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js index e70e3bb18..0aeb032d5 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js @@ -12,7 +12,7 @@ const persons = JSON.parse(container.dataset.persons) persons.forEach(person => { store.dispatch('addPerson', person) - store.dispatch('fetchInfoForPerson', person) + //store.dispatch('fetchInfoForPerson', person) }) const app = createApp({ @@ -22,6 +22,3 @@ const app = createApp({ .use(i18n) .component('app', App) .mount('#relationship-graph') - - -//console.log('container dataset', container.dataset.persons) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index ecb79c16e..d286bf75f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -1,5 +1,5 @@ import { createStore } from 'vuex' -import { getHousehold, getCourse, getRelationship } from './api' +import { getHouseholdByPerson, getCourseByPerson, getRelationship } from './api' const debug = process.env.NODE_ENV !== 'production' @@ -10,36 +10,75 @@ const store = createStore({ households: [], courses: [], relationships: [], + householdLoadingIds: [], }, getters: { - getNodes() { + nodes(state) { let nodes = []; + state.persons.forEach(p => { + nodes.push(p) + }) state.households.forEach(h => { nodes.push(h) - }); + }) + // push all others kinds of nodes.. return nodes }, - getEdges() { - } + edges(state) { + return [] + }, + isHouseholdLoading: (state) => (household_id) => { + return state.householdLoadingIds.includes(household_id); + }, }, mutations: { addPerson(state, person) { person.label = person.text // vis need label state.persons.push(person) + }, + addHousehold(state, household) { + household.label = `Ménage n° ${household.id}` // vis need label + state.households.push(household) + }, + markHouseholdLoading(state, id) { + console.log('mutation: markHouseholdLoading', id) + state.householdLoadingIds.push(id) + }, + unmarkHouseholdLoading(state, id) { + state.householdLoadingIds = state.householdLoadingIds.filter(i => i !== id) } }, actions: { - addPerson({ commit }, person) { - //console.log('addPerson', person) + addPerson({ commit, dispatch }, person) { + console.log('addPerson', person.id) commit('addPerson', person) + dispatch('fetchInfoForPerson', person) + }, + fetchInfoForPerson({ dispatch }, person) { + //console.log('fetchInfoForPerson', person.id) + dispatch('fetchHouseholdForPerson', person) + //getCourseByPerson(person) + //getRelationship(person) }, - fetchInfoForPerson({ commit }, person) { - console.log('fetchInfoForPerson', person) - - getHousehold(person) - getCourse(person) - getRelationship(person) + /** + * Fetch person current household if it is not already loading + * check first isHouseholdLoading to fetch household once + */ + fetchHouseholdForPerson({ commit, getters }, person) { + console.log('isHouseholdLoading', getters.isHouseholdLoading(person.current_household_id)) + if (! getters.isHouseholdLoading(person.current_household_id)) { + commit('markHouseholdLoading', person.current_household_id) + getHouseholdByPerson(person) + .then(household => new Promise(resolve => { + console.log('getHouseholdByPerson', household) + commit('addHousehold', household) + resolve() + }) + ).catch( () => { + commit('unmarkHouseholdLoading', person.current_household_id) + }); + } }, } }); From 6ff80be88d958cb49f84046284ec01327a554adc Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 22 Oct 2021 10:11:33 +0200 Subject: [PATCH 005/135] vue_visgraph: add vis manipulation actions and vis styles --- .../Resources/public/vuejs/VisGraph/App.vue | 82 +++++++++++++------ .../Resources/public/vuejs/VisGraph/store.js | 2 + 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index f78b9fb62..0518a93d2 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -1,59 +1,87 @@ + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index 77a01af4a..f7af08240 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -6,7 +6,8 @@ const visMessages = { 'Course': 'Parcours', 'Household': 'Ménage', } - } + }, + en: {} } //Object.assign(visMessages.fr, personMessages.fr); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 288bc1f94..a06e6e55c 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -74,10 +74,19 @@ const store = createStore({ }, }, actions: { + /** + * 1) Add a person in state + * @param Person person + */ addPerson({ commit, dispatch }, person) { commit('addPerson', person) dispatch('fetchInfoForPerson', person) }, + + /** + * 2) Fetch infos for this person (hub) + * @param Person person + */ fetchInfoForPerson({ dispatch }, person) { dispatch('fetchHouseholdForPerson', person) dispatch('fetchCoursesByPerson', person) @@ -85,8 +94,9 @@ const store = createStore({ }, /** - * Fetch person current household if it is not already loading + * 3) Fetch person current household (if it is not already loading) * check first isHouseholdLoading to fetch household once + * @param Person person */ fetchHouseholdForPerson({ commit, getters, dispatch }, person) { console.log(' isHouseholdLoading ?', getters.isHouseholdLoading(person.current_household_id)) @@ -104,6 +114,11 @@ const store = createStore({ }) } }, + + /** + * 4) Add an edge for each household member (household -> person) + * @param Household household + */ addLinkFromPersonsToHousehold({ commit }, household) { const members = household.members.filter(v => household.current_members_id.includes(v.id)) members.forEach(m => { @@ -111,14 +126,20 @@ const store = createStore({ commit('addRelationship', { from: `${m.person.type}_${m.person.id}`, to: `household_${m.person.current_household_id}`, - id: `p${m.person.id}-h${m.person.current_household_id}` + id: `p${m.person.id}-h${m.person.current_household_id}`, + arrows: 'from', + color: 'pink', + font: { color: 'pink' }, + label: 'enfant', + ////group: 'link_person_household', }) }) }, /** - * Fetch person current AccompanyingCourses + * 5) Fetch AccompanyingCourses for the person + * @param Person person */ fetchCoursesByPerson({ dispatch }, person) { //console.log('fetchCoursesByPerson', person) @@ -130,6 +151,11 @@ const store = createStore({ })) }, + + /** + * 6) Add each distinct course + * @param array courses + */ addCourse({ commit, getters, dispatch }, courses) { //console.log('addCourse', courses) let currentCourses = courses.filter(c => c.closingDate === null) @@ -143,6 +169,11 @@ const store = createStore({ } }) }, + + /** + * 7) Add an edge for each course participation (course <- person) + * @param AccompanyingCourse course + */ addLinkFromPersonsToCourse({ commit }, course) { let currentParticipations = course.participations.filter(p => p.endDate === null) console.log(' participations', currentParticipations.length) @@ -150,7 +181,12 @@ const store = createStore({ commit('addRelationship', { from: `${p.person.type}_${p.person.id}`, to: `${course.id}`, - id: `p${p.person.id}-c`+ course.id.split('_')[2] + id: `p${p.person.id}-c`+ course.id.split('_')[2], + arrows: 'to', + color: 'orange', + font: { color: 'orange' }, + label: 'usager', + //group: 'link_person_course', }) }) }, diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index f90b8a917..cc0ef717a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -8,6 +8,8 @@ import { visMessages } from './i18n' */ window.options = { + locale: 'fr', + locales: visMessages, manipulation: { enabled: true, initiallyActive: true, @@ -20,6 +22,10 @@ window.options = { console.log('editNode', nodeData) callback(nodeData); }, + deleteNode: function(nodeData, callback) { + console.log('deleteNode', nodeData) + callback(nodeData); + }, addEdge: function(edgeData, callback) { console.log('addEdge', edgeData) callback(edgeData); @@ -28,12 +34,78 @@ window.options = { console.log('editNode', edgeData) callback(edgeData); }, + deleteEdge: function(edgeData, callback) { + console.log('deleteNode', edgeData) + callback(edgeData); + }, + controlNodeStyle: { /* + shape:'dot', + size: 6, + color: { + background: '#ff0000', + border: '#3c3c3c', + highlight: { + background: '#07f968', + border: '#3c3c3c' + } + }, + borderWidth: 2, + borderWidthSelected: 2 + */ + } }, nodes: { - physics: true + physics: true, + borderWidth: 1, + borderWidthSelected: 3, }, edges: { - physics: true + physics: true, + font: { + color: '#b0b0b0', + size: 9, + face: 'arial', + background: 'none', + strokeWidth: 2, // px + strokeColor: '#ffffff', + align: 'horizontal', + multi: false, + vadjust: 0, + }, + scaling:{ + label: true, + }, + smooth: true, + }, + groups: { + person: { + shape: 'box', + shapeProperties: { + borderDashes: false, + borderRadius: 3, + }, + color: { + border: '#b0b0b0', + background: 'rgb(193,229,222)', + highlight: { + border: '#368d7e', + background: 'rgb(193,229,222)' + } + } + }, + household: { + /* + shape: 'dot', + */ + color: 'pink' + }, + accompanying_period: { + /* + shape: 'triangle', + */ + color: 'orange', + + }, } }; @@ -45,6 +117,7 @@ window.network = {}; * and add properties needed by vis */ const adapt2vis = (entity) => { + entity.group = entity.type switch (entity.type) { case 'person': entity._id = entity.id diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig index db143e39f..c6d7330fa 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Household/relationship.html.twig @@ -8,13 +8,11 @@
- {# - {{ dump() }} - #} - {% endblock %} -{% block block_post_menu %}{% endblock %} +{% block block_post_menu %} +
+{% endblock %} {% block js %} {{ encore_entry_script_tags('vue_visgraph') }} From b7466c7e85291b449e164abd9d48628f916f8f92 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 26 Oct 2021 14:49:12 +0200 Subject: [PATCH 014/135] GET for relationship fixed: associated relation displayed --- .../Controller/RelationshipApiController.php | 7 +--- .../Relationships/RelationshipRepository.php | 4 +- .../Normalizer/RelationshipNormalizer.php | 37 +++++++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php diff --git a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php index 0327d335e..921f2d151 100644 --- a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php @@ -23,12 +23,6 @@ class RelationshipApiController extends ApiController $this->repository = $repository; } - public function createEntity(string $action, Request $request): object - { - $relationship = parent::createEntity($action, $request); - return $relationship; - } - /** * @Route("/api/1.0/relation/relationship/by-person/{person_id}.json", * name="chill_relation_relationship_by_person") @@ -39,6 +33,7 @@ class RelationshipApiController extends ApiController { //TODO: add permissions? (voter?) $relationships = $this->repository->findByPerson($person); + dump($relationships[0]->getRelation()); return $this->json(\array_values($relationships), Response::HTTP_OK, [], ['groups' => [ 'read']]); } diff --git a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php index ad251b4ff..00546e424 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php @@ -27,7 +27,9 @@ class RelationshipRepository extends ServiceEntityRepository { // return all relationships of which person is part? or only where person is the fromPerson? return $this->createQueryBuilder('r') - ->andWhere('r.fromPerson = :val') + ->select('r, t') // entity Relationship + ->join('r.relation', 't') + ->where('r.fromPerson = :val') ->orWhere('r.toPerson = :val') ->setParameter('val', $personId) ->getQuery() diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php new file mode 100644 index 000000000..6036a18e9 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php @@ -0,0 +1,37 @@ + 'relationship', + 'fromPerson' => $this->normalizer->normalize($relationship->getFromPerson()), + 'toPerson' => $this->normalizer->normalize($relationship->getToPerson()), + 'relation' => $this->normalizer->normalize($relationship->getRelation()), + 'reverse' => $relationship->getReverse() + ]; + } + + public function supportsNormalization($data, ?string $format = null) + { + return $data instanceof Relationship; + } + +} \ No newline at end of file From 9609fcb5d3974c72c8d94b1ad71cb6a18f536af2 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 26 Oct 2021 14:53:42 +0200 Subject: [PATCH 015/135] visgraph: edit interface fr translations --- .../Resources/public/vuejs/VisGraph/i18n.js | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index f7af08240..9fa8eca26 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -5,9 +5,37 @@ const visMessages = { visgraph: { 'Course': 'Parcours', 'Household': 'Ménage', - } + }, + edit: 'Éditer', + del: 'Supprimer', + back: 'Revenir en arrière', + addNode: 'Ajouter un noeuds', + addEdge: 'Ajouter un lien', + editNode: 'Éditer un noeuds', + editEdge: 'Éditer un lien', + addDescription: 'Cliquez dans un espace vide pour créer un nouveau nœud.', + edgeDescription: 'Cliquez sur un nœud et faites glisser le lien vers un autre nœud pour les connecter.', + editEdgeDescription: 'Cliquez sur les points de contrôle et faites-les glisser vers un nœud pour les relier.', + createEdgeError: 'Il est impossible de relier des arêtes à un cluster.', + deleteClusterError: 'Les clusters ne peuvent pas être supprimés.', + editClusterError: 'Les clusters ne peuvent pas être modifiés.' }, - en: {} + en: { + edit: 'Edit', + del: 'Delete selected', + back: 'Back', + addNode: 'Add Node', + addEdge: 'Add Link', + editNode: 'Edit Switch', + editEdge: 'Edit Link', + addDescription: 'Click in an empty space to place a new node.', + edgeDescription: 'Click on a node and drag the link to another node to connect them.', + editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.', + createEdgeError: 'Cannot link edges to a cluster.', + deleteClusterError: 'Clusters cannot be deleted.', + editClusterError: 'Clusters cannot be edited.' + + } } //Object.assign(visMessages.fr, personMessages.fr); From a20eeb6a34a10b304e50b47881fdfecd40f984fa Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 26 Oct 2021 15:15:44 +0200 Subject: [PATCH 016/135] vue_visgraph: add a mechanism to force update component cfr. https://medium.com/emblatech/ways-to-force-vue-to-re-render-a-component-df866fbacf47 --- .../Resources/public/vuejs/VisGraph/App.vue | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 5979a2c71..d0e78bfaa 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -66,6 +66,11 @@ export default { // Instanciate vis objects in window variables, see vis-network.js window.network = new vis.Network(this.container, this.visgraph_data, window.options ) // A + }, + forceUpdateComponent() { + console.log('forceUpdateComponent - method 3') + this.$forceUpdate() + this.refreshNetwork } } /* From 2a86fd12d7a0e0f2e97eebdede5541d5538991ac Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 26 Oct 2021 21:29:17 +0200 Subject: [PATCH 017/135] vue_visgraph: add checkbox legend to enable/disable layers --- .../Resources/public/vuejs/VisGraph/App.vue | 104 +++++++++++++----- .../Resources/public/vuejs/VisGraph/store.js | 17 ++- .../public/vuejs/VisGraph/vis-network.js | 10 +- 3 files changed, 97 insertions(+), 34 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index d0e78bfaa..cb9e07716 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -1,30 +1,28 @@ @@ -37,12 +35,19 @@ export default { name: "App", data() { return { - container: '' + container: '', + checkedLayers: [], } }, computed: { - //not used ...mapState(['persons', 'households', 'courses', 'relationships', 'householdLoadingIds', 'courseLoadedIds']), ...mapGetters(['nodes', 'edges']), + ...mapState(['households', 'courses', + 'excludedNodesIds' + //'persons', + //'relationships', + //'householdLoadingIds', + //'courseLoadedIds', + ]), visgraph_data() { console.log('::: visgraph_data :::', this.nodes.length, 'nodes,', this.edges.length, 'edges') @@ -51,10 +56,36 @@ export default { edges: this.edges } }, + refreshNetwork() { // B console.log('--- refresh network') window.network.setData(this.visgraph_data) + }, + + legendLayers() { + console.log('--- refresh legendLayers') + return [ + ...this.households, + ...this.courses + ] + }, + + rebuildCheckedLayers() { + console.log('-*- rebuild checked Layers Arrays from graph nodes') + this.checkedLayers = [] + let layersDisplayed = [ + ...this.nodes.filter(n => n.id.startsWith('household')), + ...this.nodes.filter(n => n.id.startsWith('accompanying')) + ] + layersDisplayed.forEach(layer => { + this.checkedLayers.push(layer.id) + }) + }, + + checkedLayers() { // required to refresh data checkedLayers + return this.checkedLayers } + }, mounted() { console.log('=== mounted: init graph') @@ -63,7 +94,6 @@ export default { methods: { initGraph() { this.container = document.getElementById('visgraph') - // Instanciate vis objects in window variables, see vis-network.js window.network = new vis.Network(this.container, this.visgraph_data, window.options ) // A }, @@ -71,7 +101,29 @@ export default { console.log('forceUpdateComponent - method 3') this.$forceUpdate() this.refreshNetwork - } + }, + + toggleLayer(value) { + let id = value.target.value + console.log('--> toggleLayer', this.checkedLayers) + if (this.checkedLayers.includes(id)) { + this.removeLayer(id) + } else { + this.addLayer(id) + } + console.log('<-- toggleLayer after', this.checkedLayers) + }, + addLayer(id) { + console.log('+ add Layer', id) + this.checkedLayers.push(id) + this.$store.commit('removeExcludedNode', id) + }, + removeLayer(id) { + console.log('- remove Layer', id) + this.checkedLayers = this.checkedLayers.filter(i => i !== id) + this.$store.commit('addExcludedNode', id) + }, + } /* TODO / TO CHECK / TO UNDERSTAND @@ -98,14 +150,6 @@ div#visgraph { } div#visgraph-legend { div.post-menu.legend { - ul.legend-list { - padding-left: 0; - list-style-type: square; - li::marker { - color: red; - background-color: cyan; - } - } } } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index a06e6e55c..b4938ff4a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -12,7 +12,8 @@ const store = createStore({ courses: [], relationships: [], householdLoadingIds: [], - courseLoadedIds: [] + courseLoadedIds: [], + excludedNodesIds: [] }, getters: { nodes(state) { @@ -26,6 +27,10 @@ const store = createStore({ state.courses.forEach(c => { nodes.push(c) }) + // except excluded nodes (unchecked layers) + state.excludedNodesIds.forEach(excluded => { + nodes = nodes.filter(n => n.id !== excluded) + }) return nodes }, edges(state) { @@ -56,7 +61,7 @@ const store = createStore({ state.courses.push(adapt2vis(course)) }, addRelationship(state, relationship) { - console.log('+ addRelationship', relationship) + console.log('+ addRelationship from', relationship.from, 'to', relationship.to) state.relationships.push(relationship) }, markHouseholdLoading(state, id) { @@ -72,6 +77,12 @@ const store = createStore({ unmarkCourseLoaded(state, id) { state.courseLoadedIds = state.courseLoadedIds.filter(i => i !== id) }, + addExcludedNode(state, id) { + state.excludedNodesIds.push(id) + }, + removeExcludedNode(state, id) { + state.excludedNodesIds = state.excludedNodesIds.filter(e => e !== id) + } }, actions: { /** @@ -185,7 +196,7 @@ const store = createStore({ arrows: 'to', color: 'orange', font: { color: 'orange' }, - label: 'usager', + label: 'concerné', //group: 'link_person_course', }) }) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index cc0ef717a..bfdc74991 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -10,6 +10,14 @@ import { visMessages } from './i18n' window.options = { locale: 'fr', locales: visMessages, + /* + configure: { + enabled: true, + filter: 'nodes,edges', + container: undefined, + showButton: true + }, + */ manipulation: { enabled: true, initiallyActive: true, @@ -63,7 +71,7 @@ window.options = { physics: true, font: { color: '#b0b0b0', - size: 9, + size: 9, face: 'arial', background: 'none', strokeWidth: 2, // px From 326fe5f50b27cc389cf6b1b16057a4d86cb0e81c Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 11:53:34 +0200 Subject: [PATCH 018/135] vue_visgraph: cleaning + i18n --- .../Resources/public/vuejs/_js/i18n.js | 3 +- .../Resources/public/vuejs/VisGraph/App.vue | 35 +++++++------------ .../Resources/public/vuejs/VisGraph/i18n.js | 5 +-- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js index c16b4c65d..4b998f98a 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js @@ -45,7 +45,8 @@ const messages = { redirect: { person: "Quitter la page et ouvrir la fiche de l'usager", thirdparty: "Quitter la page et voir le tiers", - } + }, + refresh: 'Rafraîchir' }, nav: { next: "Suivant", diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index cb9e07716..7be18e6eb 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -3,7 +3,7 @@
-

Légende

+

{{ $t('visgraph.Legend')}}

-
-Checked layers: {{ checkedLayers }}
-Unchecked layers: {{ excludedNodesIds }}
-
- +
@@ -41,8 +36,7 @@ export default { }, computed: { ...mapGetters(['nodes', 'edges']), - ...mapState(['households', 'courses', - 'excludedNodesIds' + ...mapState(['households', 'courses', 'excludedNodesIds' //'persons', //'relationships', //'householdLoadingIds', @@ -57,13 +51,13 @@ export default { } }, - refreshNetwork() { // B + refreshNetwork() { console.log('--- refresh network') window.network.setData(this.visgraph_data) }, legendLayers() { - console.log('--- refresh legendLayers') + console.log('--- refresh legend') return [ ...this.households, ...this.courses @@ -71,7 +65,7 @@ export default { }, rebuildCheckedLayers() { - console.log('-*- rebuild checked Layers Arrays from graph nodes') + console.log('--- rebuild checked Layers') this.checkedLayers = [] let layersDisplayed = [ ...this.nodes.filter(n => n.id.startsWith('household')), @@ -94,36 +88,33 @@ export default { methods: { initGraph() { this.container = document.getElementById('visgraph') - // Instanciate vis objects in window variables, see vis-network.js - window.network = new vis.Network(this.container, this.visgraph_data, window.options ) // A + // Instanciate vis objects in separate window variables, see vis-network.js + window.network = new vis.Network(this.container, this.visgraph_data, window.options ) }, forceUpdateComponent() { - console.log('forceUpdateComponent - method 3') + console.log('forceUpdateComponent') this.$forceUpdate() this.refreshNetwork }, - toggleLayer(value) { + //console.log('toggleLayer') let id = value.target.value - console.log('--> toggleLayer', this.checkedLayers) if (this.checkedLayers.includes(id)) { this.removeLayer(id) } else { this.addLayer(id) } - console.log('<-- toggleLayer after', this.checkedLayers) }, addLayer(id) { - console.log('+ add Layer', id) + console.log('+ addLayer', id) this.checkedLayers.push(id) this.$store.commit('removeExcludedNode', id) }, removeLayer(id) { - console.log('- remove Layer', id) + console.log('- removeLayer', id) this.checkedLayers = this.checkedLayers.filter(i => i !== id) this.$store.commit('addExcludedNode', id) }, - } /* TODO / TO CHECK / TO UNDERSTAND diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index 9fa8eca26..db3f8998f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -3,8 +3,9 @@ const visMessages = { fr: { visgraph: { - 'Course': 'Parcours', - 'Household': 'Ménage', + Course: 'Parcours', + Household: 'Ménage', + Legend: 'Légende', }, edit: 'Éditer', del: 'Supprimer', From c200e9909ebecfad9f7391ec59d7108109d07c33 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 15:16:13 +0200 Subject: [PATCH 019/135] i18n minor changes --- .../Resources/public/vuejs/VisGraph/i18n.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index db3f8998f..077c3c7f6 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -1,11 +1,9 @@ -//import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n' - const visMessages = { fr: { visgraph: { Course: 'Parcours', Household: 'Ménage', - Legend: 'Légende', + Legend: 'Calques', }, edit: 'Éditer', del: 'Supprimer', @@ -39,8 +37,6 @@ const visMessages = { } } -//Object.assign(visMessages.fr, personMessages.fr); - export { visMessages } From a3b203c30629c18ebb0de9e2d79f4b5dc0643ae5 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 16:28:13 +0200 Subject: [PATCH 020/135] fix backend error with AccompanyingCourse endpoints --- .../Controller/RelationshipApiController.php | 6 +++--- .../ChillPersonBundle/config/services/controller.yaml | 5 +---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php index 921f2d151..765d13d25 100644 --- a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php @@ -26,15 +26,15 @@ class RelationshipApiController extends ApiController /** * @Route("/api/1.0/relation/relationship/by-person/{person_id}.json", * name="chill_relation_relationship_by_person") - * + * * @ParamConverter("person", options={"id" = "person_id"}) */ public function getRelationshipsByPerson(Person $person) { //TODO: add permissions? (voter?) $relationships = $this->repository->findByPerson($person); - dump($relationships[0]->getRelation()); + //dump($relationships[0]->getRelation()); return $this->json(\array_values($relationships), Response::HTTP_OK, [], ['groups' => [ 'read']]); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/config/services/controller.yaml b/src/Bundle/ChillPersonBundle/config/services/controller.yaml index cb7ebd76c..45a656e89 100644 --- a/src/Bundle/ChillPersonBundle/config/services/controller.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/controller.yaml @@ -41,10 +41,7 @@ services: tags: ['controller.service_arguments'] Chill\PersonBundle\Controller\AccompanyingCourseApiController: - arguments: - $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' - $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface' - $registry: '@Symfony\Component\Workflow\Registry' + autowire: true tags: ['controller.service_arguments'] Chill\PersonBundle\Controller\PersonApiController: From 7ad0e2f2c803819db97d69928affc1c720e2d54d Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 16:29:16 +0200 Subject: [PATCH 021/135] rename fetch api method --- .../Resources/public/vuejs/VisGraph/api.js | 10 +++++----- .../Resources/public/vuejs/VisGraph/store.js | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js index 957e01fbc..ee288dcc0 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -89,14 +89,14 @@ const getCoursesByPerson = (person) => { } /** - * @function getRelationship + * @function getRelationshipByPerson * @param person * @returns {Promise} */ -const getRelationship = (person) => { - //console.log('getRelationship', person.id) +const getRelationshipByPerson = (person) => { + //console.log('getRelationshipByPerson', person.id) return getFetch( - `/api/1.0/relations/relationship/by-person/${person.id}.json`) + `/api/1.0/relations/relationship/by-person/${person._id}.json`) } /** @@ -120,6 +120,6 @@ const postRelationship = (person) => { export { getHouseholdByPerson, getCoursesByPerson, - getRelationship, + getRelationshipByPerson, postRelationship } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index b4938ff4a..25d044afb 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -1,5 +1,5 @@ import { createStore } from 'vuex' -import { getHouseholdByPerson, getCoursesByPerson, getRelationship } from './api' +import { getHouseholdByPerson, getCoursesByPerson, getRelationshipByPerson } from './api' import { adapt2vis } from './vis-network' const debug = process.env.NODE_ENV !== 'production' @@ -208,9 +208,9 @@ const store = createStore({ */ fetchRelationship({ commit, getters }, person) { console.log('fetchRelationship', person) - getRelationship(person) + getRelationshipByPerson(person) .then(relationship => new Promise(resolve => { - console.log('getRelationship', relationship) + console.log('getRelationshipByPerson', relationship) commit('addRelationship', relationship) resolve() })) From 8ff581d5facce919fa108beecd4221404d1bfe15 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 16:29:54 +0200 Subject: [PATCH 022/135] vue_visgraph: add links array state in store --- .../Resources/public/vuejs/VisGraph/App.vue | 1 + .../Resources/public/vuejs/VisGraph/store.js | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 7be18e6eb..916fb05ef 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -38,6 +38,7 @@ export default { ...mapGetters(['nodes', 'edges']), ...mapState(['households', 'courses', 'excludedNodesIds' //'persons', + //'links, //'relationships', //'householdLoadingIds', //'courseLoadedIds', diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 25d044afb..310315946 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -11,6 +11,7 @@ const store = createStore({ households: [], courses: [], relationships: [], + links: [], householdLoadingIds: [], courseLoadedIds: [], excludedNodesIds: [] @@ -35,6 +36,9 @@ const store = createStore({ }, edges(state) { let edges = [] + state.links.forEach(l => { + edges.push(l) + }) state.relationships.forEach(r => { edges.push(r) }) @@ -60,6 +64,10 @@ const store = createStore({ console.log('+ addCourse', course.id) state.courses.push(adapt2vis(course)) }, + addLink(state, link) { + console.log('+ addLink from', link.from, 'to', link.to) + state.links.push(link) + }, addRelationship(state, relationship) { console.log('+ addRelationship from', relationship.from, 'to', relationship.to) state.relationships.push(relationship) @@ -134,7 +142,7 @@ const store = createStore({ const members = household.members.filter(v => household.current_members_id.includes(v.id)) members.forEach(m => { //console.log('-> addLink from person', m.person.id, 'to household', m.person.current_household_id) - commit('addRelationship', { + commit('addLink', { from: `${m.person.type}_${m.person.id}`, to: `household_${m.person.current_household_id}`, id: `p${m.person.id}-h${m.person.current_household_id}`, @@ -189,7 +197,7 @@ const store = createStore({ let currentParticipations = course.participations.filter(p => p.endDate === null) console.log(' participations', currentParticipations.length) currentParticipations.forEach(p => { - commit('addRelationship', { + commit('addLink', { from: `${p.person.type}_${p.person.id}`, to: `${course.id}`, id: `p${p.person.id}-c`+ course.id.split('_')[2], @@ -202,7 +210,6 @@ const store = createStore({ }) }, - /** * Fetch Relationship */ From 1d1a54f653f7b58a72534ca8cf3723229c0e9e5c Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 17:24:23 +0200 Subject: [PATCH 023/135] vue_visgraph: improve household links (edges) --- .../Resources/public/vuejs/VisGraph/i18n.js | 1 + .../Resources/public/vuejs/VisGraph/store.js | 15 +++-- .../public/vuejs/VisGraph/vis-network.js | 59 +++++++++++++++---- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index 077c3c7f6..c4ad74907 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -3,6 +3,7 @@ const visMessages = { visgraph: { Course: 'Parcours', Household: 'Ménage', + Holder: 'Titulaire', Legend: 'Calques', }, edit: 'Éditer', diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 310315946..0d0ff4442 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -1,6 +1,6 @@ import { createStore } from 'vuex' import { getHouseholdByPerson, getCoursesByPerson, getRelationshipByPerson } from './api' -import { adapt2vis } from './vis-network' +import { adapt2vis, getHouseholdLabel, getHouseholdWidth } from './vis-network' const debug = process.env.NODE_ENV !== 'production' @@ -139,8 +139,8 @@ const store = createStore({ * @param Household household */ addLinkFromPersonsToHousehold({ commit }, household) { - const members = household.members.filter(v => household.current_members_id.includes(v.id)) - members.forEach(m => { + const currentMembers = household.members.filter(v => household.current_members_id.includes(v.id)) + currentMembers.forEach(m => { //console.log('-> addLink from person', m.person.id, 'to household', m.person.current_household_id) commit('addLink', { from: `${m.person.type}_${m.person.id}`, @@ -148,9 +148,9 @@ const store = createStore({ id: `p${m.person.id}-h${m.person.current_household_id}`, arrows: 'from', color: 'pink', - font: { color: 'pink' }, - label: 'enfant', - ////group: 'link_person_household', + font: { color: '#D04A60' }, + label: getHouseholdLabel(m), + width: getHouseholdWidth(m), }) }) @@ -203,9 +203,8 @@ const store = createStore({ id: `p${p.person.id}-c`+ course.id.split('_')[2], arrows: 'to', color: 'orange', - font: { color: 'orange' }, + font: { color: 'darkorange' }, label: 'concerné', - //group: 'link_person_course', }) }) }, diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index bfdc74991..8774501a0 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -1,12 +1,14 @@ import { visMessages } from './i18n' -/* +/** * Vis-network initial data/configuration script * Notes: * Use window.network and window.options to avoid conflict between vue and vis * cfr. https://github.com/almende/vis/issues/2524#issuecomment-307108271 */ +window.network = {}; + window.options = { locale: 'fr', locales: visMessages, @@ -14,7 +16,7 @@ window.options = { configure: { enabled: true, filter: 'nodes,edges', - container: undefined, + //container: undefined, showButton: true }, */ @@ -46,7 +48,8 @@ window.options = { console.log('deleteNode', edgeData) callback(edgeData); }, - controlNodeStyle: { /* + controlNodeStyle: { + /* shape:'dot', size: 6, color: { @@ -112,18 +115,16 @@ window.options = { shape: 'triangle', */ color: 'orange', - }, } }; -window.network = {}; - -/* -* Adapt entity to graph (id, label) -* we rename id in _id -* and add properties needed by vis -*/ +/** + * Adapt entity to graph (id, label) + * rename id in _id and add properties needed by vis + * @param entity + * @returns entity + */ const adapt2vis = (entity) => { entity.group = entity.type switch (entity.type) { @@ -146,6 +147,38 @@ const adapt2vis = (entity) => { return entity } -export { - adapt2vis +/** + * Return member position in household + * @param member + * @returns string + */ +const getHouseholdLabel = (member) => { + let position = member.position.label.fr + let holder = member.holder ? ` (${visMessages.fr.visgraph.Holder})` : '' + return position + holder +} + +/** + * Return edge width for member (depends of position in household) + * @param member + * @returns string + */ +const getHouseholdWidth = (member) => { + switch (member.position.ordering) { + case 1: //adult + if (member.holder) { + return 6 + } + return 3 + case 2: //children + case 3: //children out of household + return 1 + } +} + + +export { + adapt2vis, + getHouseholdLabel, + getHouseholdWidth } From 6752a2f6d3279865bf0465591c54c2685d63f29f Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 27 Oct 2021 17:40:15 +0200 Subject: [PATCH 024/135] fixture created for Relation entity --- .../DataFixtures/ORM/LoadRelations.php | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php new file mode 100644 index 000000000..bcd7df547 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php @@ -0,0 +1,45 @@ + ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fille']], + ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fils']], + ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fils']], + ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fille']], + ['title' => ['fr' => 'Frère'], 'reverseTitle' => ['fr' => 'Soeur']], + ['title' => ['fr' => 'Soeur'], 'reverseTitle' => ['fr' => 'Frère']], + ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Nièce']], + ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Neveu']], + ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Nièce']], + ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Neveu']], + ]; + + foreach($relations as $value){ + print "Creating a new relation type: relation" . $value['title']['fr'] . "reverse relation: " . $value['reverseTitle']['fr'] . "\n"; + $relation = new Relation(); + $relation->setTitle($value['title']) + ->setReverseTitle($value['reverseTitle']); + $manager->persist($relation); + } + + $manager->flush(); + + } + +} \ No newline at end of file From 83e8b117db388e39f75716de1770ae1d9bd147dc Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 27 Oct 2021 18:10:35 +0200 Subject: [PATCH 025/135] start of Relationship fixture --- .../ChillPersonBundle/DataFixtures/ORM/LoadRelations.php | 3 +++ .../ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php | 0 2 files changed, 3 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php index bcd7df547..2b72052c6 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php @@ -10,6 +10,8 @@ use Doctrine\Persistence\ObjectManager; class LoadRelations extends Fixture implements FixtureGroupInterface { + public const RELATIONS = 'relations'; + public static function getGroups(): array { return ['person_relations']; @@ -36,6 +38,7 @@ class LoadRelations extends Fixture implements FixtureGroupInterface $relation->setTitle($value['title']) ->setReverseTitle($value['reverseTitle']); $manager->persist($relation); + $this->addReference(self::RELATIONS, $relation); } $manager->flush(); diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php new file mode 100644 index 000000000..e69de29bb From 2cb1ad6afc3bcb2820d6815517aa09ecad197b8a Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 18:11:14 +0200 Subject: [PATCH 026/135] improve household position fixture --- .../DataFixtures/ORM/LoadHouseholdPosition.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php index cf0bf3de1..23bd499f8 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php @@ -10,8 +10,8 @@ class LoadHouseholdPosition extends Fixture { const POSITIONS_DATA = [ ["Adulte", true, true, 1.0, self::ADULT ], - ["Enfants", true, false, 2.0, self::CHILD ], - ["Enfants hors ménage", false, false, 3.0, self::CHILD_OUT ] + ["Enfant", true, false, 2.0, self::CHILD ], + ["Enfant hors ménage", false, false, 3.0, self::CHILD_OUT ] ]; const ADULT = "position_adulte"; From f834bb3bd613342aeff825852abcd947f51e0d2e Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 19:54:28 +0200 Subject: [PATCH 027/135] backend normalizer: add id to relationship endpoint --- .../Serializer/Normalizer/RelationshipNormalizer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php index 6036a18e9..e410dd90b 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php @@ -22,6 +22,7 @@ class RelationshipNormalizer implements NormalizerInterface, NormalizerAwareInte { return [ 'type' => 'relationship', + 'id' => $this->normalizer->normalize($relationship->getId()), 'fromPerson' => $this->normalizer->normalize($relationship->getFromPerson()), 'toPerson' => $this->normalizer->normalize($relationship->getToPerson()), 'relation' => $this->normalizer->normalize($relationship->getRelation()), From 92c1bf15cc6194fad153faa1470bba5711f85973 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 27 Oct 2021 19:55:24 +0200 Subject: [PATCH 028/135] vue_visgraph: add relationship links with relations --- .../Resources/public/vuejs/VisGraph/App.vue | 1 + .../Resources/public/vuejs/VisGraph/api.js | 8 +- .../Resources/public/vuejs/VisGraph/i18n.js | 1 + .../Resources/public/vuejs/VisGraph/store.js | 100 ++++++++++++++---- .../public/vuejs/VisGraph/vis-network.js | 17 ++- 5 files changed, 104 insertions(+), 23 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 916fb05ef..1804460f7 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -42,6 +42,7 @@ export default { //'relationships', //'householdLoadingIds', //'courseLoadedIds', + //'relationshipLoadedIds', ]), visgraph_data() { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js index ee288dcc0..f595daa34 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -89,12 +89,12 @@ const getCoursesByPerson = (person) => { } /** - * @function getRelationshipByPerson + * @function getRelationshipsByPerson * @param person * @returns {Promise} */ -const getRelationshipByPerson = (person) => { - //console.log('getRelationshipByPerson', person.id) +const getRelationshipsByPerson = (person) => { + //console.log('getRelationshipsByPerson', person.id) return getFetch( `/api/1.0/relations/relationship/by-person/${person._id}.json`) } @@ -120,6 +120,6 @@ const postRelationship = (person) => { export { getHouseholdByPerson, getCoursesByPerson, - getRelationshipByPerson, + getRelationshipsByPerson, postRelationship } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index c4ad74907..9ca273f72 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -5,6 +5,7 @@ const visMessages = { Household: 'Ménage', Holder: 'Titulaire', Legend: 'Calques', + concerned: 'concerné', }, edit: 'Éditer', del: 'Supprimer', diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 0d0ff4442..da13d9bd3 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -1,6 +1,7 @@ import { createStore } from 'vuex' -import { getHouseholdByPerson, getCoursesByPerson, getRelationshipByPerson } from './api' -import { adapt2vis, getHouseholdLabel, getHouseholdWidth } from './vis-network' +import { getHouseholdByPerson, getCoursesByPerson, getRelationshipsByPerson } from './api' +import { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel } from './vis-network' +import { visMessages } from './i18n' const debug = process.env.NODE_ENV !== 'production' @@ -14,6 +15,7 @@ const store = createStore({ links: [], householdLoadingIds: [], courseLoadedIds: [], + relationshipLoadedIds: [], excludedNodesIds: [] }, getters: { @@ -39,9 +41,9 @@ const store = createStore({ state.links.forEach(l => { edges.push(l) }) - state.relationships.forEach(r => { - edges.push(r) - }) + //state.relationships.forEach(r => { + // edges.push(r) + //}) return edges }, isHouseholdLoading: (state) => (household_id) => { @@ -50,6 +52,9 @@ const store = createStore({ isCourseLoaded: (state) => (course_id) => { return state.courseLoadedIds.includes(course_id) }, + isRelationshipLoaded: (state) => (relationship_id) => { + return state.relationshipLoadedIds.includes(relationship_id) + } }, mutations: { addPerson(state, person) { @@ -64,14 +69,14 @@ const store = createStore({ console.log('+ addCourse', course.id) state.courses.push(adapt2vis(course)) }, + addRelationship(state, relationship) { + console.log('+ addRelationship', relationship.id) + state.relationships.push(adapt2vis(relationship)) + }, addLink(state, link) { console.log('+ addLink from', link.from, 'to', link.to) state.links.push(link) }, - addRelationship(state, relationship) { - console.log('+ addRelationship from', relationship.from, 'to', relationship.to) - state.relationships.push(relationship) - }, markHouseholdLoading(state, id) { console.log('..loading household', id) state.householdLoadingIds.push(id) @@ -85,6 +90,12 @@ const store = createStore({ unmarkCourseLoaded(state, id) { state.courseLoadedIds = state.courseLoadedIds.filter(i => i !== id) }, + markRelationshipLoaded(state, id) { + state.relationshipLoadedIds.push(id) + }, + unmarkRelationshipLoaded(state, id) { + state.relationshipLoadedIds = state.relationshipLoadedIds.filter(i => i !== id) + }, addExcludedNode(state, id) { state.excludedNodesIds.push(id) }, @@ -109,7 +120,7 @@ const store = createStore({ fetchInfoForPerson({ dispatch }, person) { dispatch('fetchHouseholdForPerson', person) dispatch('fetchCoursesByPerson', person) - //dispatch('fetchRelationship', person) + dispatch('fetchRelationshipByPerson', person) }, /** @@ -204,23 +215,76 @@ const store = createStore({ arrows: 'to', color: 'orange', font: { color: 'darkorange' }, - label: 'concerné', + label: visMessages.fr.visgraph.concerned, }) }) }, /** - * Fetch Relationship + * 8) Fetch Relationship + * @param Person person */ - fetchRelationship({ commit, getters }, person) { - console.log('fetchRelationship', person) - getRelationshipByPerson(person) - .then(relationship => new Promise(resolve => { - console.log('getRelationshipByPerson', relationship) - commit('addRelationship', relationship) + fetchRelationshipByPerson({ dispatch }, person) { + //console.log('fetchRelationshipByPerson', person) + getRelationshipsByPerson(person) + .then(relationships => new Promise(resolve => { + console.log('fetch relationships', relationships.length) + dispatch('addRelationship', relationships) resolve() })) + }, + + /** + * 9) Add each distinct relationship + * @param array relationships + */ + addRelationship({ commit, getters, dispatch }, relationships) { + relationships.forEach(relationship => { + console.log(' isRelationshipLoaded ?', getters.isRelationshipLoaded(relationship.id)) + if (! getters.isRelationshipLoaded(relationship.id)) { + //console.log('relationship', relationship.id) + commit('markRelationshipLoaded', relationship.id) + commit('addRelationship', relationship) + dispatch('addLinkFromRelationship', relationship) + } + }) + }, + + /** + * 10) Add an edge for each relationship (person -> person) + * @param Relationship relationship + */ + addLinkFromRelationship({ commit }, r) { + + console.log( + '-> addLink from person', r.fromPerson.id, 'to person', r.toPerson.id, + //'reverse', r.reverse, + //'relation', r.relation.title.fr, r.relation.reverseTitle.fr + ) + + commit('addLink', { + from: `person_${r.fromPerson.id}`, + to: `person_${r.toPerson.id}`, + id: 'r' + r.id + '_p' + r.fromPerson.id + '_p' + r.toPerson.id, + arrows: 'from', + color: 'lightblue', dashes: true, + font: { color: 'lightblue' }, + label: getRelationshipLabel(r, false), + }) + + /* + // add reverse relation + commit('addLink', { + from: `person_${r.toPerson.id}`, + to: `person_${r.fromPerson.id}`, + id: 'rr' + r.id + '_p' + r.fromPerson.id + '_p' + r.toPerson.id, + arrows: 'from', + color: 'lightblue', dashes: true, + font: { color: 'lightblue' }, + label: getRelationshipLabel(r, true), + }) + */ }, } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 8774501a0..3ed6a7e7a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -143,6 +143,12 @@ const adapt2vis = (entity) => { entity.label = `${visMessages.fr.visgraph.Course} n° ${entity.id}` entity.id = `accompanying_period_${entity.id}` break + case 'relationship': + entity._id = entity.id + entity.id = `relationship_${entity.id}` + + // sera utilisé pour les links : + //entity.id = 'r' + entity._id + '_p' + entity.fromPerson.id + '_p' + entity.toPerson.id } return entity } @@ -176,9 +182,18 @@ const getHouseholdWidth = (member) => { } } +/** + * Return label edge + * @param relationship + * @returns string + */ +const getRelationshipLabel = (relationship, reverse) => { + return (!reverse) ? relationship.relation.title.fr : relationship.relation.reverseTitle.fr +} export { adapt2vis, getHouseholdLabel, - getHouseholdWidth + getHouseholdWidth, + getRelationshipLabel } From 317ba0a095ab9c4ce86b21b99de0de4519311ab7 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Thu, 28 Oct 2021 12:11:51 +0200 Subject: [PATCH 029/135] vue_visgraph: store missing persons from courses, household and relationship --- .../Resources/public/vuejs/VisGraph/App.vue | 10 +-- .../Resources/public/vuejs/VisGraph/store.js | 83 +++++++++++-------- .../public/vuejs/VisGraph/vis-network.js | 8 +- 3 files changed, 57 insertions(+), 44 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 1804460f7..74409c7f1 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -36,13 +36,9 @@ export default { }, computed: { ...mapGetters(['nodes', 'edges']), - ...mapState(['households', 'courses', 'excludedNodesIds' - //'persons', - //'links, - //'relationships', - //'householdLoadingIds', - //'courseLoadedIds', - //'relationshipLoadedIds', + ...mapState(['households', 'courses', 'excludedNodesIds', + // not used + 'persons', 'links', 'relationships', 'personLoadedIds', 'householdLoadingIds', 'courseLoadedIds', 'relationshipLoadedIds', ]), visgraph_data() { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index da13d9bd3..c18323684 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -13,6 +13,7 @@ const store = createStore({ courses: [], relationships: [], links: [], + personLoadedIds: [], householdLoadingIds: [], courseLoadedIds: [], relationshipLoadedIds: [], @@ -41,9 +42,6 @@ const store = createStore({ state.links.forEach(l => { edges.push(l) }) - //state.relationships.forEach(r => { - // edges.push(r) - //}) return edges }, isHouseholdLoading: (state) => (household_id) => { @@ -54,6 +52,9 @@ const store = createStore({ }, isRelationshipLoaded: (state) => (relationship_id) => { return state.relationshipLoadedIds.includes(relationship_id) + }, + isPersonLoaded: (state) => (person_id) => { + return state.personLoadedIds.includes(person_id) } }, mutations: { @@ -77,6 +78,12 @@ const store = createStore({ console.log('+ addLink from', link.from, 'to', link.to) state.links.push(link) }, + markPersonLoaded(state, id) { + state.personLoadedIds.push(id) + }, + unmarkPersonLoaded(state, id) { + state.personLoadedIds = state.personLoadedIds.filter(i => i !== id) + }, markHouseholdLoading(state, id) { console.log('..loading household', id) state.householdLoadingIds.push(id) @@ -108,7 +115,9 @@ const store = createStore({ * 1) Add a person in state * @param Person person */ + addPerson({ commit, dispatch }, person) { + commit('markPersonLoaded', person.id) commit('addPerson', person) dispatch('fetchInfoForPerson', person) }, @@ -149,7 +158,7 @@ const store = createStore({ * 4) Add an edge for each household member (household -> person) * @param Household household */ - addLinkFromPersonsToHousehold({ commit }, household) { + addLinkFromPersonsToHousehold({ commit, getters, dispatch }, household) { const currentMembers = household.members.filter(v => household.current_members_id.includes(v.id)) currentMembers.forEach(m => { //console.log('-> addLink from person', m.person.id, 'to household', m.person.current_household_id) @@ -163,30 +172,32 @@ const store = createStore({ label: getHouseholdLabel(m), width: getHouseholdWidth(m), }) + if (!getters.isPersonLoaded(m.person.id)) { + console.log(' person is not loaded', m.person.id) + dispatch('addMissingPerson', m.person) + } }) - }, /** * 5) Fetch AccompanyingCourses for the person * @param Person person */ - fetchCoursesByPerson({ dispatch }, person) { + fetchCoursesByPerson({ commit, dispatch }, person) { //console.log('fetchCoursesByPerson', person) getCoursesByPerson(person) .then(courses => new Promise(resolve => { console.log('fetch courses', courses.length) - dispatch('addCourse', courses) + dispatch('addCourses', courses) resolve() })) - }, /** * 6) Add each distinct course * @param array courses */ - addCourse({ commit, getters, dispatch }, courses) { + addCourses({ commit, getters, dispatch }, courses) { //console.log('addCourse', courses) let currentCourses = courses.filter(c => c.closingDate === null) currentCourses.forEach(course => { @@ -204,7 +215,7 @@ const store = createStore({ * 7) Add an edge for each course participation (course <- person) * @param AccompanyingCourse course */ - addLinkFromPersonsToCourse({ commit }, course) { + addLinkFromPersonsToCourse({ commit, getters, dispatch }, course) { let currentParticipations = course.participations.filter(p => p.endDate === null) console.log(' participations', currentParticipations.length) currentParticipations.forEach(p => { @@ -217,6 +228,10 @@ const store = createStore({ font: { color: 'darkorange' }, label: visMessages.fr.visgraph.concerned, }) + if (!getters.isPersonLoaded(p.person.id)) { + console.log(' person is not loaded', p.person.id) + dispatch('addMissingPerson', p.person) + } }) }, @@ -229,7 +244,7 @@ const store = createStore({ getRelationshipsByPerson(person) .then(relationships => new Promise(resolve => { console.log('fetch relationships', relationships.length) - dispatch('addRelationship', relationships) + dispatch('addRelationships', relationships) resolve() })) }, @@ -239,7 +254,7 @@ const store = createStore({ * 9) Add each distinct relationship * @param array relationships */ - addRelationship({ commit, getters, dispatch }, relationships) { + addRelationships({ commit, getters, dispatch }, relationships) { relationships.forEach(relationship => { console.log(' isRelationshipLoaded ?', getters.isRelationshipLoaded(relationship.id)) if (! getters.isRelationshipLoaded(relationship.id)) { @@ -253,40 +268,36 @@ const store = createStore({ /** * 10) Add an edge for each relationship (person -> person) - * @param Relationship relationship + * @param Relationship r */ - addLinkFromRelationship({ commit }, r) { - - console.log( - '-> addLink from person', r.fromPerson.id, 'to person', r.toPerson.id, - //'reverse', r.reverse, - //'relation', r.relation.title.fr, r.relation.reverseTitle.fr - ) - + addLinkFromRelationship({ commit, getters, dispatch }, r) { + //console.log('-> addLink from person', r.fromPerson.id, 'to person', r.toPerson.id) commit('addLink', { from: `person_${r.fromPerson.id}`, to: `person_${r.toPerson.id}`, id: 'r' + r.id + '_p' + r.fromPerson.id + '_p' + r.toPerson.id, - arrows: 'from', + arrows: 'to', color: 'lightblue', dashes: true, - font: { color: 'lightblue' }, + font: { color: '#33839d' }, label: getRelationshipLabel(r, false), }) - - /* - // add reverse relation - commit('addLink', { - from: `person_${r.toPerson.id}`, - to: `person_${r.fromPerson.id}`, - id: 'rr' + r.id + '_p' + r.fromPerson.id + '_p' + r.toPerson.id, - arrows: 'from', - color: 'lightblue', dashes: true, - font: { color: 'lightblue' }, - label: getRelationshipLabel(r, true), - }) - */ + for (let person of [r.fromPerson, r.toPerson]) { + if (!getters.isPersonLoaded(person.id)) { + console.log(' person is not loaded', person.id) + dispatch('addMissingPerson', person) + } + } }, + /** + * Fetch missing person + * @param Person person + */ + addMissingPerson({ commit, getters, dispatch }, person) { + //console.log('addMissingPerson', person) + commit('markPersonLoaded', person.id) + commit('addPerson', person) + }, } }) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 3ed6a7e7a..f1e9ab05e 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -167,7 +167,11 @@ const getHouseholdLabel = (member) => { /** * Return edge width for member (depends of position in household) * @param member - * @returns string + * @returns integer (width) + * + * TODO + * to use: holder, shareHousehold + * not use: ordering, position (-> null) */ const getHouseholdWidth = (member) => { switch (member.position.ordering) { @@ -179,6 +183,8 @@ const getHouseholdWidth = (member) => { case 2: //children case 3: //children out of household return 1 + default: + throw 'Ordering not supported' } } From 998295dc5fb5004ca80e13581cefc10b87d49735 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Thu, 28 Oct 2021 15:47:40 +0200 Subject: [PATCH 030/135] vue_visgraph improve (physics, corrections) --- .../Resources/public/vuejs/VisGraph/App.vue | 1 + .../Resources/public/vuejs/VisGraph/store.js | 2 +- .../public/vuejs/VisGraph/vis-network.js | 79 +++++++++++++++++-- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 74409c7f1..fd45dd750 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -96,6 +96,7 @@ export default { }, toggleLayer(value) { //console.log('toggleLayer') + this.forceUpdateComponent() let id = value.target.value if (this.checkedLayers.includes(id)) { this.removeLayer(id) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index c18323684..394fd55e6 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -223,7 +223,7 @@ const store = createStore({ from: `${p.person.type}_${p.person.id}`, to: `${course.id}`, id: `p${p.person.id}-c`+ course.id.split('_')[2], - arrows: 'to', + arrows: 'from', color: 'orange', font: { color: 'darkorange' }, label: visMessages.fr.visgraph.concerned, diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index f1e9ab05e..eeddb7da4 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -20,6 +20,55 @@ window.options = { showButton: true }, */ + physics:{ + enabled: true, + barnesHut: { + theta: 0.5, + gravitationalConstant: -2000, + centralGravity: 0.1, //// 0.3 + springLength: 200, //// 95 + springConstant: 0.04, + damping: 0.09, + avoidOverlap: 0 + }, + forceAtlas2Based: { + theta: 0.5, + gravitationalConstant: -50, + centralGravity: 0.01, + springConstant: 0.08, + springLength: 100, + damping: 0.4, + avoidOverlap: 0 + }, + repulsion: { + centralGravity: 0.2, + springLength: 200, + springConstant: 0.05, + nodeDistance: 100, + damping: 0.09 + }, + hierarchicalRepulsion: { + centralGravity: 0.0, + springLength: 100, + springConstant: 0.01, + nodeDistance: 120, + damping: 0.09, + avoidOverlap: 0 + }, + maxVelocity: 50, + minVelocity: 0.1, + solver: 'barnesHut', + stabilization: { + enabled: true, + iterations: 1000, + updateInterval: 100, + onlyDynamicEdges: false, + fit: true + }, + timestep: 0.5, + adaptiveTimestep: true, + wind: { x: 0, y: 0 } + }, manipulation: { enabled: true, initiallyActive: true, @@ -66,12 +115,12 @@ window.options = { } }, nodes: { - physics: true, + //physics: true, borderWidth: 1, borderWidthSelected: 3, }, edges: { - physics: true, + //physics: true, font: { color: '#b0b0b0', size: 9, @@ -130,7 +179,7 @@ const adapt2vis = (entity) => { switch (entity.type) { case 'person': entity._id = entity.id - entity.label = entity.text + entity.label = `${entity.text}\n` + getGender(entity.gender_numeric) +' - '+ getAge(entity.birthdate) entity.id = `person_${entity.id}` break case 'household': @@ -146,13 +195,31 @@ const adapt2vis = (entity) => { case 'relationship': entity._id = entity.id entity.id = `relationship_${entity.id}` - - // sera utilisé pour les links : - //entity.id = 'r' + entity._id + '_p' + entity.fromPerson.id + '_p' + entity.toPerson.id } return entity } +const getGender = (gender) => { + switch (gender) { + case 0: + return 'N' + case 1: + return 'M' + case 2: + return 'F' + default: + throw 'gender undefined' + } +} +const getAge = (birthdate) => { + if (null === birthdate) { + return null + } + const birthday = new Date(birthdate.datetime) + const now = new Date() + return (now.getFullYear() - birthday.getFullYear()) + ' ans' +} + /** * Return member position in household * @param member From 3a7af94058e0bd6d9c7c42d0651a9656abd1b5a0 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 29 Oct 2021 09:29:27 +0200 Subject: [PATCH 031/135] GET and POST both working. --- .../AccompanyingCourseApiController.php | 2 - .../DataFixtures/ORM/LoadRelationships.php | 22 +++++++ .../ChillPersonExtension.php | 4 -- .../Entity/Relationships/Relation.php | 16 +++-- .../Entity/Relationships/Relationship.php | 58 +++++++++++-------- 5 files changed, 68 insertions(+), 34 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index 891a0f461..132dc1172 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -32,8 +32,6 @@ class AccompanyingCourseApiController extends ApiController private Registry $registry; - private AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository; - public function __construct( EventDispatcherInterface $eventDispatcher, ValidatorInterface $validator, diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php index e69de29bb..cfabde912 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php @@ -0,0 +1,22 @@ + [ '_entity' => [ 'methods' => [ - Request::METHOD_GET => true, - Request::METHOD_HEAD => true, Request::METHOD_POST => true, Request::METHOD_PATCH => true ], 'roles' => [ - Request::METHOD_GET => 'ROLE_USER', - Request::METHOD_HEAD => 'ROLE_USER', Request::METHOD_POST => 'ROLE_USER', Request::METHOD_PATCH => 'ROLE_USER' ] diff --git a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php index 7cd000dd5..a0fefc877 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php +++ b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php @@ -3,10 +3,16 @@ namespace Chill\PersonBundle\Entity\Relationships; use Doctrine\ORM\Mapping as ORM; +use Doctrine\ORM\Mapping\DiscriminatorColumn; +use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Symfony\Component\Serializer\Annotation as Serializer; /** * @ORM\Entity() * @ORM\Table(name="chill_person_relations") + * @DiscriminatorMap(typeProperty="type", mapping={ + * "relation"=Relation::class + * }) */ class Relation { @@ -15,17 +21,19 @@ class Relation * @ORM\GeneratedValue * @ORM\Column(type="integer") */ - private $id; + private ?int $id = null; /** * @ORM\Column(type="json", nullable=true) + * @Serializer\Groups({"read"}) */ - private $title = []; + private array $title = []; /** * @ORM\Column(type="json", nullable=true) + * @Serializer\Groups({"read"}) */ - private $reverseTitle = []; + private array $reverseTitle = []; public function getId(): ?int { @@ -55,4 +63,4 @@ class Relation return $this; } -} +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php index e748f9797..54be21140 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php +++ b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php @@ -2,50 +2,60 @@ namespace Chill\PersonBundle\Entity\Relationships; +use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; +use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Relationships\Relation; +use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Doctrine\ORM\Mapping\DiscriminatorColumn; +use Symfony\Component\Serializer\Annotation as Serializer; /** * @ORM\Entity() * @ORM\Table(name="chill_person_relationships") + * @DiscriminatorColumn(name="relation_id", type="integer") + * @DiscriminatorMap(typeProperty="type", mapping={ + * "relationship"=Relationship::class + * }) + * */ -class Relationship +class Relationship implements TrackCreationInterface, TrackUpdateInterface { /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") - * @Groups({"read"}) + * @Serializer\Groups({"read"}) */ - private $id; + private ?int $id = null; /** * @ORM\ManyToOne(targetEntity=Person::class) * @ORM\JoinColumn(nullable=false) - * @Assert\NotBlank() - * @Groups({"read", "write"}) + * @Assert\NotNull() + * @Serializer\Groups({"read", "write"}) */ - private $fromPerson; + private ?Person $fromPerson = null; /** * @ORM\ManyToOne(targetEntity=Person::class) * @ORM\JoinColumn(nullable=false) - * @Assert\NotBlank() - * @Groups({"read", "write"}) + * @Assert\NotNull() + * @Serializer\Groups({"read", "write"}) */ - private $toPerson; + private ?Person $toPerson = null; /** * @ORM\ManyToOne(targetEntity=Relation::class) * @ORM\JoinColumn(nullable=false, name="relation_id", referencedColumnName="id") - * @Assert\NotBlank() - * @Groups({"read", "write"}) + * @Assert\NotNull() + * @Serializer\Groups({"read", "write"}) */ - private $relation; + private ?Relation $relation = null; /** * @ORM\Column(type="boolean") @@ -53,30 +63,30 @@ class Relationship * type="bool", * message="This must be of type boolean" * ) - * @Groups({"read"}) + * @Serializer\Groups({"read", "write"}) */ - private $reverse; + private bool $reverse; /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(nullable=false) */ - private $createdBy; + private ?User $createdBy = null; /** * @ORM\Column(type="datetime_immutable") */ - private $createdAt; + private ?DateTimeImmutable $createdAt = null; /** * @ORM\ManyToOne(targetEntity=User::class) */ - private $updatedBy; + private ?User $updatedBy = null; /** * @ORM\Column(type="datetime_immutable", nullable=true) */ - private $updatedAt; + private ?DateTimeImmutable $updatedAt = null; public function getId(): ?int @@ -125,9 +135,9 @@ class Relationship return $this->createdBy; } - public function setCreatedBy(?User $createdBy): self + public function setCreatedBy(?User $user): self { - $this->createdBy = $createdBy; + $this->createdBy = $user; return $this; } @@ -137,7 +147,7 @@ class Relationship return $this->createdAt; } - public function setCreatedAt(\DateTimeImmutable $createdAt): self + public function setCreatedAt(\DateTimeInterface $createdAt): self { $this->createdAt = $createdAt; @@ -161,7 +171,7 @@ class Relationship return $this->updatedAt; } - public function setUpdatedAt(?\DateTimeImmutable $updatedAt): self + public function setUpdatedAt(?\DateTimeInterface $updatedAt): self { $this->updatedAt = $updatedAt; @@ -179,4 +189,4 @@ class Relationship return $this; } -} +} \ No newline at end of file From 76d6a9b4dfe2943cf5ff3bf6301edeba7b18e187 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 29 Oct 2021 10:01:14 +0200 Subject: [PATCH 032/135] vue_visgraph: makeFetch (api), add validation exception --- .../Resources/public/vuejs/VisGraph/api.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js index f595daa34..5533bd6ff 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -20,7 +20,9 @@ const makeFetch = (method, url, body) => { } if (response.status === 422) { - return response.json(); + return response.json().then(violations => { + throw ValidationException(violations) + }); } throw { @@ -33,13 +35,22 @@ const makeFetch = (method, url, body) => { }); } +/** + * @param violations + * @constructor + */ +const ValidationException = (violations) => { + this.violations = violations + this.name = 'ValidationException' +} + /** * @function getFetch * @param url * @returns {Promise} */ const getFetch = (url) => { - return makeFetch('GET', url, null); + return makeFetch('GET', url, null) } /** @@ -49,7 +60,7 @@ const getFetch = (url) => { * @returns {Promise} */ const postFetch = (url, body) => { - return makeFetch('POST', url, body); + return makeFetch('POST', url, body) } /** @@ -59,7 +70,7 @@ const postFetch = (url, body) => { * @returns {Promise} */ const patchFetch = (url, body) => { - return makeFetch('PATCH', url, body); + return makeFetch('PATCH', url, body) } From 1155555bb3ec1c375ef683f13ea355772d305214 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 29 Oct 2021 10:37:51 +0200 Subject: [PATCH 033/135] backend: adapt deprecated getGenderNumeric --- src/Bundle/ChillPersonBundle/Entity/Person.php | 14 ++++++++++---- .../Serializer/Normalizer/PersonNormalizer.php | 1 - 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 9aaad8c04..01a524beb 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -901,13 +901,19 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI * return gender as a Numeric form. * This is used for translations * @return int + * @deprecated Keep for legacy. Used in Chill 1.5 for feminize before icu translations */ public function getGenderNumeric() { - if ($this->getGender() == self::FEMALE_GENDER) { - return 1; - } else { - return 0; + switch ($this->getGender()) { + case self::FEMALE_GENDER: + return 1; + case self::MALE_GENDER: + return 0; + case self::BOTH_GENDER: + return 2; + default: + return -1; } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php index 2b82780c2..380112a12 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php @@ -79,7 +79,6 @@ class PersonNormalizer implements 'mobilenumber' => $person->getMobilenumber(), 'altNames' => $this->normalizeAltNames($person->getAltNames()), 'gender' => $person->getGender(), - 'gender_numeric' => $person->getGenderNumeric(), 'current_household_address' => $this->normalizer->normalize($person->getCurrentHouseholdAddress()), 'current_household_id' => $household ? $this->normalizer->normalize($household->getId()) : null, ]; From 50fbc7fd158b9c038953433b338cdc5c3d70b8b6 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 29 Oct 2021 11:30:01 +0200 Subject: [PATCH 034/135] processing of review. still ACL left to do --- .../Controller/RelationshipApiController.php | 2 +- .../Entity/Relationships/Relation.php | 18 ++++++ .../Relationships/RelationRepository.php | 62 ++++++++----------- .../Relationships/RelationshipRepository.php | 50 ++++++++++----- .../Normalizer/RelationshipNormalizer.php | 38 ------------ .../migrations/Version20211029075117.php | 29 +++++++++ 6 files changed, 110 insertions(+), 89 deletions(-) delete mode 100644 src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php diff --git a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php index 765d13d25..69809d6ee 100644 --- a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php @@ -25,7 +25,7 @@ class RelationshipApiController extends ApiController /** * @Route("/api/1.0/relation/relationship/by-person/{person_id}.json", - * name="chill_relation_relationship_by_person") + * name="chill_relationship_by_person") * * @ParamConverter("person", options={"id" = "person_id"}) */ diff --git a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php index a0fefc877..7628863fe 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php +++ b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php @@ -35,6 +35,12 @@ class Relation */ private array $reverseTitle = []; + /** + * @ORM\Column(type="boolean", nullable=true) + * @Serializer\Groups({"read"}) + */ + private bool $isActive = true; + public function getId(): ?int { return $this->id; @@ -63,4 +69,16 @@ class Relation return $this; } + + public function getIsActive(): bool + { + return $this->isActive; + } + + public function setIsActive(?bool $isActive): self + { + $this->isActive = $isActive; + + return $this; + } } \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php index 8b5fbb743..b735138f4 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php @@ -2,49 +2,41 @@ namespace Chill\PersonBundle\Repository\Relationships; -use App\Entity\Relation; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -use Doctrine\Persistence\ManagerRegistry; +use Chill\PersonBundle\Entity\Relationships\Relation; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; +use Doctrine\Persistence\ObjectRepository; -/** - * @method Relation|null find($id, $lockMode = null, $lockVersion = null) - * @method Relation|null findOneBy(array $criteria, array $orderBy = null) - * @method Relation[] findAll() - * @method Relation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -class RelationRepository extends ServiceEntityRepository +class RelationRepository implements ObjectRepository { - public function __construct(ManagerRegistry $registry) + private EntityRepository $repository; + + public function __construct(EntityManagerInterface $entityManager) { - parent::__construct($registry, Relation::class); + $this->repository = $entityManager->getRepository(Relation::class); + } + public function find($id): ?Relation + { + return $this->repository->find($id); } - // /** - // * @return Relation[] Returns an array of Relation objects - // */ - /* - public function findByExampleField($value) + public function findAll(): array { - return $this->createQueryBuilder('r') - ->andWhere('r.exampleField = :val') - ->setParameter('val', $value) - ->orderBy('r.id', 'ASC') - ->setMaxResults(10) - ->getQuery() - ->getResult() - ; + return $this->repository->findAll(); } - */ - /* - public function findOneBySomeField($value): ?Relation + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { - return $this->createQueryBuilder('r') - ->andWhere('r.exampleField = :val') - ->setParameter('val', $value) - ->getQuery() - ->getOneOrNullResult() - ; + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?Relation + { + return $this->findOneBy($criteria); + } + + public function getClassName(): string + { + return MaritalStatus::class; } - */ } diff --git a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php index 00546e424..3f105537a 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php @@ -3,30 +3,50 @@ namespace Chill\PersonBundle\Repository\Relationships; use Chill\PersonBundle\Entity\Relationships\Relationship; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\ObjectRepository; -/** - * @method Relationship|null find($id, $lockMode = null, $lockVersion = null) - * @method Relationship|null findOneBy(array $criteria, array $orderBy = null) - * @method Relationship[] findAll() - * @method Relationship[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -class RelationshipRepository extends ServiceEntityRepository +class RelationshipRepository implements ObjectRepository { - public function __construct(ManagerRegistry $registry) + + private EntityRepository $repository; + + public function __construct(EntityManagerInterface $em) { - parent::__construct($registry, Relationship::class); + $this->repository = $em->getRepository(Relationship::class); } - // /** - // * @return Relationship[] Returns an array of Relationship objects linked to certain person. - // */ + public function find($id): ?Relationship + { + return $this->repository->find($id); + } + + public function findAll(): array + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?Relationship + { + return $this->findOneBy($criteria); + } + + public function getClassName(): string + { + return MaritalStatus::class; + } - public function findByPerson($personId) + public function findByPerson($personId): array { // return all relationships of which person is part? or only where person is the fromPerson? - return $this->createQueryBuilder('r') + return $this->repository->createQueryBuilder('r') ->select('r, t') // entity Relationship ->join('r.relation', 't') ->where('r.fromPerson = :val') diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php deleted file mode 100644 index e410dd90b..000000000 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/RelationshipNormalizer.php +++ /dev/null @@ -1,38 +0,0 @@ - 'relationship', - 'id' => $this->normalizer->normalize($relationship->getId()), - 'fromPerson' => $this->normalizer->normalize($relationship->getFromPerson()), - 'toPerson' => $this->normalizer->normalize($relationship->getToPerson()), - 'relation' => $this->normalizer->normalize($relationship->getRelation()), - 'reverse' => $relationship->getReverse() - ]; - } - - public function supportsNormalization($data, ?string $format = null) - { - return $data instanceof Relationship; - } - -} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php b/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php new file mode 100644 index 000000000..9c3d5131e --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php @@ -0,0 +1,29 @@ +addSql('ALTER TABLE chill_person_relations ADD isActive BOOLEAN NOT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_relations DROP isActive'); + } +} From 039c74a1e435426a4f8840ee943aa4d65b78ff96 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 29 Oct 2021 13:20:56 +0200 Subject: [PATCH 035/135] route annotation removed --- .../Controller/AccompanyingCourseApiController.php | 7 ------- .../Controller/RelationshipApiController.php | 5 ----- 2 files changed, 12 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index 132dc1172..72ca7aa5b 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -21,7 +21,6 @@ use Chill\MainBundle\Entity\Scope; use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Symfony\Component\Workflow\Registry; -use Symfony\Component\Routing\Annotation\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; class AccompanyingCourseApiController extends ApiController @@ -195,12 +194,6 @@ $workflow = $this->registry->get($accompanyingPeriod); } /** - * @Route("/api/1.0/person/accompanying-course/by-person/{person_id}.{_format}", - * name="chill_person_accompanyingperiod_by_person", - * requirements={ - * "_format"="json" - * }) - * * @ParamConverter("person", options={"id" = "person_id"}) */ public function getAccompanyingPeriodsByPerson(Person $person){ diff --git a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php index 69809d6ee..bf4452942 100644 --- a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php @@ -8,9 +8,7 @@ use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Repository\Relationships\RelationshipRepository; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\Validator\ValidatorInterface; -use Symfony\Component\Routing\Annotation\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; -use Symfony\Component\HttpFoundation\Request; class RelationshipApiController extends ApiController { @@ -24,9 +22,6 @@ class RelationshipApiController extends ApiController } /** - * @Route("/api/1.0/relation/relationship/by-person/{person_id}.json", - * name="chill_relationship_by_person") - * * @ParamConverter("person", options={"id" = "person_id"}) */ public function getRelationshipsByPerson(Person $person) From 1c60a5b51e33a3a8159886c81108d0835d94352a Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 29 Oct 2021 12:06:59 +0200 Subject: [PATCH 036/135] vue_visgraph: improve graph --- .../Resources/public/vuejs/VisGraph/i18n.js | 5 ++ .../Resources/public/vuejs/VisGraph/store.js | 13 ++-- .../public/vuejs/VisGraph/vis-network.js | 74 +++++++++++-------- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index 9ca273f72..0e1cf4686 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -6,6 +6,11 @@ const visMessages = { Holder: 'Titulaire', Legend: 'Calques', concerned: 'concerné', + both: 'neutre, non binaire', + woman: 'féminin', + man: 'masculin', + years: 'ans' + }, edit: 'Éditer', del: 'Supprimer', diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 394fd55e6..b336da45a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -1,6 +1,6 @@ import { createStore } from 'vuex' import { getHouseholdByPerson, getCoursesByPerson, getRelationshipsByPerson } from './api' -import { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel } from './vis-network' +import { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, getRelationshipTitle } from './vis-network' import { visMessages } from './i18n' const debug = process.env.NODE_ENV !== 'production' @@ -115,7 +115,6 @@ const store = createStore({ * 1) Add a person in state * @param Person person */ - addPerson({ commit, dispatch }, person) { commit('markPersonLoaded', person.id) commit('addPerson', person) @@ -127,7 +126,9 @@ const store = createStore({ * @param Person person */ fetchInfoForPerson({ dispatch }, person) { - dispatch('fetchHouseholdForPerson', person) + if (null !== person.current_household_id) { + dispatch('fetchHouseholdForPerson', person) + } dispatch('fetchCoursesByPerson', person) dispatch('fetchRelationshipByPerson', person) }, @@ -226,7 +227,7 @@ const store = createStore({ arrows: 'from', color: 'orange', font: { color: 'darkorange' }, - label: visMessages.fr.visgraph.concerned, + //label: visMessages.fr.visgraph.concerned, }) if (!getters.isPersonLoaded(p.person.id)) { console.log(' person is not loaded', p.person.id) @@ -277,9 +278,11 @@ const store = createStore({ to: `person_${r.toPerson.id}`, id: 'r' + r.id + '_p' + r.fromPerson.id + '_p' + r.toPerson.id, arrows: 'to', - color: 'lightblue', dashes: true, + color: 'lightblue', font: { color: '#33839d' }, + dashes: true, label: getRelationshipLabel(r, false), + title: getRelationshipTitle(r), }) for (let person of [r.fromPerson, r.toPerson]) { if (!getters.isPersonLoaded(person.id)) { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index eeddb7da4..f8001f441 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -128,7 +128,7 @@ window.options = { background: 'none', strokeWidth: 2, // px strokeColor: '#ffffff', - align: 'horizontal', + align: 'middle', multi: false, vadjust: 0, }, @@ -154,15 +154,9 @@ window.options = { } }, household: { - /* - shape: 'dot', - */ color: 'pink' }, accompanying_period: { - /* - shape: 'triangle', - */ color: 'orange', }, } @@ -179,7 +173,8 @@ const adapt2vis = (entity) => { switch (entity.type) { case 'person': entity._id = entity.id - entity.label = `${entity.text}\n` + getGender(entity.gender_numeric) +' - '+ getAge(entity.birthdate) + entity.label = `${entity.text}\n` + getGender(entity.gender) +' - '+ getAge(entity.birthdate) + //entity.title = `${entity.text}` entity.id = `person_${entity.id}` break case 'household': @@ -195,29 +190,42 @@ const adapt2vis = (entity) => { case 'relationship': entity._id = entity.id entity.id = `relationship_${entity.id}` + break + default: + throw 'entity undefined' } return entity } +/** + * @param gender + * @returns {string} + */ const getGender = (gender) => { switch (gender) { - case 0: - return 'N' - case 1: - return 'M' - case 2: - return 'F' + case 'both': + return visMessages.fr.visgraph.both + case 'woman': + return visMessages.fr.visgraph.woman + case 'man': + return visMessages.fr.visgraph.man default: throw 'gender undefined' } } + +/** + * TODO Repeat getAge() in PersonRenderBox.vue + * @param birthdate + * @returns {string|null} + */ const getAge = (birthdate) => { if (null === birthdate) { return null } const birthday = new Date(birthdate.datetime) const now = new Date() - return (now.getFullYear() - birthday.getFullYear()) + ' ans' + return (now.getFullYear() - birthday.getFullYear()) + ' '+ visMessages.fr.visgraph.years } /** @@ -235,24 +243,15 @@ const getHouseholdLabel = (member) => { * Return edge width for member (depends of position in household) * @param member * @returns integer (width) - * - * TODO - * to use: holder, shareHousehold - * not use: ordering, position (-> null) */ const getHouseholdWidth = (member) => { - switch (member.position.ordering) { - case 1: //adult - if (member.holder) { - return 6 - } - return 3 - case 2: //children - case 3: //children out of household - return 1 - default: - throw 'Ordering not supported' + if (member.holder) { + return 5 } + if (member.shareHousehold) { + return 2 + } + return 1 } /** @@ -264,9 +263,22 @@ const getRelationshipLabel = (relationship, reverse) => { return (!reverse) ? relationship.relation.title.fr : relationship.relation.reverseTitle.fr } +/** + * Return title edge + * @param relationship + * @returns string + */ +const getRelationshipTitle = (relationship) => { + return relationship.relation.title.fr + ': ' + + relationship.fromPerson.text + '\n' + + relationship.relation.reverseTitle.fr + ': ' + + relationship.toPerson.text +} + export { adapt2vis, getHouseholdLabel, getHouseholdWidth, - getRelationshipLabel + getRelationshipLabel, + getRelationshipTitle } From a9d3d2027b84bfa9c95e19e93925e2910cb4ab3e Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 29 Oct 2021 15:32:12 +0200 Subject: [PATCH 037/135] minor --- .../Resources/public/vuejs/VisGraph/store.js | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index b336da45a..86b21d3de 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -1,7 +1,6 @@ import { createStore } from 'vuex' import { getHouseholdByPerson, getCoursesByPerson, getRelationshipsByPerson } from './api' import { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, getRelationshipTitle } from './vis-network' -import { visMessages } from './i18n' const debug = process.env.NODE_ENV !== 'production' @@ -113,7 +112,8 @@ const store = createStore({ actions: { /** * 1) Add a person in state - * @param Person person + * @param object + * @param person */ addPerson({ commit, dispatch }, person) { commit('markPersonLoaded', person.id) @@ -123,7 +123,8 @@ const store = createStore({ /** * 2) Fetch infos for this person (hub) - * @param Person person + * @param object + * @param person */ fetchInfoForPerson({ dispatch }, person) { if (null !== person.current_household_id) { @@ -136,7 +137,8 @@ const store = createStore({ /** * 3) Fetch person current household (if it is not already loading) * check first isHouseholdLoading to fetch household once - * @param Person person + * @param object + * @param person */ fetchHouseholdForPerson({ commit, getters, dispatch }, person) { console.log(' isHouseholdLoading ?', getters.isHouseholdLoading(person.current_household_id)) @@ -157,7 +159,8 @@ const store = createStore({ /** * 4) Add an edge for each household member (household -> person) - * @param Household household + * @param object + * @param household */ addLinkFromPersonsToHousehold({ commit, getters, dispatch }, household) { const currentMembers = household.members.filter(v => household.current_members_id.includes(v.id)) @@ -182,7 +185,8 @@ const store = createStore({ /** * 5) Fetch AccompanyingCourses for the person - * @param Person person + * @param object + * @param person */ fetchCoursesByPerson({ commit, dispatch }, person) { //console.log('fetchCoursesByPerson', person) @@ -196,7 +200,8 @@ const store = createStore({ /** * 6) Add each distinct course - * @param array courses + * @param object + * @param courses */ addCourses({ commit, getters, dispatch }, courses) { //console.log('addCourse', courses) @@ -214,7 +219,8 @@ const store = createStore({ /** * 7) Add an edge for each course participation (course <- person) - * @param AccompanyingCourse course + * @param object + * @param course */ addLinkFromPersonsToCourse({ commit, getters, dispatch }, course) { let currentParticipations = course.participations.filter(p => p.endDate === null) @@ -227,7 +233,6 @@ const store = createStore({ arrows: 'from', color: 'orange', font: { color: 'darkorange' }, - //label: visMessages.fr.visgraph.concerned, }) if (!getters.isPersonLoaded(p.person.id)) { console.log(' person is not loaded', p.person.id) @@ -238,7 +243,8 @@ const store = createStore({ /** * 8) Fetch Relationship - * @param Person person + * @param object + * @param person */ fetchRelationshipByPerson({ dispatch }, person) { //console.log('fetchRelationshipByPerson', person) @@ -253,7 +259,8 @@ const store = createStore({ /** * 9) Add each distinct relationship - * @param array relationships + * @param object + * @param relationships */ addRelationships({ commit, getters, dispatch }, relationships) { relationships.forEach(relationship => { @@ -269,7 +276,8 @@ const store = createStore({ /** * 10) Add an edge for each relationship (person -> person) - * @param Relationship r + * @param object + * @param r (relationship) */ addLinkFromRelationship({ commit, getters, dispatch }, r) { //console.log('-> addLink from person', r.fromPerson.id, 'to person', r.toPerson.id) @@ -294,7 +302,8 @@ const store = createStore({ /** * Fetch missing person - * @param Person person + * @param object + * @param person */ addMissingPerson({ commit, getters, dispatch }, person) { //console.log('addMissingPerson', person) From e6183f664629f315ef8666ade8796b79c697a53c Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 29 Oct 2021 15:56:57 +0200 Subject: [PATCH 038/135] migration fixed to insert default true value for isActive --- .../ChillPersonBundle/migrations/Version20211029075117.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php b/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php index 9c3d5131e..ef739dcb8 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php @@ -19,7 +19,7 @@ final class Version20211029075117 extends AbstractMigration public function up(Schema $schema): void { - $this->addSql('ALTER TABLE chill_person_relations ADD isActive BOOLEAN NOT NULL'); + $this->addSql('ALTER TABLE chill_person_relations ADD isActive BOOLEAN DEFAULT true NOT NULL'); } public function down(Schema $schema): void From 8eedee5e9106792f58624891c3244fdefcab698e Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 29 Oct 2021 16:54:22 +0200 Subject: [PATCH 039/135] visgraph: default uncheck layers when loading --- .../ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 86b21d3de..a0109c9c8 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -148,6 +148,7 @@ const store = createStore({ .then(household => new Promise(resolve => { //console.log('getHouseholdByPerson', household) commit('addHousehold', household) + commit('addExcludedNode', household.id) dispatch('addLinkFromPersonsToHousehold', household) resolve() }) @@ -212,6 +213,7 @@ const store = createStore({ //console.log('course', course.id) commit('markCourseLoaded', course.id) commit('addCourse', course) + commit('addExcludedNode', course.id) dispatch('addLinkFromPersonsToCourse', course) } }) From 83129553913d030a3298de333a9691192f416fa9 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 29 Oct 2021 17:34:37 +0200 Subject: [PATCH 040/135] visgraph: hide somes persons nodes labels (folded) --- .../Resources/public/vuejs/VisGraph/i18n.js | 4 +- .../Resources/public/vuejs/VisGraph/store.js | 50 +++++++++++-------- .../public/vuejs/VisGraph/vis-network.js | 9 +++- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index 0e1cf4686..5b408e209 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -9,8 +9,8 @@ const visMessages = { both: 'neutre, non binaire', woman: 'féminin', man: 'masculin', - years: 'ans' - + years: 'ans', + click_to_expand: 'cliquez pour étendre', }, edit: 'Éditer', del: 'Supprimer', diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index a0109c9c8..0944667bc 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -59,49 +59,53 @@ const store = createStore({ mutations: { addPerson(state, person) { console.log('+ addPerson', person.id) - state.persons.push(adapt2vis(person)) + state.persons.push(person) }, addHousehold(state, household) { console.log('+ addHousehold', household.id) - state.households.push(adapt2vis(household)) + state.households.push(household) }, addCourse(state, course) { console.log('+ addCourse', course.id) - state.courses.push(adapt2vis(course)) + state.courses.push(course) }, addRelationship(state, relationship) { console.log('+ addRelationship', relationship.id) - state.relationships.push(adapt2vis(relationship)) + state.relationships.push(relationship) }, addLink(state, link) { console.log('+ addLink from', link.from, 'to', link.to) state.links.push(link) }, + + //// id markers markPersonLoaded(state, id) { state.personLoadedIds.push(id) }, - unmarkPersonLoaded(state, id) { - state.personLoadedIds = state.personLoadedIds.filter(i => i !== id) - }, + unmarkPersonLoaded(state, id) { + state.personLoadedIds = state.personLoadedIds.filter(i => i !== id) + }, markHouseholdLoading(state, id) { console.log('..loading household', id) state.householdLoadingIds.push(id) }, - unmarkHouseholdLoading(state, id) { - state.householdLoadingIds = state.householdLoadingIds.filter(i => i !== id) - }, + unmarkHouseholdLoading(state, id) { + state.householdLoadingIds = state.householdLoadingIds.filter(i => i !== id) + }, markCourseLoaded(state, id) { state.courseLoadedIds.push(id) }, - unmarkCourseLoaded(state, id) { - state.courseLoadedIds = state.courseLoadedIds.filter(i => i !== id) - }, + unmarkCourseLoaded(state, id) { + state.courseLoadedIds = state.courseLoadedIds.filter(i => i !== id) + }, markRelationshipLoaded(state, id) { state.relationshipLoadedIds.push(id) }, - unmarkRelationshipLoaded(state, id) { - state.relationshipLoadedIds = state.relationshipLoadedIds.filter(i => i !== id) - }, + unmarkRelationshipLoaded(state, id) { + state.relationshipLoadedIds = state.relationshipLoadedIds.filter(i => i !== id) + }, + + //// excluded addExcludedNode(state, id) { state.excludedNodesIds.push(id) }, @@ -117,7 +121,7 @@ const store = createStore({ */ addPerson({ commit, dispatch }, person) { commit('markPersonLoaded', person.id) - commit('addPerson', person) + commit('addPerson', adapt2vis(person, { folded: false })) dispatch('fetchInfoForPerson', person) }, @@ -147,7 +151,7 @@ const store = createStore({ getHouseholdByPerson(person) .then(household => new Promise(resolve => { //console.log('getHouseholdByPerson', household) - commit('addHousehold', household) + commit('addHousehold', adapt2vis(household)) commit('addExcludedNode', household.id) dispatch('addLinkFromPersonsToHousehold', household) resolve() @@ -212,7 +216,7 @@ const store = createStore({ if (! getters.isCourseLoaded(course.id)) { //console.log('course', course.id) commit('markCourseLoaded', course.id) - commit('addCourse', course) + commit('addCourse', adapt2vis(course)) commit('addExcludedNode', course.id) dispatch('addLinkFromPersonsToCourse', course) } @@ -270,7 +274,7 @@ const store = createStore({ if (! getters.isRelationshipLoaded(relationship.id)) { //console.log('relationship', relationship.id) commit('markRelationshipLoaded', relationship.id) - commit('addRelationship', relationship) + commit('addRelationship', adapt2vis(relationship)) dispatch('addLinkFromRelationship', relationship) } }) @@ -308,9 +312,11 @@ const store = createStore({ * @param person */ addMissingPerson({ commit, getters, dispatch }, person) { - //console.log('addMissingPerson', person) commit('markPersonLoaded', person.id) - commit('addPerson', person) + commit('addPerson', adapt2vis(person, { folded: true })) + + console.log('********* fetch infos for missing', person.id, '******') + //dispatch('fetchInfoForPerson', person) }, } }) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index f8001f441..8cafdda9f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -166,15 +166,20 @@ window.options = { * Adapt entity to graph (id, label) * rename id in _id and add properties needed by vis * @param entity + * @param options * @returns entity */ -const adapt2vis = (entity) => { +const adapt2vis = (entity, options = {}) => { entity.group = entity.type switch (entity.type) { case 'person': entity._id = entity.id entity.label = `${entity.text}\n` + getGender(entity.gender) +' - '+ getAge(entity.birthdate) - //entity.title = `${entity.text}` + if (options.folded) { + entity.title = visMessages.fr.visgraph.click_to_expand + entity._label = entity.label // keep label + entity.label = null + } entity.id = `person_${entity.id}` break case 'household': From 09903c2f52ea8dbd370f6ee1aab8765c1009ee12 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 29 Oct 2021 19:08:52 +0200 Subject: [PATCH 041/135] click node event (wip) --- .../ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index fd45dd750..9ff406e47 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -114,6 +114,10 @@ export default { this.checkedLayers = this.checkedLayers.filter(i => i !== id) this.$store.commit('addExcludedNode', id) }, + clickOnNode(callback) { + console.log('** click on node **') + window.network.on('click', callback) + }, } /* TODO / TO CHECK / TO UNDERSTAND From 851a24625798bd9489a0bd8a9876887d3685218b Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Sat, 30 Oct 2021 00:27:10 +0200 Subject: [PATCH 042/135] visgraph: improve label with basic markdown --- .../Resources/public/vuejs/VisGraph/vis-network.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 8cafdda9f..ecec18c9b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -118,6 +118,9 @@ window.options = { //physics: true, borderWidth: 1, borderWidthSelected: 3, + font: { + multi: 'md' + } }, edges: { //physics: true, @@ -148,7 +151,7 @@ window.options = { border: '#b0b0b0', background: 'rgb(193,229,222)', highlight: { - border: '#368d7e', + border: '#8d3686', background: 'rgb(193,229,222)' } } @@ -174,7 +177,7 @@ const adapt2vis = (entity, options = {}) => { switch (entity.type) { case 'person': entity._id = entity.id - entity.label = `${entity.text}\n` + getGender(entity.gender) +' - '+ getAge(entity.birthdate) + entity.label = `*${entity.text}*\n_${getGender(entity.gender)} - ${getAge(entity.birthdate)}_` if (options.folded) { entity.title = visMessages.fr.visgraph.click_to_expand entity._label = entity.label // keep label From a57a23dc4934225c9e6a5310c1767e4ec5b7ae63 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Sat, 30 Oct 2021 01:51:02 +0200 Subject: [PATCH 043/135] visgraph options settings --- .../Resources/public/vuejs/VisGraph/store.js | 2 +- .../public/vuejs/VisGraph/vis-network.js | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 0944667bc..80e4d0768 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -316,7 +316,7 @@ const store = createStore({ commit('addPerson', adapt2vis(person, { folded: true })) console.log('********* fetch infos for missing', person.id, '******') - //dispatch('fetchInfoForPerson', person) + dispatch('fetchInfoForPerson', person) }, } }) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index ecec18c9b..fca3c0876 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -25,8 +25,8 @@ window.options = { barnesHut: { theta: 0.5, gravitationalConstant: -2000, - centralGravity: 0.1, //// 0.3 - springLength: 200, //// 95 + centralGravity: 0.08, //// 0.3 + springLength: 220, //// 95 springConstant: 0.04, damping: 0.09, avoidOverlap: 0 @@ -151,10 +151,22 @@ window.options = { border: '#b0b0b0', background: 'rgb(193,229,222)', highlight: { - border: '#8d3686', - background: 'rgb(193,229,222)' + border: '#89c9a9', + background: 'rgb(156,213,203)' + }, + hover: { + border: '#89c9a9', + background: 'rgb(156,213,203)' } - } + }, + opacity: 0.85, + shadow:{ + enabled: true, + color: 'rgba(0,0,0,0.5)', + size:10, + x:5, + y:5 + }, }, household: { color: 'pink' From 869e442c2c515bb01ab614beee93a890db4aa105 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 1 Nov 2021 09:49:55 +0100 Subject: [PATCH 044/135] visgraph: add hover interaction --- .../Resources/public/vuejs/VisGraph/store.js | 4 ++-- .../Resources/public/vuejs/VisGraph/vis-network.js | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 80e4d0768..066b7c1dc 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -294,7 +294,7 @@ const store = createStore({ arrows: 'to', color: 'lightblue', font: { color: '#33839d' }, - dashes: true, + dashes: true, //physics: false, label: getRelationshipLabel(r, false), title: getRelationshipTitle(r), }) @@ -316,7 +316,7 @@ const store = createStore({ commit('addPerson', adapt2vis(person, { folded: true })) console.log('********* fetch infos for missing', person.id, '******') - dispatch('fetchInfoForPerson', person) + //dispatch('fetchInfoForPerson', person) }, } }) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index fca3c0876..15d9fafdd 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -69,6 +69,16 @@ window.options = { adaptiveTimestep: true, wind: { x: 0, y: 0 } }, + interaction: { + hover: true, + keyboard: { + enabled: true, + speed: {x: 3, y: 3, zoom: 0.02}, + bindToWindow: false + }, + multiselect: true, + navigationButtons: false + }, manipulation: { enabled: true, initiallyActive: true, @@ -115,7 +125,6 @@ window.options = { } }, nodes: { - //physics: true, borderWidth: 1, borderWidthSelected: 3, font: { @@ -123,7 +132,6 @@ window.options = { } }, edges: { - //physics: true, font: { color: '#b0b0b0', size: 9, From c4ba78d076a3106575cc13f71068e33af4708d7e Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 1 Nov 2021 10:50:13 +0100 Subject: [PATCH 045/135] minor --- .../public/vuejs/VisGraph/vis-network.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 15d9fafdd..7932217b1 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -7,7 +7,7 @@ import { visMessages } from './i18n' * cfr. https://github.com/almende/vis/issues/2524#issuecomment-307108271 */ -window.network = {}; +window.network = {} window.options = { locale: 'fr', @@ -84,28 +84,28 @@ window.options = { initiallyActive: true, addNode: function(nodeData, callback) { console.log('addNode', nodeData) - nodeData.label = 'hello world'; - callback(nodeData); + nodeData.label = 'hello world' + callback(nodeData) }, editNode: function(nodeData, callback) { console.log('editNode', nodeData) - callback(nodeData); + callback(nodeData) }, deleteNode: function(nodeData, callback) { console.log('deleteNode', nodeData) - callback(nodeData); + callback(nodeData) }, addEdge: function(edgeData, callback) { console.log('addEdge', edgeData) - callback(edgeData); + callback(edgeData) }, editEdge: function(edgeData, callback) { console.log('editNode', edgeData) - callback(edgeData); + callback(edgeData) }, deleteEdge: function(edgeData, callback) { console.log('deleteNode', edgeData) - callback(edgeData); + callback(edgeData) }, controlNodeStyle: { /* @@ -183,7 +183,7 @@ window.options = { color: 'orange', }, } -}; +} /** * Adapt entity to graph (id, label) @@ -285,6 +285,7 @@ const getHouseholdWidth = (member) => { /** * Return label edge * @param relationship + * @param reverse * @returns string */ const getRelationshipLabel = (relationship, reverse) => { From a0940a0c8517667dc27374a8d7403bd5b9d48c61 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 1 Nov 2021 10:45:37 +0100 Subject: [PATCH 046/135] visgraph: init window.eventHub as external emitter called in Vue. This implementation works with vue2, but is deprecated in vue3 !! see https://vue3-fr.netlify.app/guide/migration/events-api.html#_2-x-syntax --- .../Resources/public/vuejs/VisGraph/App.vue | 9 +++++++++ .../Resources/public/vuejs/VisGraph/index.js | 1 + .../Resources/public/vuejs/VisGraph/vis-network.js | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 9ff406e47..c72c3689f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -79,6 +79,12 @@ export default { } }, + created() { + eventHub.$on('add-switch', this.addSwitch) + }, + unmounted() { + eventHub.$off('add-switch', this.addSwitch) + }, mounted() { console.log('=== mounted: init graph') this.initGraph() @@ -118,6 +124,9 @@ export default { console.log('** click on node **') window.network.on('click', callback) }, + addSwitch(edgeData) { + console.log('==> addSwitch <=======================', edgeData) + }, } /* TODO / TO CHECK / TO UNDERSTAND diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js index 332b6cf6c..9e3da390f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js @@ -3,6 +3,7 @@ import { store } from "./store.js" import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n' import { visMessages } from './i18n' import App from './App.vue' + import './vis-network' const i18n = _createI18n(visMessages) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 7932217b1..a5d2a8daa 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -1,4 +1,5 @@ import { visMessages } from './i18n' +import {createApp} from "vue" /** * Vis-network initial data/configuration script @@ -7,6 +8,11 @@ import { visMessages } from './i18n' * cfr. https://github.com/almende/vis/issues/2524#issuecomment-307108271 */ +console.log('@@@@@@@ eventHub App @@@@@@@@@@') +window.eventHub = createApp() +console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') + + window.network = {} window.options = { @@ -98,6 +104,7 @@ window.options = { addEdge: function(edgeData, callback) { console.log('addEdge', edgeData) callback(edgeData) + eventHub.$emit('add-switch', edgeData) }, editEdge: function(edgeData, callback) { console.log('editNode', edgeData) From 41f815bbb91e0b06bb6d30914141665a771e9b1d Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 1 Nov 2021 11:46:30 +0100 Subject: [PATCH 047/135] tiny-emitter package is used as "centralized event hub" between vis-network and vue3 --- .../Resources/public/vuejs/VisGraph/App.vue | 8 ++++---- .../Resources/public/vuejs/VisGraph/vis-network.js | 12 +++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index c72c3689f..5bd654bd5 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -80,10 +80,10 @@ export default { }, created() { - eventHub.$on('add-switch', this.addSwitch) + eventHub.on('add-relationship-link', this.addRelationshipLink) }, unmounted() { - eventHub.$off('add-switch', this.addSwitch) + eventHub.off('add-relationship-link', this.addRelationshipLink) }, mounted() { console.log('=== mounted: init graph') @@ -124,8 +124,8 @@ export default { console.log('** click on node **') window.network.on('click', callback) }, - addSwitch(edgeData) { - console.log('==> addSwitch <=======================', edgeData) + addRelationshipLink(edgeData) { + console.log('==> addRelationshipLink <=======================', edgeData) }, } /* diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index a5d2a8daa..086608e19 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -1,5 +1,5 @@ import { visMessages } from './i18n' -import {createApp} from "vue" +import { TinyEmitter } from "tiny-emitter"; /** * Vis-network initial data/configuration script @@ -8,10 +8,8 @@ import {createApp} from "vue" * cfr. https://github.com/almende/vis/issues/2524#issuecomment-307108271 */ -console.log('@@@@@@@ eventHub App @@@@@@@@@@') -window.eventHub = createApp() -console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') - +console.log('@@@ init eventHub App @@@') +window.eventHub = new TinyEmitter() window.network = {} @@ -26,7 +24,7 @@ window.options = { showButton: true }, */ - physics:{ + physics: { enabled: true, barnesHut: { theta: 0.5, @@ -104,7 +102,7 @@ window.options = { addEdge: function(edgeData, callback) { console.log('addEdge', edgeData) callback(edgeData) - eventHub.$emit('add-switch', edgeData) + eventHub.emit('add-relationship-link', edgeData) }, editEdge: function(edgeData, callback) { console.log('editNode', edgeData) From 5d995115babc03b5a476b046e8117db5f0f1e935 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 1 Nov 2021 12:40:22 +0100 Subject: [PATCH 048/135] visgraph: only addEdge for person to person --- .../Resources/public/vuejs/VisGraph/i18n.js | 2 +- .../Resources/public/vuejs/VisGraph/store.js | 4 +-- .../public/vuejs/VisGraph/vis-network.js | 31 ++++++++++++++++--- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js index 5b408e209..609299cfe 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/i18n.js @@ -20,7 +20,7 @@ const visMessages = { editNode: 'Éditer un noeuds', editEdge: 'Éditer un lien', addDescription: 'Cliquez dans un espace vide pour créer un nouveau nœud.', - edgeDescription: 'Cliquez sur un nœud et faites glisser le lien vers un autre nœud pour les connecter.', + edgeDescription: 'Cliquez sur un usager et faites glisser le lien vers un autre usager pour les connecter.', editEdgeDescription: 'Cliquez sur les points de contrôle et faites-les glisser vers un nœud pour les relier.', createEdgeError: 'Il est impossible de relier des arêtes à un cluster.', deleteClusterError: 'Les clusters ne peuvent pas être supprimés.', diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 066b7c1dc..772af6630 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -1,6 +1,6 @@ import { createStore } from 'vuex' import { getHouseholdByPerson, getCoursesByPerson, getRelationshipsByPerson } from './api' -import { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, getRelationshipTitle } from './vis-network' +import { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, getRelationshipTitle, splitId } from './vis-network' const debug = process.env.NODE_ENV !== 'production' @@ -235,7 +235,7 @@ const store = createStore({ commit('addLink', { from: `${p.person.type}_${p.person.id}`, to: `${course.id}`, - id: `p${p.person.id}-c`+ course.id.split('_')[2], + id: `p${p.person.id}-c`+ splitId(course.id,'id'), arrows: 'from', color: 'orange', font: { color: 'darkorange' }, diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 086608e19..b13f9ac32 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -100,9 +100,14 @@ window.options = { callback(nodeData) }, addEdge: function(edgeData, callback) { - console.log('addEdge', edgeData) - callback(edgeData) - eventHub.emit('add-relationship-link', edgeData) + if ( + splitId(edgeData.from,'type') === 'person' + && splitId(edgeData.to,'type') === 'person' + ) { + console.log('addEdge', edgeData) + eventHub.emit('add-relationship-link', edgeData) + callback(edgeData) + } }, editEdge: function(edgeData, callback) { console.log('editNode', edgeData) @@ -309,10 +314,28 @@ const getRelationshipTitle = (relationship) => { + relationship.toPerson.text } +/** + * Split string id and return type|id substring + * @param id + * @param position + * @returns string + */ +const splitId = (id, position) => { + switch (position) { + case 'type': + return /(.+)_/.exec(id)[1] // return 'accompanying_period' + case 'id': + return id.split("_").pop() // return '124' + default: + throw 'position undefined' + } +} + export { adapt2vis, getHouseholdLabel, getHouseholdWidth, getRelationshipLabel, - getRelationshipTitle + getRelationshipTitle, + splitId } From d3a08149f0f12886cef414b2a25d12df5f927c73 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Mon, 1 Nov 2021 13:31:58 +0100 Subject: [PATCH 049/135] visgraph: open vue modal when adding/editing edge --- .../Resources/public/vuejs/VisGraph/App.vue | 45 ++++++++++++++++--- .../public/vuejs/VisGraph/vis-network.js | 20 ++++++--- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 5bd654bd5..ffe73a7ab 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -4,7 +4,6 @@

{{ $t('visgraph.Legend')}}

-
-

+

{{ $t('visgraph.relation_from_to_like', [ - getPerson(modal.data.to).text, - getPerson(modal.data.from).text, - relation.title.fr.toLowerCase(), - ])}} -
+ getPerson(modal.data.to).text, getPerson(modal.data.from).text, relation.title.fr.toLowerCase() ])}}
{{ $t('visgraph.relation_from_to_like', [ - getPerson(modal.data.from).text, - getPerson(modal.data.to).text, - relation.reverseTitle.fr.toLowerCase(), - ])}} + getPerson(modal.data.from).text, getPerson(modal.data.to).text, relation.reverseTitle.fr.toLowerCase() ])}}

{{ $t('visgraph.relation_from_to_like', [ - getPerson(modal.data.from).text, - getPerson(modal.data.to).text, - relation.title.fr.toLowerCase(), - ])}} -
+ getPerson(modal.data.from).text, getPerson(modal.data.to).text, relation.title.fr.toLowerCase() ])}}
{{ $t('visgraph.relation_from_to_like', [ - getPerson(modal.data.to).text, - getPerson(modal.data.from).text, - relation.reverseTitle.fr.toLowerCase(), - ])}} + getPerson(modal.data.to).text, getPerson(modal.data.from).text, relation.reverseTitle.fr.toLowerCase() ])}}

From 9cffe5161af93dd9742025c10f96f435862537a5 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 2 Nov 2021 18:45:15 +0100 Subject: [PATCH 058/135] visgraph: test form without vis-network --- .../Resources/public/vuejs/VisGraph/App.vue | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index a83ff1456..03cf624ea 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -1,4 +1,9 @@ @@ -147,8 +147,8 @@ export default { container: '', checkedLayers: [], relations: [], - relation: null, - reverse: false, + //relation: null, + //reverse: false, displayHelpMessage: false, listenPersonFlag: 'normal', newEdgeData: {}, @@ -157,7 +157,13 @@ export default { modalDialogClass: "modal-md", title: null, action: null, - data: {}, + data: { + type: 'relationship', + from: null, + to: null, + relation: null, + reverse: false + }, button: { class: null, text: null @@ -216,26 +222,24 @@ export default { }, - /* relation: { get() { - return this.relation + return this.modal.data.relation }, set(value) { - //console.log('setter relation', value) // <=== InternalError: too much recursion - this.relation = value + this.modal.data.relation = value } }, reverse: { get() { - return this.reverse + return this.modal.data.reverse }, - set(newValue) { - //console.log('setter reverse', newValue) // <=== InternalError: too much recursion - this.reverse = newValue + set(value) { + this.modal.data.reverse = value } }, + /* */ }, @@ -377,8 +381,9 @@ export default { /// control Modal addRelationshipModal(edgeData) { - this.modal.data = edgeData - console.log('==- addRelationshipModal', edgeData) // { from: "person_1617", to: "person_1614" } + console.log('==- addRelationshipModal', edgeData) + this.modal.data.from = edgeData.from + this.modal.data.to = edgeData.to this.modal.action = 'create' this.modal.title = 'visgraph.add_relationship_link' this.modal.button.class = 'btn-create' @@ -410,7 +415,13 @@ export default { resetForm() { console.log('==- reset Form') - this.modal.data = {} + this.modal.data = { + type: 'relationship', + from: null, + to: null, + relation: null, + reverse: false + } this.modal.action = null this.modal.title = null this.modal.button.class = null @@ -428,6 +439,7 @@ export default { //console.log('customLabel', value) return (value.title && value.reverseTitle) ? `${value.title.fr} ↔ ${value.reverseTitle.fr}` : '' }, + getPerson(idtext) { let person = this.persons.filter(p => p.id === idtext) return person[0] @@ -439,8 +451,9 @@ export default { console.log(' @@> switch listener to create link mode:', this.listenPersonFlag) }, dropRelationship() { - console.log('delete') - deleteRelationship(relationship) /// param ? + console.log('delete', this.modal.data) + deleteRelationship(this.modal.data) + this.$store.commit('removeLink', this.modal.data.id) this.modal.showModal = false this.resetForm() }, @@ -449,9 +462,7 @@ export default { switch (this.modal.action) { case 'create': - return postRelationship( - this.getPerson(this.modal.data.from), this.getPerson(this.modal.data.to), this.relation, this.reverse - ) + return postRelationship(this.modal.data) .then(relationship => new Promise(resolve => { console.log('post response', relationship) this.$store.dispatch('addLinkFromRelationship', relationship) @@ -462,10 +473,10 @@ export default { .catch() case 'edit': - return patchRelationship(relationship) + return patchRelationship(this.modal.data) .then(relationship => new Promise(resolve => { console.log('patch relationship', relationship) - this.$store.dispatch('updateLinkFromRelationship', relationship) + this.$store.commit('updateLink', relationship) this.modal.showModal = false this.resetForm() resolve() diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js index 024486a07..2035c8e1e 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -1,3 +1,5 @@ +import { splitId } from './vis-network' + /** * @function makeFetch * @param method @@ -130,21 +132,19 @@ const getRelationsList = () => { /** * @function postRelationship - * @param fromPerson - * @param toPerson - * @param relation - * @param reverse + * @param relationship * @returns {Promise} */ -const postRelationship = (fromPerson, toPerson, relation, reverse) => { +const postRelationship = (relationship) => { + console.log(relationship) return postFetch( `/api/1.0/relations/relationship.json`, { type: 'relationship', - fromPerson: { type: 'person', id: fromPerson._id }, - toPerson: { type: 'person', id: toPerson._id }, - relation: { type: 'relation', id: relation.id }, - reverse: reverse + fromPerson: { type: 'person', id: splitId(relationship.from, 'id') }, + toPerson: { type: 'person', id: splitId(relationship.to, 'id') }, + relation: { type: 'relation', id: relationship.relation.id }, + reverse: relationship.reverse } ) } @@ -156,12 +156,14 @@ const postRelationship = (fromPerson, toPerson, relation, reverse) => { */ const patchRelationship = (relationship) => { console.log(relationship) + let linkType = splitId(relationship.id, 'link') + let id = splitId(linkType, 'id') return patchFetch( - `/api/1.0/relations/relationship/${relationship.id}.json`, + `/api/1.0/relations/relationship/${id}.json`, { type: 'relationship', - fromPerson: { type: 'person', id: relationship.fromPerson.id }, - toPerson: { type: 'person', id: relationship.toPerson.id }, + fromPerson: { type: 'person', id: splitId(relationship.from, 'id') }, + toPerson: { type: 'person', id: splitId(relationship.to, 'id') }, relation: { type: 'relation', id: relationship.relation.id }, reverse: relationship.reverse } @@ -174,8 +176,11 @@ const patchRelationship = (relationship) => { * @returns {Promise} */ const deleteRelationship = (relationship) => { + console.log(relationship) + let linkType = splitId(relationship.id, 'link') + let id = splitId(linkType, 'id') return deleteFetch( - `/api/1.0/relations/relationship/${relationship.id}.json` + `/api/1.0/relations/relationship/${id}.json` ) } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 98f188fdf..1cdd472d8 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -160,6 +160,30 @@ const store = createStore({ addLink(state, link) { state.links.push(link) }, + updateLink(state, link) { + console.log('updateLink', link) + let link_ = { + from: `person_${link.fromPerson.id}`, + to: `person_${link.toPerson.id}`, + id: 'relationship_' + splitId(link.id,'id') + + '-person_' + link.fromPerson.id + '-person_' + link.toPerson.id, + arrows: getRelationshipDirection(link), + color: 'lightblue', + font: { color: '#33839d' }, + dashes: true, + label: getRelationshipLabel(link), + title: getRelationshipTitle(link), + relation: link.relation, + reverse: link.reverse + } + // find row position and replace by updatedLink + state.links.splice( + state.links.findIndex(item => item.id === link_.id), 1, link_ + ) + }, + removeLink(state, link_id) { + state.links = state.links.filter(l => l.id !== link_id) + }, //// id markers markInWhitelist(state, person) { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 011f83977..98ea88fb5 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -266,13 +266,12 @@ const getRelationshipTitle = (relationship) => { * @param position * @returns string|integer */ -const splitId = (id, position) => { +const splitId = (id, position) => { console.log(id, position) switch (position) { case 'type': // return 'accompanying_period' return /(.+)_/.exec(id)[1] case 'id': // return 124 - return parseInt(id - .toString() + return parseInt(id.toString() .split("_") .pop()) case 'link': From bfca6d2afc549b73626666e925742e1efa44652f Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 9 Nov 2021 19:58:04 +0100 Subject: [PATCH 105/135] cleaning --- .../Resources/public/vuejs/VisGraph/App.vue | 30 ++++--------------- .../Resources/public/vuejs/VisGraph/api.js | 6 ++-- .../Resources/public/vuejs/VisGraph/store.js | 7 ++--- .../public/vuejs/VisGraph/vis-network.js | 3 +- 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index d21f21446..312b5d722 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -82,10 +82,8 @@

-
+
@@ -108,10 +107,6 @@ >
- @@ -147,8 +142,6 @@ export default { container: '', checkedLayers: [], relations: [], - //relation: null, - //reverse: false, displayHelpMessage: false, listenPersonFlag: 'normal', newEdgeData: {}, @@ -218,9 +211,11 @@ export default { return this.checkedLayers }, + /* toggleIdPerson() { - + console.log('toggleIdPerson') }, + */ relation: { get() { @@ -239,8 +234,6 @@ export default { this.modal.data.reverse = value } }, - /* - */ }, mounted() { @@ -394,24 +387,13 @@ export default { this.modal.data = edgeData this.relation = this.modal.data.relation this.reverse = this.modal.data.reverse - console.log('==- editRelationshipModal', this.modal.data, this.relation, this.reverse) + console.log('==- editRelationshipModal', this.modal.data) this.modal.action = 'edit' this.modal.title = 'visgraph.edit_relationship_link' this.modal.button.class = 'btn-edit' this.modal.button.text = 'action.edit' this.modal.showModal = true }, - /* - deleteRelationshipModal(edgeData) { - this.modal.data = edgeData - console.log('==- deleteRelationshipModal', edgeData) - this.modal.action = 'delete' - this.modal.title = 'visgraph.delete_relationship_link' - this.modal.button.class = 'btn-delete' - this.modal.button.text = 'action.delete' - this.modal.showModal = true - }, - */ resetForm() { console.log('==- reset Form') diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js index 2035c8e1e..448ff6633 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -136,7 +136,7 @@ const getRelationsList = () => { * @returns {Promise} */ const postRelationship = (relationship) => { - console.log(relationship) + //console.log(relationship) return postFetch( `/api/1.0/relations/relationship.json`, { @@ -155,7 +155,7 @@ const postRelationship = (relationship) => { * @returns {Promise} */ const patchRelationship = (relationship) => { - console.log(relationship) + //console.log(relationship) let linkType = splitId(relationship.id, 'link') let id = splitId(linkType, 'id') return patchFetch( @@ -176,7 +176,7 @@ const patchRelationship = (relationship) => { * @returns {Promise} */ const deleteRelationship = (relationship) => { - console.log(relationship) + //console.log(relationship) let linkType = splitId(relationship.id, 'link') let id = splitId(linkType, 'id') return deleteFetch( diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index 1cdd472d8..edde88f1f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -71,7 +71,7 @@ const store = createStore({ //console.log(link.id, state.excludedNodesIds.indexOf(splitId(link.id, 'link'))) } }) - console.log(array.length, array.map(i => i.id)) + console.log('count links', array.length, array.map(i => i.id)) return array.length }, @@ -120,9 +120,8 @@ const store = createStore({ mutations: { addPerson(state, [person, options]) { let debug = '' - /// Debug mode ~ display person_id on visgraph - // uncomment - debug = `\nid ${person.id}` + /// Debug mode: uncomment to display person_id on visgraph + //debug = `\nid ${person.id}` person.group = person.type person._id = person.id person.id = `person_${person.id}` diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 98ea88fb5..cf3dc1baa 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -266,7 +266,8 @@ const getRelationshipTitle = (relationship) => { * @param position * @returns string|integer */ -const splitId = (id, position) => { console.log(id, position) +const splitId = (id, position) => { + //console.log(id, position) switch (position) { case 'type': // return 'accompanying_period' return /(.+)_/.exec(id)[1] From a63e1321b0f7ac65e06676a77dc729e390e4a4e8 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Tue, 9 Nov 2021 22:48:29 +0100 Subject: [PATCH 106/135] cleaning --- .../Resources/public/vuejs/VisGraph/App.vue | 60 ++++++++----------- .../Resources/public/vuejs/VisGraph/store.js | 4 +- .../public/vuejs/VisGraph/vis-network.js | 12 ++-- 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 312b5d722..3cd3de56d 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -5,7 +5,7 @@
- -
@@ -211,12 +204,6 @@ export default { return this.checkedLayers }, - /* - toggleIdPerson() { - console.log('toggleIdPerson') - }, - */ - relation: { get() { return this.modal.data.relation @@ -249,6 +236,8 @@ export default { // Instanciate vis objects in separate window variables, see vis-network.js window.network = new vis.Network(this.container, this.visgraph_data, window.options) }, + + // events listenOnGraph() { window.network.on('selectNode', (data) => { if (data.nodes.length > 1) { @@ -300,7 +289,7 @@ export default { console.log('@@@@@ event on selected Edge', data.edges.length, linkType, data) if (linkType.startsWith('relationship')) { - console.log('linkType relationship') + //console.log('linkType relationship') let relationships = this.edges.filter(l => l.id === link) if (relationships.length > 1) { @@ -308,7 +297,7 @@ export default { } let relationship = relationships[0] - console.log(relationship) + //console.log(relationship) this.editRelationshipModal({ from: relationship.from, @@ -318,20 +307,12 @@ export default { reverse: relationship.reverse }) } - /* Disabled - if (linkType.startsWith('household')) { - console.log('linkType household') - } else - if (linkType.startsWith('accompanying_period')) { - console.log('linkType accompanying_period') - } else - */ }) }, listenStepsToAddRelationship(person) { console.log(' @@> listenStep', this.listenPersonFlag) if (this.listenPersonFlag === 'step2') { - console.log(' @@> person 2', person) + //console.log(' @@> person 2', person) this.newEdgeData.to = person.id this.addRelationshipModal(this.newEdgeData) this.displayHelpMessage = false @@ -339,11 +320,13 @@ export default { this.newEdgeData = {} } if (this.listenPersonFlag === 'step1') { - console.log(' @@> person 1', person) + //console.log(' @@> person 1', person) this.newEdgeData.from = person.id this.listenPersonFlag = 'step2' } }, + + // force refresh forceUpdateComponent() { //console.log('!! forceUpdateComponent !!') this.$forceUpdate() @@ -374,7 +357,7 @@ export default { /// control Modal addRelationshipModal(edgeData) { - console.log('==- addRelationshipModal', edgeData) + //console.log('==- addRelationshipModal', edgeData) this.modal.data.from = edgeData.from this.modal.data.to = edgeData.to this.modal.action = 'create' @@ -387,7 +370,7 @@ export default { this.modal.data = edgeData this.relation = this.modal.data.relation this.reverse = this.modal.data.reverse - console.log('==- editRelationshipModal', this.modal.data) + //console.log('==- editRelationshipModal', this.modal.data) this.modal.action = 'edit' this.modal.title = 'visgraph.edit_relationship_link' this.modal.button.class = 'btn-edit' @@ -395,6 +378,7 @@ export default { this.modal.showModal = true }, + // form resetForm() { console.log('==- reset Form') this.modal.data = { @@ -409,6 +393,7 @@ export default { this.modal.button.class = null this.modal.button.text = null }, + getRelationsList() { //console.log('fetch relationsList') return getRelationsList().then(relations => new Promise(resolve => { @@ -421,32 +406,33 @@ export default { //console.log('customLabel', value) return (value.title && value.reverseTitle) ? `${value.title.fr} ↔ ${value.reverseTitle.fr}` : '' }, - - getPerson(idtext) { - let person = this.persons.filter(p => p.id === idtext) + getPerson(id) { + let person = this.persons.filter(p => p.id === id) return person[0] }, - newRelationshipLinkButton() { + // actions + createRelationship() { this.displayHelpMessage = true this.listenPersonFlag = 'step1' console.log(' @@> switch listener to create link mode:', this.listenPersonFlag) }, dropRelationship() { - console.log('delete', this.modal.data) + //console.log('delete', this.modal.data) deleteRelationship(this.modal.data) + .catch() this.$store.commit('removeLink', this.modal.data.id) this.modal.showModal = false this.resetForm() }, submitRelationship() { - console.log('submitRelationship with action', this.modal.action) + console.log('submitRelationship', this.modal.action) switch (this.modal.action) { case 'create': return postRelationship(this.modal.data) .then(relationship => new Promise(resolve => { - console.log('post response', relationship) + console.log('post relationship response', relationship) this.$store.dispatch('addLinkFromRelationship', relationship) this.modal.showModal = false this.resetForm() @@ -457,7 +443,7 @@ export default { case 'edit': return patchRelationship(this.modal.data) .then(relationship => new Promise(resolve => { - console.log('patch relationship', relationship) + console.log('patch relationship response', relationship) this.$store.commit('updateLink', relationship) this.modal.showModal = false this.resetForm() @@ -471,6 +457,7 @@ export default { } }, + /* /// Tiny emitter events created() { eventHub.on('add-relationship-modal', this.addRelationshipModal) @@ -482,6 +469,7 @@ export default { eventHub.off('edit-relationship-modal', this.editRelationshipModal) eventHub.off('delete-relationship-modal', this.deleteRelationshipModal) } + */ } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index edde88f1f..d9f6b5b03 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -216,11 +216,11 @@ const store = createStore({ //// excluded addExcludedNode(state, id) { - console.log('==> exclude list: +', id) + //console.log('==> exclude list: +', id) state.excludedNodesIds.push(id) }, removeExcludedNode(state, id) { - console.log('<== exclude list: -', id) + //console.log('<== exclude list: -', id) state.excludedNodesIds = state.excludedNodesIds.filter(e => e !== id) }, diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index cf3dc1baa..082d35b15 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -1,5 +1,5 @@ import { visMessages } from './i18n' -import { TinyEmitter } from "tiny-emitter"; +//import { TinyEmitter } from "tiny-emitter"; /** * Vis-network initial data/configuration script @@ -8,8 +8,8 @@ import { TinyEmitter } from "tiny-emitter"; * cfr. https://github.com/almende/vis/issues/2524#issuecomment-307108271 */ -console.log('@@@ init eventHub App @@@') -window.eventHub = new TinyEmitter() +//console.log('@@@ init eventHub App @@@') +//window.eventHub = new TinyEmitter() window.network = {} @@ -82,8 +82,11 @@ window.options = { enabled: false, initiallyActive: false, addNode: false, - //editNode: function(nodeData, callback) { callback(nodeData) }, //disabled if undefined deleteNode: false, + /* + //disabled if undefined + //editNode: function(nodeData, callback) { callback(nodeData) }, + // TODO see alternative with 'Manipulation methods to use the manipulation system without GUI.' addEdge: function(edgeData, callback) { if ( @@ -111,6 +114,7 @@ window.options = { callback(edgeData) } // end TODO + */ }, nodes: { borderWidth: 1, From 7dc9021ecaf3c566c9b09bbf3d1e24e986a4ac1e Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 10 Nov 2021 11:35:19 +0100 Subject: [PATCH 107/135] visgraph: no more need for tiny emitter. remove it --- .../Resources/public/vuejs/VisGraph/App.vue | 14 ------- .../public/vuejs/VisGraph/vis-network.js | 38 +------------------ 2 files changed, 1 insertion(+), 51 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 3cd3de56d..7ad449dc8 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -455,21 +455,7 @@ export default { throw "uncaught action" } } - }, - - /* - /// Tiny emitter events - created() { - eventHub.on('add-relationship-modal', this.addRelationshipModal) - eventHub.on('edit-relationship-modal', this.editRelationshipModal) - eventHub.on('delete-relationship-modal', this.deleteRelationshipModal) - }, - unmounted() { - eventHub.off('add-relationship-modal', this.addRelationshipModal) - eventHub.off('edit-relationship-modal', this.editRelationshipModal) - eventHub.off('delete-relationship-modal', this.deleteRelationshipModal) } - */ } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js index 082d35b15..e95bc0d0b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/vis-network.js @@ -1,5 +1,4 @@ import { visMessages } from './i18n' -//import { TinyEmitter } from "tiny-emitter"; /** * Vis-network initial data/configuration script @@ -8,9 +7,6 @@ import { visMessages } from './i18n' * cfr. https://github.com/almende/vis/issues/2524#issuecomment-307108271 */ -//console.log('@@@ init eventHub App @@@') -//window.eventHub = new TinyEmitter() - window.network = {} window.options = { @@ -82,39 +78,7 @@ window.options = { enabled: false, initiallyActive: false, addNode: false, - deleteNode: false, - /* - //disabled if undefined - //editNode: function(nodeData, callback) { callback(nodeData) }, - - // TODO see alternative with 'Manipulation methods to use the manipulation system without GUI.' - addEdge: function(edgeData, callback) { - if ( - splitId(edgeData.from,'type') === 'person' - && splitId(edgeData.to,'type') === 'person' - ) { - console.log('callback addEdge', edgeData) - eventHub.emit('add-relationship-modal', edgeData) - callback(edgeData) - } - }, - editEdge: function(edgeData, callback) { - if ( - splitId(edgeData.from,'type') === 'person' - && splitId(edgeData.to,'type') === 'person' - ) { - console.log('callback editEdge', edgeData) - eventHub.emit('edit-relationship-modal', edgeData) - callback(edgeData) - } - }, - deleteEdge: function(edgeData, callback) { - console.log('callback deleteEdge', edgeData) // array with edges id - eventHub.emit('delete-relationship-modal', edgeData) - callback(edgeData) - } - // end TODO - */ + deleteNode: false }, nodes: { borderWidth: 1, From 7230fd9c07189c2ce2517bb3bb280695664c8ac3 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 10 Nov 2021 11:38:24 +0100 Subject: [PATCH 108/135] minor changes, and cleaning code --- .../public/vuejs/AccompanyingCourse/App.vue | 4 -- .../Resources/public/vuejs/VisGraph/App.vue | 63 ++++++++----------- .../public/vuejs/VisGraph/components/test.vue | 49 --------------- .../Resources/public/vuejs/VisGraph/store.js | 2 +- 4 files changed, 27 insertions(+), 91 deletions(-) delete mode 100644 src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/components/test.vue diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue index c8dcaaa97..087248444 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue @@ -1,6 +1,4 @@ diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js index d9f6b5b03..d9f6b9d87 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/store.js @@ -328,7 +328,7 @@ const store = createStore({ }, /** - * 6) Add each distinct course + * 6) Add each distinct course (a person can have multiple courses) * @param object * @param courses */ From 95610ffd342d4c06fcb59ea474773b260adc4f67 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Wed, 10 Nov 2021 19:57:19 +0100 Subject: [PATCH 109/135] visgraph: improve update graph mechanism adding an updateHack in store, and a watcher in component. * updateHack increment a value in the lpop, * the watcher detect when value changes * and $forceUpdate improve layer checkbox legend refresh and rebuild --- .../Resources/public/vuejs/VisGraph/App.vue | 47 ++++++++++--------- .../Resources/public/vuejs/VisGraph/store.js | 27 ++++++++--- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index fa6707ed1..3f26eb13b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -8,7 +8,7 @@ - From 28afe5228a47c1e1d1852c2fae109ccb641e6712 Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 12 Nov 2021 12:14:55 +0100 Subject: [PATCH 116/135] upd CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fad2c948..c899353f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to +* [person]: delete accompanying period work, including related objects (cascade) (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/36) + + * [person]: Add civility to the person * [person]: Various improvements on the edit person form * [person]: Set available_languages and available_countries as parameters for use in the edit person form From 22bdf35eb0e7b2d902ed31e25ce2b13c814e4b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 12 Nov 2021 12:05:16 +0000 Subject: [PATCH 117/135] minor fixes --- .../Controller/AccompanyingCourseWorkController.php | 2 +- .../Entity/AccompanyingPeriod/AccompanyingPeriodWork.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php index cf8e5cab0..3625c7cca 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php @@ -29,7 +29,7 @@ class AccompanyingCourseWorkController extends AbstractController SerializerInterface $serializer, AccompanyingPeriodWorkRepository $workRepository, PaginatorFactory $paginator, - LoggerInterface $logger + LoggerInterface $chillLogger ) { $this->trans = $trans; $this->serializer = $serializer; diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php index 8ae4212cc..58b27d95d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php @@ -167,7 +167,7 @@ use Symfony\Component\Validator\Constraints as Assert; * @ORM\OneToMany( * targetEntity=AccompanyingPeriodWorkEvaluation::class, * mappedBy="accompanyingPeriodWork", - * cascade={"remove"}, + * cascade={"remove", "persist"}, * orphanRemoval=true * ) * @Serializer\Groups({"read"}) From c8135e074189269fc1ac4a706084af86511ef1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 12 Nov 2021 12:07:31 +0000 Subject: [PATCH 118/135] add validation to accompanying periods --- .../Tests/Util/DateRangeCoveringTest.php | 12 ++++ .../Util/DateRangeCovering.php | 61 ---------------- .../AccompanyingCourseApiController.php | 15 +++- .../ORM/LoadAccompanyingPeriodOrigin.php | 2 +- .../DataFixtures/ORM/LoadPeople.php | 4 +- .../Entity/AccompanyingPeriod.php | 38 +++++++++- .../Entity/AccompanyingPeriod/Resource.php | 8 ++- .../AccompanyingPeriodParticipation.php | 7 ++ .../public/vuejs/AccompanyingCourse/App.vue | 17 ++--- .../public/vuejs/AccompanyingCourse/api.js | 3 +- .../components/OriginDemand.vue | 16 ++--- .../public/vuejs/AccompanyingCourse/index.js | 3 + .../vuejs/AccompanyingCourse/store/index.js | 2 +- .../AccompanyingPeriod/LocationValidity.php | 2 +- .../ParticipationOverlap.php | 15 ++++ .../ParticipationOverlapValidator.php | 72 +++++++++++++++++++ .../ResourceDuplicateCheck.php | 16 +++++ .../ResourceDuplicateCheckValidator.php | 56 +++++++++++++++ .../config/services/validator.yaml | 6 ++ .../migrations/Version20211020131133.php | 31 ++++++++ .../migrations/Version20211021125359.php | 36 ++++++++++ .../translations/validators.fr.yml | 3 + 22 files changed, 337 insertions(+), 88 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php create mode 100644 src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlapValidator.php create mode 100644 src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php create mode 100644 src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheckValidator.php create mode 100644 src/Bundle/ChillPersonBundle/config/services/validator.yaml create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php diff --git a/src/Bundle/ChillMainBundle/Tests/Util/DateRangeCoveringTest.php b/src/Bundle/ChillMainBundle/Tests/Util/DateRangeCoveringTest.php index c06b4a4f4..18af61849 100644 --- a/src/Bundle/ChillMainBundle/Tests/Util/DateRangeCoveringTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Util/DateRangeCoveringTest.php @@ -37,6 +37,18 @@ class DateRangeCoveringTest extends TestCase $this->assertNotContains(3, $cover->getIntersections()[0][2]); } + public function testCoveringWithMinCover1_NoCoveringWithNullDates() + { + $cover = new DateRangeCovering(1, new \DateTimeZone('Europe/Brussels')); + $cover + ->add(new \DateTime('2021-10-05'), new \DateTime('2021-10-18'), 521) + ->add(new \DateTime('2021-10-26'), null, 663) + ->compute() + ; + + $this->assertFalse($cover->hasIntersections()); + } + public function testCoveringWithMinCover1WithTwoIntersections() { $cover = new DateRangeCovering(1, new \DateTimeZone('Europe/Brussels')); diff --git a/src/Bundle/ChillMainBundle/Util/DateRangeCovering.php b/src/Bundle/ChillMainBundle/Util/DateRangeCovering.php index a10ebb883..3eb6d1433 100644 --- a/src/Bundle/ChillMainBundle/Util/DateRangeCovering.php +++ b/src/Bundle/ChillMainBundle/Util/DateRangeCovering.php @@ -140,67 +140,6 @@ class DateRangeCovering return $this; } - private function process(array $intersections): array - { - $result = []; - $starts = []; - $ends = []; - $metadatas = []; - - while (null !== ($current = \array_pop($intersections))) { - list($cStart, $cEnd, $cMetadata) = $current; - $n = count($cMetadata); - - foreach ($intersections as list($iStart, $iEnd, $iMetadata)) { - $start = max($cStart, $iStart); - $end = min($cEnd, $iEnd); - - if ($start <= $end) { - if (FALSE !== ($key = \array_search($start, $starts))) { - if ($ends[$key] === $end) { - $metadatas[$key] = \array_unique(\array_merge($metadatas[$key], $iMetadata)); - continue; - } - } - $starts[] = $start; - $ends[] = $end; - $metadatas[] = \array_unique(\array_merge($iMetadata, $cMetadata)); - } - } - } - - // recompose results - foreach ($starts as $k => $start) { - $result[] = [$start, $ends[$k], \array_unique($metadatas[$k])]; - } - - return $result; - } - - private function addToIntersections(array $intersections, array $intersection) - { - $foundExisting = false; - list($nStart, $nEnd, $nMetadata) = $intersection; - - \array_walk($intersections, - function(&$i, $key) use ($nStart, $nEnd, $nMetadata, $foundExisting) { - if ($foundExisting) { - return; - }; - if ($i[0] === $nStart && $i[1] === $nEnd) { - $foundExisting = true; - $i[2] = \array_merge($i[2], $nMetadata); - } - } - ); - - if (!$foundExisting) { - $intersections[] = $intersection; - } - - return $intersections; - } - public function hasIntersections(): bool { if (!$this->computed) { diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index bce888876..ba033f562 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -54,10 +54,14 @@ class AccompanyingCourseApiController extends ApiController $accompanyingPeriod = $this->getEntity('participation', $id, $request); $this->checkACL('confirm', $request, $_format, $accompanyingPeriod); -$workflow = $this->registry->get($accompanyingPeriod); + $workflow = $this->registry->get($accompanyingPeriod); if (FALSE === $workflow->can($accompanyingPeriod, 'confirm')) { - throw new BadRequestException('It is not possible to confirm this period'); + // throw new BadRequestException('It is not possible to confirm this period'); + $errors = $this->validator->validate($accompanyingPeriod, null, [$accompanyingPeriod::STEP_CONFIRMED]); + if( count($errors) > 0 ){ + return $this->json($errors, 422); + } } $workflow->apply($accompanyingPeriod, 'confirm'); @@ -109,6 +113,13 @@ $workflow = $this->registry->get($accompanyingPeriod); public function resourceApi($id, Request $request, string $_format): Response { + $accompanyingPeriod = $this->getEntity('resource', $id, $request); + $errors = $this->validator->validate($accompanyingPeriod); + + if ($errors->count() > 0) { + return $this->json($errors, 422); + } + return $this->addRemoveSomething('resource', $id, $request, $_format, 'resource', Resource::class); } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php index cbec9c439..eef8d7b47 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php @@ -40,7 +40,7 @@ class LoadAccompanyingPeriodOrigin extends AbstractFixture implements OrderedFix public function getOrder() { - return 10005; + return 9000; } private $phoneCall = ['en' => 'phone call', 'fr' => 'appel téléphonique']; diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php index adc37d5b5..b9b0b4946 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php @@ -247,7 +247,9 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con if (\random_int(0, 10) > 3) { // always add social scope: $accompanyingPeriod->addScope($this->getReference('scope_social')); - + $origin = $this->getReference(LoadAccompanyingPeriodOrigin::ACCOMPANYING_PERIOD_ORIGIN); + $accompanyingPeriod->setOrigin($origin); + $accompanyingPeriod->setIntensity('regular'); $accompanyingPeriod->setAddressLocation($this->createAddress()); $manager->persist($accompanyingPeriod->getAddressLocation()); $workflow = $this->workflowRegistry->get($accompanyingPeriod); diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 9ad0c75dd..dab1dcb9d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -45,6 +45,9 @@ use Chill\MainBundle\Entity\User; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\GroupSequenceProviderInterface; +use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap; +use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ResourceDuplicateCheck; /** * AccompanyingPeriod Class @@ -54,9 +57,10 @@ use Symfony\Component\Validator\Constraints as Assert; * @DiscriminatorMap(typeProperty="type", mapping={ * "accompanying_period"=AccompanyingPeriod::class * }) + * @Assert\GroupSequenceProvider */ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface, - HasScopesInterface, HasCentersInterface + HasScopesInterface, HasCentersInterface, GroupSequenceProviderInterface { /** * Mark an accompanying period as "occasional" @@ -132,6 +136,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * cascade={"persist", "remove"}, * orphanRemoval=true * ) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_DRAFT}) */ private $comments; @@ -147,9 +152,10 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * @var Collection * * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class, - * mappedBy="accompanyingPeriod", + * mappedBy="accompanyingPeriod", orphanRemoval=true, * cascade={"persist", "refresh", "remove", "merge", "detach"}) * @Groups({"read"}) + * @ParticipationOverlap(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED}) */ private $participations; @@ -188,6 +194,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * @ORM\ManyToOne(targetEntity=Origin::class) * @ORM\JoinColumn(nullable=true) * @Groups({"read", "write"}) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED}) */ private $origin; @@ -195,8 +202,9 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * @var string * @ORM\Column(type="string", nullable=true) * @Groups({"read", "write"}) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED}) */ - private $intensity; + private $intensity = self::INTENSITY_OCCASIONAL; /** * @var Collection @@ -210,6 +218,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * inverseJoinColumns={@ORM\JoinColumn(name="scope_id", referencedColumnName="id")} * ) * @Groups({"read"}) + * @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}) */ private $scopes; @@ -256,6 +265,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * orphanRemoval=true * ) * @Groups({"read"}) + * @ResourceDuplicateCheck(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED, "Default", "default"}) */ private $resources; @@ -267,6 +277,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * name="chill_person_accompanying_period_social_issues" * ) * @Groups({"read"}) + * @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}) */ private Collection $socialIssues; @@ -606,6 +617,14 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $participation; } + /** + * Remove Participation + */ + + public function removeParticipation(AccompanyingPeriodParticipation $participation) + { + $participation->setAccompanyingPeriod(null); + } /** * Remove Person @@ -1115,4 +1134,17 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $centers ?? null; } + + public function getGroupSequence() + { + if($this->getStep() == self::STEP_DRAFT) + { + return [[self::STEP_DRAFT]]; + } + + if($this->getStep() == self::STEP_CONFIRMED) + { + return [[self::STEP_DRAFT, self::STEP_CONFIRMED]]; + } + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php index a50e28621..48e532e10 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php @@ -33,7 +33,13 @@ use Symfony\Component\Serializer\Annotation\Groups; /** * @ORM\Entity - * @ORM\Table(name="chill_person_accompanying_period_resource") + * @ORM\Table( + * name="chill_person_accompanying_period_resource", + * uniqueConstraints={ + * @ORM\UniqueConstraint(name="person_unique", columns={"person_id", "accompanyingperiod_id"}), + * @ORM\UniqueConstraint(name="thirdparty_unique", columns={"thirdparty_id", "accompanyingperiod_id"}) + * } + * ) * @DiscriminatorMap(typeProperty="type", mapping={ * "accompanying_period_resource"=Resource::class * }) diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php index c873e527a..f246c25bd 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php @@ -134,4 +134,11 @@ class AccompanyingPeriodParticipation { return $this->endDate === null; } + + private function checkSameStartEnd() + { + if($this->endDate == $this->startDate) { + $this->accompanyingPeriod->removeParticipation($this); + } + } } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue index 9c65137bd..ff77f77ce 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue @@ -16,16 +16,16 @@ -
+ diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js index 52f3f6c36..c372ac7a7 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js @@ -86,7 +86,8 @@ const postParticipation = (id, payload, method) => { }) .then(response => { if (response.ok) { return response.json(); } - throw { msg: 'Error while sending AccompanyingPeriod Course participation.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body }; + // TODO: adjust message according to status code? Or how to access the message from the violation array? + throw { msg: 'Error while sending AccompanyingPeriod Course participation', sta: response.status, txt: response.statusText, err: new Error(), body: response.body }; }); }; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/OriginDemand.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/OriginDemand.vue index 30001028c..30ad6afe0 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/OriginDemand.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/OriginDemand.vue @@ -10,13 +10,13 @@ @@ -47,18 +47,18 @@ export default { }, methods: { getOptions() { - //console.log('loading origins list'); getListOrigins().then(response => new Promise((resolve, reject) => { this.options = response.results; resolve(); })); }, updateOrigin(value) { - //console.log('value', value); + console.log('value', value); this.$store.dispatch('updateOrigin', value); }, transText ({ text }) { - return text.fr //TODO multilang + const parsedText = JSON.parse(text); + return parsedText.fr; }, } } diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js index e3fdec4a3..ace482d79 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js @@ -2,6 +2,8 @@ import { createApp } from 'vue' import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n' import { appMessages } from './js/i18n' import { initPromise } from './store' +import VueToast from 'vue-toast-notification'; +import 'vue-toast-notification/dist/theme-sugar.css'; import App from './App.vue'; import Banner from './components/Banner.vue'; @@ -21,6 +23,7 @@ if (root === 'app') { }) .use(store) .use(i18n) + .use(VueToast) .component('app', App) .mount('#accompanying-course'); }); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/store/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/store/index.js index 9b69845cf..41e341dd8 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/store/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/store/index.js @@ -77,7 +77,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise]) }, mutations: { catchError(state, error) { - console.log('### mutation: a new error have been catched and pushed in store !', error); + // console.log('### mutation: a new error have been catched and pushed in store !', error); state.errorMsg.push(error); }, removeParticipation(state, participation) { diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidity.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidity.php index 75c10ca75..b1b660596 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidity.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidity.php @@ -11,7 +11,7 @@ class LocationValidity extends Constraint { public $messagePersonLocatedMustBeAssociated = "The person where the course is located must be associated to the course. Change course's location before removing the person."; - public $messagePeriodMustRemainsLocated = "The period must remains located"; + public $messagePeriodMustRemainsLocated = "The period must remain located"; public function getTargets() { diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php new file mode 100644 index 000000000..38d5516b5 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php @@ -0,0 +1,15 @@ +getStartDate()->getTimezone()); + + foreach ($participations as $participation) { + + if (!$participation instanceof AccompanyingPeriodParticipation) { + throw new UnexpectedTypeException($participation, AccompanyingPeriodParticipation::class); + } + + $personId = $participation->getPerson()->getId(); + + $particpationList[$personId][] = $participation; + + } + + foreach ($particpationList as $group) { + if (count($group) > 1) { + foreach ($group as $p) { + $overlaps->add($p->getStartDate(), $p->getEndDate(), $p->getId()); + } + } + } + + $overlaps->compute(); + + if ($overlaps->hasIntersections()) { + foreach ($overlaps->getIntersections() as list($start, $end, $ids)) { + $msg = $end === null ? $constraint->message : + $constraint->message; + + $this->context->buildViolation($msg) + ->setParameters([ + '{{ start }}' => $start->format('d-m-Y'), + '{{ end }}' => $end === null ? null : $end->format('d-m-Y'), + '{{ ids }}' => $ids, + ]) + ->addViolation(); + } + } + + } +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php new file mode 100644 index 000000000..bfc9d62af --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php @@ -0,0 +1,16 @@ +personRender = $personRender; + $this->thirdpartyRender = $thirdPartyRender; + } + + public function validate($resources, Constraint $constraint) + { + if (!$constraint instanceof ResourceDuplicateCheck) { + throw new UnexpectedTypeException($constraint, ParticipationOverlap::class); + } + + if (!$resources instanceof Collection) { + throw new UnexpectedTypeException($resources, Collection::class); + } + + $resourceList = []; + + foreach ($resources as $resource) { + $id = ($resource->getResource() instanceof Person ? 'p' : + 't').$resource->getResource()->getId(); + + if (\in_array($id, $resourceList, true)) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ name }}', $resource->getResource() instanceof Person ? $this->personRender->renderString($resource->getResource(), []) : + $this->thirdpartyRender->renderString($resource->getResource(), [])) + ->addViolation(); + } + + $resourceList[] = $id; + + } + + } + +} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/config/services/validator.yaml b/src/Bundle/ChillPersonBundle/config/services/validator.yaml new file mode 100644 index 000000000..435f2f5b5 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/config/services/validator.yaml @@ -0,0 +1,6 @@ +services: + Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod: + autowire: true + autoconfigure: true + tags: ['validator.service_arguments'] + \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php b/src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php new file mode 100644 index 000000000..031356cd3 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php @@ -0,0 +1,31 @@ +addSql('CREATE UNIQUE INDEX person_unique ON chill_person_accompanying_period_resource (person_id, accompanyingperiod_id) WHERE person_id IS NOT NULL'); + $this->addSql('CREATE UNIQUE INDEX thirdparty_unique ON chill_person_accompanying_period_resource (thirdparty_id, accompanyingperiod_id) WHERE thirdparty_id IS NOT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP INDEX person_unique'); + $this->addSql('DROP INDEX thirdparty_unique'); + } +} diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php b/src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php new file mode 100644 index 000000000..a4ed54254 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php @@ -0,0 +1,36 @@ +addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT '. + "participations_no_overlap EXCLUDE USING GIST( + -- extension btree_gist required to include comparaison with integer + person_id WITH =, accompanyingperiod_id WITH =, + daterange(startdate, enddate) WITH && + ) + INITIALLY DEFERRED"); + } + + public function down(Schema $schema): void + { + $this->addSql('CREATE UNIQUE INDEX participation_unique ON chill_person_accompanying_period_participation (accompanyingperiod_id, person_id)'); + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml index 0e77dae0c..6d2ccb3cb 100644 --- a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml @@ -41,3 +41,6 @@ household: household_membership: The end date must be after start date: La date de la fin de l'appartenance doit être postérieure à la date de début. Person with membership covering: Une personne ne peut pas appartenir à deux ménages simultanément. Or, avec cette modification, %person_name% appartiendrait à %nbHousehold% ménages à partir du %from%. + +# Accompanying period +'{{ name }} is already associated to this accompanying course.': '{{ name }} est déjà associé avec ce parcours.' \ No newline at end of file From 2b0093a351d8cd01c8b3c8f80d95018ae1af0fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 12 Nov 2021 12:08:48 +0000 Subject: [PATCH 119/135] fix typo --- src/Bundle/ChillMainBundle/translations/messages.fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 7f7801805..082e4c83f 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -74,7 +74,7 @@ Choose a postal code: Choisir un code postal address: address_homeless: L'adresse est-elle celle d'un domicile fixe ? real address: Adresse d'un domicile - consider homeless: Cette addresse est incomplète + consider homeless: Cette adresse est incomplète address more: floor: ét corridor: coul From a04c499af0ca24530fd1ace9027e945adbf4a505 Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 12 Nov 2021 16:01:03 +0100 Subject: [PATCH 120/135] fix when adding multiple pick address type form in a collection --- .../Resources/public/vuejs/Address/mod_input_address_index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js index 0f39c5e75..cb7da6e07 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js @@ -6,12 +6,12 @@ import App from './App.vue'; const i18n = _createI18n(addressMessages); const addAddressInput = (inputs) => { - + console.log(inputs) inputs.forEach(el => { let addressId = el.value, uniqid = el.dataset.inputAddress, - container = document.querySelector('div[data-input-address-container="' + uniqid + '"]'), + container = el.parentNode.querySelector('div[data-input-address-container="' + uniqid + '"]'), isEdit = addressId !== '', addressIdInt = addressId !== '' ? parseInt(addressId) : null ; From e413a09a0f9256eb3319dd236a86152fba1fe9ee Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 12 Nov 2021 16:05:47 +0100 Subject: [PATCH 121/135] upd CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66de80f48..4661dcaa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to ## Unreleased +* [main] fix adding multiple AddresseDeRelais (combine PickAddressType with ChillCollection) + * unnecessary whitespace removed from person banner after person-id + double parentheses removed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/290) * [person]: delete accompanying period work, including related objects (cascade) (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/36) * [address]: Display of incomplete address adjusted. From fa7409bdf85e48c856a29f3b95ca1a15cb5042d4 Mon Sep 17 00:00:00 2001 From: Mathieu Jaumotte Date: Fri, 12 Nov 2021 15:18:41 +0100 Subject: [PATCH 122/135] visgraph: export canvas as image --- .../Resources/public/vuejs/VisGraph/App.vue | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index 3f26eb13b..60db92628 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -8,9 +8,9 @@ - + @@ -231,17 +231,17 @@ export default { this.getRelationsList() }, methods: { - forceUpdateComponent() { - //console.log('!! forceUpdateComponent !!') - this.refreshNetwork - this.$forceUpdate() - }, initGraph() { this.container = document.getElementById('visgraph') // Instanciate vis objects in separate window variables, see vis-network.js window.network = new vis.Network(this.container, this.visgraph_data, window.options) }, + forceUpdateComponent() { + //console.log('!! forceUpdateComponent !!') + this.refreshNetwork + this.$forceUpdate() + }, // events listenOnGraph() { @@ -444,6 +444,41 @@ export default { default: throw "uncaught action" } + }, + + // export image + exportCanvasAsImage() { + const canvas = document.getElementById('visgraph') + .querySelector('canvas') + console.log(canvas) + + let link = document.getElementById('exportCanvasBtn') + link.download = "filiation.png" + + canvas.toBlob(blob => { + console.log(blob) + link.href = URL.createObjectURL(blob) + }, 'image/png') + + /* + TODO improve feature + + // 1. fonctionne, mais pas de contrôle sur le nom + if (canvas && canvas.getContext('2d')) { + let img = canvas.toDataURL('image/png;base64;') + img = img.replace('image/png','image/octet-stream') + window.open(img, '', 'width=1000, height=1000') + } + + // 2. fonctionne, mais 2 click et pas compatible avec tous les browsers + let link = document.getElementById('exportCanvasBtn') + link.download = "image.png" + canvas.toBlob(blob => { + link.href = URL.createObjectURL(blob) + }, 'image/png') + */ + + } } } From 5651efe44d3847d8c1ec8c4e4dd4d68df58db21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 12 Nov 2021 17:50:12 +0100 Subject: [PATCH 123/135] fix phpstan errors --- phpstan-baseline.neon | 5 ----- .../Controller/AccompanyingCourseWorkController.php | 7 ++++--- .../ChillPersonBundle/Entity/AccompanyingPeriod.php | 9 +++++---- .../AccompanyingPeriod/ParticipationOverlapValidator.php | 9 +++++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e578c1d45..d2128437a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -905,11 +905,6 @@ parameters: count: 1 path: src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php - - - message: "#^Call to function array_search\\(\\) requires parameter \\#3 to be set\\.$#" - count: 1 - path: src/Bundle/ChillMainBundle/Util/DateRangeCovering.php - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" count: 2 diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php index 3625c7cca..cf935b7c3 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php @@ -22,7 +22,7 @@ class AccompanyingCourseWorkController extends AbstractController private SerializerInterface $serializer; private AccompanyingPeriodWorkRepository $workRepository; private PaginatorFactory $paginator; - protected LoggerInterface $logger; + private LoggerInterface $chillLogger; public function __construct( TranslatorInterface $trans, @@ -35,7 +35,7 @@ class AccompanyingCourseWorkController extends AbstractController $this->serializer = $serializer; $this->workRepository = $workRepository; $this->paginator = $paginator; - $this->logger = $logger; + $this->chillLogger = $chillLogger; } /** @@ -133,7 +133,7 @@ class AccompanyingCourseWorkController extends AbstractController if ($form->isValid()) { - $this->logger->notice("An accompanying period work has been removed", [ + $this->chillLogger->notice("An accompanying period work has been removed", [ 'by_user' => $this->getUser()->getUsername(), 'work_id' => $work->getId(), 'accompanying_period_id' => $work->getAccompanyingPeriod()->getId() @@ -162,6 +162,7 @@ class AccompanyingCourseWorkController extends AbstractController private function createDeleteForm(int $id): Form { + $params = []; $params['id'] = $id; return $this->createFormBuilder() diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index dab1dcb9d..6c9c84b56 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -1137,14 +1137,15 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface public function getGroupSequence() { - if($this->getStep() == self::STEP_DRAFT) + if ($this->getStep() == self::STEP_DRAFT) { return [[self::STEP_DRAFT]]; - } - - if($this->getStep() == self::STEP_CONFIRMED) + } elseif ($this->getStep() == self::STEP_CONFIRMED) { return [[self::STEP_DRAFT, self::STEP_CONFIRMED]]; } + + throw new \LogicException("no validation group permitted with this step"); + } } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlapValidator.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlapValidator.php index ef9868420..50c71998b 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlapValidator.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlapValidator.php @@ -30,6 +30,7 @@ class ParticipationOverlapValidator extends ConstraintValidator } $overlaps = new DateRangeCovering(self::MAX_PARTICIPATION, $participations[0]->getStartDate()->getTimezone()); + $participationList = []; foreach ($participations as $participation) { @@ -38,12 +39,12 @@ class ParticipationOverlapValidator extends ConstraintValidator } $personId = $participation->getPerson()->getId(); - - $particpationList[$personId][] = $participation; + + $participationList[$personId][] = $participation; } - foreach ($particpationList as $group) { + foreach ($participationList as $group) { if (count($group) > 1) { foreach ($group as $p) { $overlaps->add($p->getStartDate(), $p->getEndDate(), $p->getId()); @@ -69,4 +70,4 @@ class ParticipationOverlapValidator extends ConstraintValidator } } -} \ No newline at end of file +} From b07188eaaf04c2b79f24babbe151a02a52083058 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 15 Nov 2021 10:21:57 +0100 Subject: [PATCH 124/135] changelog updated --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c8fecc02..6c85f102b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,6 @@ and this project adheres to * [household]: household addresses ordered by ValidFrom date and by id to show the last created address on top. * [socialWorkAction]: display of social issue and parent issues + banner context added. * [DBAL dependencies] Upgrade to DBAL 3.1 -* [person]: double parentheses removed around age in banner + whitespace ### Test release 2021-10-27 From 4ba93bb70996e0566658868e9822e43b588d08ad Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 15 Nov 2021 11:56:29 +0100 Subject: [PATCH 125/135] failed job personControllerUpdateTest fixed --- .../Tests/Controller/PersonControllerUpdateTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php index 8a8c04538..6620a7c38 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php @@ -259,7 +259,7 @@ class PersonControllerUpdateTest extends WebTestCase return array( ['firstName', 'random Value', function(Person $person) { return $person->getFirstName(); } ], ['lastName' , 'random Value', function(Person $person) { return $person->getLastName(); } ], - ['placeOfBirth', 'none place', function(Person $person) { return $person->getPlaceOfBirth(); }], + ['placeOfBirth', 'NONE PLACE', function(Person $person) { return $person->getPlaceOfBirth(); }], ['birthdate', '1980-12-15', function(Person $person) { return $person->getBirthdate()->format('Y-m-d'); }], ['phonenumber', '+32123456789', function(Person $person) { return $person->getPhonenumber(); }], ['memo', 'jfkdlmq jkfldmsq jkmfdsq', function(Person $person) { return $person->getMemo(); }], From 3417aa8207963cd7eae4b88bf09fc7fb9211fef3 Mon Sep 17 00:00:00 2001 From: nobohan Date: Mon, 15 Nov 2021 12:00:42 +0100 Subject: [PATCH 126/135] person: do not suggest the current household of the person --- .../Controller/HouseholdApiController.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php index 11e41ba29..3f3e04cb3 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php @@ -47,13 +47,22 @@ class HouseholdApiController extends ApiController $count = $this->householdRepository->countByAccompanyingPeriodParticipation($person); $paginator = $this->getPaginatorFactory()->create($count); - if ($count === 0) { - $households = []; - } else { - $households = $this->householdRepository->findByAccompanyingPeriodParticipation($person, + $households = []; + if ($count !== 0) { + $allHouseholds = $this->householdRepository->findByAccompanyingPeriodParticipation($person, $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); - } + $currentHouseholdPerson = $person->getCurrentHousehold(); + foreach ($allHouseholds as $h) { + if ($h !== $currentHouseholdPerson) { + array_push($households, $h); + } + } + if (null !== $currentHouseholdPerson) { + $count = $count - 1; + $paginator = $this->getPaginatorFactory()->create($count); + } + } $collection = new Collection($households, $paginator); return $this->json($collection, Response::HTTP_OK, [], From bfc25c50b926905e5793081c659321335d7a81f1 Mon Sep 17 00:00:00 2001 From: nobohan Date: Mon, 15 Nov 2021 12:03:31 +0100 Subject: [PATCH 127/135] upd CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66de80f48..b2b969c66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to ## Unreleased +* [person]: do not suggest the current household of the person (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/51) + * unnecessary whitespace removed from person banner after person-id + double parentheses removed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/290) * [person]: delete accompanying period work, including related objects (cascade) (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/36) * [address]: Display of incomplete address adjusted. From 8296d60cb6f86b75e542095f0bc7030151e40584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 15 Nov 2021 11:17:03 +0000 Subject: [PATCH 128/135] add base authorization to person search + improve search ordering --- CHANGELOG.md | 2 + phpstan-baseline.neon | 20 ---- .../DataFixtures/ORM/LoadActivity.php | 29 +++--- .../config/services/fixtures.yaml | 2 + .../DataFixtures/ORM/LoadCalendarRange.php | 13 ++- .../DataFixtures/ORM/LoadDocumentACL.php | 14 +-- .../DataFixtures/ORM/LoadRolesACL.php | 20 ++-- .../ChillMainBundle/Search/SearchApi.php | 6 +- .../ChillMainBundle/Search/SearchApiQuery.php | 57 +++++++---- .../Test/PrepareClientTrait.php | 1 - .../Tests/Search/SearchApiQueryTest.php | 7 +- .../AccompanyingCourseApiController.php | 10 +- .../Helper/PersonRandomHelper.php | 40 ++++++++ .../DataFixtures/ORM/LoadPeople.php | 2 +- .../DataFixtures/ORM/LoadRelations.php | 47 +++++---- .../DataFixtures/ORM/LoadRelationships.php | 44 +++++++-- .../Relationships/RelationRepository.php | 2 +- .../Relationships/RelationshipRepository.php | 7 +- .../Search/SearchPersonApiProvider.php | 46 ++++++++- .../Controller/PersonControllerUpdateTest.php | 3 +- .../RelationshipApiControllerTest.php | 95 +++++++++++++++---- .../config/services/fixtures.yaml | 1 + 22 files changed, 317 insertions(+), 151 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 875f8c34a..5139087a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ and this project adheres to * add form to create/edit/delete relationship link, * improve graph refresh mechanism * add feature to export canvas as image (png) +* [person suggest] In widget "add person", improve the pertinence of persons when one of the names starts with the pattern; + ## Test releases diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d2128437a..b88679016 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -10,16 +10,6 @@ parameters: count: 4 path: src/Bundle/ChillActivityBundle/Controller/ActivityController.php - - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" - count: 1 - path: src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php - - - - message: "#^Variable \\$activity might not be defined\\.$#" - count: 1 - path: src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" count: 1 @@ -305,11 +295,6 @@ parameters: count: 1 path: src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php - - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" - count: 1 - path: src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 1 @@ -325,11 +310,6 @@ parameters: count: 3 path: src/Bundle/ChillEventBundle/Controller/ParticipationController.php - - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" - count: 1 - path: src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" count: 1 diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php index a23b2d73f..18a6f83d3 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php @@ -22,8 +22,10 @@ namespace Chill\ActivityBundle\DataFixtures\ORM; +use Chill\PersonBundle\Entity\Person; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ObjectManager; use Faker\Factory as FakerFactory; use Chill\ActivityBundle\Entity\Activity; @@ -31,25 +33,19 @@ use Chill\MainBundle\DataFixtures\ORM\LoadUsers; use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityReason; use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityType; use Chill\MainBundle\DataFixtures\ORM\LoadScopes; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -/** - * Load reports into DB - * - * @author Champs-Libres Coop - */ -class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface +class LoadActivity extends AbstractFixture implements OrderedFixtureInterface { - use \Symfony\Component\DependencyInjection\ContainerAwareTrait; - /** * @var \Faker\Generator */ private $faker; + private EntityManagerInterface $em; - public function __construct() + public function __construct(EntityManagerInterface $em) { $this->faker = FakerFactory::create('fr_FR'); + $this->em = $em; } public function getOrder() @@ -88,7 +84,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C { $reasonRef = LoadActivityReason::$references[array_rand(LoadActivityReason::$references)]; - if (in_array($this->getReference($reasonRef)->getId(), $excludingIds)) { + if (in_array($this->getReference($reasonRef)->getId(), $excludingIds, true)) { // we have a reason which should be excluded. Find another... return $this->getRandomActivityReason($excludingIds); } @@ -132,20 +128,17 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C public function load(ObjectManager $manager) { - $persons = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillPersonBundle:Person') + $persons = $this->em + ->getRepository(Person::class) ->findAll(); - foreach($persons as $person) { + foreach ($persons as $person) { $activityNbr = rand(0,3); - $ref = 'activity_'.$person->getFullnameCanonical(); - for($i = 0; $i < $activityNbr; $i ++) { + for ($i = 0; $i < $activityNbr; $i ++) { $activity = $this->newRandomActivity($person); $manager->persist($activity); } - - $this->setReference($ref, $activity); } $manager->flush(); } diff --git a/src/Bundle/ChillActivityBundle/config/services/fixtures.yaml b/src/Bundle/ChillActivityBundle/config/services/fixtures.yaml index 4851b7838..900453a67 100644 --- a/src/Bundle/ChillActivityBundle/config/services/fixtures.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/fixtures.yaml @@ -1,4 +1,6 @@ services: Chill\ActivityBundle\DataFixtures\ORM\: + autowire: true + autoconfigure: true resource: ../../DataFixtures/ORM tags: [ 'doctrine.fixture.orm' ] diff --git a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php index 0bf19418f..c23871c26 100644 --- a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php +++ b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php @@ -5,21 +5,20 @@ namespace Chill\CalendarBundle\DataFixtures\ORM; use Chill\CalendarBundle\Entity\CalendarRange; use Chill\MainBundle\DataFixtures\ORM\LoadUsers; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Repository\UserRepository; use DateTimeImmutable; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; -use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ObjectManager; class LoadCalendarRange extends Fixture implements FixtureGroupInterface, OrderedFixtureInterface { - public function __construct( - EntityManagerInterface $em + UserRepository $userRepository ) { - $this->userRepository = $em->getRepository(User::class); + $this->userRepository = $userRepository; } public function getOrder(): int @@ -37,7 +36,7 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere public function load(ObjectManager $manager): void { $arr = range(-50, 50); - + print "Creating calendar range ('plage de disponibilités')\n"; $users = $this->userRepository->findAll(); @@ -70,7 +69,7 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere ->setUser($u) ->setStartDate($startEvent) ->setEndDate($endEvent); - + $manager->persist($calendarRange); } @@ -79,4 +78,4 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere } $manager->flush(); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php b/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php index 0f4577ffd..ec1773640 100644 --- a/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php +++ b/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php @@ -38,7 +38,7 @@ class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface return 35000; } - + public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { @@ -57,15 +57,15 @@ class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface break; case 'administrative': case 'direction': - if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + if (in_array($scope->getName()['en'], array('administrative', 'social'), true)) { printf("denying power on %s\n", $scope->getName()['en']); break 2; // we do not want any power on social or administrative - } + } break; } - + printf("Adding Person report acl to %s " - . "permission group, scope '%s' \n", + . "permission group, scope '%s' \n", $permissionsGroup->getName(), $scope->getName()['en']); $roleScopeUpdate = (new RoleScope()) ->setRole(PersonDocumentVoter::CREATE) @@ -83,9 +83,9 @@ class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface $manager->persist($roleScopeCreate); $manager->persist($roleScopeDelete); } - + } - + $manager->flush(); } diff --git a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php index 7ef753e52..be95880e8 100644 --- a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php +++ b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php @@ -50,19 +50,19 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface break; case 'administrative': case 'direction': - if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + if (in_array($scope->getName()['en'], array('administrative', 'social'), true)) { break 2; // we do not want any power on social or administrative - } + } break; } - + printf("Adding CHILL_EVENT_UPDATE & CHILL_EVENT_CREATE " . "& CHILL_EVENT_PARTICIPATION_UPDATE & CHILL_EVENT_PARTICIPATION_CREATE " . "& CHILL_EVENT_SEE & CHILL_EVENT_SEE_DETAILS " . "to %s " - . "permission group, scope '%s' \n", + . "permission group, scope '%s' \n", $permissionsGroup->getName(), $scope->getName()['en']); - + $roleScopeUpdate = (new RoleScope()) ->setRole('CHILL_EVENT_UPDATE') ->setScope($scope); @@ -71,7 +71,7 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeUpdate); $permissionsGroup->addRoleScope($roleScopeUpdate2); - + $roleScopeCreate = (new RoleScope()) ->setRole('CHILL_EVENT_CREATE') ->setScope($scope); @@ -80,7 +80,7 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreate); $permissionsGroup->addRoleScope($roleScopeCreate2); - + $roleScopeSee = (new RoleScope()) ->setRole('CHILL_EVENT_SEE') ->setScope($scope); @@ -89,7 +89,7 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeSee); $permissionsGroup->addRoleScope($roleScopeSee2); - + $manager->persist($roleScopeUpdate); $manager->persist($roleScopeUpdate2); $manager->persist($roleScopeCreate); @@ -97,9 +97,9 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface $manager->persist($roleScopeSee); $manager->persist($roleScopeSee2); } - + } - + $manager->flush(); } diff --git a/src/Bundle/ChillMainBundle/Search/SearchApi.php b/src/Bundle/ChillMainBundle/Search/SearchApi.php index 0a7aa1737..877f1c330 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchApi.php +++ b/src/Bundle/ChillMainBundle/Search/SearchApi.php @@ -88,13 +88,13 @@ class SearchApi private function buildCountQuery(array $queries, $types, $parameters) { - $query = "SELECT COUNT(sq.key) AS count FROM ({union_unordered}) AS sq"; + $query = "SELECT COUNT(*) AS count FROM ({union_unordered}) AS sq"; $unions = []; $parameters = []; foreach ($queries as $q) { - $unions[] = $q->buildQuery(); - $parameters = \array_merge($parameters, $q->buildParameters()); + $unions[] = $q->buildQuery(true); + $parameters = \array_merge($parameters, $q->buildParameters(true)); } $unionUnordered = \implode(" UNION ", $unions); diff --git a/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php b/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php index 9188c0b5c..095d49b43 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php +++ b/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php @@ -76,33 +76,58 @@ class SearchApiQuery return $this; } - public function buildQuery(): string + public function buildQuery(bool $countOnly = false): string { - $where = \implode(' AND ', $this->whereClauses); + $isMultiple = count($this->whereClauses); + $where = + ($isMultiple ? '(' : ''). + \implode( + ($isMultiple ? ')' : '').' AND '.($isMultiple ? '(' : '') + , $this->whereClauses). + ($isMultiple ? ')' : '') + ; - return \strtr("SELECT + if (!$countOnly) { + $select = \strtr(" '{key}' AS key, {metadata} AS metadata, {pertinence} AS pertinence - FROM {from} - WHERE {where} + ", [ + '{key}' => $this->selectKey, + '{metadata}' => $this->jsonbMetadata, + '{pertinence}' => $this->pertinence, + ]); + } else { + $select = "1 AS c"; + } + + return \strtr("SELECT + {select} + FROM {from} + WHERE {where} ", [ - '{key}' => $this->selectKey, - '{metadata}' => $this->jsonbMetadata, - '{pertinence}' => $this->pertinence, + '{select}' => $select, '{from}' => $this->fromClause, '{where}' => $where, ]); } - public function buildParameters(): array + + public function buildParameters(bool $countOnly = false): array { - return \array_merge( - $this->selectKeyParams, - $this->jsonbMetadataParams, - $this->pertinenceParams, - $this->fromClauseParams, - \array_merge([], ...$this->whereClausesParams), - ); + if (!$countOnly) { + return \array_merge( + $this->selectKeyParams, + $this->jsonbMetadataParams, + $this->pertinenceParams, + $this->fromClauseParams, + \array_merge([], ...$this->whereClausesParams), + ); + } else { + return \array_merge( + $this->fromClauseParams, + \array_merge([], ...$this->whereClausesParams), + ); + } } } diff --git a/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php b/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php index 5df0b57dd..4440f2eef 100644 --- a/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php +++ b/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php @@ -30,7 +30,6 @@ trait PrepareClientTrait * * @param string $username the username (default 'center a_social') * @param string $password the password (default 'password') - * @return \Symfony\Component\BrowserKit\Client * @throws \LogicException */ public function getClientAuthenticated( diff --git a/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php b/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php index 2e63f24e0..6aeb835e7 100644 --- a/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php @@ -20,7 +20,12 @@ class SearchApiQueryTest extends TestCase $query = $q->buildQuery(); - $this->assertStringContainsString('foo AND bar', $query); + $this->assertStringContainsString('(foo) AND (bar)', $query); + $this->assertEquals(['alpha', 'beta'], $q->buildParameters()); + + $query = $q->buildQuery(true); + + $this->assertStringContainsString('(foo) AND (bar)', $query); $this->assertEquals(['alpha', 'beta'], $q->buildParameters()); } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index c2a8f6e2c..0941dd7d4 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -28,14 +28,12 @@ use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository; use Symfony\Component\Workflow\Registry; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; -class AccompanyingCourseApiController extends ApiController +final class AccompanyingCourseApiController extends ApiController { - protected EventDispatcherInterface $eventDispatcher; - - protected ValidatorInterface $validator; - + private AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository; + private EventDispatcherInterface $eventDispatcher; + private ValidatorInterface $validator; private Registry $registry; - private ReferralsSuggestionInterface $referralAvailable; public function __construct( diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php new file mode 100644 index 000000000..0f7068751 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php @@ -0,0 +1,40 @@ +countPersons) { + $qb = $em->createQueryBuilder(); + $this->countPersons = $qb->select('count(p)') + ->from(Person::class, 'p') + ->getQuery() + ->getSingleScalarResult() + ; + } + + if ([] === $this->randPersons) { + $qb = $em->createQueryBuilder(); + $this->randPersons = $qb + ->select('p') + ->from(Person::class, 'p') + ->getQuery() + ->setFirstResult(\random_int(0, $this->countPersons - $fetchBy)) + ->setMaxResults($fetchBy) + ->getResult() + ; + } + + return \array_pop($this->randPersons); + } + +} diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php index 35d11475c..df471aedd 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php @@ -262,7 +262,7 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con $manager->persist($accompanyingPeriod); echo "add person'".$person->__toString()."'\n"; - $this->addReference(self::PERSON, $person); + $this->addReference(self::PERSON.$person->getId(), $person); } private function getRandomUser(): User diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php index f433f2402..3b2b4518e 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php @@ -10,7 +10,26 @@ use Doctrine\Persistence\ObjectManager; class LoadRelations extends Fixture implements FixtureGroupInterface { - public const RELATIONS = 'relations'; + public const RELATION_KEY = 'relations'; + public const RELATIONS = [ + ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fille']], + ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fils']], + ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fille']], + ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fils']], + + ['title' => ['fr' => 'Frère'], 'reverseTitle' => ['fr' => 'Frère']], + ['title' => ['fr' => 'Soeur'], 'reverseTitle' => ['fr' => 'Soeur']], + ['title' => ['fr' => 'Frère'], 'reverseTitle' => ['fr' => 'Soeur']], + + ['title' => ['fr' => 'Demi-frère'], 'reverseTitle' => ['fr' => 'Demi-frère']], + ['title' => ['fr' => 'Demi-soeur'], 'reverseTitle' => ['fr' => 'Demi-soeur']], + ['title' => ['fr' => 'Demi-frère'], 'reverseTitle' => ['fr' => 'Demi-soeur']], + + ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Neveu']], + ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Nièce']], + ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Neveu']], + ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Nièce']], + ]; public static function getGroups(): array { @@ -19,37 +38,17 @@ class LoadRelations extends Fixture implements FixtureGroupInterface public function load(ObjectManager $manager) { - $relations = [ - ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fille']], - ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fils']], - ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fille']], - ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fils']], - - ['title' => ['fr' => 'Frère'], 'reverseTitle' => ['fr' => 'Frère']], - ['title' => ['fr' => 'Soeur'], 'reverseTitle' => ['fr' => 'Soeur']], - ['title' => ['fr' => 'Frère'], 'reverseTitle' => ['fr' => 'Soeur']], - - ['title' => ['fr' => 'Demi-frère'], 'reverseTitle' => ['fr' => 'Demi-frère']], - ['title' => ['fr' => 'Demi-soeur'], 'reverseTitle' => ['fr' => 'Demi-soeur']], - ['title' => ['fr' => 'Demi-frère'], 'reverseTitle' => ['fr' => 'Demi-soeur']], - - ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Neveu']], - ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Nièce']], - ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Neveu']], - ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Nièce']], - ]; - - foreach($relations as $value){ + foreach (self::RELATIONS as $key => $value){ print "Creating a new relation type: relation" . $value['title']['fr'] . "reverse relation: " . $value['reverseTitle']['fr'] . "\n"; $relation = new Relation(); $relation->setTitle($value['title']) ->setReverseTitle($value['reverseTitle']); $manager->persist($relation); - $this->addReference(self::RELATIONS, $relation); + + $this->addReference(self::RELATION_KEY.$key, $relation); } $manager->flush(); - } } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php index 5efc68400..cce6d0365 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php @@ -3,17 +3,24 @@ declare(strict_types=1); namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\MainBundle\DataFixtures\ORM\LoadUsers; +use Chill\MainBundle\Entity\User; +use Chill\PersonBundle\DataFixtures\Helper\PersonRandomHelper; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\DependentFixtureInterface; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ObjectManager; -use Chill\PersonBundle\DataFixtures\ORM\LoadPeople; -use Chill\PersonBundle\DataFixtures\ORM\LoadRelations; use Chill\PersonBundle\Entity\Relationships\Relationship; class LoadRelationships extends Fixture implements DependentFixtureInterface { + use PersonRandomHelper; + private EntityManagerInterface $em; - + public function __construct(EntityManagerInterface $em) + { + $this->em = $em; + } public function getDependencies() { @@ -21,16 +28,33 @@ class LoadRelationships extends Fixture implements DependentFixtureInterface LoadPeople::class, LoadRelations::class ]; - } public function load(ObjectManager $manager) { - $relationship = new Relationship; - $relationship->setFromPerson($this->getReference(LoadPeople::PERSON)); - $relationship->setToPerson($this->getReference(LoadPeople::PERSON)); - $relationship->setRelation($this->getReference(LoadRelations::RELATIONS)); - $relationship->setReverse((bool)random_int(0, 1)); + for ($i = 0; $i < 15; $i++) { + $user = $this->getRandomUser(); + $date = new \DateTimeImmutable(); + $relationship = (new Relationship()) + ->setFromPerson($this->getRandomPerson($this->em)) + ->setToPerson($this->getRandomPerson($this->em)) + ->setRelation($this->getReference(LoadRelations::RELATION_KEY. + \random_int(0, count(LoadRelations::RELATIONS) - 1))) + ->setReverse((bool) random_int(0, 1)) + ->setCreatedBy($user) + ->setUpdatedBy($user) + ->setCreatedAt($date) + ->setUpdatedAt($date) + ; + $manager->persist($relationship); + } + + $manager->flush(); } -} \ No newline at end of file + private function getRandomUser(): User + { + $userRef = array_rand(LoadUsers::$refs); + return $this->getReference($userRef); + } +} diff --git a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php index b735138f4..b68055581 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php @@ -37,6 +37,6 @@ class RelationRepository implements ObjectRepository public function getClassName(): string { - return MaritalStatus::class; + return Relation::class; } } diff --git a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php index 3f105537a..7e5f2af24 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php @@ -10,7 +10,6 @@ use Doctrine\Persistence\ObjectRepository; class RelationshipRepository implements ObjectRepository { - private EntityRepository $repository; public function __construct(EntityManagerInterface $em) @@ -40,9 +39,9 @@ class RelationshipRepository implements ObjectRepository public function getClassName(): string { - return MaritalStatus::class; + return Relationship::class; } - + public function findByPerson($personId): array { // return all relationships of which person is part? or only where person is the fromPerson? @@ -56,5 +55,5 @@ class RelationshipRepository implements ObjectRepository ->getResult() ; } - + } diff --git a/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php b/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php index dd0ae67c7..60122dbc2 100644 --- a/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php +++ b/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php @@ -2,29 +2,43 @@ namespace Chill\PersonBundle\Search; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Chill\PersonBundle\Repository\PersonRepository; use Chill\MainBundle\Search\SearchApiQuery; use Chill\MainBundle\Search\SearchApiInterface; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Symfony\Component\Security\Core\Security; class SearchPersonApiProvider implements SearchApiInterface { private PersonRepository $personRepository; + private Security $security; + private AuthorizationHelperInterface $authorizationHelper; - public function __construct(PersonRepository $personRepository) + public function __construct(PersonRepository $personRepository, Security $security, AuthorizationHelperInterface $authorizationHelper) { $this->personRepository = $personRepository; + $this->security = $security; + $this->authorizationHelper = $authorizationHelper; } public function provideQuery(string $pattern, array $parameters): SearchApiQuery + { + return $this->addAuthorizations($this->buildBaseQuery($pattern, $parameters)); + } + + public function buildBaseQuery(string $pattern, array $parameters): SearchApiQuery { $query = new SearchApiQuery(); $query ->setSelectKey("person") ->setSelectJsonbMetadata("jsonb_build_object('id', person.id)") - ->setSelectPertinence("GREATEST(". - "STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), person.fullnamecanonical), ". - "(person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%')::int". - ")", [ $pattern, $pattern ]) + ->setSelectPertinence("". + "STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), person.fullnamecanonical) + ". + "(person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%')::int + ". + "(EXISTS (SELECT 1 FROM unnest(string_to_array(fullnamecanonical, ' ')) AS t WHERE starts_with(t, UNACCENT(LOWER(?)))))::int" + , [ $pattern, $pattern, $pattern ]) ->setFromClause("chill_person_person AS person") ->setWhereClauses("LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ". "person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%' ", [ $pattern, $pattern ]) @@ -33,6 +47,28 @@ class SearchPersonApiProvider implements SearchApiInterface return $query; } + private function addAuthorizations(SearchApiQuery $query): SearchApiQuery + { + $authorizedCenters = $this->authorizationHelper + ->getReachableCenters($this->security->getUser(), PersonVoter::SEE); + + if ([] === $authorizedCenters) { + return $query->andWhereClause("FALSE = TRUE", []); + } + + return $query + ->andWhereClause( + strtr( + "person.center_id IN ({{ center_ids }})", + [ + '{{ center_ids }}' => \implode(', ', + \array_fill(0, count($authorizedCenters), '?')), + ] + ), + \array_map(function(Center $c) {return $c->getId();}, $authorizedCenters) + ); + } + public function supportsTypes(string $pattern, array $types, array $parameters): bool { return \in_array('person', $types); diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php index 6620a7c38..7e18c7c65 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php @@ -259,7 +259,8 @@ class PersonControllerUpdateTest extends WebTestCase return array( ['firstName', 'random Value', function(Person $person) { return $person->getFirstName(); } ], ['lastName' , 'random Value', function(Person $person) { return $person->getLastName(); } ], - ['placeOfBirth', 'NONE PLACE', function(Person $person) { return $person->getPlaceOfBirth(); }], + // reminder: this value is capitalized + ['placeOfBirth', 'A PLACE', function(Person $person) { return $person->getPlaceOfBirth(); }], ['birthdate', '1980-12-15', function(Person $person) { return $person->getBirthdate()->format('Y-m-d'); }], ['phonenumber', '+32123456789', function(Person $person) { return $person->getPhonenumber(); }], ['memo', 'jfkdlmq jkfldmsq jkmfdsq', function(Person $person) { return $person->getMemo(); }], diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php index 6d538a646..293dd1a10 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php @@ -2,23 +2,32 @@ declare(strict_types=1); namespace Chill\PersonBundle\Tests\Controller; +use Chill\MainBundle\Test\PrepareClientTrait; +use Chill\PersonBundle\DataFixtures\Helper\PersonRandomHelper; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Entity\Relationships\Relation; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Component\HttpFoundation\Request; use Chill\PersonBundle\Repository\PersonRepository; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class RelationshipApiControllerTest extends WebTestCase { - public static function setUpBeforeClass() - { - static::bootKernel(); - } + use PrepareClientTrait; + + private KernelBrowser $client; + + /** + * A cache for all relations + * @var array|null|Relation[] + */ + private ?array $relations = null; public function setUp() { - $this->client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'fred', - 'PHP_AUTH_PW' => 'password', - )); + static::bootKernel(); + $this->client = $this->getClientAuthenticated(); } /** @@ -38,11 +47,11 @@ class RelationshipApiControllerTest extends WebTestCase public function testPostRelationship($fromPersonId, $toPersonId, $relationId, $isReverse): void { - $this->client->request(Request::METHOD_POST, - '/api/1.0/person/relations/relationship.json', + $this->client->request(Request::METHOD_POST, + '/api/1.0/relations/relationship.json', + [], [], [], - [], \json_encode([ 'type' => 'relationship', 'fromPerson' => ['id' => $fromPersonId, 'type' => 'person'], @@ -57,18 +66,72 @@ class RelationshipApiControllerTest extends WebTestCase public function relationProvider(): array { - //TODO: which different cases to test? + static::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + $countPersons = $em->createQueryBuilder() + ->select('count(p)') + ->from(Person::class, 'p') + ->join('p.center', 'c') + ->where('c.name LIKE :name') + ->setParameter('name', 'Center A') + ->getQuery() + ->getSingleScalarResult() + ; + $persons = $em->createQueryBuilder() + ->select('p') + ->from(Person::class, 'p') + ->join('p.center', 'c') + ->where('c.name LIKE :name') + ->setParameter('name', 'Center A') + ->getQuery() + ->setMaxResults(2) + ->setFirstResult(\random_int(0, $countPersons - 1)) + ->getResult() + ; + return [ - [333, 334, 1, true], + [$persons[0]->getId(), $persons[1]->getId(), $this->getRandomRelation($em)->getId(), true], ]; } + private function getRandomRelation(EntityManagerInterface $em): Relation + { + if (null === $this->relations) { + $this->relations = $em->getRepository(Relation::class) + ->findAll(); + } + + return $this->relations[\array_rand($this->relations)]; + } + public function personProvider(): array { - //TODO: which different cases to test? + static::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + $countPersons = $em->createQueryBuilder() + ->select('count(p)') + ->from(Person::class, 'p') + ->join('p.center', 'c') + ->where('c.name LIKE :name') + ->setParameter('name', 'Center A') + ->getQuery() + ->getSingleScalarResult() + ; + $person = $em->createQueryBuilder() + ->select('p') + ->from(Person::class, 'p') + ->join('p.center', 'c') + ->where('c.name LIKE :name') + ->setParameter('name', 'Center A') + ->getQuery() + ->setMaxResults(1) + ->setFirstResult(\random_int(0, $countPersons - 1)) + ->getSingleResult() + ; + return [ - [333], + [$person->getId()], ]; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/config/services/fixtures.yaml b/src/Bundle/ChillPersonBundle/config/services/fixtures.yaml index 72bf899f4..753521ad7 100644 --- a/src/Bundle/ChillPersonBundle/config/services/fixtures.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/fixtures.yaml @@ -1,6 +1,7 @@ services: Chill\PersonBundle\DataFixtures\ORM\: autowire: true + autoconfigure: true resource: ../../DataFixtures/ORM tags: [ 'doctrine.fixture.orm' ] From 6c51d6de51bfcabaac4880c512e08ab488be3a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 15 Nov 2021 12:28:48 +0100 Subject: [PATCH 129/135] remove unnecessary space (minor, [ci-skip]) --- .../Tests/Controller/RelationshipApiControllerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php index 293dd1a10..ac785f781 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php @@ -44,7 +44,6 @@ class RelationshipApiControllerTest extends WebTestCase /** * @dataProvider relationProvider */ - public function testPostRelationship($fromPersonId, $toPersonId, $relationId, $isReverse): void { $this->client->request(Request::METHOD_POST, From 5ee67f74d9e1d739bbcb789f149d68c82a90aa70 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 15 Nov 2021 13:05:27 +0100 Subject: [PATCH 130/135] remove toast imports for vue --- .../Resources/public/vuejs/AccompanyingCourse/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js index ace482d79..fe01abd19 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js @@ -2,8 +2,6 @@ import { createApp } from 'vue' import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n' import { appMessages } from './js/i18n' import { initPromise } from './store' -import VueToast from 'vue-toast-notification'; -import 'vue-toast-notification/dist/theme-sugar.css'; import App from './App.vue'; import Banner from './components/Banner.vue'; From e2d4d9c831d8d7651e1e7da7d799680b310dc269 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 15 Nov 2021 13:07:44 +0100 Subject: [PATCH 131/135] remove use statement --- .../Resources/public/vuejs/AccompanyingCourse/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js index fe01abd19..e3fdec4a3 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/index.js @@ -21,7 +21,6 @@ if (root === 'app') { }) .use(store) .use(i18n) - .use(VueToast) .component('app', App) .mount('#accompanying-course'); }); From b217fb3c3984ecc996636a0a5082cee370b02d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 15 Nov 2021 13:06:31 +0100 Subject: [PATCH 132/135] create option config for asking (or not) center in form --- .../ChillMainBundle/DependencyInjection/Configuration.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php index be1281ee6..7cf3aed50 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php @@ -104,6 +104,9 @@ class Configuration implements ConfigurationInterface ->booleanNode('form_show_scopes') ->defaultTrue() ->end() + ->booleanNode('form_show_centers') + ->defaultTrue() + ->end() ->end() ->end() ->arrayNode('redis') From 77add46a703148017dbcf7c6aa3e5feda7b99386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 15 Nov 2021 13:06:47 +0100 Subject: [PATCH 133/135] take parameter `form_show_center` into account: not to ask center on person creation --- .../ChillPersonBundle/Entity/Person.php | 8 +++---- .../Form/CreationPersonType.php | 22 +++++++++++++------ .../Person/PersonHasCenterValidator.php | 7 ++++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index b1048ea60..7aacf6ba8 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -1182,9 +1182,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI * @param string $phonenumber * @return Person */ - public function setPhonenumber($phonenumber = '') + public function setPhonenumber(?string $phonenumber = '') { - $this->phonenumber = $phonenumber; + $this->phonenumber = (string) $phonenumber; return $this; } @@ -1205,9 +1205,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI * @param string $mobilenumber * @return Person */ - public function setMobilenumber($mobilenumber = '') + public function setMobilenumber(?string $mobilenumber = '') { - $this->mobilenumber = $mobilenumber; + $this->mobilenumber = (string) $mobilenumber; return $this; } diff --git a/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php b/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php index 8fa95fe4f..3fa8f5cda 100644 --- a/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php +++ b/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php @@ -25,6 +25,7 @@ use Chill\MainBundle\Form\Event\CustomizeFormEvent; use Chill\MainBundle\Repository\CenterRepository; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -54,14 +55,18 @@ final class CreationPersonType extends AbstractType private EventDispatcherInterface $dispatcher; + private bool $askCenters; + public function __construct( CenterRepository $centerRepository, ConfigPersonAltNamesHelper $configPersonAltNamesHelper, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, + ParameterBagInterface $parameterBag ) { $this->centerTransformer = $centerRepository; $this->configPersonAltNamesHelper = $configPersonAltNamesHelper; $this->dispatcher = $dispatcher; + $this->askCenters = $parameterBag->get('chill_main')['acl']['form_show_centers']; } /** @@ -78,12 +83,15 @@ final class CreationPersonType extends AbstractType ]) ->add('gender', GenderType::class, array( 'required' => true, 'placeholder' => null - )) - ->add('center', PickCenterType::class, [ - 'required' => false, - 'role' => PersonVoter::CREATE, - ]) - ; + )); + + if ($this->askCenters) { + $builder + ->add('center', PickCenterType::class, [ + 'required' => false, + 'role' => PersonVoter::CREATE, + ]); + } if ($this->configPersonAltNamesHelper->hasAltNames()) { $builder->add('altNames', PersonAltNameType::class, [ diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenterValidator.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenterValidator.php index 1738e6ddc..825084448 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenterValidator.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenterValidator.php @@ -2,6 +2,7 @@ namespace Chill\PersonBundle\Validator\Constraints\Person; +use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; use Chill\PersonBundle\Entity\Person; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Validator\Constraint; @@ -10,10 +11,12 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException; class PersonHasCenterValidator extends \Symfony\Component\Validator\ConstraintValidator { private bool $centerRequired; + private CenterResolverDispatcher $centerResolverDispatcher; - public function __construct(ParameterBagInterface $parameterBag) + public function __construct(ParameterBagInterface $parameterBag, CenterResolverDispatcher $centerResolverDispatcher) { $this->centerRequired = $parameterBag->get('chill_person')['validation']['center_required']; + $this->centerResolverDispatcher = $centerResolverDispatcher; } /** @@ -29,7 +32,7 @@ class PersonHasCenterValidator extends \Symfony\Component\Validator\ConstraintVa return; } - if (NULL === $person->getCenter()) { + if (NULL === $this->centerResolverDispatcher->resolveCenter($person)) { $this ->context ->buildViolation($constraint->message) From 5fb7a6d0ae526425d6e870911b20d90e4e54a1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 15 Nov 2021 13:14:08 +0100 Subject: [PATCH 134/135] take into account form_show_centers parameters into thirdparty form type --- .../views/FilterOrder/base.html.twig | 42 ++++++++++--------- .../Form/ThirdPartyType.php | 30 ++++++++----- .../views/ThirdParty/_form.html.twig | 34 ++------------- 3 files changed, 44 insertions(+), 62 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig index 3457c883a..f9924eb11 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig @@ -10,30 +10,32 @@
{% endif %}
- {% if form.checkboxes|length > 0 %} - {% for checkbox_name, options in form.checkboxes %} -
-
- {% for c in form['checkboxes'][checkbox_name].children %} -
- {{ form_widget(c) }} - {{ form_label(c) }} -
- {% endfor %} -
-
- {% if loop.last %} + {% if form.checkboxes is defined %} + {% if form.checkboxes|length > 0 %} + {% for checkbox_name, options in form.checkboxes %}
-
    -
  • - -
  • -
+ {% for c in form['checkboxes'][checkbox_name].children %} +
+ {{ form_widget(c) }} + {{ form_label(c) }} +
+ {% endfor %}
- {% endif %} - {% endfor %} + {% if loop.last %} +
+
+
    +
  • + +
  • +
+
+
+ {% endif %} + {% endfor %} + {% endif %} {% endif %}
{{ form_end(form) }} diff --git a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php index 2c7380116..e2ebfa6d9 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php @@ -18,6 +18,7 @@ use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; @@ -46,18 +47,22 @@ class ThirdPartyType extends AbstractType protected EntityManagerInterface $om; + private bool $askCenter; + public function __construct( AuthorizationHelper $authorizationHelper, TokenStorageInterface $tokenStorage, ThirdPartyTypeManager $typesManager, TranslatableStringHelper $translatableStringHelper, - EntityManagerInterface $om + EntityManagerInterface $om, + ParameterBagInterface $parameterBag ) { $this->authorizationHelper = $authorizationHelper; $this->tokenStorage = $tokenStorage; $this->typesManager = $typesManager; $this->translatableStringHelper = $translatableStringHelper; $this->om = $om; + $this->askCenter = $parameterBag->get('chill_main')['acl']['form_show_centers']; } /** @@ -78,16 +83,19 @@ class ThirdPartyType extends AbstractType ]) ->add('comment', ChillTextareaType::class, [ 'required' => false - ]) - ->add('centers', PickCenterType::class, [ - 'role' => (\array_key_exists('data', $options) && $this->om->contains($options['data'])) ? - ThirdPartyVoter::UPDATE : ThirdPartyVoter::CREATE, - 'choice_options' => [ - 'multiple' => true, - 'attr' => ['class' => 'select2'] - ] - ]) - ; + ]); + + if ($this->askCenter) { + $builder + ->add('centers', PickCenterType::class, [ + 'role' => (\array_key_exists('data', $options) && $this->om->contains($options['data'])) ? + ThirdPartyVoter::UPDATE : ThirdPartyVoter::CREATE, + 'choice_options' => [ + 'multiple' => true, + 'attr' => ['class' => 'select2'] + ] + ]); + } // Contact Person ThirdParty (child) if (ThirdParty::KIND_CONTACT === $options['kind'] || ThirdParty::KIND_CHILD === $options['kind']) { diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig index 6bc4e3da7..c53764871 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig @@ -30,38 +30,10 @@ {{ form_row(form.address) }} -{# -
- {{ form_label(form.address) }} - {{ form_widget(form.address) }} - -
- {% if thirdParty.address %} - {# include vue_address component # - {% include '@ChillMain/Address/_insert_vue_address.html.twig' with { - targetEntity: { name: 'thirdparty', id: thirdParty.id }, - mode: 'edit', - addressId: thirdParty.address.id, - buttonSize: 'btn-sm', - } %} - {# - backUrl: path('chill_3party_3party_new'), - # - {% else %} - {# include vue_address component # - {% include '@ChillMain/Address/_insert_vue_address.html.twig' with { - targetEntity: { name: 'thirdparty', id: thirdParty.id }, - mode: 'new', - buttonSize: 'btn-sm', - buttonText: 'Create a new address', - modalTitle: 'Create a new address', - } %} - {% endif %} -
-
-#} - {{ form_row(form.comment) }} + +{% if form.centers is defined %} {{ form_row(form.centers) }} +{% endif %} {{ form_row(form.active) }} From 4a15022375f8e77af3c0832c771b92f5d7b614cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 15 Nov 2021 13:15:00 +0100 Subject: [PATCH 135/135] update change log --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de73733d0..6dc54473f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to * improve graph refresh mechanism * add feature to export canvas as image (png) * [person suggest] In widget "add person", improve the pertinence of persons when one of the names starts with the pattern; +* [person] do not ask for center any more on person creation +* [3party] do not ask for center any more on 3party creation ## Test releases