diff --git a/package.json b/package.json index 6a33120..35a000b 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "react": "^16.8.6", "react-date-picker": "^7.7.0", "react-dom": "^16.8.6", - "react-i18next": "^11.3.0" + "react-highlight": "^0.14.0", + "react-i18next": "^11.3.0", + "react-tabs-redux": "^4.0.0" }, "babel": { "presets": [ diff --git a/src/DatastoreSearchSql.js b/src/DatastoreSearchSql.js index adf8736..6dc86ec 100644 --- a/src/DatastoreSearchSql.js +++ b/src/DatastoreSearchSql.js @@ -1,12 +1,16 @@ import "./i18n/i18n" -import React from 'react'; +import React, {useState} from 'react'; import {Formik, Form, FieldArray, Field} from 'formik' import DatePicker from 'react-date-picker' import {useTranslation} from "react-i18next" +import QueryBuilder from './QueryBuilder' function DatastoreSearchSql(props) { + const[showQueryBuilder, setShowQueryBuilder] = useState(false) + const[query, setQuery] = useState(`SELECT * FROM "${props.resource.id}" ORDER BY "_id" ASC LIMIT 100`) + const resource = JSON.parse(JSON.stringify(props.resource)) const dateFields = resource.schema.fields.filter(field => field.type && field.type.includes('date')) @@ -74,6 +78,7 @@ function DatastoreSearchSql(props) { const datastoreUrl = encodeURI(props.apiUrl + `datastore_search_sql?sql=${sqlQueryString}`) // Trigger Redux action resource.api = datastoreUrl + setQuery(sqlQueryString) props.action(resource) } @@ -82,6 +87,10 @@ function DatastoreSearchSql(props) { resource.api = props.apiUrl + `datastore_search?resource_id=${resource.id}&limit=100` props.action(resource) } + + function QueryBuiderToggle() { + setShowQueryBuilder(!showQueryBuilder) + } return ( ( -
-
- {defaultDateFieldName ? ( -
- - { dateFields.map((field, index) => ( - - ))} - - setFieldValue(`date.startDate`, val)} - format='yyyy-MM-dd' /> - - + +
+ {defaultDateFieldName ? ( +
+ + { dateFields.map((field, index) => ( + + ))} + + setFieldValue(`date.endDate`, val)} - returnValue='end' - format='yyyy-MM-dd' - minDate={values.date.startDate} /> -
- ) : ( - '' - )} - ( -
-
- {values.rules && values.rules.length > 0 ? ( - values.rules.map((rule, index) => ( -
- - - - - - {otherFields.map((field, index) => ( - - ))} - - - {operators.map((operator, index) => ( - - ))} - - - - -
- )) - ) : ( - - )} -
-
- - -
+ nativeInputAriaLabel="Start date input box" + dayAriaLabel="Start day" + monthAriaLabel="Start month" + yearAriaLabel="Start year" + onChange={val => setFieldValue(`date.startDate`, val)} + format='yyyy-MM-dd' /> + + setFieldValue(`date.endDate`, val)} + returnValue='end' + format='yyyy-MM-dd' + minDate={values.date.startDate} />
+ ) : ( + '' )} - /> - + ( +
+
+ {values.rules && values.rules.length > 0 ? ( + values.rules.map((rule, index) => ( +
+ + + + + + {otherFields.map((field, index) => ( + + ))} + + + {operators.map((operator, index) => ( + + ))} + + + + +
+ )) + ) : ( + + )} +
+
+ + + +
+
+ )} + /> + + { + showQueryBuilder?:null + } + )} /> ) diff --git a/src/QueryBuilder.js b/src/QueryBuilder.js new file mode 100644 index 0000000..2a25696 --- /dev/null +++ b/src/QueryBuilder.js @@ -0,0 +1,119 @@ +import './i18n/i18n' +import React, { useState } from 'react'; +import { Tabs, TabLink, TabContent } from 'react-tabs-redux' +import Highlight from 'react-highlight' +import {useTranslation} from "react-i18next" + + + +function QueryBuilder(props) { + const { t } = useTranslation(); + + const queryString = props.queryString + const [copyButton, setcopyButton] = useState('Copy'); + + const apiUrl = props.apiUrl + const datastoreUrl = encodeURI(apiUrl + `datastore_search_sql?sql=${queryString}`) + + const snippetSets = [{ + lang: 'cUrl', + format: 'bash', + snippet: `curl -L -s "${datastoreUrl}"` + }, { + lang: 'Python', + format: 'python', + snippet: `import requests +from urllib import parse + +sql_query = '''SELECT COUNT(*) OVER () AS _count, * FROM "0b2b7ce6-d7b8-41dc-a549-1b8598ca6c9d" WHERE "index" = 'high' ORDER BY "_id" ASC LIMIT 100''' +params = {'sql': sql_query} + +try: + resposne = requests.get('https://ckan-dev.nationalgrid.dev.datopian.com/api/3/action/datastore_search_sql', + params = parse.urlencode(params)) + data = resposne.json()["result"] + print(data) # Printing data +except requests.exceptions.RequestException as e: + print(e.response.text)` + }, + { + lang: 'Javascript', + format: 'javascript', + snippet: `const sql_query = \`${queryString}\` + +fetch('${apiUrl}datastore_search_sql?sql=' + encodeURI(sql_query)) + .then((response) => response.json()) + .then((data) => { + console.log('Success:', data['result']); + }) + .catch((error) => { + console.error('Error:', error); + });` + }, + { + lang: 'R', + format: 'r', + snippet: + `library(jsonlite) + +encoded_query <- '${datastoreUrl}' +returned <- fromJSON(encoded_query) + +df <- returned$result$records +print(df)` + }, + { + lang: 'Pandas', + format: 'python', + snippet: `# Install pandas python package +# pip install pandas + +# Get data and convert into dataframe +import pandas as pd +import requests +from urllib import parse + +sql_query = '''SELECT COUNT(*) OVER () AS _count, * FROM "0b2b7ce6-d7b8-41dc-a549-1b8598ca6c9d" WHERE "index" = 'high' ORDER BY "_id" ASC LIMIT 100''' +params = {'sql': sql_query} + +try: + resposne = requests.get('https://ckan-dev.nationalgrid.dev.datopian.com/api/3/action/datastore_search_sql', + params = parse.urlencode(params)) + data_dict = resposne.json()["result"] + df = pd.DataFrame(data_dict['records']) + print(df) # Dataframe +except requests.exceptions.RequestException as e: + print(e.response.text)` + }] + + function handleCopy(snippet) { + navigator.clipboard.writeText(snippet) + setcopyButton('Copied'); + } + + function onTabChange() { + setcopyButton('Copy'); + } + + return ( +
+

{t('Integrate into your toolsr')}

+ + {snippetSets.map((item, key) => { + return {item.lang} + })} + + {snippetSets.map((item, key) => { + return + + + {item.snippet} + + + })} + +
+ ) +} +export default QueryBuilder \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index dc9ae78..c89635b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2160,6 +2160,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classnames@^2.2.6: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + clean-css@4.2.x: version "4.2.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" @@ -4122,6 +4127,11 @@ hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" +highlight.js@^10.5.0: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -7571,6 +7581,13 @@ react-fit@^1.0.3: detect-element-overflow "^1.1.1" prop-types "^15.6.0" +react-highlight@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/react-highlight/-/react-highlight-0.14.0.tgz#5aefa5518baa580f96b68d48129d7a5d2dc0c9ef" + integrity sha512-kWE+KXOXidS7SABhVopOgMnowbI3RAfeGZbnrduLNlWrYAED8sycL9l/Fvw3w0PFpIIawB7mRDnyhDcM/cIIGA== + dependencies: + highlight.js "^10.5.0" + react-i18next@^11.3.0: version "11.3.0" resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.3.0.tgz#8c827b084708924fd2e8c787aca78e0f7966fa44" @@ -7646,6 +7663,14 @@ react-scripts@3.0.1: optionalDependencies: fsevents "2.0.6" +react-tabs-redux@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/react-tabs-redux/-/react-tabs-redux-4.0.0.tgz#b803aa3e80ae317311a83b3740ae13a938247156" + integrity sha512-yk5afCpUlmWqXA/fhSi02YaCSlpFH5v6QlUiiVRx+V1OTyLDaZFDnARCflUoGkwIq00o7ryVWUXNkQ3UwAcebA== + dependencies: + classnames "^2.2.6" + prop-types "^15.6.2" + react@^16.8.6: version "16.9.0" resolved "https://registry.yarnpkg.com/react/-/react-16.9.0.tgz#40ba2f9af13bc1a38d75dbf2f4359a5185c4f7aa"