mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 15:19:08 +03:00
Merge branch 'master' into feat/compute-and-disk
This commit is contained in:
commit
2570147a79
9 files changed
+127
-8
No files matched your search
@@ -58,6 +58,7 @@ const nextConfig = {
|
||||
experimental: {
|
||||
outputFileTracingIncludes: {
|
||||
'/api/crawlers': ['./features/docs/generated/**/*', './docs/ref/**/*'],
|
||||
'/reference/**/*': ['./features/docs/generated/**/*', './docs/ref/**/*'],
|
||||
},
|
||||
},
|
||||
webpack: (config, options) => {
|
||||
|
||||
@@ -68,6 +68,8 @@ const formUnion = z.discriminatedUnion('type', [
|
||||
type: z.literal('loki'),
|
||||
url: z.string().min(1, { message: 'Loki URL is required' }),
|
||||
headers: z.record(z.string(), z.string()),
|
||||
username: z.string().optional(),
|
||||
password: z.string().optional(),
|
||||
}),
|
||||
])
|
||||
|
||||
@@ -162,6 +164,8 @@ export function LogDrainDestinationSheetForm({
|
||||
url: defaultValues?.config?.url || '',
|
||||
api_key: defaultValues?.config?.api_key || '',
|
||||
region: defaultValues?.config?.region || '',
|
||||
username: defaultValues?.config?.username || '',
|
||||
password: defaultValues?.config?.password || '',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -422,10 +426,24 @@ export function LogDrainDestinationSheetForm({
|
||||
<LogDrainFormItem
|
||||
type="url"
|
||||
value="url"
|
||||
placeholder="https://my-logs-endpoint.grafana.net/loki/api/v1/push"
|
||||
label="Loki URL"
|
||||
formControl={form.control}
|
||||
description="The Loki HTTP(S) endpoint to send events."
|
||||
/>
|
||||
<LogDrainFormItem
|
||||
value="username"
|
||||
label="Username"
|
||||
placeholder="123456789"
|
||||
formControl={form.control}
|
||||
/>
|
||||
<LogDrainFormItem
|
||||
type="password"
|
||||
value="password"
|
||||
label="Password"
|
||||
placeholder="glc_ABCD1234567890"
|
||||
formControl={form.control}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<FormMessage_Shadcn_ />
|
||||
|
||||
@@ -131,8 +131,15 @@ export function LogDrains({
|
||||
<TableBody>
|
||||
{logDrains?.map((drain) => (
|
||||
<TableRow key={drain.id}>
|
||||
<TableCell className="font-medium">{drain.name}</TableCell>
|
||||
<TableCell>{drain.description}</TableCell>
|
||||
<TableCell className="font-medium truncate max-w-72" title={drain.name}>
|
||||
{drain.name}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="text-foreground-light truncate max-w-72"
|
||||
title={drain.description}
|
||||
>
|
||||
{drain.description}
|
||||
</TableCell>
|
||||
<TableCell className="text-right font-mono">{drain.type}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
@@ -180,7 +187,7 @@ export function LogDrains({
|
||||
}}
|
||||
onCancel={() => setIsDeleteModalOpen(false)}
|
||||
>
|
||||
<div className="text-foreground-light">
|
||||
<div className="text-foreground-light text-sm">
|
||||
<p>
|
||||
Are you sure you want to delete{' '}
|
||||
<span className="text-foreground">{selectedLogDrain?.name}</span>?
|
||||
|
||||
@@ -4,10 +4,14 @@ import { Info } from 'lucide-react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from '@ui/components/shadcn/ui/alert'
|
||||
import { Message as MessageType } from 'ai'
|
||||
import { useChat } from 'ai/react'
|
||||
import { useParams } from 'common'
|
||||
import { IS_PLATFORM } from 'common/constants/environment'
|
||||
import { Markdown } from 'components/interfaces/Markdown'
|
||||
import { SchemaComboBox } from 'components/ui/SchemaComboBox'
|
||||
import { useCheckOpenAIKeyQuery } from 'data/ai/check-api-key-query'
|
||||
import { useEntityDefinitionsQuery } from 'data/database/entity-definitions-query'
|
||||
import { useOrganizationUpdateMutation } from 'data/organizations/organization-update-mutation'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
@@ -73,6 +77,9 @@ export const AiAssistantPanel = ({
|
||||
const shouldShowNotOptimizedAlert =
|
||||
selectedOrganization && !includeSchemaMetadata && showAiNotOptimizedWarningSetting
|
||||
|
||||
const { data: check } = useCheckOpenAIKeyQuery()
|
||||
const isApiKeySet = IS_PLATFORM || !!check?.hasKey
|
||||
|
||||
const { data } = useEntityDefinitionsQuery(
|
||||
{
|
||||
schemas: selectedSchemas,
|
||||
@@ -289,11 +296,21 @@ export const AiAssistantPanel = ({
|
||||
<div ref={bottomRef} className="h-1" />
|
||||
</div>
|
||||
|
||||
<div className="sticky p-5 flex-0 border-t">
|
||||
<div className="sticky p-5 flex-0 border-t grid gap-4">
|
||||
{!isApiKeySet && (
|
||||
<Alert>
|
||||
<AlertTitle>OpenAI API key not set</AlertTitle>
|
||||
<AlertDescription>
|
||||
<Markdown
|
||||
content={'Add your `OPENAI_API_KEY` to `./docker/.env` to use the AI Assistant.'}
|
||||
/>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<AssistantChatForm
|
||||
textAreaRef={inputRef}
|
||||
loading={isLoading}
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || !isApiKeySet}
|
||||
icon={
|
||||
<AiIconAnimation
|
||||
allowHoverEffect
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ const DeployNewReplicaPanel = ({
|
||||
</div>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
) : isAWSProvider ? (
|
||||
) : !isAWSProvider ? (
|
||||
<Alert_Shadcn_>
|
||||
<WarningIcon />
|
||||
<AlertTitle_Shadcn_>
|
||||
|
||||
@@ -9,9 +9,11 @@ import { toast } from 'sonner'
|
||||
import type { Message as MessageType } from 'ai/react'
|
||||
import { useChat } from 'ai/react'
|
||||
import { useParams } from 'common'
|
||||
import { Markdown } from 'components/interfaces/Markdown'
|
||||
import OptInToOpenAIToggle from 'components/interfaces/Organization/GeneralSettings/OptInToOpenAIToggle'
|
||||
import { MessageWithDebug } from 'components/interfaces/SQLEditor/AiAssistantPanel'
|
||||
import { DiffType } from 'components/interfaces/SQLEditor/SQLEditor.types'
|
||||
import { useCheckOpenAIKeyQuery } from 'data/ai/check-api-key-query'
|
||||
import { useSqlDebugMutation } from 'data/ai/sql-debug-mutation'
|
||||
import { useEntityDefinitionQuery } from 'data/database/entity-definition-query'
|
||||
import { useEntityDefinitionsQuery } from 'data/database/entity-definitions-query'
|
||||
@@ -116,6 +118,9 @@ export const AIAssistant = ({
|
||||
selectedSchemas.length === 0 &&
|
||||
selectedTables.length === 0
|
||||
|
||||
const { data: check } = useCheckOpenAIKeyQuery()
|
||||
const isApiKeySet = IS_PLATFORM || !!check?.hasKey
|
||||
|
||||
const { data: existingDefinition } = useEntityDefinitionQuery({
|
||||
id: entity?.id,
|
||||
type: editor,
|
||||
@@ -457,6 +462,19 @@ export const AIAssistant = ({
|
||||
description="Give us a moment while we work on bringing the Assistant back online"
|
||||
/>
|
||||
)}
|
||||
{!isApiKeySet && (
|
||||
<Admonition
|
||||
type="warning"
|
||||
title="OpenAI API key not set"
|
||||
description={
|
||||
<Markdown
|
||||
content={
|
||||
'Add your `OPENAI_API_KEY` to `./docker/.env` to use the AI Assistant.'
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div className="w-full border rounded">
|
||||
<div className="py-2 px-3 border-b flex gap-2 flex-wrap">
|
||||
<DropdownMenu>
|
||||
@@ -619,7 +637,7 @@ export const AIAssistant = ({
|
||||
'[&>textarea]:rounded-none [&>textarea]:border-0 [&>textarea]:!outline-none [&>textarea]:!ring-offset-0 [&>textarea]:!ring-0'
|
||||
)}
|
||||
loading={isLoading}
|
||||
disabled={disablePrompts || isLoading}
|
||||
disabled={!isApiKeySet || disablePrompts || isLoading}
|
||||
placeholder={
|
||||
hasMessages ? 'Reply to the assistant...' : 'How can we help you today?'
|
||||
}
|
||||
@@ -630,7 +648,7 @@ export const AIAssistant = ({
|
||||
sendMessageToAssistant(value)
|
||||
}}
|
||||
/>
|
||||
{!hasMessages && (
|
||||
{!hasMessages && IS_PLATFORM && (
|
||||
<div className="text-xs text-foreground-lighter text-opacity-60 bg-control px-3 pb-2">
|
||||
The Assistant is in Alpha and your prompts might be rate limited
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
|
||||
|
||||
import { get, isResponseOk } from 'lib/common/fetch'
|
||||
import { BASE_PATH, IS_PLATFORM } from 'lib/constants'
|
||||
import { resourceKeys } from './keys'
|
||||
|
||||
// check to see if the OPENAI_API_KEY env var is set in self-hosted
|
||||
// so we can disable the chat editor and add a warning about manually adding the key
|
||||
|
||||
export async function checkOpenAIKey(signal?: AbortSignal) {
|
||||
const response = await get(`${BASE_PATH}/api/ai/sql/check-api-key`, { signal })
|
||||
|
||||
if (!isResponseOk(response)) {
|
||||
throw (response as any).error
|
||||
}
|
||||
|
||||
return response as { hasKey: boolean }
|
||||
}
|
||||
|
||||
export type ResourceData = Awaited<ReturnType<typeof checkOpenAIKey>>
|
||||
export type ResourceError = { errorEventId: string; message: string }
|
||||
|
||||
export const useCheckOpenAIKeyQuery = <TData = ResourceData>({
|
||||
enabled = true,
|
||||
...options
|
||||
}: UseQueryOptions<ResourceData, ResourceError, TData> = {}) =>
|
||||
useQuery<ResourceData, ResourceError, TData>(
|
||||
resourceKeys.apiKey(),
|
||||
({ signal }) => checkOpenAIKey(signal),
|
||||
{ enabled: !IS_PLATFORM && enabled, ...options }
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
export const resourceKeys = {
|
||||
apiKey: () => ['api-key'] as const,
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { method } = req
|
||||
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
return handleGet(req, res)
|
||||
default:
|
||||
res.setHeader('Allow', ['POST'])
|
||||
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
|
||||
}
|
||||
}
|
||||
|
||||
const handleGet = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
if (process.env.OPENAI_API_KEY) {
|
||||
return res.status(200).json({ hasKey: true })
|
||||
} else {
|
||||
return res.status(404).json({ hasKey: false })
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user