diff options
Diffstat (limited to 'client')
| -rw-r--r-- | client/applet.js | 7 | ||||
| -rw-r--r-- | client/index.js | 4 | ||||
| -rw-r--r-- | client/table/citations.table.js | 107 | ||||
| -rw-r--r-- | client/table/file.table.js | 60 | ||||
| -rw-r--r-- | client/table/index.js | 11 | ||||
| -rw-r--r-- | client/table/tabulator.css | 45 | ||||
| -rw-r--r-- | client/tables.js | 96 |
7 files changed, 231 insertions, 99 deletions
diff --git a/client/applet.js b/client/applet.js index 21e1e4fa..db95168a 100644 --- a/client/applet.js +++ b/client/applet.js @@ -4,11 +4,12 @@ import { Container as FaceSearchContainer } from './faceSearch' import { Container as FaceAnalysisContainer } from './faceAnalysis' import { Container as NameSearchContainer } from './nameSearch' import { Container as DatasetListContainer } from './datasetList' +import { CitationsTable, FileTable } from './table' import { CountriesByYear, PieCharts } from './chart' export default class Applet extends Component { render() { - // console.log(this.props) + // console.log(this.props.payload.cmd) switch (this.props.payload.cmd) { case 'face_analysis': return <FaceAnalysisContainer {...this.props} /> @@ -22,6 +23,10 @@ export default class Applet extends Component { return <CountriesByYear {...this.props} /> case 'piechart': return <PieCharts {...this.props} /> + case 'citations': + return <CitationsTable {...this.props} /> + case 'load_file': + return <FileTable {...this.props} /> default: return <pre style={{ color: '#0f0' }}>{'Megapixels'}</pre> } diff --git a/client/index.js b/client/index.js index 5a7315b5..668aebfb 100644 --- a/client/index.js +++ b/client/index.js @@ -6,7 +6,6 @@ import { Provider } from 'react-redux' import { toArray } from './util' import Applet from './applet' import { store } from './store' -import appendTable from './tables' import appendMap from './map' function appendReactApplet(el, payload) { @@ -33,7 +32,8 @@ function appendApplets(applets) { case 'citations': case 'load_file': el.parentNode.classList.add('wide') - appendTable(el, payload) + appendReactApplet(el, payload) + el.classList.add('loaded') break case 'map': el.parentNode.classList.add('wide') diff --git a/client/table/citations.table.js b/client/table/citations.table.js new file mode 100644 index 00000000..f9599f5d --- /dev/null +++ b/client/table/citations.table.js @@ -0,0 +1,107 @@ +import React, { Component } from 'react' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { ReactTabulator } from 'react-tabulator' +import MultiValueFormatter from "react-tabulator/lib/formatters/MultiValueFormatter" + +import { Loader } from '../common' +import { toArray, toTuples } from '../util' + +export const citationsColumns = [ + { title: 'Title', field: 'title', sorter: 'string' }, + { title: 'Institution', field: 'institution', sorter: 'string', }, + { title: 'Country', field: 'country', sorter: 'string', width: 140, }, + { title: 'Year', field: 'year', sorter: 'number', width: 70 }, + { title: 'PDF', field: 'pdf_text', formatter: 'link', + formatterParams: { target: "_blank", urlField: 'pdf_link', }, + sorter: 'string', width: 100 }, +] + +class CitationsTable extends Component { + state = { + q: '', + formattedCitations: [], + filteredCitations: [], + } + + componentDidMount(){ + this.updateCitations() + } + componentDidUpdate(oldProps){ + if (this.props.payload.data.citations !== oldProps.payload.data.citations) { + this.updateCitations() + } + } + updateCitations(){ + const { paper, citations } = this.props.payload.data + if (!citations.length) this.setState({ formattedCitations: [] }) + console.log(citations.filter(a => a.title.match('Coarse'))) + const formattedCitations = citations.sort((a,b) => a.title.localeCompare(b.title)).map(citation => { + const pdf_link = (citation.pdf && citation.pdf.length) + ? citation.pdf[0] + : (citation.doi && citation.doi.length) + ? citation.doi[0] + : 'https://www.semanticscholar.org/paper/' + citation.id + let pdf_text + const pdf_partz = pdf_link.split('/')[2].split('.') + if (pdf_partz.length > 2 && pdf_partz[pdf_partz.length - 2].length == 2) { + pdf_text = pdf_partz.slice(-3).join('.') + } else { + pdf_text = pdf_partz.slice(-2).join('.') + } + return { + title: citation.title, + institution: citation.addresses.map(a => a.name).sort().join('; '), + country: Array.from(new Set(citation.addresses.map(a => a.country))).sort().join('; '), + year: citation.year, + pdf_link, pdf_text, + } + }) + this.setState({ + formattedCitations, + filteredCitations: formattedCitations, + }) + } + + updateFilter(q) { + const { formattedCitations } = this.state + if (!q.length) { + this.setState({ q, filteredCitations: formattedCitations }) + } else { + let q_re = new RegExp('(' + q.replace(/\s+/g, ' ').trim().replace(' ', '|') + ')', 'gi') + let filteredCitations = formattedCitations.filter(citation => ( + citation.title.match(q_re) || + citation.institution.match(q_re) || + citation.country.match(q_re) + )) + this.setState({ q, filteredCitations }) + } + } + + render() { + const { formattedCitations, filteredCitations } = this.state + if (!formattedCitations.length) return <Loader /> + return ( + <div className='citationBrowser'> + <input + type="text" + value={this.state.q} + onChange={e => this.updateFilter(e.target.value)} + className='q' + placeholder='Enter text to search citations...' + /> + <ReactTabulator + columns={citationsColumns} + data={filteredCitations} + options={{ + height: 311, + layout: 'fitColumns', + placeholder: formattedCitations.length ? '' : 'Nothing matches your query', + }} + /> + </div> + ) + } +} + +export default CitationsTable diff --git a/client/table/file.table.js b/client/table/file.table.js new file mode 100644 index 00000000..92f5cf72 --- /dev/null +++ b/client/table/file.table.js @@ -0,0 +1,60 @@ +import React, { Component } from 'react' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { toArray, toTuples } from '../util' + +import { Loader } from '../common' + +import csv from 'parse-csv' + +class FileTable extends Component { + state = { + data: [] + } + + componentDidMount() { + console.log(payload.url) + fetch(payload.url, { mode: 'cors' }) + .then(r => r.text()) + .then(text => { + try { + const data = csv.toJSON(text, { headers: { included: true } }) + this.setState({ data }) + } catch (e) { + console.error("error making json:", payload.url) + console.error(e) + } + }) + } + + getColumns(payload) { + let { cmd, url, fields } = payload + return ((fields && fields.length) ? fields[0] : '').split(', ').map(field => { + switch (field) { + default: + return { title: field, field: field.toLowerCase(), sorter: 'string' } + } + }) + } + + render() { + const { payload } = this.props + const { paper, citations } = payload.data + const columns = getColumns(payload) + if (!this.state.data.length) { + return <Loader /> + } + return ( + <ReactTabulator + columns={citationsColumns} + data={this.state.data} + options={{ + height: 311, + layout: 'fitColumns', + placeholder: 'No Data Set', + }} + /> + ) + } +} +export default FileTable diff --git a/client/table/index.js b/client/table/index.js new file mode 100644 index 00000000..c741f33e --- /dev/null +++ b/client/table/index.js @@ -0,0 +1,11 @@ +import 'react-tabulator/lib/styles.css' +import 'react-tabulator/lib/css/tabulator_midnight.css' +import './tabulator.css' + +import CitationsTable from './citations.table' +import FileTable from './file.table' + +export { + CitationsTable, + FileTable, +}
\ No newline at end of file diff --git a/client/table/tabulator.css b/client/table/tabulator.css new file mode 100644 index 00000000..c08ad580 --- /dev/null +++ b/client/table/tabulator.css @@ -0,0 +1,45 @@ +.tabulator { + border-left: 1px solid #333; + border-bottom: 1px solid #333; +} +.tabulator-row.tabulator-row-odd { + background-color: #222; +} +.tabulator-row.tabulator-row-even { + background-color: #333; +} +.desktop .tabulator-row.tabulator-selectable:hover { + background-color: #555; +} +.tabulator-row .tabulator-cell { + border-right: 1px solid #444; + padding: 8px; +} +.tabulator .tabulator-header { + border-bottom: 0; +} +.tabulator .tabulator-header .tabulator-col { + border-right: 1px solid #444; +} +.tabulator .tabulator-tableHolder .tabulator-table { + background-color: #333; +} +.multi-value-formatter-content span { + border: 0; + padding: 0 5px 0 0; +} + +.citationBrowser { + padding: 10px; + border-radius: 4px; + background: #666; +} +.citationBrowser .q { + max-width: 400px; + margin-bottom: 10px; + background-image: url(/assets/img/icon-search.png); + background-position: 390px center; + background-repeat: no-repeat; + box-shadow: 0px 2px 4px rgba(0,0,0,0.2); + border: 0; +}
\ No newline at end of file diff --git a/client/tables.js b/client/tables.js deleted file mode 100644 index 3b53b5db..00000000 --- a/client/tables.js +++ /dev/null @@ -1,96 +0,0 @@ -import Tabulator from 'tabulator-tables' -import csv from 'parse-csv' - -const datasetColumns = [ - { title: 'Title', field: 'title', sorter: 'string' }, - { title: 'Images', field: 'images', sorter: 'number' }, - { title: 'People', field: 'people', sorter: 'number' }, - { title: 'Year', field: 'year', sorter: 'number' }, - { title: 'Citations', field: 'citations', sorter: 'number' }, - { title: 'Influenced', field: 'influenced', sorter: 'number' }, - // { title: 'Origin', field: 'origin', sorter: 'string' }, -] -const citationsColumns = [ - { title: 'Title', field: 'title', sorter: 'string' }, - { title: 'Institution', field: 'institution', sorter: 'string' }, - { title: 'Country', field: 'country', sorter: 'string', width: 140 }, - { title: 'Year', field: 'year', sorter: 'number', width: 70 }, - { title: 'PDF', field: 'pdf', formatter: 'link', - formatterParams: { target: "_blank", urlField: 'pdf', }, - sorter: 'string', width: 100 }, -] - -function getColumns(payload) { - let { cmd, url, fields } = payload - if (cmd === 'citations') { - return citationsColumns - } - if (url && url.match('datasets.csv')) { - return datasetColumns - } - return ((fields && fields.length) ? fields[0] : '').split(', ').map(field => { - switch (field) { - default: - return { title: field, field: field.toLowerCase(), sorter: 'string' } - } - }) -} - -function getCitations(dataset) { - // console.log(dataset.citations) - // console.log(dataset.citations.map(d => [d.pdf, d.doi])) - return dataset.citations.map(citation => ({ - title: citation.title, - institution: citation.addresses[0].name, - country: citation.addresses[0].country, - year: citation.year, - pdf: (citation.pdf && citation.pdf.length) - ? citation.pdf[0] - : (citation.doi && citation.doi.length) - ? citation.doi[0] - : "", - })) -} - -export default function append(el, payload) { - const columns = getColumns(payload) - // console.log(columns) - const table = new Tabulator(el, { - height: '311px', - layout: 'fitColumns', - placeholder: 'No Data Set', - columns, - }) - // let path = payload.opt - // console.log(path, columns) - - if (payload.cmd === 'citations') { - let { data } = payload - if (!data) return null - const citations = getCitations(data) - // console.log(citations) - table.setData(citations) - el.classList.add('loaded') - } else { - fetch(payload.url, { mode: 'cors' }) - .then(r => r.text()) - .then(text => { - try { - // console.log(text) - const data = csv.toJSON(text, { headers: { included: true } }) - // console.log(data) - table.setData(data) - el.classList.add('loaded') - } catch (e) { - - console.error("error making json:", payload.url) - console.error(e) - // console.log(text) - } - }) - } - - // if (fields && fields.length > 1 && fields[1].indexOf('filter')) { - // const filter = fields[1].split(' ') - // } -} |
