From 988e03bcca159e9e9e12c4ac4ed3c6d70c8fa99d Mon Sep 17 00:00:00 2001 From: Jernej Pregelj Date: Wed, 22 May 2019 16:53:21 +0200 Subject: [PATCH] channel view, latest assets from aquarius --- client/package-lock.json | 41 ++++--- client/src/Routes.tsx | 2 + client/src/routes/Channel.module.scss | 0 client/src/routes/Channel.test.tsx | 51 ++++++++ client/src/routes/Channel.tsx | 169 ++++++++++++++++++++++++++ client/src/routes/Home.tsx | 53 ++++---- 6 files changed, 274 insertions(+), 42 deletions(-) create mode 100644 client/src/routes/Channel.module.scss create mode 100644 client/src/routes/Channel.test.tsx create mode 100644 client/src/routes/Channel.tsx diff --git a/client/package-lock.json b/client/package-lock.json index d3f0df4..4ffe037 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -15624,14 +15624,6 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { "version": "3.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", @@ -16425,7 +16417,33 @@ "integrity": "sha512-8p6ZLv+1JYa5Vs8oBn33Nn3VGFBbF+wVfO+b78RJS1Qf1uIOzjFVDk3XwYDD7rlz9G5BKpxhaQw+6EGQ7L02aw==", "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.37", + "web3-core-helpers": "1.0.0-beta.37" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + }, + "web3-core-helpers": { + "version": "1.0.0-beta.37", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.37.tgz", + "integrity": "sha512-efaLOzN28RMnbugnyelgLwPWWaSwElQzcAJ/x3PZu+uPloM/lE5x0YuBKvIh7/PoSMlHqtRWj1B8CpuQOUQ5Ew==", + "requires": { + "underscore": "1.8.3", + "web3-eth-iban": "1.0.0-beta.37", + "web3-utils": "1.0.0-beta.37" + } + }, + "web3-eth-iban": { + "version": "1.0.0-beta.37", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.37.tgz", + "integrity": "sha512-WQRniGJFxH/XCbd7miO6+jnUG+6bvuzfeufPIiOtCbeIC1ypp1kSqER8YVBDrTyinU1xnf1U5v0KBZ2yiWBJxQ==", + "requires": { + "bn.js": "4.11.6", + "web3-utils": "1.0.0-beta.37" + } + }, "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" } }, @@ -17202,11 +17220,6 @@ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" - }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", diff --git a/client/src/Routes.tsx b/client/src/Routes.tsx index 9d4b078..ad27973 100644 --- a/client/src/Routes.tsx +++ b/client/src/Routes.tsx @@ -10,6 +10,7 @@ import Publish from './routes/Publish/' import Search from './routes/Search' import Faucet from './routes/Faucet' import History from './routes/History' +import Channel from './routes/Channel' import Styleguide from './routes/Styleguide' const Routes = () => ( @@ -22,6 +23,7 @@ const Routes = () => ( + ) diff --git a/client/src/routes/Channel.module.scss b/client/src/routes/Channel.module.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/src/routes/Channel.test.tsx b/client/src/routes/Channel.test.tsx new file mode 100644 index 0000000..9ef6c0a --- /dev/null +++ b/client/src/routes/Channel.test.tsx @@ -0,0 +1,51 @@ +import React from 'react' +import { render } from 'react-testing-library' +import Channel from './Channel' +import { User } from '../context' +import { createMemoryHistory } from 'history' + +describe('Channel', () => { + it('renders without crashing', () => { + const history = createMemoryHistory() + + const { container } = render( + { + return { + results: [], + totalResults: 1, + totalPages: 1 + } + } + } + }, + balance: { eth: 0, ocn: 0 }, + network: '', + requestFromFaucet: () => {}, + unlockAccounts: () => {}, + message: '' + }} + > + + + ) + expect(container.firstChild).toBeInTheDocument() + }) +}) diff --git a/client/src/routes/Channel.tsx b/client/src/routes/Channel.tsx new file mode 100644 index 0000000..e3006a6 --- /dev/null +++ b/client/src/routes/Channel.tsx @@ -0,0 +1,169 @@ +import React, { PureComponent } from 'react' +import queryString from 'query-string' +import { History, Location } from 'history' +import { Logger } from '@oceanprotocol/squid' +import Spinner from '../components/atoms/Spinner' +import Route from '../components/templates/Route' +import { User } from '../context' +import Asset from '../components/molecules/Asset' +import Pagination from '../components/molecules/Pagination' +import styles from './Channel.module.scss' +import Content from '../components/atoms/Content' + +interface ChannelProps { + location: Location + history: History + match: { + params: any + } +} + +interface ChannelState { + results: any[] + totalResults: number + offset: number + totalPages: number + currentPage: number + isLoading: boolean + searchTerm: string + searchCategories: string + channel: { + title: string + description: string + } +} + +export default class Channel extends PureComponent { + public state = { + results: [], + totalResults: 0, + offset: 25, + totalPages: 1, + currentPage: 1, + isLoading: true, + searchTerm: '', + searchCategories: '', + channel: { + title: 'AI for Good', + description: 'AI 4 Good is an initiative to promote the use of artificial intelligence for good causes, such as fighting poverty, climate change, improving healthcare, safer transportation, and so on. The AI for Good Global Summit is THE leading United Nations platform for global and inclusive dialogue on AI. The Summit is hosted each year in Geneva by the ITU in partnership wutg UN Suster agencies, XPRIZE Foundtation and ACM.' + } + } + + public async componentDidMount() { + const { match } = this.props; + + // TODO: use next line to use channel name + // const category = match.params.channel + const category = 'Engineering' + + const { page } = queryString.parse(this.props.location.search) + + if (category) { + await this.setState({ + searchCategories: encodeURIComponent(`${category}`) + }) + } + + // switch to respective page if query string is present + if (page) { + const currentPage = Number(page) + await this.setState({ currentPage }) + } + + this.getChannelAssets() + } + + private getChannelAssets = async () => { + const { ocean } = this.context + const { offset, currentPage, searchTerm, searchCategories } = this.state + + const queryValues = + searchCategories !== '' && searchTerm !== '' + ? { text: [searchTerm], categories: [searchCategories] } + : searchCategories !== '' && searchTerm === '' + ? { categories: [searchCategories] } + : { text: [searchTerm] } + + const searchQuery = { + offset, + page: currentPage, + query: { + ...queryValues, + price: [-1, 1] + }, + sort: { + datePublished: 1 + } + } + + try { + const search = await ocean.aquarius.queryMetadata(searchQuery) + this.setState({ + results: search.results, + totalResults: search.totalResults, + totalPages: search.totalPages, + isLoading: false + }) + } catch (error) { + Logger.error(error.message) + this.setState({ isLoading: false }) + } + } + + private handlePageClick = async (data: { selected: number }) => { + // react-pagination starts counting at 0, we start at 1 + let toPage = data.selected + 1 + + this.props.history.push({ + pathname: this.props.location.pathname, + search: `?text=${this.state.searchTerm}&page=${toPage}` + }) + + await this.setState({ currentPage: toPage, isLoading: true }) + await this.getChannelAssets() + } + + public renderResults = () => + this.state.isLoading ? ( + + ) : this.state.results && this.state.results.length ? ( +
+ {this.state.results.map((asset: any) => ( + + ))} +
+ ) : ( +
No data sets found.
+ ) + + public render() { + const { totalResults, totalPages, currentPage, channel } = this.state + const { match } = this.props; + return ( + + +
{channel.description}
+ {totalResults > 0 && ( +

${decodeURIComponent( + '' // this.state.channelName + )}` + }} + /> + )} + {this.renderResults()} + + + + + ) + } +} + +Channel.contextType = User diff --git a/client/src/routes/Home.tsx b/client/src/routes/Home.tsx index 92d842a..359cafa 100644 --- a/client/src/routes/Home.tsx +++ b/client/src/routes/Home.tsx @@ -77,35 +77,28 @@ class Home extends Component { private getLastAssets = async () => { const { ocean } = this.context - ocean.keeper.didRegistry.contract.getPastEvents( - 'DIDAttributeRegistered', - { - filter: {}, - fromBlock: 0, - toBlock: 'latest' + + const searchQuery = { + offset: 3, + page: 1, + query: { + price: [-1, 1] }, - async (error: any, events: any) => { - if (error) { - Logger.log('error retrieving', error) - this.setState({ isLoadingLast: false }) - } else { - Logger.log('events retrieving', events) - const lastAssets = [] - // this will tranverse all published assets from latest to first - for (const event of events.reverse()) { - const ddo = await ocean.assets.resolve( - `did:op:${event.returnValues._did.substring(2)}` - ) - // ddo not resolved jump to next ddo - if (ddo === null) continue - lastAssets.push(ddo) - // stop tranversing all events when reaching certain number - if (lastAssets.length >= 1) break - } - this.setState({ lastAssets, isLoadingLast: false }) - } + sort: { + created: -1 } - ) + } + + try { + const search = await ocean.aquarius.queryMetadata(searchQuery) + this.setState({ + lastAssets: search.results, + isLoadingLast: false + }) + } catch (error) { + Logger.error(error.message) + this.setState({ isLoadingLast: false }) + } } public render() { @@ -135,7 +128,7 @@ class Home extends Component { -

AI for Good

+

this.openChannel('AI for Good')}>AI for Good

{isLoadingCategory ? ( @@ -190,6 +183,10 @@ class Home extends Component { event.preventDefault() this.props.history.push(`/search?text=${this.state.search}`) } + + private openChannel = (channel: string) => { + this.props.history.push(`/channel/${channel}`) + } } Home.contextType = User