diff --git a/Changelog.md b/Changelog.md index ec680207e..e8bceebfe 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,7 +5,8 @@ ### Other changes - **Added** query editor for Gremlin connections - ([#878](https://github.com/aws/graph-explorer/pull/878)) + ([#878](https://github.com/aws/graph-explorer/pull/878), + [#855](https://github.com/aws/graph-explorer/pull/855)) - **Added** ability to customize default neighbor expansion limit ([#925](https://github.com/aws/graph-explorer/pull/925)) - **Added** ability to resize the sidebar diff --git a/packages/graph-explorer/src/connector/queries.ts b/packages/graph-explorer/src/connector/queries.ts index b7cd969b3..a84576b84 100644 --- a/packages/graph-explorer/src/connector/queries.ts +++ b/packages/graph-explorer/src/connector/queries.ts @@ -5,8 +5,6 @@ import { Explorer, KeywordSearchRequest, KeywordSearchResponse, - RawQueryRequest, - RawQueryResponse, SchemaResponse, toMappedQueryResults, VertexDetailsRequest, @@ -146,27 +144,6 @@ export function edgeDetailsQuery( }); } -export function rawQueryQuery( - request: RawQueryRequest, - updateSchema: (entities: { vertices: Vertex[]; edges: Edge[] }) => void, - explorer: Explorer, - queryClient: QueryClient -) { - return queryOptions({ - queryKey: ["db", "raw-query", request, explorer, queryClient], - queryFn: async ({ signal }): Promise => { - const results = await explorer.rawQuery(request, { signal }); - - // Update the schema and the cache - updateVertexDetailsCache(explorer, queryClient, results.vertices); - updateEdgeDetailsCache(explorer, queryClient, results.edges); - updateSchema(results); - - return results; - }, - }); -} - /** Sets the vertex details cache for the given vertices. */ export function updateVertexDetailsCache( explorer: Explorer, diff --git a/packages/graph-explorer/src/modules/SearchSidebar/FilterSearchTabContent.tsx b/packages/graph-explorer/src/modules/SearchSidebar/FilterSearchTabContent.tsx index 6d769fce1..a8dace0ce 100644 --- a/packages/graph-explorer/src/modules/SearchSidebar/FilterSearchTabContent.tsx +++ b/packages/graph-explorer/src/modules/SearchSidebar/FilterSearchTabContent.tsx @@ -11,9 +11,16 @@ import { Label, Checkbox, Input, + LoadingSpinner, + PanelEmptyState, + PanelError, + SearchSadIcon, } from "@/components"; import { useTranslations } from "@/hooks"; +import { KeywordSearchResponse } from "@/connector"; +import { UseQueryResult } from "@tanstack/react-query"; +import { useCancelKeywordSearch } from "./useKeywordSearchQuery"; export function FilterSearchTabContent() { const t = useTranslations(); @@ -108,7 +115,52 @@ export function FilterSearchTabContent() { - + ); } + +function SearchResultsListContainer({ + query, +}: { + query: UseQueryResult; +}) { + const cancelAll = useCancelKeywordSearch(); + + if (query.isLoading) { + return ( + cancelAll()} + icon={} + className="p-8" + /> + ); + } + + if (query.isError && !query.data) { + return ( + + ); + } + + if ( + !query.data || + (query.data.vertices.length === 0 && + query.data.edges.length === 0 && + query.data.scalars.length === 0) + ) { + return ( + } + className="p-8" + /> + ); + } + + return ; +} diff --git a/packages/graph-explorer/src/modules/SearchSidebar/QuerySearchTabContent.tsx b/packages/graph-explorer/src/modules/SearchSidebar/QuerySearchTabContent.tsx index 7a9302498..dd849c80b 100644 --- a/packages/graph-explorer/src/modules/SearchSidebar/QuerySearchTabContent.tsx +++ b/packages/graph-explorer/src/modules/SearchSidebar/QuerySearchTabContent.tsx @@ -4,21 +4,24 @@ import { FormControl, FormField, FormItem, - Label, + LoadingSpinner, + PanelEmptyState, + PanelError, + SearchSadIcon, TextArea, } from "@/components"; -import { rawQueryQuery } from "@/connector"; import { useExplorer, useUpdateSchemaFromEntities } from "@/core"; -import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { CornerDownRightIcon } from "lucide-react"; -import { SearchResultsList } from "./SearchResultsList"; -import { useCallback, useDeferredValue } from "react"; import { z } from "zod"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { logger } from "@/utils"; import { useAtom } from "jotai"; +import { SearchResultsList } from "./SearchResultsList"; import { atomWithReset } from "jotai/utils"; +import { updateEdgeDetailsCache, updateVertexDetailsCache } from "@/connector"; +import { useRef } from "react"; const formDataSchema = z.object({ query: z.string().default(""), @@ -26,64 +29,65 @@ const formDataSchema = z.object({ type FormData = z.infer; +/** + * Stores the current query text. + * + * This is used to restore the query text when the user switches tabs in the + * sidebar, which forces React to create this view from scratch. + */ export const queryTextAtom = atomWithReset(""); export function QuerySearchTabContent() { const [queryText, setQueryText] = useAtom(queryTextAtom); - const form = useForm({ + const { mutation, cancel } = useRawQueryMutation(); + + const form = useForm({ resolver: zodResolver(formDataSchema), defaultValues: { query: queryText, }, }); - const query = useQuerySearch(queryText); + // Execute the query when the form is submitted + const onSubmit = (data: FormData) => { + logger.debug("Executing query:", data); + setQueryText(data.query); + mutation.mutate(data.query); + }; - const executeQuery = useCallback( - (data: FormData) => { - logger.debug("Executing query", data); - if (data.query !== queryText) { - setQueryText(data.query); - } else { - query.refetch(); - } - }, - [query, queryText, setQueryText] - ); + // Submit the form when the user presses cmd+enter or ctrl+enter + const onKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + form.handleSubmit(onSubmit)(); + } + }; return (
( - - +