diff --git a/apps/studio/components/interfaces/App/FeaturePreview/AssistantV2Preview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/AssistantV2Preview.tsx new file mode 100644 index 00000000000..a10d9531f87 --- /dev/null +++ b/apps/studio/components/interfaces/App/FeaturePreview/AssistantV2Preview.tsx @@ -0,0 +1,55 @@ +import Image from 'next/image' + +import { useParams } from 'common' +import { Markdown } from 'components/interfaces/Markdown' +import { BASE_PATH } from 'lib/constants' +import { detectOS } from 'lib/helpers' + +export const AssistantV2Preview = () => { + const os = detectOS() + const { ref } = useParams() + + return ( +
+

+ We're changing the way our AI Assistant integrates with the dashboard by making it shared + and accessible universally across the whole dashboard. This hopes to make using the + Assistant as a supporting tool more seamless while you build your project. +

+ api-docs-side-panel-preview +

+ The Assistant will also be automatically provided with contexts depending on where you are + in the dashboard to generate more relevant and higher quality outputs. You may also ask for + insights on your own data apart from help with SQL and Postgres! +

+

+ We believe that this should further lower the barrier of working with databases especially + if you're not well acquainted with Postgres (yet!), so please do feel free to let us know + what you think in the attached GitHub discussion above! +

+
+

Enabling this preview will:

+ +
+
+ ) +} diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx index 84aa5f6c7fe..03ef6fa224f 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx @@ -5,13 +5,13 @@ import { LOCAL_STORAGE_KEYS } from 'lib/constants' import { EMPTY_OBJ } from 'lib/void' import { APISidePanelPreview } from './APISidePanelPreview' import { CLSPreview } from './CLSPreview' -import { FunctionsAssistantPreview } from './FunctionsAssistantPreview' +import { AssistantV2Preview } from './AssistantV2Preview' export const FEATURE_PREVIEWS = [ { - key: LOCAL_STORAGE_KEYS.UI_PREVIEW_FUNCTIONS_ASSISTANT, - name: 'Database Functions Assistant', - content: , + key: LOCAL_STORAGE_KEYS.UI_PREVIEW_ASSISTANT_V2, + name: 'Supabase AI Assistant V2', + content: , discussionsUrl: undefined, isNew: true, }, @@ -86,7 +86,7 @@ export const useIsColumnLevelPrivilegesEnabled = () => { return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS] } -export const useIsDatabaseFunctionsAssistantEnabled = () => { +export const useIsAssistantV2Enabled = () => { const { flags } = useFeaturePreviewContext() - return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_FUNCTIONS_ASSISTANT] + return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_ASSISTANT_V2] } diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx index 01cbee09063..01c76d67997 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx @@ -3,10 +3,12 @@ import Link from 'next/link' import { useEffect, useState } from 'react' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' +import { useFlag } from 'hooks/ui/useFlag' +import { LOCAL_STORAGE_KEYS } from 'lib/constants' +import { TELEMETRY_EVENTS } from 'lib/constants/telemetry' import { useAppStateSnapshot } from 'state/app-state' import { Badge, Button, Modal, ScrollArea, cn } from 'ui' import { FEATURE_PREVIEWS, useFeaturePreviewContext } from './FeaturePreviewContext' -import { useFlag } from 'hooks/ui/useFlag' const FeaturePreviewModal = () => { const snap = useAppStateSnapshot() @@ -36,10 +38,17 @@ const FeaturePreviewModal = () => { const toggleFeature = () => { onUpdateFlag(selectedFeatureKey, !isSelectedFeatureEnabled) sendEvent({ - category: 'ui_feature_previews', - action: isSelectedFeatureEnabled ? 'disabled' : 'enabled', + action: TELEMETRY_EVENTS.FEATURE_PREVIEWS, label: selectedFeatureKey, + value: isSelectedFeatureEnabled ? 'disabled' : 'enabled', }) + + if ( + selectedFeatureKey === LOCAL_STORAGE_KEYS.UI_PREVIEW_ASSISTANT_V2 && + isSelectedFeatureEnabled + ) { + snap.setAiAssistantPanel({ open: false }) + } } function handleCloseFeaturePreviewModal() { diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FunctionsAssistantPreview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FunctionsAssistantPreview.tsx deleted file mode 100644 index 513715133e7..00000000000 --- a/apps/studio/components/interfaces/App/FeaturePreview/FunctionsAssistantPreview.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import Image from 'next/image' - -import { useParams } from 'common' -import { Markdown } from 'components/interfaces/Markdown' -import { BASE_PATH } from 'lib/constants' -import { detectOS } from 'lib/helpers' - -export const FunctionsAssistantPreview = () => { - const os = detectOS() - const { ref } = useParams() - - return ( -
-

- We're providing an additional alternative UX to creating database functions through the - dashboard with the integration of our AI Assistant that you might have seen in the Auth - Policies section. -

- api-docs-side-panel-preview -

- This preview also shares an improved Assistant interface where you may provide the Assistant - with contexts in hopes to generate more relevant and higher quality outputs. Contexts that - you may provide include specific schemas, and / or specific tables from your database. -

-

- We'd hope to use this as a consistent pattern throughout the dashboard eventually if this - feature preview proves itself to benefit most of our users, so as usual please do feel free - to let us know what you think if the attached GitHub discussion above! -

-
-

Enabling this preview will:

-
    -
  • - -
  • -
  • - -
  • -
-
-
- ) -} diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyRow.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyRow.tsx index 5f75945624d..eb02e72693e 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyRow.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyRow.tsx @@ -21,8 +21,9 @@ import { TooltipContent_Shadcn_, TooltipTrigger_Shadcn_, } from 'ui' -import { useIsDatabaseFunctionsAssistantEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { useIsAssistantV2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { useAppStateSnapshot } from 'state/app-state' +import { generatePolicyCreateSQL } from './PolicyTableRow.utils' interface PolicyRowProps { policy: PostgresPolicy @@ -38,7 +39,7 @@ const PolicyRow = ({ onSelectDeletePolicy = noop, }: PolicyRowProps) => { const { setAiAssistantPanel } = useAppStateSnapshot() - const enableAssistantV2 = useIsDatabaseFunctionsAssistantEnabled() + const isAssistantV2Enabled = useIsAssistantV2Enabled() const canUpdatePolicies = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'policies') const { project } = useProjectContext() @@ -102,21 +103,21 @@ const PolicyRow = ({ onSelectEditPolicy(policy)}>

Edit policy

- {enableAssistantV2 && ( + {isAssistantV2Enabled && ( { + const sql = generatePolicyCreateSQL(policy) setAiAssistantPanel({ open: true, - editor: 'rls-policies', - entity: policy, - tables: [{ schema: policy.schema, name: policy.table }], + sqlSnippets: [sql], + initialInput: `Update the policy with name "${policy.name}" in the ${policy.schema} schema on the ${policy.table} table. It should...`, }) }} > diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRow.utils.ts b/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRow.utils.ts new file mode 100644 index 00000000000..09c9b82e3c9 --- /dev/null +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRow.utils.ts @@ -0,0 +1,22 @@ +import { PostgresPolicy } from '@supabase/postgres-meta' + +export const generatePolicyCreateSQL = (policy: PostgresPolicy) => { + let expression = '' + if (policy.definition !== null && policy.definition !== undefined) { + expression += `USING (${policy.definition})${ + policy.check === null || policy.check === undefined ? ';' : '' + }\n` + } + if (policy.check !== null && policy.check !== undefined) { + expression += `WITH CHECK (${policy.check});\n` + } + + return ` +CREATE POLICY "${policy.name}" +ON "${policy.schema}"."${policy.table}" +AS ${policy.action} +FOR ${policy.command} +TO ${policy.roles.join(', ')} +${expression} +`.trim() +} diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRowHeader.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRowHeader.tsx index c75be788248..b4c4193ff36 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRowHeader.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRowHeader.tsx @@ -4,7 +4,7 @@ import { Lock, Unlock } from 'lucide-react' import { useQueryState } from 'nuqs' import { useParams } from 'common' -import { useIsDatabaseFunctionsAssistantEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { useIsAssistantV2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { EditorTablePageLink } from 'data/prefetchers/project.$ref.editor.$id' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' @@ -37,7 +37,8 @@ const PolicyTableRowHeader = ({ const { ref } = useParams() const { setAiAssistantPanel } = useAppStateSnapshot() - const enableAssistantV2 = useIsDatabaseFunctionsAssistantEnabled() + const enableAssistantV2 = useIsAssistantV2Enabled() + const canCreatePolicies = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'policies') const canToggleRLS = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'tables') const isRealtimeSchema = table.schema === 'realtime' @@ -96,13 +97,13 @@ const PolicyTableRowHeader = ({ )} onSelectCreatePolicy()} tooltip={{ content: { side: 'bottom', text: !canToggleRLS - ? !canToggleRLS + ? !canToggleRLS || !canCreatePolicies ? 'You need additional permissions to create RLS policies' : undefined : undefined, @@ -119,9 +120,7 @@ const PolicyTableRowHeader = ({ if (enableAssistantV2) { setAiAssistantPanel({ open: true, - editor: 'rls-policies', - entity: undefined, - tables: [{ schema: table.schema, name: table.name }], + initialInput: `Create a new policy for the ${table.schema} schema on the ${table.name} table that ...`, }) } else { onSelectCreatePolicy() @@ -131,9 +130,10 @@ const PolicyTableRowHeader = ({ tooltip={{ content: { side: 'bottom', - text: !canToggleRLS - ? 'You need additional permissions to create RLS policies' - : 'Create with Supabase Assistant', + text: + !canToggleRLS || !canCreatePolicies + ? 'You need additional permissions to create RLS policies' + : 'Create with Supabase Assistant', }, }} > diff --git a/apps/studio/components/interfaces/Database/EnumeratedTypes/EnumeratedTypes.tsx b/apps/studio/components/interfaces/Database/EnumeratedTypes/EnumeratedTypes.tsx index ccf3e960299..752b9a9ae8a 100644 --- a/apps/studio/components/interfaces/Database/EnumeratedTypes/EnumeratedTypes.tsx +++ b/apps/studio/components/interfaces/Database/EnumeratedTypes/EnumeratedTypes.tsx @@ -63,16 +63,16 @@ const EnumeratedTypes = () => {
setSearch(e.target.value)} placeholder="Search for a type" icon={} diff --git a/apps/studio/components/interfaces/Database/Extensions/Extensions.tsx b/apps/studio/components/interfaces/Database/Extensions/Extensions.tsx index 7435439eb3c..98f74fd2443 100644 --- a/apps/studio/components/interfaces/Database/Extensions/Extensions.tsx +++ b/apps/studio/components/interfaces/Database/Extensions/Extensions.tsx @@ -57,11 +57,11 @@ const Extensions = () => {
setFilterString(e.target.value)} - className="w-64" + className="w-52" icon={} /> diff --git a/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionList.tsx b/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionList.tsx index 263da4ab55b..4bb65cd5979 100644 --- a/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionList.tsx +++ b/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionList.tsx @@ -18,7 +18,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from 'ui' -import { useIsDatabaseFunctionsAssistantEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { useIsAssistantV2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' interface FunctionListProps { schema: string @@ -37,8 +37,8 @@ const FunctionList = ({ }: FunctionListProps) => { const router = useRouter() const { project: selectedProject } = useProjectContext() - const enableAssistantV2 = useIsDatabaseFunctionsAssistantEnabled() const { setAiAssistantPanel } = useAppStateSnapshot() + const isAssistantV2Enabled = useIsAssistantV2Enabled() const { data: functions } = useDatabaseFunctionsQuery({ projectRef: selectedProject?.ref, @@ -113,7 +113,7 @@ const FunctionList = ({ {isApiDocumentAvailable && (

Edit function

- {enableAssistantV2 && ( + {isAssistantV2Enabled && ( { - setAiAssistantPanel({ open: true, editor: 'functions', entity: x }) + setAiAssistantPanel({ + open: true, + initialInput: 'Update this function to do...', + suggestions: { + title: + 'I can help you make a change to this function, here are a few example prompts to get you started:', + prompts: [ + 'Rename this function to ...', + 'Modify this function so that it ...', + 'Add a trigger for this function that calls it when ...', + ], + }, + sqlSnippets: [x.complete_statement], + }) }} > diff --git a/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionsList.tsx b/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionsList.tsx index 56b09f32faf..5b0e7b1de75 100644 --- a/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionsList.tsx +++ b/apps/studio/components/interfaces/Database/Functions/FunctionsList/FunctionsList.tsx @@ -5,7 +5,7 @@ import { Search } from 'lucide-react' import { useRouter } from 'next/router' import { useParams } from 'common' -import { useIsDatabaseFunctionsAssistantEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { useIsAssistantV2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState' import Table from 'components/to-be-cleaned/Table' @@ -38,7 +38,7 @@ const FunctionsList = ({ const { search } = useParams() const { project } = useProjectContext() const { setAiAssistantPanel } = useAppStateSnapshot() - const enableFunctionsAssistant = useIsDatabaseFunctionsAssistantEnabled() + const isAssistantV2Enabled = useIsAssistantV2Enabled() const { selectedSchema, setSelectedSchema } = useQuerySchemaState() const filterString = search ?? '' @@ -104,10 +104,10 @@ const FunctionsList = ({ ) : (
-
+
{ @@ -119,10 +119,10 @@ const FunctionsList = ({ /> } value={filterString} - className="w-64" + className="w-52" onChange={(e) => setFilterString(e.target.value)} />
@@ -144,7 +144,7 @@ const FunctionsList = ({ > Create a new function - {enableFunctionsAssistant && ( + {isAssistantV2Enabled && ( setAiAssistantPanel({ open: true, - editor: 'functions', - entity: undefined, + initialInput: `Create a new function for the schema ${selectedSchema} that does ...`, }) } tooltip={{ diff --git a/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx b/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx index 49430ddef1e..81b7d0b2dd2 100644 --- a/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx +++ b/apps/studio/components/interfaces/Database/Hooks/HooksList/HooksList.tsx @@ -49,10 +49,10 @@ const HooksList = ({ createHook = noop, editHook = noop, deleteHook = noop }: Ho
} value={filterString} - className="w-64" + className="w-52" onChange={(e) => setFilterString(e.target.value)} />
diff --git a/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx b/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx index 63c139672b5..2a82a604860 100644 --- a/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx +++ b/apps/studio/components/interfaces/Database/Indexes/Indexes.tsx @@ -109,17 +109,17 @@ const Indexes = () => { )} {isSuccessSchemas && ( )} setSearch(e.target.value)} placeholder="Search for an index" icon={} diff --git a/apps/studio/components/interfaces/Database/Privileges/PrivilegesHead.tsx b/apps/studio/components/interfaces/Database/Privileges/PrivilegesHead.tsx index 963a9083ea3..85deba33f12 100644 --- a/apps/studio/components/interfaces/Database/Privileges/PrivilegesHead.tsx +++ b/apps/studio/components/interfaces/Database/Privileges/PrivilegesHead.tsx @@ -43,23 +43,15 @@ const PrivilegesHead = ({ }: PrivilegesHeadProps) => { return (
-
+
-
- -
+
-
- -
+
@@ -96,14 +88,14 @@ const RolesSelect = ({ }) => { return ( - + {roles.map((role) => ( - - role {role} + + role {role} ))} @@ -125,7 +117,7 @@ const TablesSelect = ({ }) => { return ( - + @@ -136,8 +128,8 @@ const TablesSelect = ({
) : null} {tables.map((table) => ( - - table {table} + + table {table} ))} diff --git a/apps/studio/components/interfaces/Database/Publications/PublicationsList.tsx b/apps/studio/components/interfaces/Database/Publications/PublicationsList.tsx index 9e7dc03b552..ff3fe002a89 100644 --- a/apps/studio/components/interfaces/Database/Publications/PublicationsList.tsx +++ b/apps/studio/components/interfaces/Database/Publications/PublicationsList.tsx @@ -81,7 +81,7 @@ const PublicationsList = ({ onSelectPublication = noop }: PublicationsListProps)
} placeholder={'Filter'} value={filterString} diff --git a/apps/studio/components/interfaces/Database/Roles/RolesList.tsx b/apps/studio/components/interfaces/Database/Roles/RolesList.tsx index 080d34a9bc8..c529d9f348a 100644 --- a/apps/studio/components/interfaces/Database/Roles/RolesList.tsx +++ b/apps/studio/components/interfaces/Database/Roles/RolesList.tsx @@ -63,7 +63,8 @@ const RolesList = () => {
} value={filterString} @@ -81,10 +82,10 @@ const RolesList = () => { ) } /> -
+
diff --git a/apps/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx b/apps/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx index 9fca6e7978d..706c526cfd5 100644 --- a/apps/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx +++ b/apps/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx @@ -8,12 +8,12 @@ import 'reactflow/dist/style.css' import { useParams } from 'common' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import AlertError from 'components/ui/AlertError' +import { ButtonTooltip } from 'components/ui/ButtonTooltip' import SchemaSelector from 'components/ui/SchemaSelector' import { useSchemasQuery } from 'data/database/schemas-query' import { useTablesQuery } from 'data/tables/tables-query' import { useLocalStorage } from 'hooks/misc/useLocalStorage' import { LOCAL_STORAGE_KEYS } from 'lib/constants' -import { Button, Tooltip_Shadcn_, TooltipContent_Shadcn_, TooltipTrigger_Shadcn_ } from 'ui' import { SchemaGraphLegend } from './SchemaGraphLegend' import { getGraphDataFromTables, getLayoutedElementsViaDagre } from './Schemas.utils' import { TableNode } from './SchemaTableNode' @@ -117,22 +117,21 @@ export const SchemaGraph = () => { {isSuccessSchemas && ( <> - - - - - - Automatically arrange the layout of all nodes - - + + Auto layout + )}
diff --git a/apps/studio/components/interfaces/Database/Tables/TableList.tsx b/apps/studio/components/interfaces/Database/Tables/TableList.tsx index 8ff037d2ca5..60da3feaed6 100644 --- a/apps/studio/components/interfaces/Database/Tables/TableList.tsx +++ b/apps/studio/components/interfaces/Database/Tables/TableList.tsx @@ -203,11 +203,11 @@ const TableList = ({ } return ( -
-
+
+