From 8b77ed54357a1ee97163c27845331ad15858ee8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matt=C3=A9o=20Delabre?= Date: Wed, 27 Nov 2019 03:33:03 -0500 Subject: [PATCH] =?UTF-8?q?app:=20Impl=C3=A9mentation=20d=E2=80=99une=20re?= =?UTF-8?q?cherche=20de=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .babelrc | 3 +- app/index.html | 2 +- app/{ => src}/App.js | 4 +- app/{ => src}/Graph.js | 1 - app/src/ResultsGraph.js | 13 ++++ app/src/SearchResults.js | 37 +++++++++ app/{ => src}/TermInput.js | 13 +++- app/{ResultsGraph.js => src/fetch.js} | 108 +++++++++++++++++++------- app/{ => src}/index.js | 0 app/style/style.css | 2 +- package-lock.json | 44 +++++++++-- package.json | 2 + 12 files changed, 188 insertions(+), 41 deletions(-) rename app/{ => src}/App.js (76%) rename app/{ => src}/Graph.js (99%) create mode 100644 app/src/ResultsGraph.js create mode 100644 app/src/SearchResults.js rename app/{ => src}/TermInput.js (78%) rename app/{ResultsGraph.js => src/fetch.js} (55%) rename app/{ => src}/index.js (100%) diff --git a/.babelrc b/.babelrc index 2b7bafa..50b9c61 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["@babel/preset-env", "@babel/preset-react"] + "presets": ["@babel/preset-env", "@babel/preset-react"], + "plugins": ["@babel/plugin-transform-runtime"] } diff --git a/app/index.html b/app/index.html index a5720c5..20701d2 100644 --- a/app/index.html +++ b/app/index.html @@ -9,6 +9,6 @@
- + diff --git a/app/App.js b/app/src/App.js similarity index 76% rename from app/App.js rename to app/src/App.js index 0521762..23f74f7 100644 --- a/app/App.js +++ b/app/src/App.js @@ -1,6 +1,6 @@ import React, {useState} from 'react'; import TermInput from './TermInput.js'; -import ResultsGraph from './ResultsGraph.js'; +import SearchResults from './SearchResults.js'; const App = () => { @@ -9,7 +9,7 @@ const App = () => return (
- +
); }; diff --git a/app/Graph.js b/app/src/Graph.js similarity index 99% rename from app/Graph.js rename to app/src/Graph.js index 2c55ece..d4d7cef 100644 --- a/app/Graph.js +++ b/app/src/Graph.js @@ -191,7 +191,6 @@ const Graph = ({nodes, edges, render}) => return () => { - layout.stop(); graphParent.current.removeEventListener('mousedown', mouseDown); document.body.removeEventListener('mousemove', mouseMove); document.body.removeEventListener('mouseup', mouseUp); diff --git a/app/src/ResultsGraph.js b/app/src/ResultsGraph.js new file mode 100644 index 0000000..4b98bd0 --- /dev/null +++ b/app/src/ResultsGraph.js @@ -0,0 +1,13 @@ +import React from 'react'; +import Graph from './Graph.js'; + + +const ResultsGraph = () => ( + nodes[id].name} + /> +); + +export default ResultsGraph; diff --git a/app/src/SearchResults.js b/app/src/SearchResults.js new file mode 100644 index 0000000..b243e93 --- /dev/null +++ b/app/src/SearchResults.js @@ -0,0 +1,37 @@ +import React, {useState, useEffect} from 'react'; +import Graph from './Graph.js'; +import {searchTerms} from './fetch.js'; + +const useResults = terms => +{ + const [results, setResults] = useState({ + nodes: {}, + edges: [] + }); + + useEffect(() => + { + const fetch = async () => + { + setResults(await searchTerms(terms)); + }; + + fetch(); + }, [terms]); + + return results; +}; + +const SearchResults = ({terms}) => +{ + const {nodes, edges} = useResults(terms); + return ( + nodes[id].name} + /> + ); +}; + +export default SearchResults; diff --git a/app/TermInput.js b/app/src/TermInput.js similarity index 78% rename from app/TermInput.js rename to app/src/TermInput.js index 397667f..2dda373 100644 --- a/app/TermInput.js +++ b/app/src/TermInput.js @@ -1,6 +1,7 @@ import React, {useState} from 'react'; const enterKey = 13; +const backspaceKey = 8; const TermInput = ({terms, setTerms}) => { @@ -8,7 +9,7 @@ const TermInput = ({terms, setTerms}) => const handleKeyDown = ev => { - if (ev.keyCode === enterKey) + if (ev.keyCode === enterKey && value) { ev.preventDefault(); @@ -18,6 +19,14 @@ const TermInput = ({terms, setTerms}) => } setValue(''); + return; + } + + if (ev.keyCode === backspaceKey && !value) + { + ev.preventDefault(); + setTerms(terms.slice(0, -1)); + return; } }; @@ -42,7 +51,7 @@ const TermInput = ({terms, setTerms}) => >{term} )} diff --git a/app/ResultsGraph.js b/app/src/fetch.js similarity index 55% rename from app/ResultsGraph.js rename to app/src/fetch.js index 3845d12..9db8dff 100644 --- a/app/ResultsGraph.js +++ b/app/src/fetch.js @@ -1,21 +1,4 @@ -import React from 'react'; -import Graph from './Graph.js'; - -// const config = { -// automaticRearrangeAfterDropNode: true, -// node: { -// color: 'lightgreen', -// size: 240, -// fontSize: 14, -// highlightStrokeColor: 'blue', -// labelProperty: 'name' -// }, -// link: { -// highlightColor: 'lightblue' -// } -// }; - -const nodes = { +const mockNodes = { Q2840: { id: 'Q2840', name: 'Grippe', @@ -127,7 +110,7 @@ const nodes = { } }; -const edges = [ +const mockEdges = [ ['Q2840', 'Q38933'], ['Q2840', 'Q1115038'], ['Q2840', 'Q474959'], @@ -165,12 +148,83 @@ const edges = [ ['Q133780', 'Q160796'] ]; -const ResultsGraph = () => ( - nodes[id].name} - /> -); +/** + * Vérifie si une liste d’arêtes contient une arête donnée, dans un sens ou + * dans l’autre. + * + * @param list Liste d’arêtes. + * @param from Premier nœud de l’arête. + * @param to Second nœud de l’arête. + * @return Vrai si et seulement si l’arête existe. + */ +const includesEdge = (list, from, to) => + list.some(([source, target]) => ( + (source === from && target === to) + || (source === to && target === from) + )); -export default ResultsGraph; +export const searchTerms = terms => new Promise((res, rej) => +{ + // Fait attendre artificiellement pour simuler une requête + setTimeout(() => + { + const nodes = {}; + const edges = []; + + // Récupération des identifiants correspondant aux termes de la requête + const termIds = terms.map(term => + Object.keys(mockNodes) + .find(id => mockNodes[id].name === term) + ); + + // Si l’un des termes est inconnu, aucun résultat + if (!termIds.includes(undefined)) + { + // Sélection des termes de la requête + for (let termId of termIds) + { + nodes[termId] = mockNodes[termId]; + } + + // Sélection des nœuds liés à tous les éléments de la requête + const resultIds = []; + + for (let [id, data] of Object.entries(mockNodes)) + { + if (termIds.every( + termId => includesEdge(mockEdges, id, termId) + )) + { + nodes[id] = data; + resultIds.push(id); + } + } + + // Sélection des voisins des résultats de la requête + for (let [id, data] of Object.entries(mockNodes)) + { + for (let resultId of resultIds) + { + if (includesEdge(mockEdges, resultId, id)) + { + nodes[id] = data; + } + } + } + + // Sélection des arêtes liant les nœuds sélectionnés + for (let [from, to] of mockEdges) + { + if ( + (from in nodes && to in nodes) + && !includesEdge(edges, from, to) + ) + { + edges.push([from, to]); + } + } + } + + res({nodes, edges}); + }, 500); +}); diff --git a/app/index.js b/app/src/index.js similarity index 100% rename from app/index.js rename to app/src/index.js diff --git a/app/style/style.css b/app/style/style.css index d41761b..f0dac4c 100644 --- a/app/style/style.css +++ b/app/style/style.css @@ -104,7 +104,7 @@ input color: var(--color-light); border-radius: 2px; - padding: calc(.2 * var(--base-size)); + padding: calc(.25 * var(--base-size)) calc(.5 * var(--base-size)); margin-left: calc(.3 * var(--base-size)); cursor: pointer; diff --git a/package-lock.json b/package-lock.json index 993e674..e23597f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -730,6 +730,40 @@ "@babel/helper-plugin-utils": "^7.0.0" } }, + "@babel/plugin-transform-runtime": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.4.tgz", + "integrity": "sha512-O8kSkS5fP74Ad/8pfsCMGa8sBRdLxYoSReaARRNSz3FbFQj3z/QUvoUmJ28gn9BO93YfnXc3j+Xyaqe8cKDNBQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "@babel/helper-module-imports": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz", + "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, "@babel/plugin-transform-shorthand-properties": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", @@ -860,10 +894,9 @@ } }, "@babel/runtime": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", - "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", - "dev": true, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.4.tgz", + "integrity": "sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw==", "requires": { "regenerator-runtime": "^0.13.2" } @@ -5954,8 +5987,7 @@ "regenerator-runtime": { "version": "0.13.3", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", - "dev": true + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" }, "regenerator-transform": { "version": "0.14.1", diff --git a/package.json b/package.json index 54f5fd4..79cc7c2 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,13 @@ "main": "index.js", "devDependencies": { "@babel/core": "^7.7.2", + "@babel/plugin-transform-runtime": "^7.7.4", "@babel/preset-env": "^7.7.1", "@babel/preset-react": "^7.7.0", "parcel-bundler": "^1.12.4" }, "dependencies": { + "@babel/runtime": "^7.7.4", "react": "^16.12.0", "react-dom": "^16.12.0", "springy": "^2.8.0"