From 2a578dc668c93e3949884e694b142383aac74c41 Mon Sep 17 00:00:00 2001 From: Valerij Fredriksen Date: Sat, 13 Aug 2022 12:12:42 +0200 Subject: Implement GET query --- .../context/query-builder-provider.jsx | 68 +++++++++++++++++----- .../querybuilder/query-derived/query-derived.jsx | 2 +- .../querybuilder/query-endpoint/query-endpoint.jsx | 50 ++++++++-------- .../querybuilder/query-filters/query-filters.jsx | 4 +- .../querybuilder/query-response/query-response.jsx | 2 +- 5 files changed, 79 insertions(+), 47 deletions(-) (limited to 'client') diff --git a/client/js/app/src/app/pages/querybuilder/context/query-builder-provider.jsx b/client/js/app/src/app/pages/querybuilder/context/query-builder-provider.jsx index 622641e8cb6..98a040159da 100644 --- a/client/js/app/src/app/pages/querybuilder/context/query-builder-provider.jsx +++ b/client/js/app/src/app/pages/querybuilder/context/query-builder-provider.jsx @@ -10,12 +10,24 @@ const context = createContext(null); export const ACTION = Object.freeze({ SET_QUERY: 0, SET_HTTP: 1, + SET_METHOD: 2, + SET_URL: 3, INPUT_ADD: 10, INPUT_UPDATE: 11, INPUT_REMOVE: 12, }); +function inputsToSearchParams(inputs, parent) { + return inputs.reduce((acc, { input, type: { name }, children }) => { + const key = parent ? `${parent}.${name}` : name; + return Object.assign( + acc, + children ? inputsToSearchParams(children, key) : { [key]: input } + ); + }, {}); +} + function inputsToJson(inputs) { return Object.fromEntries( inputs.map(({ children, input, type: { name, type } }) => [ @@ -53,9 +65,9 @@ function parseInput(input, type) { return input; } -function inputAdd(query, { id: parentId, type: typeName }) { - const inputs = cloneDeep(query.children); - const parent = parentId ? findInput(inputs, parentId) : query; +function inputAdd(params, { id: parentId, type: typeName }) { + const inputs = cloneDeep(params.children); + const parent = parentId ? findInput(inputs, parentId) : params; const nextId = parseInt(last(last(parent.children)?.id?.split('.')) ?? -1) + 1; @@ -68,21 +80,21 @@ function inputAdd(query, { id: parentId, type: typeName }) { type.children && { children: [] } ) ); - return { ...query, children: inputs }; + return { ...params, children: inputs }; } -function inputUpdate(query, { id, ...props }) { +function inputUpdate(params, { id, ...props }) { const keys = Object.keys(props); if (keys.length !== 1) throw new Error(`Expected to update exactly 1 input prop, got: ${keys}`); if (!['input', 'type'].includes(keys[0])) throw new Error(`Cannot update key ${keys[0]}`); - const inputs = cloneDeep(query.children); + const inputs = cloneDeep(params.children); const node = Object.assign(findInput(inputs, id), props); if (node.type.children) node.children = []; else delete node.children; - return { ...query, children: inputs }; + return { ...params, children: inputs }; } function findInput(inputs, id, Delete = false) { @@ -95,9 +107,25 @@ function findInput(inputs, id, Delete = false) { function reducer(state, action) { const result = preReducer(state, action); - if (state.query.children !== result.query.children) { - const json = inputsToJson(result.query.children); - result.query.input = JSON.stringify(json, null, 4); + const { request: sr, params: sp } = state; + const { request: rr, params: rp } = result; + if (sp.children !== rp.children || sr.method !== rr.method) { + result.query = + rr.method === 'POST' + ? JSON.stringify(inputsToJson(rp.children), null, 4) + : new URLSearchParams(inputsToSearchParams(rp.children)).toString(); + } + + if (sr.url !== rr.url || state.query !== result.query) { + if (rr.method === 'POST') { + rr.fullUrl = rr.url; + rr.body = result.query; + } else { + const url = new URL(rr.url); + url.search = result.query; + rr.fullUrl = url.toString(); + rr.body = null; + } } return result; } @@ -107,22 +135,26 @@ function preReducer(state, { action, data }) { case ACTION.SET_QUERY: { try { const children = jsonToInputs(JSON.parse(data)); - return { ...state, query: { ...root, children } }; + return { ...state, params: { ...root, children } }; } catch (error) { return state; } } case ACTION.SET_HTTP: return { ...state, http: data }; + case ACTION.SET_METHOD: + return { ...state, request: { ...state.request, method: data } }; + case ACTION.SET_URL: + return { ...state, request: { ...state.request, url: data } }; case ACTION.INPUT_ADD: - return { ...state, query: inputAdd(state.query, data) }; + return { ...state, params: inputAdd(state.params, data) }; case ACTION.INPUT_UPDATE: - return { ...state, query: inputUpdate(state.query, data) }; + return { ...state, params: inputUpdate(state.params, data) }; case ACTION.INPUT_REMOVE: { - const inputs = cloneDeep(state.query.children); + const inputs = cloneDeep(state.params.children); findInput(inputs, data, true); - return { ...state, query: { ...state.query, children: inputs } }; + return { ...state, params: { ...state.params, children: inputs } }; } default: @@ -133,7 +165,11 @@ function preReducer(state, { action, data }) { export function QueryBuilderProvider({ children }) { const [value, dispatch] = useReducer( reducer, - { http: {}, query: { ...root, input: '', children: [] } }, + { + request: { url: 'http://localhost:8080/search/', method: 'POST' }, + http: {}, + params: { ...root, children: [] }, + }, (s) => reducer(s, { action: ACTION.SET_QUERY, data: '{"yql":""}' }) ); _dispatch = dispatch; diff --git a/client/js/app/src/app/pages/querybuilder/query-derived/query-derived.jsx b/client/js/app/src/app/pages/querybuilder/query-derived/query-derived.jsx index c369083a6a0..e4626d194c5 100644 --- a/client/js/app/src/app/pages/querybuilder/query-derived/query-derived.jsx +++ b/client/js/app/src/app/pages/querybuilder/query-derived/query-derived.jsx @@ -12,7 +12,7 @@ import { Icon } from 'app/components'; import { PasteModal } from 'app/pages/querybuilder/query-derived/paste-modal'; export function QueryDerived() { - const query = useQueryBuilderContext((ctx) => ctx.query.input); + const query = useQueryBuilderContext('query'); return ( diff --git a/client/js/app/src/app/pages/querybuilder/query-endpoint/query-endpoint.jsx b/client/js/app/src/app/pages/querybuilder/query-endpoint/query-endpoint.jsx index 36545316255..8e8b64bb0d1 100644 --- a/client/js/app/src/app/pages/querybuilder/query-endpoint/query-endpoint.jsx +++ b/client/js/app/src/app/pages/querybuilder/query-endpoint/query-endpoint.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Select, TextInput, Button } from '@mantine/core'; import { errorMessage } from 'app/libs/notification'; import { @@ -8,12 +8,13 @@ import { } from 'app/pages/querybuilder/context/query-builder-provider'; import { Container, Content } from 'app/components'; -function send(method, url, query) { +function send(event, method, url, body) { + event.preventDefault(); dispatch(ACTION.SET_HTTP, { loading: true }); fetch(url, { method, headers: { 'Content-Type': 'application/json;charset=utf-8' }, - body: method === 'POST' ? query : null, + body, }) .then((response) => response.json()) .then((result) => @@ -28,34 +29,29 @@ function send(method, url, query) { } export default function QueryEndpoint() { - const httpMethods = ['POST', 'GET']; - const [method, setMethod] = useState('POST'); - const [url, setUrl] = useState('http://localhost:8080/search/'); - const query = useQueryBuilderContext((ctx) => ctx.query.input); + const { method, url, fullUrl, body } = useQueryBuilderContext('request'); const loading = useQueryBuilderContext((ctx) => ctx.http.loading); return ( - - dispatch(ACTION.SET_METHOD, value)} + value={method} + radius={0} + /> + dispatch(ACTION.SET_URL, e.currentTarget.value)} + value={url} + radius={0} + /> + + + ); } diff --git a/client/js/app/src/app/pages/querybuilder/query-filters/query-filters.jsx b/client/js/app/src/app/pages/querybuilder/query-filters/query-filters.jsx index 628f52908a1..2f59b0af86e 100644 --- a/client/js/app/src/app/pages/querybuilder/query-filters/query-filters.jsx +++ b/client/js/app/src/app/pages/querybuilder/query-filters/query-filters.jsx @@ -121,11 +121,11 @@ function Inputs({ id, type, inputs }) { } export function QueryFilters() { - const { children, type } = useQueryBuilderContext('query'); + const { children, type } = useQueryBuilderContext('params'); return ( - Query filters + Parameters diff --git a/client/js/app/src/app/pages/querybuilder/query-response/query-response.jsx b/client/js/app/src/app/pages/querybuilder/query-response/query-response.jsx index 055618ac636..56562ae1717 100644 --- a/client/js/app/src/app/pages/querybuilder/query-response/query-response.jsx +++ b/client/js/app/src/app/pages/querybuilder/query-response/query-response.jsx @@ -17,7 +17,7 @@ export function QueryResponse() { return ( - Query response + Response {({ copied, copy }) => ( -- cgit v1.2.3