diff --git a/.github/workflows/validate-workflow.yml b/.github/workflows/validate-workflow.yml index 3c12c08a..fbbfcd9f 100644 --- a/.github/workflows/validate-workflow.yml +++ b/.github/workflows/validate-workflow.yml @@ -21,7 +21,7 @@ jobs: # optional (defaults to `5432`) POSTGRES_PORT: 5432 # optional (defaults to `postgres`) - POSTGRES_USER: test + POSTGRES_USER: postgres ports: # maps tcp port 5432 on service container to the host - 5432:5432 @@ -76,7 +76,9 @@ jobs: run: POSTGRES_OR_WEBHOOK_URL=noop NEXT_PUBLIC_SUPABASE_URL=noop NEXT_PUBLIC_SUPABASE_ANON_KEY=noop node --loader tsx ./bin/venice.ts health - name: Run migration check - run: POSTGRES_OR_WEBHOOK_URL=postgres://test:test@localhost:5432/test pnpm migration up + run: POSTGRES_OR_WEBHOOK_URL=postgres://postgres:test@localhost:5432/test pnpm migration up + # To test this with a locally install postgres, run + # psql postgres -c 'drop database if exists test;' && psql postgres -c 'create database test;' && POSTGRES_OR_WEBHOOK_URL=postgres://localhost:5432/test pnpm migration up - name: Run lint run: pnpm run lint diff --git a/apps/app-config/backendConfig.ts b/apps/app-config/backendConfig.ts index 58ac0108..bb769b96 100644 --- a/apps/app-config/backendConfig.ts +++ b/apps/app-config/backendConfig.ts @@ -15,7 +15,7 @@ import {joinPath, R, Rx, zParser} from '@usevenice/util' import {veniceCommonConfig} from './commonConfig' import type {PROVIDERS} from './env' import {parseIntConfigsFromRawEnv, zAllEnv} from './env' -import {getServerUrl} from './server-url' +import {getServerUrl} from './constants' export {Papa} from '@usevenice/integration-import' export {makePostgresClient} from '@usevenice/integration-postgres' diff --git a/apps/app-config/commonConfig.ts b/apps/app-config/commonConfig.ts index ba04dce8..15b5c29d 100644 --- a/apps/app-config/commonConfig.ts +++ b/apps/app-config/commonConfig.ts @@ -3,7 +3,7 @@ import {VeniceProvider} from '@usevenice/engine-frontend' import {joinPath, zParser} from '@usevenice/util' import {PROVIDERS, zCommonEnv} from './env' -import {getServerUrl} from './server-url' +import {getServerUrl} from './constants' export {Papa} from '@usevenice/integration-import' diff --git a/apps/app-config/server-url.ts b/apps/app-config/constants.ts similarity index 69% rename from apps/app-config/server-url.ts rename to apps/app-config/constants.ts index 9e6e3817..ea428bf8 100644 --- a/apps/app-config/server-url.ts +++ b/apps/app-config/constants.ts @@ -15,3 +15,11 @@ export function getServerUrl(req: GetServerSidePropsContext['req'] | null) { }` ) } + +export const graphqlEndpoint = new URL('/api/graphql', getServerUrl(null)) + +export const restEndpoint = new URL('/api/rest', getServerUrl(null)) + +export const xPatHeaderKey = 'x-token' +export const xPatUrlParamKey = 'token' +export const xPatUserMetadataKey = 'apiKey' diff --git a/apps/cli/admin-queries/2023-02-27_1710 json and plv8 test.sql b/apps/cli/admin-queries/2023-02-27_1710 json and plv8 test.sql new file mode 100644 index 00000000..b114c954 --- /dev/null +++ b/apps/cli/admin-queries/2023-02-27_1710 json and plv8 test.sql @@ -0,0 +1,32 @@ +CREATE OR REPLACE FUNCTION public.xjsonb_object_keys(obj jsonb) + RETURNS text[] + LANGUAGE plv8 + IMMUTABLE STRICT +AS $function$ + return Object.keys(obj); +$function$ + +CREATE OR REPLACE FUNCTION public.jsonb_object_keys_to_text_array(_js jsonb) + RETURNS text[] + LANGUAGE sql + IMMUTABLE PARALLEL SAFE STRICT +AS $function$SELECT ARRAY(SELECT jsonb_object_keys(_js))$function$ + +CREATE OR REPLACE FUNCTION public.plv8_test(keys text[], vals text[]) + RETURNS json + LANGUAGE plv8 + IMMUTABLE STRICT +AS $function$ + var o = {}; + for(var i=0; i diff --git a/apps/web/components/PageLayout/AuthLayout/Sidebar.tsx b/apps/web/components/PageLayout/AuthLayout/Sidebar.tsx index ce3598d8..0cd86c8a 100644 --- a/apps/web/components/PageLayout/AuthLayout/Sidebar.tsx +++ b/apps/web/components/PageLayout/AuthLayout/Sidebar.tsx @@ -1,8 +1,7 @@ import { ArrowLeftRightIcon, - DatabaseIcon, + CodeIcon, DocsIcon, - ExportIcon, IntegrationsIcon, ProfileIcon, SupportIcon, @@ -17,11 +16,10 @@ const mainNavigation = [ href: '/connections', icon: ArrowLeftRightIcon, }, - {name: 'Export Data', href: '/export', icon: ExportIcon}, { name: 'API Access', href: '/api-access', - icon: DatabaseIcon, + icon: CodeIcon, }, { name: 'Integrations', diff --git a/apps/web/components/ResourceCard.tsx b/apps/web/components/ResourceCard.tsx index 719f91d9..d29582e3 100644 --- a/apps/web/components/ResourceCard.tsx +++ b/apps/web/components/ResourceCard.tsx @@ -16,7 +16,7 @@ export function ResourceCard(props: ResourceCardProps) {
diff --git a/apps/web/components/api-access/DatabaseAccessCard.tsx b/apps/web/components/api-access/DatabaseAccessCard.tsx deleted file mode 100644 index 820398e5..00000000 --- a/apps/web/components/api-access/DatabaseAccessCard.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import {Input, InstructionCard} from '@usevenice/ui' -import {DatabaseIcon} from '@usevenice/ui/icons' -import {CopyTextButton} from '../CopyTextButton' - -interface DatabaseAccessCardProps { - databaseUrl: string -} - -export function DatabaseAccessCard(props: DatabaseAccessCardProps) { - const {databaseUrl} = props - return ( - -

- Directly connect to Venice's unified database to: -

-
    -
  • Build apps & internal tools
  • -
  • Create dashboards & charts
  • -
  • Use your favorite SQL editor
  • -
  • Write custom data analysis scripts
  • -
-
- - -
-
- ) -} diff --git a/apps/web/components/api-access/GraphQLExplorer.tsx b/apps/web/components/api-access/GraphQLExplorer.tsx new file mode 100644 index 00000000..3afdbd16 --- /dev/null +++ b/apps/web/components/api-access/GraphQLExplorer.tsx @@ -0,0 +1,44 @@ +import {createGraphiQLFetcher} from '@graphiql/toolkit' +import {graphqlEndpoint, xPatHeaderKey} from '@usevenice/app-config/constants' +import {useConstant} from '@usevenice/ui' +import {GraphiQL} from 'graphiql' +import 'graphiql/graphiql.css' +import React from 'react' + +export function GraphQLExplorer({pat}: {pat: string}) { + const fetcher = useConstant(() => + createGraphiQLFetcher({url: graphqlEndpoint.pathname}), + ) + const headersString = React.useMemo( + () => JSON.stringify({[xPatHeaderKey]: pat}, null, 4), + [pat], + ) + + return ( +
+ + +
+ + +
+ ) +} diff --git a/apps/web/components/api-access/VeniceDatabaseExplorer/QueryOutput/ActionsBar.tsx b/apps/web/components/api-access/VeniceDatabaseExplorer/QueryOutput/ActionsBar.tsx deleted file mode 100644 index 9c435f7e..00000000 --- a/apps/web/components/api-access/VeniceDatabaseExplorer/QueryOutput/ActionsBar.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import {Button, CircularProgress} from '@usevenice/ui' -import {DownloadIcon, PlayIcon} from '@usevenice/ui/icons' -import {useEffect} from 'react' -import {OutputFormatTabs} from './OutputFormatTabs' -import {OutputTabsKey} from './OutputTabsKey' -import type {DatabaseQuery} from './useDatabaseQuery' - -interface ActionsBarProps { - databaseQuery: DatabaseQuery -} - -export function ActionsBar(props: ActionsBarProps) { - const {databaseQuery} = props - const isFetching = - databaseQuery.csv.isFetching || databaseQuery.json.isFetching - - return ( -
- - {/* OutputControlsActionGroup */} -
- - -
-
- ) -} - -interface ExecuteQueryActionGroupProps { - executeQuery: () => void - isFetching: boolean -} - -function ExecuteQueryActionGroup(props: ExecuteQueryActionGroupProps) { - const {executeQuery, isFetching} = props - - // binds keyboard shortcuts - useEffect(() => { - function handleKeyboardShortcut(event: KeyboardEvent) { - // TODO handle Windows platform - if (event.metaKey && event.key === 'Enter') { - executeQuery() - } - } - document.addEventListener('keydown', handleKeyboardShortcut) - return () => document.removeEventListener('keydown', handleKeyboardShortcut) - }, [executeQuery]) - - return ( -
- - - or hit ⌘ + Enter - -
- ) -} diff --git a/apps/web/components/api-access/VeniceDatabaseExplorer/QueryOutput/ApiEndpointCard.tsx b/apps/web/components/api-access/VeniceDatabaseExplorer/QueryOutput/ApiEndpointCard.tsx deleted file mode 100644 index 8e53fd47..00000000 --- a/apps/web/components/api-access/VeniceDatabaseExplorer/QueryOutput/ApiEndpointCard.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import {InstructionCard} from '@usevenice/ui' -import {CsvFileIcon, JsonFileIcon} from '@usevenice/ui/icons' -import {CopyTextButton} from '../../../CopyTextButton' -import {OutputFormat} from './OutputFormat' - -interface ApiEndpointCardProps { - format: OutputFormat - queryUrl: string -} - -export function ApiEndpointCard(props: ApiEndpointCardProps) { - const {format, queryUrl} = props - const icon = iconByOutputFormat[format] - return ( - -

- Easily call into Venice as a {format.toUpperCase()} API for this query: -

-