diff --git a/app/browser/dataset-preview.tsx b/app/browser/dataset-preview.tsx index 112db9b915..7aa9546e5f 100644 --- a/app/browser/dataset-preview.tsx +++ b/app/browser/dataset-preview.tsx @@ -12,6 +12,7 @@ import Flex from "@/components/flex"; import { HintRed, Loading, LoadingDataError } from "@/components/hint"; import { DataSource } from "@/config-types"; import { sourceToLabel } from "@/domain/datasource"; +import { getQueryRequestContext } from "@/graphql/hooks"; import { useDataCubeMetadataQuery, useDataCubePreviewQuery, @@ -86,6 +87,11 @@ export interface Preview { label: string; } +const DATA_CUBE_PREVIEW_QUERY_REQUEST_CONTEXT = getQueryRequestContext({ + querySource: "DataSetPreview / dataset-preview.tsx", + queryReason: "Needed to display a dataset preview in the /browse page.", +}); + export const DataSetPreview = ({ dataSetIri, dataSource, @@ -110,7 +116,10 @@ export const DataSetPreview = ({ useDataCubeMetadataQuery({ variables }); const [ { data: previewData, fetching: fetchingPreview, error: previewError }, - ] = useDataCubePreviewQuery({ variables }); + ] = useDataCubePreviewQuery({ + variables, + context: DATA_CUBE_PREVIEW_QUERY_REQUEST_CONTEXT, + }); const classes = useStyles({ descriptionPresent: !!metadata?.dataCubeMetadata.description, }); diff --git a/app/gql-flamegraph/devtool.tsx b/app/gql-flamegraph/devtool.tsx index e11f6a3b31..158296982e 100644 --- a/app/gql-flamegraph/devtool.tsx +++ b/app/gql-flamegraph/devtool.tsx @@ -330,14 +330,29 @@ const Queries = ({ queries }: { queries: RequestQueryMeta[] }) => { return (
+ {q.source && ( + <> + + {q.source} + + {" – "} + + )} {q.endTime - q.startTime}ms {" "} - -{" "} + –{" "} Copy
+ {q.reason && ( +
+ + ℹ️ {q.reason} + +
+ )} { const debug = flag("debug"); const disableCache = flag("server-side-cache.disable"); return { - "x-visualize-debug": debug ? "true" : "", - "x-visualize-cache-control": disableCache ? "no-cache" : "", + [GQL_DEBUG_HEADER]: debug ? "true" : "", + [GQL_CACHE_CONTROL_HEADER]: disableCache ? "no-cache" : "", + [GQL_QUERY_SOURCE_HEADER]: querySource ?? "", + [GQL_QUERY_REASON_HEADER]: queryReason ?? "", }; -} +}; + +export const client = createClient({ + url: graphqlEndpointFlag ?? GRAPHQL_ENDPOINT, + exchanges: [...devtoolsExchanges, ...defaultExchanges], + fetchOptions: { + headers: getGraphqlHeaders(), + }, +}); diff --git a/app/graphql/context.tsx b/app/graphql/context.tsx index 4222a1b234..e274b26cc4 100644 --- a/app/graphql/context.tsx +++ b/app/graphql/context.tsx @@ -12,6 +12,12 @@ import { SPARQL_GEO_ENDPOINT } from "@/domain/env"; import { Awaited } from "@/domain/types"; import { Timings } from "@/gql-flamegraph/resolvers"; import { getMaybeCachedSparqlUrl } from "@/graphql/caching-utils"; +import { + GQL_CACHE_CONTROL_HEADER, + GQL_DEBUG_HEADER, + GQL_QUERY_REASON_HEADER, + GQL_QUERY_SOURCE_HEADER, +} from "@/graphql/client"; import { RequestQueryMeta } from "@/graphql/query-meta"; import { QueryResolvers, @@ -84,10 +90,17 @@ const createLoaders = async ( export type Loaders = Awaited>; -const setupSparqlClients = ( - ctx: VisualizeGraphQLContext, - sourceUrl: string -) => { +const setupSparqlClients = ({ + ctx, + sourceUrl, + querySource, + queryReason, +}: { + ctx: VisualizeGraphQLContext; + sourceUrl: string; + querySource: string | undefined; + queryReason: string | undefined; +}) => { const sparqlClient = new ParsingClient({ endpointUrl: sourceUrl, }); @@ -105,6 +118,8 @@ const setupSparqlClients = ( startTime: t.start, endTime: t.end, text: args[0], + source: querySource, + reason: queryReason, }); }; @@ -147,11 +162,11 @@ const sparqlCache = new LRUCache({ }); const shouldUseServerSideCache = (req: IncomingMessage) => { - return req.headers["x-visualize-cache-control"] !== "no-cache"; + return req.headers[GQL_CACHE_CONTROL_HEADER] !== "no-cache"; }; const isDebugMode = (req: IncomingMessage) => { - return req.headers["x-visualize-debug"] === "true"; + return req.headers[GQL_DEBUG_HEADER] === "true"; }; const createContextContent = async ({ @@ -164,7 +179,12 @@ const createContextContent = async ({ req: IncomingMessage; }) => { const { sparqlClient, sparqlClientStream, geoSparqlClient } = - setupSparqlClients(ctx, sourceUrl); + setupSparqlClients({ + ctx, + sourceUrl, + querySource: req.headers[GQL_QUERY_SOURCE_HEADER]?.toString(), + queryReason: req.headers[GQL_QUERY_REASON_HEADER]?.toString(), + }); const contextCache = shouldUseServerSideCache(req) ? sparqlCache : undefined; const loaders = await createLoaders( sparqlClient, diff --git a/app/graphql/hooks.ts b/app/graphql/hooks.ts index 5d6ad323a9..57b9bec01f 100644 --- a/app/graphql/hooks.ts +++ b/app/graphql/hooks.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useMemo, useState } from "react"; -import { Client, useClient } from "urql"; +import { Client, OperationContext, useClient } from "urql"; import { ConfiguratorState, hasChartConfigs } from "@/configurator"; import { @@ -7,10 +7,8 @@ import { DataCubeMetadata, DataCubesObservations, } from "@/domain/data"; -import { Locale } from "@/locales/locales"; -import { assert } from "@/utils/assert"; - -import { joinDimensions, mergeObservations } from "./join"; +import { getGraphqlHeaders } from "@/graphql/client"; +import { joinDimensions, mergeObservations } from "@/graphql/join"; import { DataCubeComponentFilter, DataCubeComponentsDocument, @@ -24,7 +22,24 @@ import { DataCubeObservationsDocument, DataCubeObservationsQuery, DataCubeObservationsQueryVariables, -} from "./query-hooks"; +} from "@/graphql/query-hooks"; +import { Locale } from "@/locales/locales"; +import { assert } from "@/utils/assert"; + +export const getQueryRequestContext = (options: { + querySource?: string; + queryReason?: string; +}): Partial => { + if (!options) { + return {}; + } + + return { + fetchOptions: { + headers: getGraphqlHeaders(options), + }, + }; +}; const useQueryKey = (options: object) => { return useMemo(() => { diff --git a/app/graphql/query-meta.ts b/app/graphql/query-meta.ts index 840fbe264b..1781442adf 100644 --- a/app/graphql/query-meta.ts +++ b/app/graphql/query-meta.ts @@ -2,5 +2,6 @@ export type RequestQueryMeta = { text: string; startTime: number; endTime: number; - label?: string; + source?: string; + reason?: string; };