diff --git a/components/dataset/Org.tsx b/components/dataset/Org.tsx
index 0971532c..00b7fd9f 100644
--- a/components/dataset/Org.tsx
+++ b/components/dataset/Org.tsx
@@ -1,20 +1,53 @@
import Link from 'next/link';
+import ErrorMessage from '../Error';
+import { NetworkStatus } from 'apollo-client';
+import { useQuery } from '@apollo/react-hooks';
+import gql from 'graphql-tag';
-export default function Org({ org }) {
+export const GET_ORG_QUERY = gql`
+ query dataset($id: String) {
+ dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
+ result {
+ organization {
+ name
+ title
+ image_url
+ }
+ }
+ }
+ }
+`;
+
+export default function Org({ variables }) {
+ const { loading, error, data, fetchMore, networkStatus } = useQuery(
+ GET_ORG_QUERY,
+ {
+ variables,
+ // Setting this value to true will make the component rerender when
+ // the "networkStatus" changes, so we are able to know if it is fetching
+ // more data
+ notifyOnNetworkStatusChange: true,
+ }
+ );
+
+ if (error) return ;
+ if (loading) return
Loading
;
+
+ const { organization } = data.dataset.result;
return (
<>
- {org ? (
+ {organization ? (
<>
-
+
- {org.title || org.name}
+ {organization.title || organization.name}
>
diff --git a/components/dataset/Resources.tsx b/components/dataset/Resources.tsx
index e4753de1..1105a47c 100644
--- a/components/dataset/Resources.tsx
+++ b/components/dataset/Resources.tsx
@@ -1,6 +1,43 @@
import Link from 'next/link';
+import ErrorMessage from '../Error';
+import { NetworkStatus } from 'apollo-client';
+import { useQuery } from '@apollo/react-hooks';
+import gql from 'graphql-tag';
+
+export const GET_DATAPACKAGE_QUERY = gql`
+ query dataset($id: String) {
+ dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
+ result {
+ name
+ resources {
+ name
+ title
+ format
+ created
+ last_modified
+ }
+ }
+ }
+ }
+`;
+
+export default function Resources({ variables }) {
+ const { loading, error, data, fetchMore, networkStatus } = useQuery(
+ GET_DATAPACKAGE_QUERY,
+ {
+ variables,
+ // Setting this value to true will make the component rerender when
+ // the "networkStatus" changes, so we are able to know if it is fetching
+ // more data
+ notifyOnNetworkStatusChange: true,
+ }
+ );
+
+ if (error) return ;
+ if (loading) return
Loading
;
+
+ const { result } = data.dataset;
-export default function Resources({ datapackage }) {
return (
<>
diff --git a/components/resource/DataExplorer.tsx b/components/resource/DataExplorer.tsx
index 6f2fbd8a..5fdf4363 100644
--- a/components/resource/DataExplorer.tsx
+++ b/components/resource/DataExplorer.tsx
@@ -1,5 +1,45 @@
import Link from 'next/link';
+import ErrorMessage from '../Error';
+import { NetworkStatus } from 'apollo-client';
+import { useQuery } from '@apollo/react-hooks';
+import gql from 'graphql-tag';
+
+const QUERY = gql`
+ query dataset($id: String) {
+ dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
+ result {
+ resources {
+ name
+ id
+ title
+ description
+ format
+ size
+ created
+ last_modified
+ url
+ }
+ }
+ }
+ }
+`;
+
+export default function DataExplorer({ variables }) {
+ const { loading, error, data } = useQuery(QUERY, {
+ variables,
+ // Setting this value to true will make the component rerender when
+ // the "networkStatus" changes, so we are able to know if it is fetching
+ // more data
+ notifyOnNetworkStatusChange: true,
+ });
+
+ if (error) return ;
+ if (loading) return
- );
-}
diff --git a/components/search/Total.tsx b/components/search/Total.tsx
index e370af1c..0a77a25a 100644
--- a/components/search/Total.tsx
+++ b/components/search/Total.tsx
@@ -1,7 +1,33 @@
-export default function Total({ total }) {
+import { useQuery } from '@apollo/react-hooks';
+import gql from 'graphql-tag';
+
+const QUERY = gql`
+ query search($q: String, $sort: String) {
+ search(q: $q, sort: $sort)
+ @rest(type: "Search", path: "package_search?{args}") {
+ result {
+ count
+ }
+ }
+ }
+`;
+
+export default function Total({ variables }) {
+ const { loading, error, data } = useQuery(QUERY, {
+ variables,
+ // Setting this value to true will make the component rerender when
+ // the "networkStatus" changes, so we are able to know if it is fetching
+ // more data
+ notifyOnNetworkStatusChange: true,
+ });
+
+ if (loading) return
Loading
;
+
+ const { result } = data.search;
+
return (
- {total} results found
+ {result.count} results found
);
}
diff --git a/config/index.js b/config/index.js
deleted file mode 100644
index dd7c03c5..00000000
--- a/config/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-'use strict';
-
-const nconf = require('nconf');
-require('dotenv').config({ path: process.env.DOTENV_PATH || '.env' });
-
-nconf.argv().env();
-
-nconf.use('memory');
-
-const dms = (process.env.DMS || 'http://mock.ckan').replace(/\/?$/, '');
-const cms = (process.env.CMS || 'http://mock.cms').replace(/\/?$/, '');
-
-// This is the object that you want to override in your own local config
-nconf.defaults({
- env: process.env.NODE_ENV || 'development',
- debug: process.env.DEBUG || false,
- DMS: dms,
- CMS: cms,
-});
-
-module.exports = {
- get: nconf.get.bind(nconf),
- set: nconf.set.bind(nconf),
- reset: nconf.reset.bind(nconf),
-};
diff --git a/lib/apolloClient.ts b/lib/apolloClient.ts
new file mode 100644
index 00000000..c3cdecb6
--- /dev/null
+++ b/lib/apolloClient.ts
@@ -0,0 +1,79 @@
+import { useMemo } from 'react';
+import getConfig from 'next/config';
+import { ApolloClient } from 'apollo-client';
+import { InMemoryCache } from 'apollo-cache-inmemory';
+import { RestLink } from 'apollo-link-rest';
+
+let apolloClient;
+
+const restLink = new RestLink({
+ uri: getConfig().publicRuntimeConfig.DMS + '/api/3/action/',
+ typePatcher: {
+ Search: (
+ data: any,
+ outerType: string,
+ patchDeeper: RestLink.FunctionalTypePatcher
+ ): any => {
+ if (data.result != null) {
+ data.result.__typename = 'SearchResponse';
+
+ if (data.result.results != null) {
+ data.result.results = data.result.results.map((item) => {
+ if (item.organization != null) {
+ item.organization.__typename = 'Organization';
+ }
+ return { __typename: 'Package', ...item };
+ });
+ }
+ }
+ return data;
+ },
+ Response: (
+ data: any,
+ outerType: string,
+ patchDeeper: RestLink.FunctionalTypePatcher
+ ): any => {
+ if (data.result != null) {
+ data.result.__typename = 'Package';
+ if (data.result.organization != null) {
+ data.result.organization.__typename = 'Organization';
+ }
+
+ if (data.result.resources != null) {
+ data.result.resources = data.result.resources.map((item) => {
+ return { __typename: 'Resource', ...item };
+ });
+ }
+ }
+ return data;
+ },
+ },
+});
+
+function createApolloClient() {
+ return new ApolloClient({
+ link: restLink,
+ cache: new InMemoryCache(),
+ });
+}
+
+export function initializeApollo(initialState = null) {
+ const _apolloClient = apolloClient ?? createApolloClient();
+
+ // If your page has Next.js data fetching methods that use Apollo Client, the initial state
+ // gets hydrated here
+ if (initialState) {
+ _apolloClient.cache.restore(initialState);
+ }
+ // For SSG and SSR always create a new Apollo Client
+ if (typeof window === 'undefined') return _apolloClient;
+ // Create the Apollo Client once in the client
+ if (!apolloClient) apolloClient = _apolloClient;
+
+ return _apolloClient;
+}
+
+export function useApollo(initialState) {
+ const store = useMemo(() => initializeApollo(initialState), [initialState]);
+ return store;
+}
diff --git a/mocks/index.js b/mocks/index.js
index 17c11e04..8c4c15ff 100644
--- a/mocks/index.js
+++ b/mocks/index.js
@@ -28,6 +28,7 @@ const gdp = {
},
metadata_created: '2019-03-07T11:56:19.696257',
metadata_modified: '2019-03-07T12:03:58.817280',
+ size: '',
};
const population = {
@@ -66,9 +67,7 @@ module.exports.initMocks = function () {
nock('http://mock.ckan/api/3/action', { encodedQueryParams: true })
.persist()
// 1. Call without query.
- .get(
- '/package_search?facet.field=organization&facet.field=groups&facet.field=tags&facet.field=res_format&facet.field=license_id&facet.limit=5'
- )
+ .get('/package_search?')
.reply(200, {
success: true,
result: {
@@ -80,9 +79,7 @@ module.exports.initMocks = function () {
},
})
// 2. Call with `q=gdp` query.
- .get(
- '/package_search?q=gdp&facet.field=organization&facet.field=groups&facet.field=tags&facet.field=res_format&facet.field=license_id&facet.limit=5'
- )
+ .get('/package_search?q=gdp')
.reply(200, {
success: true,
result: {
diff --git a/next.config.js b/next.config.js
new file mode 100644
index 00000000..577f4853
--- /dev/null
+++ b/next.config.js
@@ -0,0 +1,37 @@
+const { PHASE_DEVELOPMENT_SERVER } = require('next/constants');
+
+module.exports = (phase, { defaultConfig }) => {
+ const dms = process.env.DMS;
+ if (phase === PHASE_DEVELOPMENT_SERVER) {
+ if (dms) {
+ console.log('\nYou are running the app in dev mode 🌀');
+ console.log(
+ 'Did you know that you can use mocked CKAN API? Just unset your `DMS` env var.'
+ );
+ console.log('Happy coding ☀️\n');
+ } else {
+ const mocks = require('./mocks');
+ mocks.initMocks();
+ console.log(
+ '\nYou have not defined any DMS API so we are activating the mocks ⚠️'
+ );
+ console.log(
+ 'If you wish to run against your CKAN API, you can set `DMS` env var.'
+ );
+ console.log(
+ 'For example, to run against demo ckan site: `DMS=https://demo.ckan.org`\n'
+ );
+ }
+
+ return {
+ publicRuntimeConfig: {
+ DMS: dms ? dms.replace(/\/?$/, '') : 'http://mock.ckan',
+ },
+ };
+ }
+ return {
+ publicRuntimeConfig: {
+ DMS: dms ? dms.replace(/\/?$/, '') : 'https://demo.ckan.org',
+ },
+ };
+};
diff --git a/package.json b/package.json
index 4210fc07..f602ed84 100644
--- a/package.json
+++ b/package.json
@@ -13,10 +13,18 @@
"pre-commit": "echo 'formating your changes.....' && prettier --single-quote --write"
},
"dependencies": {
+ "@apollo/react-hooks": "^3.1.5",
+ "apollo-cache-inmemory": "^1.6.6",
+ "apollo-client": "^2.6.10",
+ "apollo-link": "^1.2.14",
+ "apollo-link-rest": "0.7.3",
"bytes": "^3.1.0",
+ "graphql": "^15.1.0",
+ "graphql-anywhere": "^4.2.7",
+ "graphql-tag": "^2.10.3",
"markdown-it": "^11.0.0",
"next": "9.4.2",
- "querystring": "^0.2.0",
+ "qs": "^6.9.4",
"react": "16.13.1",
"react-dom": "16.13.1",
"slugify": "^1.4.0"
@@ -27,12 +35,12 @@
"@types/jest": "^25.2.3",
"@types/react": "^16.9.35",
"babel-jest": "^26.0.1",
- "dotenv": "^8.2.0",
+ "babel-plugin-graphql-tag": "^2.5.0",
"husky": ">=4",
"jest": "^26.0.1",
"lint-staged": ">=10",
- "nconf": "^0.10.0",
"nock": "^12.0.3",
+ "npm-run-all": "^4.1.5",
"postcss-preset-env": "^6.7.0",
"prettier": "2.0.5",
"react-test-renderer": "^16.13.1",
diff --git a/pages/[org]/[dataset]/index.tsx b/pages/[org]/[dataset]/index.tsx
index 43210a48..5122fca8 100644
--- a/pages/[org]/[dataset]/index.tsx
+++ b/pages/[org]/[dataset]/index.tsx
@@ -1,39 +1,82 @@
import { GetServerSideProps } from 'next';
-import config from '../../../config';
+import { useQuery } from '@apollo/react-hooks';
+import { initializeApollo } from '../../../lib/apolloClient';
import utils from '../../../utils';
import Head from 'next/head';
import Nav from '../../../components/home/Nav';
import About from '../../../components/dataset/About';
import Org from '../../../components/dataset/Org';
import Resources from '../../../components/dataset/Resources';
+import gql from 'graphql-tag';
+
+const QUERY = gql`
+ query dataset($id: String) {
+ dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
+ result {
+ name
+ title
+ size
+ metadata_created
+ metadata_modified
+ resources {
+ name
+ title
+ format
+ created
+ last_modified
+ }
+ organization {
+ name
+ title
+ image_url
+ }
+ }
+ }
+ }
+`;
+
+function Dataset({ variables }) {
+ const { data, loading } = useQuery(QUERY, { variables });
+
+ if (loading) return