Skip to content

Commit

Permalink
[integration][l]: Tools integration guided instruction added
Browse files Browse the repository at this point in the history
  • Loading branch information
sagargg committed Sep 5, 2022
1 parent 80f92db commit 005075f
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 87 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
187 changes: 101 additions & 86 deletions src/DatastoreSearchSql.js
Original file line number Diff line number Diff line change
@@ -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'))
Expand Down Expand Up @@ -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)
}

Expand All @@ -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 (
<Formik
Expand All @@ -103,94 +112,100 @@ function DatastoreSearchSql(props) {
handleReset()
}
render={({ values, setFieldValue, handleReset }) => (
<Form className="form-inline dq-main-container">
<div className="dq-heading"></div>
{defaultDateFieldName ? (
<div className="dq-date-picker">
<Field name={`date.fieldName`} component="select" className="form-control">
{ dateFields.map((field, index) => (
<option value={field.name} key={`dateField${index}`}>{field.title || field.name}</option>
))}
</Field>
<DatePicker
value={values.date.startDate}
clearIcon='X'
nativeInputAriaLabel="Start date input box"
dayAriaLabel="Start day"
monthAriaLabel="Start month"
yearAriaLabel="Start year"
onChange={val => setFieldValue(`date.startDate`, val)}
format='yyyy-MM-dd' />
<span className="fa fa-long-arrow-right" aria-hidden="true"></span>
<DatePicker
value={values.date.endDate}
<>
<Form className="form-inline dq-main-container">
<div className="dq-heading"></div>
{defaultDateFieldName ? (
<div className="dq-date-picker">
<Field name={`date.fieldName`} component="select" className="form-control">
{ dateFields.map((field, index) => (
<option value={field.name} key={`dateField${index}`}>{field.title || field.name}</option>
))}
</Field>
<DatePicker
value={values.date.startDate}
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} />
</div>
) : (
''
)}
<FieldArray
name='rules'
render={arrayHelpers => (
<div className="dq-rule-container">
<div className="dq-body">
{values.rules && values.rules.length > 0 ? (
values.rules.map((rule, index) => (
<div key={index} className="dq-rule-item">
<Field name={`rules.${index}.combinator`} aria-label="Choose combinator: AND/OR" component="select" className="form-control" required>
<option value="AND">AND</option>
<option value="OR">OR</option>
</Field>
<Field name={`rules.${index}.field`} aria-label="Choose field" component="select" className="form-control" required>
{otherFields.map((field, index) => (
<option value={field.name} key={`field${index}`}>{field.title || field.name}</option>
))}
</Field>
<Field name={`rules.${index}.operator`} aria-label="Choose operator" component="select" className="form-control" required>
{operators.map((operator, index) => (
<option value={operator.name} key={`operator${index}`}>{operator.label}</option>
))}
</Field>
<Field name={`rules.${index}.value`} aria-label="Input custom rule" className="form-control" required />
<button
type="button"
className="btn btn-default dq-btn-remove"
onClick={() => arrayHelpers.remove(index)} // remove a rule from the list
>
-
</button>
<button
type="button"
className="btn btn-default dq-btn-add"
onClick={() => arrayHelpers.insert(index, {combinator: 'AND', field: otherFields[0].name, operator: '=', value: ''})} // insert an empty rule at a position
>
+
</button>
</div>
))
) : (
<button type="button" className="btn btn-default dq-rule-add" onClick={() => arrayHelpers.push({combinator: 'AND', field: otherFields[0].name, operator: '=', value: ''})}>
{/* show this when user has removed all rules from the list */}
{t('Add a rule')}
</button>
)}
</div>
<div className="dq-rule-submit dq-footer">
<button type="submit" className="btn btn-primary submit-button">{t('Submit')}</button>
<button type="submit" className="btn btn-primary reset-button" onClick={handleReset}>{t('Reset')}</button>
</div>
nativeInputAriaLabel="Start date input box"
dayAriaLabel="Start day"
monthAriaLabel="Start month"
yearAriaLabel="Start year"
onChange={val => setFieldValue(`date.startDate`, val)}
format='yyyy-MM-dd' />
<span className="fa fa-long-arrow-right" aria-hidden="true"></span>
<DatePicker
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} />
</div>
) : (
''
)}
/>
</Form>
<FieldArray
name='rules'
render={arrayHelpers => (
<div className="dq-rule-container">
<div className="dq-body">
{values.rules && values.rules.length > 0 ? (
values.rules.map((rule, index) => (
<div key={index} className="dq-rule-item">
<Field name={`rules.${index}.combinator`} aria-label="Choose combinator: AND/OR" component="select" className="form-control" required>
<option value="AND">AND</option>
<option value="OR">OR</option>
</Field>
<Field name={`rules.${index}.field`} aria-label="Choose field" component="select" className="form-control" required>
{otherFields.map((field, index) => (
<option value={field.name} key={`field${index}`}>{field.title || field.name}</option>
))}
</Field>
<Field name={`rules.${index}.operator`} aria-label="Choose operator" component="select" className="form-control" required>
{operators.map((operator, index) => (
<option value={operator.name} key={`operator${index}`}>{operator.label}</option>
))}
</Field>
<Field name={`rules.${index}.value`} aria-label="Input custom rule" className="form-control" required />
<button
type="button"
className="btn btn-default dq-btn-remove"
onClick={() => arrayHelpers.remove(index)} // remove a rule from the list
>
-
</button>
<button
type="button"
className="btn btn-default dq-btn-add"
onClick={() => arrayHelpers.insert(index, {combinator: 'AND', field: otherFields[0].name, operator: '=', value: ''})} // insert an empty rule at a position
>
+
</button>
</div>
))
) : (
<button type="button" className="btn btn-default dq-rule-add" onClick={() => arrayHelpers.push({combinator: 'AND', field: otherFields[0].name, operator: '=', value: ''})}>
{/* show this when user has removed all rules from the list */}
{t('Add a rule')}
</button>
)}
</div>
<div className="dq-rule-submit dq-footer">
<button type="submit" className="btn btn-primary submit-button">{t('Submit')}</button>
<button type="submit" className="btn btn-primary reset-button" onClick={handleReset}>{t('Reset')}</button>
<button type='button' className={`btn btn-default query-builder-button ${showQueryBuilder?'active': ''}`} onClick={QueryBuiderToggle}>{t('Query Builder')}</button>
</div>
</div>
)}
/>
</Form>
{
showQueryBuilder?<QueryBuilder apiUrl={props.apiUrl} queryString={query}/>:null
}
</>
)}
/>
)
Expand Down
119 changes: 119 additions & 0 deletions src/QueryBuilder.js
Original file line number Diff line number Diff line change
@@ -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 (
<div className="dq-querybuilder">
<h3>{t('Integrate into your toolsr')}</h3>
<Tabs>
{snippetSets.map((item, key) => {
return <TabLink onClick={onTabChange} to={item.lang} key={key} className={`mr-4 tab-${item.lang}`}>{item.lang}</TabLink>
})}

{snippetSets.map((item, key) => {
return <TabContent key={key} for={item.lang} className="dq">
<button className="snippet-copy" style={{ float: 'right' }}
onClick={() => handleCopy(item.snippet)}>{copyButton}</button>
<Highlight language={item.format} className={`language-${item.format}`}>
{item.snippet}
</Highlight>
</TabContent>
})}
</Tabs>
</div>
)
}
export default QueryBuilder
Loading

0 comments on commit 005075f

Please sign in to comment.