Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
tiberiuichim committed Nov 3, 2022
1 parent f5bf5e5 commit f17c429
Show file tree
Hide file tree
Showing 212 changed files with 15,151 additions and 42 deletions.
58 changes: 35 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,43 @@
"type": "git",
"url": "git@github.com:eea/volto-searchlib.git"
},
"old_dependencies": {
"@elastic/react-search-ui": "1.9.0",
"@elastic/react-search-ui-views": "1.9.0",
"@elastic/search-ui": "1.9.0",
"@visx/group": "2.1.0",
"@visx/responsive": "2.1.1",
"@visx/scale": "2.1.0",
"@visx/shape": "2.1.1",
"@visx/tooltip": "2.1.0",
"csv-stringify": "5.6.5",
"dependencies": {
"@elastic/react-search-ui": "^1.9.0",
"@elastic/react-search-ui-views": "^1.9.0",
"@elastic/search-ui": "^1.9.0",
"@visx/group": "^1.7.0",
"@visx/responsive": "^1.10.1",
"@visx/scale": "^1.11.1",
"@visx/shape": "^1.12.0",
"@visx/tooltip": "^1.7.2",
"classnames": "^2.2.6",
"csv-stringify": "^5.6.5",
"d3-array": "^2.12.1",
"d3-scale": "^3.3.0",
"deep-equal": "^2.0.5",
"downshift": "^3.4.8",
"elasticsearch": "16.7.3",
"jotai": "1.6.0",
"lodash.clonedeep": "4.5.0",
"lodash.isfunction": "3.0.9",
"lodash.uniq": "4.5.0",
"re-resizable": "6.9.1",
"react-compound-slider": "3.3.1",
"fast-deep-equal": "^3.1.3",
"http-proxy-middleware": "^2.0.1",
"jotai": "^1.6.0",
"lodash": "4.17.21",
"lodash.clonedeep": "^4.5.0",
"lodash.isfunction": "^3.0.9",
"lodash.uniq": "^4.5.0",
"luxon": "^1.22.0",
"node-fetch": "^2.6.1",
"prop-types": "15.7.2",
"re-resizable": "^6.9.0",
"react-compound-slider": "^3.4.0",
"react-masonry-component": "6.3.0",
"react-motion": "0.5.2",
"react-speech-recognition": "3.8.2",
"@eeacms/volto-eea-design-system": "0.3.1",
"@eeacms/search": "0.2.5"
},
"dependencies": {
"@eeacms/search": "*",
"react-motion": "^0.5.2",
"react-speech-recognition": "^3.8.2",
"react-toastify": "5.4.1",
"redux": "4.1.0",
"semantic-ui-react": "2.0.3",
"superagent": "3.8.2",
"svg-loader": "0.0.2",
"use-deep-compare-effect": "1.8.1",
"@eeacms/volto-eea-design-system": "*"
},
"devDependencies": {
Expand Down
27 changes: 8 additions & 19 deletions razzle.extend.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
const path = require('path');
const makeLoaderFinder = require('razzle-dev-utils/makeLoaderFinder');

const pkgs = ['@eeacms/search'];

// const nodeExternals = require('webpack-node-externals');
// , '@eeacms/globalsearch'

const modify = (config, { target, dev }, webpack) => {
const projectRootPath = path.resolve('.');

const jsConfig = require(`${projectRootPath}/jsconfig.json`);
const searchlibConf = jsConfig.compilerOptions.paths.searchlib;

if (!searchlibConf) return config;
const voltoSearchlibPath = path.dirname(
require.resolve('@eeacms/volto-searchlib'),
);
const searchlibPath = path.resolve(`${voltoSearchlibPath}/../searchlib`);

// because we load @eeacms/search "through the back door" (via webpack
// aliases and jsconfig.json), we need to instruct babel to include this
// package as well
// because we load @eeacms/search "through the back door" , we need to
// instruct babel to include this package as well
const babelLoaderFinder = makeLoaderFinder('babel-loader');
const babelLoader = config.module.rules.find(babelLoaderFinder);
const { include } = babelLoader;

pkgs.forEach((name) => {
// const incl = path.dirname(require.resolve(name));
const incl = config.resolve.alias[name];
include.push(incl);
});
config.resolve.alias['@eeacms/search'] = searchlibPath;
include.push(searchlibPath);

return config;
};
Expand Down
166 changes: 166 additions & 0 deletions searchlib/components/AnswerBox/AnswerBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import React from 'react';

import { Segment, Button, Message, Label, Icon } from 'semantic-ui-react'; //, Accordion

import { useAppConfig, useSearchContext } from '@eeacms/search/lib/hocs';
import { hasNonDefaultFilters } from '@eeacms/search/lib/search/helpers';

import Answers from './Answers';
import withAnswers from './withAnswers';
import useTimedMessage from './useTimedMessage';
import Loader from '../Loaders';

const AnswerBox = (props) => {
const { appConfig } = useAppConfig();

const { data = {}, loading, loaded, searchedTerm, isQuestion } = props;
const { sortedClusters = [] } = data || {};
const { searchContext } = props;
const { resultSearchTerm = '', filters, resetFilters } = searchContext;

const hasActiveFilters = hasNonDefaultFilters(filters, appConfig);
// TODO: this is hardcoded for globalsearch
const hasActiveCluster =
filters.findIndex((f) => f.field === 'op_cluster') > -1;

const messageCounter = useTimedMessage({
resultSearchTerm,
searchedTerm,
timeout: 15,
});

if (!isQuestion) return null;

const showLoader = loading && !loaded;
const hasAnswers =
resultSearchTerm &&
searchedTerm === resultSearchTerm &&
sortedClusters.length;

const dontShow =
!(showLoader || (resultSearchTerm && searchedTerm === resultSearchTerm)) ||
hasActiveCluster;

if (dontShow) return null;

return showLoader ? (
<div className="answers-list">
<Segment className="answers__loading">
<div className="loading-tip">
Searching answers for <strong>{resultSearchTerm}</strong>
<Loader
className="three-dots-loader"
type="ThreeDots"
visible={true}
color="#2d9390"
width={80}
height={10}
/>
</div>

<div className="progress"></div>
</Segment>
</div>
) : hasAnswers ? (
<div className="answers-list">
<Answers
hasActiveFilters={hasActiveFilters}
data={data}
searchedTerm={searchedTerm}
resetFilters={resetFilters}
/>
</div>
) : hasActiveFilters ? (
<div className="answers-list">
<Message icon warning size="small">
<Icon name="exclamation circle" />
<Message.Content>
<p>
No answers found, but you have active filters. You may try to{' '}
<Button
size="mini"
compact
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
resetFilters();
}}
>
reset
</Button>{' '}
the filters to improve the quality of results.
</p>
</Message.Content>
</Message>
</div>
) : (
messageCounter > 0 && (
<div className="answers-list">
<Message icon warning size="small">
<Icon name="exclamation circle" />
<Message.Content>
<span>
No direct answers for your question.
<Label circular color="teal">
{messageCounter}
</Label>
</span>
</Message.Content>
</Message>
</div>
)
);
};

const WithLiveAnswers = withAnswers(AnswerBox);

const withStateAnswers = (WrappedComponent) => {
const WrappedAnswerBox = (props) => {
const searchContext = useSearchContext();
const { resultSearchTerm = '', query_type } = searchContext;

const { appConfig } = useAppConfig();
const {
qa_queryTypes = [
'query:interrogative',
'query:declarative',
'query:keyword',
'request:query', // temporary
],
} = appConfig?.nlp?.qa || {};

const isQuestion = qa_queryTypes.indexOf(query_type) > -1;

if (searchContext.answers) {
return (
<WrappedComponent
isQuestion={isQuestion}
data={searchContext.answers}
loading={false}
loaded={true}
searchedTerm={resultSearchTerm}
searchContext={searchContext}
/>
);
} else {
return <WithLiveAnswers {...props} />;
}
};
return WrappedAnswerBox;
};

export default withStateAnswers(AnswerBox);

/*
answer: "organoleptic factors, physico-chemical factors, toxic substances, microbiological parameters"
context: "nto account when assessing water quality (organoleptic factors, physico-chemical factors, toxic substances, microbiological parameters.↵(Source: RRDA)"
document_id: "http://www.eea.europa.eu/help/glossary/gemet-environmental-thesaurus/total-parameter"
id: "http://www.eea.europa.eu/help/glossary/gemet-environmental-thesaurus/total-parameter"
offset_end: 134
offset_end_in_doc: 176
offset_start: 42
offset_start_in_doc: 84
probability: 0.752453625202179
question: null
score: 6.118757247924805
*/
55 changes: 55 additions & 0 deletions searchlib/components/AnswerBox/AnswerBoxDetails.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import { Modal, Button } from 'semantic-ui-react'; // Icon
import AnswerFeedback from './AnswerFeedback';

export default (props) => {
const [open, setOpen] = React.useState(false);
const { basic } = props;
return (
<Modal
open={open}
trigger={
<Button
basic={basic}
onClick={() => setOpen(true)}
className="header-btn"
>
{/*<Icon name="help circle" />*/}
About direct answers
</Button>
}
>
<Modal.Header>Direct answers</Modal.Header>
<Modal.Content>
<p>
Sometimes we show direct answers to your queries when our AI algorithm
automatically detects them within the top search results.
</p>
<p>
Some answers may not be correct or up to date, they may be based on
obsolete content. Therefore, we appreciate your feedback to help us
improve.
</p>
<p>
Our goal is to keep this information and material timely and accurate.
If errors are brought to our attention, we will try to correct them.
</p>
<AnswerFeedback />
<p>
<a
href="https://www.eea.europa.eu/legal/disclaimer"
target="_blank"
rel="noreferrer"
>
EEA Disclaimer
</a>
</p>
</Modal.Content>
<Modal.Actions>
<Button color="black" onClick={() => setOpen(false)} positive>
OK
</Button>
</Modal.Actions>
</Modal>
);
};
Loading

0 comments on commit f17c429

Please sign in to comment.