From 005075f74558a1790aed6bf636fa31faa59469c8 Mon Sep 17 00:00:00 2001 From: sagarggh Date: Mon, 5 Sep 2022 13:48:12 +0545 Subject: [PATCH 1/7] [integration][l]: Tools integration guided instruction added --- package.json | 4 +- src/DatastoreSearchSql.js | 187 ++++++++++++++++++++------------------ src/QueryBuilder.js | 119 ++++++++++++++++++++++++ yarn.lock | 25 +++++ 4 files changed, 248 insertions(+), 87 deletions(-) create mode 100644 src/QueryBuilder.js 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" From d1e308cc4d4952fd641ff852f9a3ef9bdc83ae6a Mon Sep 17 00:00:00 2001 From: sagarggh Date: Mon, 5 Sep 2022 16:08:18 +0545 Subject: [PATCH 2/7] [cleanup][xs]: typo fixed with build files. --- dist/DatastoreSearchSql.js | 42 +++++++++++++-- dist/QueryBuilder.js | 103 +++++++++++++++++++++++++++++++++++++ src/QueryBuilder.js | 4 +- 3 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 dist/QueryBuilder.js diff --git a/dist/DatastoreSearchSql.js b/dist/DatastoreSearchSql.js index 4668fd7..d723884 100644 --- a/dist/DatastoreSearchSql.js +++ b/dist/DatastoreSearchSql.js @@ -7,7 +7,7 @@ exports.default = void 0; require("./i18n/i18n"); -var _react = _interopRequireDefault(require("react")); +var _react = _interopRequireWildcard(require("react")); var _formik = require("formik"); @@ -15,9 +15,31 @@ var _reactDatePicker = _interopRequireDefault(require("react-date-picker")); var _reactI18next = require("react-i18next"); +var _QueryBuilder = _interopRequireDefault(require("./QueryBuilder")); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + function DatastoreSearchSql(props) { + var _useState = (0, _react.useState)(false), + _useState2 = _slicedToArray(_useState, 2), + showQueryBuilder = _useState2[0], + setShowQueryBuilder = _useState2[1]; + + var _useState3 = (0, _react.useState)("SELECT * FROM \"".concat(props.resource.id, "\" ORDER BY \"_id\" ASC LIMIT 100")), + _useState4 = _slicedToArray(_useState3, 2), + query = _useState4[0], + setQuery = _useState4[1]; + var resource = JSON.parse(JSON.stringify(props.resource)); var dateFields = resource.schema.fields.filter(function (field) { return field.type && field.type.includes('date'); @@ -119,6 +141,7 @@ function DatastoreSearchSql(props) { var datastoreUrl = encodeURI(props.apiUrl + "datastore_search_sql?sql=".concat(sqlQueryString)); // Trigger Redux action resource.api = datastoreUrl; + setQuery(sqlQueryString); props.action(resource); } @@ -128,6 +151,10 @@ function DatastoreSearchSql(props) { props.action(resource); } + function QueryBuiderToggle() { + setShowQueryBuilder(!showQueryBuilder); + } + return _react.default.createElement(_formik.Formik, { initialValues: { rules: resource.rules || [], @@ -150,7 +177,7 @@ function DatastoreSearchSql(props) { var values = _ref.values, setFieldValue = _ref.setFieldValue, handleReset = _ref.handleReset; - return _react.default.createElement(_formik.Form, { + return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement(_formik.Form, { className: "form-inline dq-main-container" }, _react.default.createElement("div", { className: "dq-heading" @@ -280,9 +307,16 @@ function DatastoreSearchSql(props) { type: "submit", className: "btn btn-primary reset-button", onClick: handleReset - }, t('Reset')))); + }, t('Reset')), _react.default.createElement("button", { + type: "button", + className: "btn btn-default query-builder-button ".concat(showQueryBuilder ? 'active' : ''), + onClick: QueryBuiderToggle + }, t('Query Builder')))); } - })); + })), showQueryBuilder ? _react.default.createElement(_QueryBuilder.default, { + apiUrl: props.apiUrl, + queryString: query + }) : null); } }); } diff --git a/dist/QueryBuilder.js b/dist/QueryBuilder.js new file mode 100644 index 0000000..7958a2a --- /dev/null +++ b/dist/QueryBuilder.js @@ -0,0 +1,103 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +require("./i18n/i18n"); + +var _react = _interopRequireWildcard(require("react")); + +var _reactTabsRedux = require("react-tabs-redux"); + +var _reactHighlight = _interopRequireDefault(require("react-highlight")); + +var _reactI18next = require("react-i18next"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +function QueryBuilder(props) { + var _useTranslation = (0, _reactI18next.useTranslation)(), + t = _useTranslation.t; + + var queryString = props.queryString; + + var _useState = (0, _react.useState)('Copy'), + _useState2 = _slicedToArray(_useState, 2), + copyButton = _useState2[0], + setcopyButton = _useState2[1]; + + var apiUrl = props.apiUrl; + var datastoreUrl = encodeURI(apiUrl + "datastore_search_sql?sql=".concat(queryString)); + var snippetSets = [{ + lang: 'cUrl', + format: 'bash', + snippet: "curl -L -s \"".concat(datastoreUrl, "\"") + }, { + lang: 'Python', + format: 'python', + snippet: "import requests\nfrom urllib import parse\n\nsql_query = '''SELECT COUNT(*) OVER () AS _count, * FROM \"0b2b7ce6-d7b8-41dc-a549-1b8598ca6c9d\" WHERE \"index\" = 'high' ORDER BY \"_id\" ASC LIMIT 100'''\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('https://ckan-dev.nationalgrid.dev.datopian.com/api/3/action/datastore_search_sql', \n\t\t\t\t\t\t\t params = parse.urlencode(params))\n data = resposne.json()[\"result\"]\n print(data) # Printing data\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)" + }, { + lang: 'Javascript', + format: 'javascript', + snippet: "const sql_query = `".concat(queryString, "`\n\nfetch('").concat(apiUrl, "datastore_search_sql?sql=' + encodeURI(sql_query))\n .then((response) => response.json())\n .then((data) => {\n console.log('Success:', data['result']);\n })\n .catch((error) => {\n console.error('Error:', error);\n });") + }, { + lang: 'R', + format: 'r', + snippet: "library(jsonlite)\n\nencoded_query <- '".concat(datastoreUrl, "'\nreturned <- fromJSON(encoded_query)\n\ndf <- returned$result$records\nprint(df)") + }, { + lang: 'Pandas', + format: 'python', + snippet: "# Install pandas python package\n# pip install pandas\n\n# Get data and convert into dataframe\nimport pandas as pd\nimport requests\nfrom urllib import parse\n\nsql_query = '''SELECT COUNT(*) OVER () AS _count, * FROM \"0b2b7ce6-d7b8-41dc-a549-1b8598ca6c9d\" WHERE \"index\" = 'high' ORDER BY \"_id\" ASC LIMIT 100'''\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('https://ckan-dev.nationalgrid.dev.datopian.com/api/3/action/datastore_search_sql', \n params = parse.urlencode(params))\n data_dict = resposne.json()[\"result\"]\n df = pd.DataFrame(data_dict['records'])\n print(df) # Dataframe\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)" + }]; + + function handleCopy(snippet) { + navigator.clipboard.writeText(snippet); + setcopyButton('Copied'); + } + + function onTabChange() { + setcopyButton('Copy'); + } + + return _react.default.createElement("div", { + className: "dq-querybuilder" + }, _react.default.createElement("h3", null, t('Integrate into your tools')), _react.default.createElement(_reactTabsRedux.Tabs, null, snippetSets.map(function (item, key) { + return _react.default.createElement(_reactTabsRedux.TabLink, { + onClick: onTabChange, + to: item.lang, + key: key, + className: "mr-4 tab-".concat(item.lang) + }, item.lang); + }), snippetSets.map(function (item, key) { + return _react.default.createElement(_reactTabsRedux.TabContent, { + key: key, + for: item.lang + }, _react.default.createElement("button", { + className: "snippet-copy", + style: { + float: 'right' + }, + onClick: function onClick() { + return handleCopy(item.snippet); + } + }, copyButton), _react.default.createElement(_reactHighlight.default, { + language: item.format, + className: "language-".concat(item.format) + }, item.snippet)); + }))); +} + +var _default = QueryBuilder; +exports.default = _default; \ No newline at end of file diff --git a/src/QueryBuilder.js b/src/QueryBuilder.js index 2a25696..7ad9cd2 100644 --- a/src/QueryBuilder.js +++ b/src/QueryBuilder.js @@ -97,14 +97,14 @@ except requests.exceptions.RequestException as e: return (
-

{t('Integrate into your toolsr')}

+

{t('Integrate into your tools')}

{snippetSets.map((item, key) => { return {item.lang} })} {snippetSets.map((item, key) => { - return + return From 5a02751a426f054ed7000d3f4824fdd15f12f717 Mon Sep 17 00:00:00 2001 From: sagarggh Date: Wed, 14 Sep 2022 12:01:13 +0545 Subject: [PATCH 3/7] [improve][s]: Bug fix in reset and remove hardcoded python snippets --- dist/DatastoreSearchSql.js | 2 +- dist/QueryBuilder.js | 4 ++-- src/DatastoreSearchSql.js | 2 +- src/QueryBuilder.js | 17 ++++++++--------- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/dist/DatastoreSearchSql.js b/dist/DatastoreSearchSql.js index d723884..d280a92 100644 --- a/dist/DatastoreSearchSql.js +++ b/dist/DatastoreSearchSql.js @@ -148,7 +148,7 @@ function DatastoreSearchSql(props) { function handleReset() { // Initial api url should be `datastore_search` without any options. resource.api = props.apiUrl + "datastore_search?resource_id=".concat(resource.id, "&limit=100"); - props.action(resource); + setQuery("SELECT * FROM \"".concat(props.resource.id, "\" ORDER BY \"_id\" ASC LIMIT 100")); } function QueryBuiderToggle() { diff --git a/dist/QueryBuilder.js b/dist/QueryBuilder.js index 7958a2a..1d64764 100644 --- a/dist/QueryBuilder.js +++ b/dist/QueryBuilder.js @@ -47,7 +47,7 @@ function QueryBuilder(props) { }, { lang: 'Python', format: 'python', - snippet: "import requests\nfrom urllib import parse\n\nsql_query = '''SELECT COUNT(*) OVER () AS _count, * FROM \"0b2b7ce6-d7b8-41dc-a549-1b8598ca6c9d\" WHERE \"index\" = 'high' ORDER BY \"_id\" ASC LIMIT 100'''\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('https://ckan-dev.nationalgrid.dev.datopian.com/api/3/action/datastore_search_sql', \n\t\t\t\t\t\t\t params = parse.urlencode(params))\n data = resposne.json()[\"result\"]\n print(data) # Printing data\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)" + snippet: "import requests\nfrom urllib import parse\n\nsql_query = '''".concat(queryString, "'''\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('").concat(apiUrl, "datastore_search_sql', params = parse.urlencode(params))\n data = resposne.json()[\"result\"]\n print(data) # Printing data\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)") }, { lang: 'Javascript', format: 'javascript', @@ -59,7 +59,7 @@ function QueryBuilder(props) { }, { lang: 'Pandas', format: 'python', - snippet: "# Install pandas python package\n# pip install pandas\n\n# Get data and convert into dataframe\nimport pandas as pd\nimport requests\nfrom urllib import parse\n\nsql_query = '''SELECT COUNT(*) OVER () AS _count, * FROM \"0b2b7ce6-d7b8-41dc-a549-1b8598ca6c9d\" WHERE \"index\" = 'high' ORDER BY \"_id\" ASC LIMIT 100'''\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('https://ckan-dev.nationalgrid.dev.datopian.com/api/3/action/datastore_search_sql', \n params = parse.urlencode(params))\n data_dict = resposne.json()[\"result\"]\n df = pd.DataFrame(data_dict['records'])\n print(df) # Dataframe\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)" + snippet: "# Install pandas package if you don't have it already\n# pip install pandas\n\n# Get data and convert into dataframe\nimport pandas as pd\nimport requests\nfrom urllib import parse\n\nsql_query = '''".concat(queryString, "'''\n\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('").concat(apiUrl, "datastore_search_sql', params = parse.urlencode(params))\n data = resposne.json()[\"result\"]\n df = pd.DataFrame(data[\"records\"])\n print(df) # Dataframe\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)") }]; function handleCopy(snippet) { diff --git a/src/DatastoreSearchSql.js b/src/DatastoreSearchSql.js index 6dc86ec..02a0ffb 100644 --- a/src/DatastoreSearchSql.js +++ b/src/DatastoreSearchSql.js @@ -85,7 +85,7 @@ function DatastoreSearchSql(props) { function handleReset() { // Initial api url should be `datastore_search` without any options. resource.api = props.apiUrl + `datastore_search?resource_id=${resource.id}&limit=100` - props.action(resource) + setQuery(`SELECT * FROM "${props.resource.id}" ORDER BY "_id" ASC LIMIT 100`) } function QueryBuiderToggle() { diff --git a/src/QueryBuilder.js b/src/QueryBuilder.js index 7ad9cd2..169754f 100644 --- a/src/QueryBuilder.js +++ b/src/QueryBuilder.js @@ -25,12 +25,11 @@ function QueryBuilder(props) { 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''' +sql_query = '''${queryString}''' 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)) + resposne = requests.get('${apiUrl}datastore_search_sql', params = parse.urlencode(params)) data = resposne.json()["result"] print(data) # Printing data except requests.exceptions.RequestException as e: @@ -65,7 +64,7 @@ print(df)` { lang: 'Pandas', format: 'python', - snippet: `# Install pandas python package + snippet: `# Install pandas package if you don't have it already # pip install pandas # Get data and convert into dataframe @@ -73,14 +72,14 @@ 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''' +sql_query = '''${queryString}''' + 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']) + resposne = requests.get('${apiUrl}datastore_search_sql', params = parse.urlencode(params)) + data = resposne.json()["result"] + df = pd.DataFrame(data["records"]) print(df) # Dataframe except requests.exceptions.RequestException as e: print(e.response.text)` From 176b9f91655a4b67a3f0a66a629e1ad4cbd8809c Mon Sep 17 00:00:00 2001 From: sagarggh Date: Wed, 14 Sep 2022 12:36:49 +0545 Subject: [PATCH 4/7] [improve][xs]: removed extra line --- dist/QueryBuilder.js | 2 +- src/QueryBuilder.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dist/QueryBuilder.js b/dist/QueryBuilder.js index 1d64764..31f2c1e 100644 --- a/dist/QueryBuilder.js +++ b/dist/QueryBuilder.js @@ -59,7 +59,7 @@ function QueryBuilder(props) { }, { lang: 'Pandas', format: 'python', - snippet: "# Install pandas package if you don't have it already\n# pip install pandas\n\n# Get data and convert into dataframe\nimport pandas as pd\nimport requests\nfrom urllib import parse\n\nsql_query = '''".concat(queryString, "'''\n\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('").concat(apiUrl, "datastore_search_sql', params = parse.urlencode(params))\n data = resposne.json()[\"result\"]\n df = pd.DataFrame(data[\"records\"])\n print(df) # Dataframe\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)") + snippet: "# Install pandas package if you don't have it already\n# pip install pandas\n\n# Get data and convert into dataframe\nimport pandas as pd\nimport requests\nfrom urllib import parse\n\nsql_query = '''".concat(queryString, "'''\nparams = {'sql': sql_query}\n\ntry:\n resposne = requests.get('").concat(apiUrl, "datastore_search_sql', params = parse.urlencode(params))\n data = resposne.json()[\"result\"]\n df = pd.DataFrame(data[\"records\"])\n print(df) # Dataframe\nexcept requests.exceptions.RequestException as e:\n print(e.response.text)") }]; function handleCopy(snippet) { diff --git a/src/QueryBuilder.js b/src/QueryBuilder.js index 169754f..ea86c74 100644 --- a/src/QueryBuilder.js +++ b/src/QueryBuilder.js @@ -73,7 +73,6 @@ import requests from urllib import parse sql_query = '''${queryString}''' - params = {'sql': sql_query} try: From b71c357209509cc3c2dbf3819399c2adbae1623b Mon Sep 17 00:00:00 2001 From: sagarggh Date: Wed, 14 Sep 2022 13:18:01 +0545 Subject: [PATCH 5/7] [reset][xs]: fixed reset function --- dist/DatastoreSearchSql.js | 1 + src/DatastoreSearchSql.js | 1 + 2 files changed, 2 insertions(+) diff --git a/dist/DatastoreSearchSql.js b/dist/DatastoreSearchSql.js index d280a92..da97098 100644 --- a/dist/DatastoreSearchSql.js +++ b/dist/DatastoreSearchSql.js @@ -149,6 +149,7 @@ function DatastoreSearchSql(props) { // Initial api url should be `datastore_search` without any options. resource.api = props.apiUrl + "datastore_search?resource_id=".concat(resource.id, "&limit=100"); setQuery("SELECT * FROM \"".concat(props.resource.id, "\" ORDER BY \"_id\" ASC LIMIT 100")); + props.action(resource); } function QueryBuiderToggle() { diff --git a/src/DatastoreSearchSql.js b/src/DatastoreSearchSql.js index 02a0ffb..ea73a3e 100644 --- a/src/DatastoreSearchSql.js +++ b/src/DatastoreSearchSql.js @@ -86,6 +86,7 @@ function DatastoreSearchSql(props) { // Initial api url should be `datastore_search` without any options. resource.api = props.apiUrl + `datastore_search?resource_id=${resource.id}&limit=100` setQuery(`SELECT * FROM "${props.resource.id}" ORDER BY "_id" ASC LIMIT 100`) + props.action(resource) } function QueryBuiderToggle() { From 78c4f67a76bf10c3a270a13dcdd867a0adcda871 Mon Sep 17 00:00:00 2001 From: Sagar Ghimire Date: Tue, 7 Jan 2025 15:26:09 +0545 Subject: [PATCH 6/7] fix: accessibility bug fix and code format --- src/DatastoreSearchSql.js | 146 ++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 70 deletions(-) diff --git a/src/DatastoreSearchSql.js b/src/DatastoreSearchSql.js index ea73a3e..aef03d5 100644 --- a/src/DatastoreSearchSql.js +++ b/src/DatastoreSearchSql.js @@ -1,15 +1,15 @@ import "./i18n/i18n" -import React, {useState} from 'react'; -import {Formik, Form, FieldArray, Field} from 'formik' +import React, { useState } from 'react'; +import { Formik, Form, FieldArray, Field } from 'formik' import DatePicker from 'react-date-picker' -import {useTranslation} from "react-i18next" +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 [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)) @@ -20,12 +20,12 @@ function DatastoreSearchSql(props) { const { t } = useTranslation(); const operators = [ - {name: '=', label: '='}, - {name: '!=', label: '!='}, - {name: '<', label: '<'}, - {name: '>', label: '>'}, - {name: '<=', label: '<='}, - {name: '>=', label: '>='} + { name: '=', label: '=' }, + { name: '!=', label: '!=' }, + { name: '<', label: '<' }, + { name: '>', label: '>' }, + { name: '<=', label: '<=' }, + { name: '>=', label: '>=' } ] function validate(values) { @@ -43,7 +43,7 @@ function DatastoreSearchSql(props) { // we get number of total rows info. let sqlQueryString = `SELECT COUNT(*) OVER () AS _count, * FROM "${resource.id}" WHERE ` if (clonedValues.date.startDate) { - const rule = { combinator: 'AND', field: clonedValues.date.fieldName, operator: '>=', value: clonedValues.date.startDate} + const rule = { combinator: 'AND', field: clonedValues.date.fieldName, operator: '>=', value: clonedValues.date.startDate } let localDateTime = new Date(clonedValues.date.startDate); // Now, convert it into GMT considering offset let offset = localDateTime.getTimezoneOffset(); @@ -52,7 +52,7 @@ function DatastoreSearchSql(props) { clonedValues.rules.push(rule) } if (clonedValues.date.endDate) { - const rule = { combinator: 'AND', field: clonedValues.date.fieldName, operator: '<=', value: clonedValues.date.endDate} + const rule = { combinator: 'AND', field: clonedValues.date.fieldName, operator: '<=', value: clonedValues.date.endDate } let localDateTime = new Date(clonedValues.date.endDate); // Now, convert it into GMT considering offset let offset = localDateTime.getTimezoneOffset(); @@ -88,7 +88,7 @@ function DatastoreSearchSql(props) { setQuery(`SELECT * FROM "${props.resource.id}" ORDER BY "_id" ASC LIMIT 100`) props.action(resource) } - + function QueryBuiderToggle() { setShowQueryBuilder(!showQueryBuilder) } @@ -101,7 +101,7 @@ function DatastoreSearchSql(props) { startDate: null, endDate: null, fieldName: defaultDateFieldName - } + } }} validate={values => validate(values) @@ -118,12 +118,14 @@ function DatastoreSearchSql(props) {
{defaultDateFieldName ? (
- - { dateFields.map((field, index) => ( + + {dateFields.map((field, index) => ( ))} + setFieldValue(`date.startDate`, val)} - format='yyyy-MM-dd' /> + format='yyyy-MM-dd' + altInput={true} + /> setFieldValue(`date.endDate`, val)} - returnValue='end' - format='yyyy-MM-dd' - minDate={values.date.startDate} /> + calendarAriaLabel="select end date from calendar" + value={values.date.endDate} + clearIcon='X' + nativeInputAriaLabel="End date input box" + dayAriaLabel="End day" + monthAriaLabel="End month" + yearAriaLabel="End year" + onChange={val => setFieldValue(`date.endDate`, val)} + returnValue='end' + format='yyyy-MM-dd' + minDate={values.date.startDate} />
) : ( '' @@ -153,58 +158,59 @@ function DatastoreSearchSql(props) { render={arrayHelpers => (
- {values.rules && values.rules.length > 0 ? ( - values.rules.map((rule, index) => ( -
- - - - - - {otherFields.map((field, index) => ( - - ))} - - - {operators.map((operator, index) => ( - - ))} - - - - -
- )) - ) : ( - - )} + {values.rules && values.rules.length > 0 ? ( + values.rules.map((rule, index) => ( +
+ + + + + + {otherFields.map((field, index) => ( + + ))} + + + {operators.map((operator, index) => ( + + ))} + + + + +
+ )) + ) : ( + + )}
- +
)} /> + { - showQueryBuilder?:null + showQueryBuilder ? : null } )} From 289ae664d786b314eb419960cef37866a6ba5229 Mon Sep 17 00:00:00 2001 From: Sagar Ghimire Date: Tue, 7 Jan 2025 18:35:50 +0545 Subject: [PATCH 7/7] fix: accessibility bug fix and code format --- dist/DatastoreSearchSql.js | 8 ++++++-- src/DatastoreSearchSql.js | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dist/DatastoreSearchSql.js b/dist/DatastoreSearchSql.js index da97098..f3bc804 100644 --- a/dist/DatastoreSearchSql.js +++ b/dist/DatastoreSearchSql.js @@ -187,13 +187,15 @@ function DatastoreSearchSql(props) { }, _react.default.createElement(_formik.Field, { name: "date.fieldName", component: "select", - className: "form-control" + className: "form-control", + "aria-label": "Choose date field" }, dateFields.map(function (field, index) { return _react.default.createElement("option", { value: field.name, key: "dateField".concat(index) }, field.title || field.name); })), _react.default.createElement(_reactDatePicker.default, { + calendarAriaLabel: "select start date from calendar", value: values.date.startDate, clearIcon: "X", nativeInputAriaLabel: "Start date input box", @@ -203,11 +205,13 @@ function DatastoreSearchSql(props) { onChange: function onChange(val) { return setFieldValue("date.startDate", val); }, - format: "yyyy-MM-dd" + format: "yyyy-MM-dd", + altInput: true }), _react.default.createElement("span", { className: "fa fa-long-arrow-right", "aria-hidden": "true" }), _react.default.createElement(_reactDatePicker.default, { + calendarAriaLabel: "select end date from calendar", value: values.date.endDate, clearIcon: "X", nativeInputAriaLabel: "End date input box", diff --git a/src/DatastoreSearchSql.js b/src/DatastoreSearchSql.js index aef03d5..76548ca 100644 --- a/src/DatastoreSearchSql.js +++ b/src/DatastoreSearchSql.js @@ -118,7 +118,7 @@ function DatastoreSearchSql(props) {
{defaultDateFieldName ? (
- + {dateFields.map((field, index) => ( ))}