diff --git a/src/client/components/FacetDialog.js b/src/client/components/FacetDialog.js index 2868820e2e4451b84d86808d11a5c20adadce9f7..2fccf2c4940da4857bdc7942601c920598b84ea1 100644 --- a/src/client/components/FacetDialog.js +++ b/src/client/components/FacetDialog.js @@ -32,6 +32,11 @@ class FacetDialog extends React.Component { }; } + componentDidMount = () => { + console.log('facet dialog mounted, fetch facet') + this.props.fetchFacet(); + } + componentDidUpdate(prevProps) { if (prevProps.facet.fetchingFacet !== this.props.facet.fetchingFacet) { this.setState({ @@ -40,13 +45,14 @@ class FacetDialog extends React.Component { } } + handleClickOpen = () => this.setState({ open: true }); handleClose = () => this.setState({ open: false }); render() { const { classes, propertyLabel, facet } = this.props; - // console.log(facet) + //console.log(facet) return ( <div className={classes.root}> <IconButton diff --git a/src/client/components/Manuscripts.js b/src/client/components/Manuscripts.js index a2b6650c7a17fa84b757a4a36e209dccecdbca0c..f41848cc4024713fbef0ccd8d3138885d04b3934 100644 --- a/src/client/components/Manuscripts.js +++ b/src/client/components/Manuscripts.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Route, Switch, Redirect } from 'react-router-dom'; +import { Route, Redirect } from 'react-router-dom'; import ViewTabs from './ViewTabs'; import ResultTable from './ResultTable'; import LeafletMap from './LeafletMap'; @@ -12,59 +12,57 @@ let Manuscripts = props => { return ( <React.Fragment> <ViewTabs routeProps={props.routeProps} /> - <Switch> - <Route - exact path='/manuscripts' - render={() => <Redirect to='manuscripts/table' />} - /> - <Route - path={'/manuscripts/table'} - render={routeProps => - <ResultTable - rows={props.search.manuscripts} - facet={props.facet} - fetchManuscripts={props.fetchManuscripts} - fetchPlaces={props.fetchPlaces} - fetchingManuscripts={props.search.fetchingManuscripts} - fetchFacet={props.fetchFacet} - resultCount={props.search.manuscriptCount} - updateFilter={props.updateFilter} - page={props.search.page} - updatePage={props.updatePage} - routeProps={routeProps} - /> - } - /> - <Route - path={'/manuscripts/creation_places'} - render={() => - <LeafletMap - fetchPlaces={props.fetchPlaces} - fetchPlace={props.fetchPlace} - results={props.search.places} - place={props.search.place} - mapMode='cluster' - />} - /> - <Route - path={'/manuscripts/migrations'} - render={() => - <Deck - fetchPlaces={props.fetchPlaces} - fetchingPlaces={props.search.fetchingPlaces} - data={props.search.places} - />} - /> - <Route - path={'/manuscripts/statistics'} - render={() => - <Pie - fetchPlaces={props.fetchPlaces} - fetchingPlaces={props.search.fetchingPlaces} - data={props.search.places} - />} - /> - </Switch> + <Route + exact path='/manuscripts' + render={() => <Redirect to='manuscripts/table' />} + /> + <Route + path={'/manuscripts/table'} + render={routeProps => + <ResultTable + rows={props.search.manuscripts} + facet={props.facet} + fetchManuscripts={props.fetchManuscripts} + fetchPlaces={props.fetchPlaces} + fetchingManuscripts={props.search.fetchingManuscripts} + fetchFacet={props.fetchFacet} + resultCount={props.search.manuscriptCount} + updateFilter={props.updateFilter} + page={props.search.page} + updatePage={props.updatePage} + routeProps={routeProps} + /> + } + /> + <Route + path={'/manuscripts/creation_places'} + render={() => + <LeafletMap + fetchPlaces={props.fetchPlaces} + fetchPlace={props.fetchPlace} + results={props.search.places} + place={props.search.place} + mapMode='cluster' + />} + /> + <Route + path={'/manuscripts/migrations'} + render={() => + <Deck + fetchPlaces={props.fetchPlaces} + fetchingPlaces={props.search.fetchingPlaces} + data={props.search.places} + />} + /> + <Route + path={'/manuscripts/statistics'} + render={() => + <Pie + fetchPlaces={props.fetchPlaces} + fetchingPlaces={props.search.fetchingPlaces} + data={props.search.places} + />} + /> </React.Fragment> ); }; diff --git a/src/client/components/ResultTable.js b/src/client/components/ResultTable.js index 898153f5156bc5f18b37566884ba69765261cd55..67de20fc0645ec2601a4ffdb084cf718be0a87fb 100644 --- a/src/client/components/ResultTable.js +++ b/src/client/components/ResultTable.js @@ -62,7 +62,7 @@ class ResultTable extends React.Component { let page; if (this.props.routeProps.location.search === '') { page = this.props.page === -1 ? 0 : this.props.page; - this.props.routeProps.history.push({ + this.props.routeProps.history.replace({ pathname: '/manuscripts/table', search: `?page=${page}`, }); @@ -70,8 +70,9 @@ class ResultTable extends React.Component { page = parseInt(parse(this.props.routeProps.location.search).page); } this.props.updatePage(page); + console.log('mounted, fetching manuscripts') this.props.fetchManuscripts(); - this.props.fetchFacet(); + //this.props.fetchFacet(); } componentDidUpdate = prevProps => { diff --git a/src/client/components/Tree.js b/src/client/components/Tree.js index 42085c592e5052bf76fe0c3bab4f3f240d780840..076492366db6a2c9102164cda04f53bade232ab4 100644 --- a/src/client/components/Tree.js +++ b/src/client/components/Tree.js @@ -46,7 +46,7 @@ class Tree extends Component { }); this.props.updatePage(0); this.props.fetchManuscripts(); - this.props.fetchFacet(); + //this.props.fetchFacet(); }; render() { diff --git a/src/client/containers/MapApp.js b/src/client/containers/MapApp.js index 2c14d00162c933f5ffd81d00f21b3fd51b31b606..77fa697bcba29ae9a00276aa4bcf9f8f22013b7f 100644 --- a/src/client/containers/MapApp.js +++ b/src/client/containers/MapApp.js @@ -53,7 +53,8 @@ const styles = theme => ({ }, borderRight: '4px solid' + theme.palette.primary.main, borderLeft: '4px solid' + theme.palette.primary.main, - backgroundColor: 'rgb(238, 238, 238)' + //backgroundColor: 'rgb(238, 238, 238)' + backgroundColor: theme.palette.background.paper }, footer: { position: 'absolute', @@ -97,26 +98,24 @@ let MapApp = (props) => { <React.Fragment> <TopBar /> <div className={classes.mainContainer}> - <Switch> - <Route exact path="/" component={Main} /> - <Route - path="/manuscripts" - render={routeProps => - <Manuscripts - facet={facet} - map={map} - search={search} - fetchManuscripts={props.fetchManuscripts} - fetchPlaces={props.fetchPlaces} - fetchPlace={props.fetchPlace} - fetchFacet={props.fetchFacet} - fetchResults={props.fetchResults} - updateFilter={props.updateFilter} - updatePage={props.updatePage} - routeProps={routeProps} - />} - /> - </Switch> + <Route exact path="/" component={Main} /> + <Route + path="/manuscripts" + render={routeProps => + <Manuscripts + facet={facet} + map={map} + search={search} + fetchManuscripts={props.fetchManuscripts} + fetchPlaces={props.fetchPlaces} + fetchPlace={props.fetchPlace} + fetchFacet={props.fetchFacet} + fetchResults={props.fetchResults} + updateFilter={props.updateFilter} + updatePage={props.updatePage} + routeProps={routeProps} + />} + /> </div> </React.Fragment> </Router> diff --git a/src/client/epics/index.js b/src/client/epics/index.js index 0e2231ddf709db7e49d1de0df252f3d89d296b58..d50668e2dcde15f12db6887b7b94106a8701d9ef 100644 --- a/src/client/epics/index.js +++ b/src/client/epics/index.js @@ -68,8 +68,22 @@ const getFacet = (action$, state$) => action$.pipe( ofType(FETCH_FACET), withLatestFrom(state$), mergeMap(([, state]) => { - const filterStr = stringify(state.facet.facetFilters); - const requestUrl = `${apiUrl}facet?filters=${filterStr}`; + let params = {}; + let filters = {}; + let activeFilters = false; + console.log(state.facet.facetFilters) + for (const [key, value] of Object.entries(state.facet.facetFilters)) { + if (value.size != 0) { + activeFilters = true; + filters[key] = Array.from(value); + } + } + if (activeFilters) { + params.filters = JSON.stringify(filters); + } + const searchUrl = apiUrl + 'facets'; + const requestUrl = `${searchUrl}?${stringify(params)}`; + console.log(requestUrl) return ajax.getJSON(requestUrl).pipe( map(response => updateFacet({ facetValues: response })) ); diff --git a/src/server/index.js b/src/server/index.js index b1b8da2835c2313a58ec64b742b5c45206a637bb..456b05aa5387e6b7cbfb72b46fa69eec0096caba 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -6,7 +6,7 @@ import { getManuscripts, getPlaces, getPlace, - getFacet + getFacets } from './sparql/Manuscripts'; const DEFAULT_PORT = 3001; const app = express(); @@ -28,7 +28,7 @@ app.get('/manuscripts', (req, res) => { const page = parseInt(req.query.page) || 0; const filters = req.query.filters == null ? null : JSON.parse(req.query.filters); const pagesize = 5; - // console.log(filters) + //console.log(filters) return getManuscripts(page, pagesize, filters).then(data => { // console.log(data); res.json(data); @@ -39,17 +39,6 @@ app.get('/manuscripts', (req, res) => { }); }); -// app.get('/manuscript-count', (req, res) => { -// return getManuscriptCount({}).then((data) => { -// // console.log(data); -// res.json(data); -// }) -// .catch((err) => { -// console.log(err); -// return res.sendStatus(500); -// }); -// }); - app.get('/places/:placeId?', (req, res) => { if (req.params.placeId) { return getPlace(req.params.placeId).then(data => { @@ -73,14 +62,11 @@ app.get('/places/:placeId?', (req, res) => { } }); -app.get('/facet', (req, res) => { - return getFacet().then((data) => { - const facetValues = { - creationPlace: data, - author: [] - }; - // console.log(data); - res.json(facetValues); +app.get('/facets', (req, res) => { + const filters = req.query.filters == null ? null : JSON.parse(req.query.filters); + console.log(filters) + return getFacets(filters).then((data) => { + res.json(data); }) .catch((err) => { console.log(err); diff --git a/src/server/sparql/Datasets.js b/src/server/sparql/Datasets.js index 5ec1be8dc6e779b07c9bd18f9909a49961ad2d38..4e00283094a8a3e43317bb1b043b6a50517ea8d7 100644 --- a/src/server/sparql/Datasets.js +++ b/src/server/sparql/Datasets.js @@ -211,8 +211,8 @@ module.exports = { { SELECT DISTINCT (count(DISTINCT ?id) as ?cnt) ?value ?parent { ?id a frbroo:F4_Manifestation_Singleton . - ?id skos:prefLabel ?name . - ?id ^frbroo:R18_created/crm:P7_took_place_at ?value . + <FILTER> + ?id <PREDICATE> ?value . OPTIONAL { ?value mmm-schema:parent ?parent } } GROUP BY ?value ?parent diff --git a/src/server/sparql/Manuscripts.js b/src/server/sparql/Manuscripts.js index 570122ee2917c93bef2da84ace58102d5e04ae89..071b5f3468ee9e65de3e73f89870d2f4c2154580 100644 --- a/src/server/sparql/Manuscripts.js +++ b/src/server/sparql/Manuscripts.js @@ -2,18 +2,30 @@ import SparqlSearchEngine from './SparqlSearchEngine'; import datasetConfig from './Datasets'; import { mapFacet, + mapHierarchicalFacet, mapCount, - //mapManuscripts } from './Mappers'; import { makeObjectList } from './SparqlObjectMapper'; const sparqlSearchEngine = new SparqlSearchEngine(); +const facetConfigs = { + creationPlace: { + id: 'creationPlace', + predicate: '^frbroo:R18_created/crm:P7_took_place_at', + hierarchical: true, + }, + author: { + id: 'author', + predicate: '^frbroo:R18_created/mmm-schema:carried_out_by_as_author', + hierarchical: false, + } +}; -export const getManuscripts = (page, pagesize, filterObj) => { +export const getManuscripts = (page, pagesize, filters) => { return Promise.all([ - getManuscriptCount(filterObj), - getManuscriptData(page, pagesize, filterObj), + getManuscriptCount(filters), + getManuscriptData(page, pagesize, filters), ]).then(data => { return { manuscriptCount: data[0].count, @@ -24,21 +36,21 @@ export const getManuscripts = (page, pagesize, filterObj) => { }); }; -const getManuscriptData = (page, pagesize, filterObj) => { +const getManuscriptData = (page, pagesize, filters) => { let { endpoint, manuscriptQuery } = datasetConfig['mmm']; - if (filterObj == null) { + if (filters == null) { manuscriptQuery = manuscriptQuery.replace('<FILTER>', ''); } else { - manuscriptQuery = manuscriptQuery.replace('<FILTER>', generateFilter(filterObj)); + manuscriptQuery = manuscriptQuery.replace('<FILTER>', generateResultFilter(filters)); } manuscriptQuery = manuscriptQuery.replace('<PAGE>', `LIMIT ${pagesize} OFFSET ${page * pagesize}`); // console.log(manuscriptQuery) return sparqlSearchEngine.doSearch(manuscriptQuery, endpoint, makeObjectList); }; -const getManuscriptCount = filterObj => { +const getManuscriptCount = filters => { let { endpoint, countQuery } = datasetConfig['mmm']; - countQuery = countQuery.replace('<FILTER>', generateFilter(filterObj)); + countQuery = countQuery.replace('<FILTER>', generateResultFilter(filters)); return sparqlSearchEngine.doSearch(countQuery, endpoint, mapCount); }; @@ -46,43 +58,63 @@ export const getPlaces = variant => { // console.log(variant) const config = datasetConfig['mmm']; const query = config[`${variant}Query`]; - // console.log(query) + // console.log(query) return sparqlSearchEngine.doSearch(query, config.endpoint, makeObjectList); }; -export const getPlace = (id) => { +export const getPlace = id => { let { endpoint, placeQuery } = datasetConfig['mmm']; placeQuery = placeQuery.replace('<PLACE_ID>', `<http://ldf.fi/mmm/place/${id}>`); return sparqlSearchEngine.doSearch(placeQuery, endpoint, makeObjectList); }; -export const getFacet = () => { - const { endpoint, facetQuery } = datasetConfig['mmm']; - // console.log(facetQuery) - return sparqlSearchEngine.doSearch(facetQuery, endpoint, mapFacet); +export const getFacets = filters => { + return Promise.all(Object.values(facetConfigs).map(value => getFacet(value, filters))) + .then(data => { + let results = {}; + let i = 0; + Object.keys(facetConfigs).forEach(key => { + results[key] = data[i]; + i += 1; + }); + return results; + }); }; -const generateFilter = filterObj => { - const facetOptions = { - creationPlace: { - predicate: '^frbroo:R18_created/crm:P7_took_place_at', - hierarchical: true, - }, - author: { - hierarchical: false, - predicate: '^frbroo:R18_created/crm:P14_carried_out_by', - } - }; +const getFacet = (facetConfig, filters) => { + let { endpoint, facetQuery } = datasetConfig['mmm']; + if (filters == null) { + facetQuery = facetQuery.replace('<FILTER>', ''); + } else { + facetQuery = facetQuery.replace('<FILTER>', generateFacetFilter(facetConfig, filters)); + } + facetQuery = facetQuery.replace('<PREDICATE>', facetConfig.predicate); + console.log(filters) + let mapper = facetConfig.hierarchical ? mapHierarchicalFacet : mapFacet; + return sparqlSearchEngine.doSearch(facetQuery, endpoint, mapper); +}; - //filterObj.creationPlace.predicate = '^<http://erlangen-crm.org/efrbroo/R18_created>/<http://www.cidoc-crm.org/cidoc-crm/P7_took_place_at>'; +const generateFacetFilter = (facetConfig, filters) => { + delete filters[facetConfig.id]; // apply filters only from other facets let filterStr = ''; + for (let property in filters) { + filterStr += ` + ?id ${facetConfigs[property].predicate} ?${property}Filter + VALUES ?${property}Filter { <${filters[property].join('> <')}> } + `; + } + return filterStr; +}; - for (let property in filterObj) { - //console.log(filterObj[property]) +const generateResultFilter = filters => { + //console.log(filters) + let filterStr = ''; + for (let property in filters) { filterStr += ` - ?id ${facetOptions[property].predicate} ?${property}Filter - VALUES ?${property}Filter { <${filterObj[property].join('> <')}> } + ?id ${facetConfigs[property].predicate} ?${property}Filter + VALUES ?${property}Filter { <${filters[property].join('> <')}> } `; } + //console.log(filterStr) return filterStr; }; diff --git a/src/server/sparql/Mappers.js b/src/server/sparql/Mappers.js index 9561ec1bcf6a3f3915ca4c8052cc2e32d202b7bd..5ab779f1f18d0905b8027f75d8f1b08a56018c82 100644 --- a/src/server/sparql/Mappers.js +++ b/src/server/sparql/Mappers.js @@ -122,7 +122,18 @@ export const mapCount = (sparqlBindings) => { }; }; -export const mapFacet = (sparqlBindings) => { +export const mapFacet = sparqlBindings => { + const results = sparqlBindings.map(b => { + return { + title: b.facet_text.value, + id: _.has(b, 'value',) ? b.value.value : 'no_selection', + cnt: b.cnt.value, + }; + }); + return results; +}; + +export const mapHierarchicalFacet = sparqlBindings => { const results = sparqlBindings.map(b => { return { title: b.facet_text.value,