From 3862bf561c2e857b4a2cf56433289351b3d3d12f Mon Sep 17 00:00:00 2001 From: Ivana Huckova Date: Thu, 20 Jun 2024 13:28:59 +0200 Subject: [PATCH] Refactor to fix type issues --- package.json | 1 + src/app/utils.ts | 30 +++++++++++++++- src/editors/query/query.url.test.tsx | 32 ++++++++--------- src/editors/query/query.url.tsx | 28 ++++++++------- yarn.lock | 53 +++++++++++++--------------- 5 files changed, 86 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index 6e99438ea..73a33cadc 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "mathjs": "11.7.0", "react": "18.2.0", "react-dom": "18.2.0", + "react-use": "^17.5.0", "tslib": "2.5.3", "uql": "0.0.22", "xml2js": "^0.6.2" diff --git a/src/app/utils.ts b/src/app/utils.ts index 1482017e1..d159a4262 100644 --- a/src/app/utils.ts +++ b/src/app/utils.ts @@ -1,5 +1,15 @@ import { ArrayVector, MutableDataFrame, FieldType, DataFrame, Field, Labels, TableData } from '@grafana/data'; -import type { InfinityCSVQuery, InfinityGraphQLQuery, InfinityHTMLQuery, InfinityJSONQuery, InfinityQuery, InfinityQueryWithDataSource, InfinityXMLQuery } from './../types'; +import type { + InfinityCSVQuery, + InfinityGraphQLQuery, + InfinityHTMLQuery, + InfinityJSONQuery, + InfinityQuery, + InfinityQueryWithDataSource, + InfinityQueryWithURLSource, + InfinityXMLQuery, + InfinityQueryType, +} from './../types'; export const isTableData = (res: any): res is TableData => res && res.columns; export const isDataFrame = (res: any): res is DataFrame => res && res.fields; @@ -33,6 +43,24 @@ export const isDataQuery = (query: InfinityQuery): query is InfinityQueryWithDat return false; } }; + +// We have to have query: unknown here as InfinityQuery and InfinityQueryWithURLSource are not compatible according to TypeScript +export const isInfinityQueryWithUrlSource = (query: unknown): query is InfinityQueryWithURLSource => { + // We do a basic check to ensure that query is an object and has a type property + if (!query || typeof query !== 'object' || !('type' in query)) { + return false; + } + + // we check if the query is a data query or has suitable type + if (isDataQuery(query as InfinityQuery) || query.type === 'uql' || query.type === 'groq') { + // It needs to have a source property and it should be 'url' + if ('source' in query) { + return query.source === 'url'; + } + } + + return false; +}; export const toTimeSeriesLong = (data: DataFrame[]): DataFrame[] => { if (!Array.isArray(data) || data.length === 0) { return data; diff --git a/src/editors/query/query.url.test.tsx b/src/editors/query/query.url.test.tsx index df4464556..304bcd820 100644 --- a/src/editors/query/query.url.test.tsx +++ b/src/editors/query/query.url.test.tsx @@ -1,12 +1,12 @@ -import React from "react"; -import { URL } from "./query.url"; -import { screen, render } from "@testing-library/react"; -import { InfinityQuery } from "types"; +import React from 'react'; +import { URL } from './query.url'; +import { screen, render } from '@testing-library/react'; +import { InfinityQuery } from 'types'; -describe("URL", () => { - it("should show changed URL", () => { +describe('URL', () => { + it('should show changed URL', () => { const mockQuery1 = { - url: "https://example1.com", + url: 'https://example1.com', type: 'json', source: 'url', } as InfinityQuery; @@ -16,18 +16,18 @@ describe("URL", () => { onChange: jest.fn(), onRunQuery: jest.fn(), onShowUrlOptions: jest.fn(), - } + }; + + const { rerender } = render(); + expect(screen.getByDisplayValue('https://example1.com')).toBeInTheDocument(); - const { rerender } = render(); - expect(screen.getByDisplayValue('https://example1.com')).toBeInTheDocument() - const mockQuery2 = { - url: "https://example2.com", + url: 'https://example2.com', type: 'json', source: 'url', } as InfinityQuery; - - rerender(); - expect(screen.getByDisplayValue('https://example2.com')).toBeInTheDocument() + + rerender(); + expect(screen.getByDisplayValue('https://example2.com')).toBeInTheDocument(); }); -}); \ No newline at end of file +}); diff --git a/src/editors/query/query.url.tsx b/src/editors/query/query.url.tsx index 098c2a16c..e38b6fdd1 100644 --- a/src/editors/query/query.url.tsx +++ b/src/editors/query/query.url.tsx @@ -1,9 +1,10 @@ import React, { useEffect, useState } from 'react'; +import { usePrevious } from 'react-use'; import { InlineFormLabel, CodeEditor, Select, Input, RadioButtonGroup, Icon } from '@grafana/ui'; import { EditorRow } from './../../components/extended/EditorRow'; import { EditorField } from './../../components/extended/EditorField'; import { Stack } from './../../components/extended/Stack'; -import { isDataQuery } from './../../app/utils'; +import { isDataQuery, isInfinityQueryWithUrlSource } from './../../app/utils'; import { KeyValueEditor } from './../../components/KeyValuePairEditor'; import type { InfinityQuery, InfinityURLOptions, QueryBodyContentType, QueryBodyType } from './../../types'; import type { SelectableValue } from '@grafana/data'; @@ -62,24 +63,27 @@ export const Method = ({ query, onChange, onRunQuery }: { query: InfinityQuery; }; export const URL = ({ query, onChange, onRunQuery, onShowUrlOptions }: { query: InfinityQuery; onChange: (value: InfinityQuery) => void; onRunQuery: () => void; onShowUrlOptions: () => void }) => { - const [url, setURL] = useState((isDataQuery(query) || query.type === 'uql' || query.type === 'groq') && query.source === 'url' ? query.url || '' : ''); - if (!(isDataQuery(query) || query.type === 'uql' || query.type === 'groq')) { - return <>; - } - if (query.source !== 'url') { + const [url, setURL] = useState(isInfinityQueryWithUrlSource(query) ? query.url || '' : ''); + const previousQuery = usePrevious(query); + + useEffect(() => { + if (isInfinityQueryWithUrlSource(query) && isInfinityQueryWithUrlSource(previousQuery)) { + // We want to check if the URL has changed outside of component and update the state accordingly + if (query.url !== previousQuery.url) { + setURL(query.url); + } + } + }, [query, previousQuery]); + + if (!isInfinityQueryWithUrlSource(query)) { return <>; } + const onURLChange = () => { onChange({ ...query, url }); onRunQuery(); }; - useEffect(() => { - if(query.url !== url) { - setURL(query.url ?? '') - } - }, [query.url]) - return (