diff --git a/apps/docs/content/guides/self-hosting/docker.mdx b/apps/docs/content/guides/self-hosting/docker.mdx
index eced3b834fb1d..365055a18b627 100644
--- a/apps/docs/content/guides/self-hosting/docker.mdx
+++ b/apps/docs/content/guides/self-hosting/docker.mdx
@@ -182,6 +182,10 @@ Edit the following settings in the `.env` file:
- `PG_META_CRYPTO_KEY`: encryption key for securing connection strings used by Studio against postgres-meta. (Must be at least 32 characters; generate with `openssl rand -base64 24`)
- `LOGFLARE_PUBLIC_ACCESS_TOKEN`: API token for log ingestion and querying. Used by Vector and Studio to send and query logs. (Must be at least 32 characters; generate with `openssl rand -base64 24`)
- `LOGFLARE_PRIVATE_ACCESS_TOKEN`: API token for Logflare management operations. Used by Studio for administrative tasks. Never expose client-side. (Must be at least 32 characters; generate with `openssl rand -base64 24`)
+- `S3_PROTOCOL_ACCESS_KEY_ID`: Access key ID (username-like) for authenticating API requests to S3-compatible storage. (Generate with `openssl rand -hex 16`)
+- `S3_PROTOCOL_ACCESS_KEY_SECRET`: Secret key (password-like) used with S3_PROTOCOL_ACCESS_KEY_ID to sign and authorize S3 storage operations. (Generate with `openssl rand -hex 32`)
+{/* supa-mdx-lint-disable-next-line Rule003Spelling */}
+- `MINIO_ROOT_PASSWORD`: Root administrator password for the MinIO server. (Must be 8+ characters; generate with `openssl rand -hex 16`)
Review and change URL environment variables:
diff --git a/apps/studio/.github/eslint-rule-baselines.json b/apps/studio/.github/eslint-rule-baselines.json
index d8ffa12f34063..94e3e7c1bb6ef 100644
--- a/apps/studio/.github/eslint-rule-baselines.json
+++ b/apps/studio/.github/eslint-rule-baselines.json
@@ -1,9 +1,9 @@
{
"rules": {
- "react-hooks/exhaustive-deps": 213,
+ "react-hooks/exhaustive-deps": 211,
"import/no-anonymous-default-export": 57,
"@tanstack/query/exhaustive-deps": 13,
- "@typescript-eslint/no-explicit-any": 1231
+ "@typescript-eslint/no-explicit-any": 1220
},
"ruleFiles": {
"react-hooks/exhaustive-deps": {
@@ -39,6 +39,7 @@
"components/interfaces/Billing/Payment/PaymentConfirmation.tsx": 1,
"components/interfaces/Billing/Payment/PaymentMethods/NewPaymentMethodElement.tsx": 2,
"components/interfaces/Connect/DatabaseConnectionString.tsx": 2,
+ "components/interfaces/ConnectSheet/content/steps/mcp/cursor/content.tsx": 1,
"components/interfaces/Database/Backups/PITR/TimeInput.tsx": 4,
"components/interfaces/Database/EnumeratedTypes/CreateEnumeratedTypeSidePanel.tsx": 1,
"components/interfaces/Database/Indexes/Indexes.tsx": 2,
@@ -79,7 +80,6 @@
"components/interfaces/SQLEditor/RenameQueryModal.tsx": 1,
"components/interfaces/SQLEditor/SQLEditor.tsx": 3,
"components/interfaces/SQLEditor/UtilityPanel/SavingIndicator.tsx": 1,
- "components/interfaces/Settings/API/PostgrestConfig.tsx": 1,
"components/interfaces/Settings/Addons/CustomDomainSidePanel.tsx": 1,
"components/interfaces/Settings/Addons/IPv4SidePanel.tsx": 1,
"components/interfaces/Settings/Addons/PITRSidePanel.tsx": 1,
@@ -105,7 +105,6 @@
"components/interfaces/UnifiedLogs/ServiceFlow/components/ServiceFlowHeader.tsx": 2,
"components/layouts/EdgeFunctionsLayout/EdgeFunctionDetailsLayout.tsx": 1,
"components/layouts/ProjectLayout/ConnectingState.tsx": 1,
- "components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx": 2,
"components/layouts/ProjectLayout/PausedState/PauseDisabledState.tsx": 1,
"components/layouts/ProjectLayout/index.tsx": 1,
"components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorNav.tsx": 4,
@@ -246,7 +245,7 @@
"components/grid/components/editor/JsonEditor.tsx": 2,
"components/grid/components/editor/SelectEditor.tsx": 1,
"components/grid/components/editor/TextEditor.tsx": 2,
- "components/grid/components/formatter/ReferenceRecordPeek.tsx": 4,
+ "components/grid/components/formatter/ReferenceRecordPeek.tsx": 3,
"components/grid/components/grid/AddColumn.tsx": 2,
"components/grid/components/grid/Grid.utils.tsx": 2,
"components/grid/components/grid/SelectColumn.tsx": 3,
@@ -258,8 +257,7 @@
"components/grid/utils/column.ts": 2,
"components/grid/utils/common.ts": 1,
"components/grid/utils/gridColumns.tsx": 10,
- "components/interfaces/Account/AccessTokens/NewAccessTokenButton.tsx": 1,
- "components/interfaces/Account/AccessTokens/NewAccessTokenDialog.tsx": 1,
+ "components/interfaces/Account/AccessTokens/Scoped/Form/ResourceAccess/ResourceAccess.types.ts": 2,
"components/interfaces/Auth/AuditLogsForm.tsx": 1,
"components/interfaces/Auth/AuthProvidersForm/AuthProvidersForm.types.ts": 1,
"components/interfaces/Auth/AuthProvidersForm/FormField.tsx": 4,
@@ -308,7 +306,6 @@
"components/interfaces/Database/EnumeratedTypes/EnumeratedTypeValueRow.tsx": 1,
"components/interfaces/Database/Functions/CreateFunction/FunctionEditor.tsx": 1,
"components/interfaces/Database/Functions/FunctionsList/FunctionList.tsx": 3,
- "components/interfaces/Database/Hooks/HooksList/HooksList.tsx": 2,
"components/interfaces/Database/Indexes/Indexes.tsx": 1,
"components/interfaces/Database/Migrations/Migrations.tsx": 2,
"components/interfaces/Database/Privileges/PrivilegesTable.tsx": 1,
@@ -371,7 +368,6 @@
"components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx": 1,
"components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx": 6,
"components/interfaces/Organization/BillingSettings/Subscription/UpgradeModal.tsx": 3,
- "components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx": 3,
"components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx": 1,
"components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx": 1,
"components/interfaces/Organization/InvoicesSettings/InvoicesSettings.tsx": 2,
@@ -389,7 +385,6 @@
"components/interfaces/ProjectAPIDocs/ProjectAPIDocs.constants.ts": 2,
"components/interfaces/ProjectAPIDocs/ResourceContent.tsx": 1,
"components/interfaces/ProjectCreation/PostgresVersionSelector.tsx": 2,
- "components/interfaces/ProjectCreation/SchemaGenerator.tsx": 1,
"components/interfaces/QueryPerformance/IndexAdvisor/EnableIndexAdvisorButton.tsx": 1,
"components/interfaces/QueryPerformance/IndexAdvisor/IndexAdvisorDisabledState.tsx": 1,
"components/interfaces/QueryPerformance/IndexAdvisor/index-advisor.utils.ts": 2,
@@ -427,7 +422,6 @@
"components/interfaces/SQLEditor/UtilityPanel/UtilityPanel.tsx": 1,
"components/interfaces/SQLEditor/hooks.ts": 1,
"components/interfaces/SQLEditor/useAddDefinitions.ts": 1,
- "components/interfaces/SchemaVisualizer/index.tsx": 1,
"components/interfaces/Settings/Addons/Addons.tsx": 1,
"components/interfaces/Settings/Addons/CustomDomainSidePanel.tsx": 1,
"components/interfaces/Settings/Addons/IPv4SidePanel.tsx": 1,
@@ -708,7 +702,7 @@
"lib/role-impersonation.ts": 1,
"lib/telemetry/track.ts": 1,
"pages/_app.tsx": 1,
- "pages/account/tokens.tsx": 1,
+ "pages/account/tokens/scoped.tsx": 1,
"pages/api/ai/feedback/rate.ts": 2,
"pages/api/check-cname.ts": 1,
"pages/api/edge-functions/test.ts": 1,
@@ -724,7 +718,6 @@
"pages/integrations/vercel/[slug]/deploy-button/new-project.tsx": 1,
"pages/integrations/vercel/[slug]/marketplace/choose-project.tsx": 1,
"pages/new/index.tsx": 1,
- "pages/project/[ref]/api/index.tsx": 3,
"pages/project/[ref]/auth/templates/[templateId].tsx": 1,
"pages/project/[ref]/functions/[functionSlug]/index.tsx": 3,
"pages/project/[ref]/settings/log-drains.tsx": 1,
diff --git a/apps/studio/components/grid/components/grid/Grid.tsx b/apps/studio/components/grid/components/grid/Grid.tsx
index 0b589f5451fb0..2079e3692ea28 100644
--- a/apps/studio/components/grid/components/grid/Grid.tsx
+++ b/apps/studio/components/grid/components/grid/Grid.tsx
@@ -97,12 +97,7 @@ export const Grid = memo(
const { mutate: sendEvent } = useSendEventMutation()
- const {
- isValidFile: isValidFileDraggedOver,
- isDraggedOver,
- onDragOver,
- onFileDrop,
- } = useCsvFileDrop({
+ const { isDraggedOver, onDragOver, onFileDrop } = useCsvFileDrop({
enabled: isTableEmpty && !isForeignTable,
onFileDropped: (file) => tableEditorSnap.onImportData(valtioRef(file)),
onTelemetryEvent: (eventName) => {
@@ -241,9 +236,7 @@ export const Grid = memo(
{(rows ?? []).length === 0 && (
{isLoading && !isDisabled && (
@@ -272,18 +265,13 @@ export const Grid = memo(
) : (filters ?? []).length === 0 ? (
-
-
- {isDraggedOver ? (
- isValidFileDraggedOver ? (
- 'Drop your CSV file here'
- ) : (
- Only CSV files are accepted
- )
- ) : (
- 'This table is empty'
- )}
-
+
+
This table is empty
{tableEntityType === ENTITY_TYPE.FOREIGN_TABLE ? (
@@ -292,30 +280,28 @@ export const Grid = memo(
) : (
- !isDraggedOver && (
-
-
-
- or drag and drop a CSV file here
-
-
- )
+
+
+
+ or drag and drop a CSV file here
+
+
)}
) : (
diff --git a/apps/studio/components/interfaces/Settings/Logs/LogTable.tsx b/apps/studio/components/interfaces/Settings/Logs/LogTable.tsx
index 68fccc043e14a..64046af1178ce 100644
--- a/apps/studio/components/interfaces/Settings/Logs/LogTable.tsx
+++ b/apps/studio/components/interfaces/Settings/Logs/LogTable.tsx
@@ -1,4 +1,10 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
+import { IS_PLATFORM, useParams } from 'common'
+import { ButtonTooltip } from 'components/ui/ButtonTooltip'
+import { DownloadResultsButton } from 'components/ui/DownloadResultsButton'
+import { useSelectedLog } from 'hooks/analytics/useSelectedLog'
+import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
+import { useProfile } from 'lib/profile'
import { isEqual } from 'lodash'
import { Copy, Eye, EyeOff, Play } from 'lucide-react'
import { Key, ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
@@ -6,31 +12,25 @@ import { Item, Menu, useContextMenu } from 'react-contexify'
import DataGrid, { Column, RenderRowProps, Row } from 'react-data-grid'
import { createPortal } from 'react-dom'
import { toast } from 'sonner'
-
-import { IS_PLATFORM, useParams } from 'common'
-import { ButtonTooltip } from 'components/ui/ButtonTooltip'
-import { DownloadResultsButton } from 'components/ui/DownloadResultsButton'
-import { useSelectedLog } from 'hooks/analytics/useSelectedLog'
-import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
-import { useProfile } from 'lib/profile'
import type { ResponseError } from 'types'
import {
Button,
+ cn,
+ copyToClipboard,
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
- cn,
- copyToClipboard,
} from 'ui'
+
import AuthColumnRenderer from './LogColumnRenderers/AuthColumnRenderer'
import DatabaseApiColumnRender from './LogColumnRenderers/DatabaseApiColumnRender'
import DatabasePostgresColumnRender from './LogColumnRenderers/DatabasePostgresColumnRender'
import DefaultPreviewColumnRenderer from './LogColumnRenderers/DefaultPreviewColumnRenderer'
import FunctionsEdgeColumnRender from './LogColumnRenderers/FunctionsEdgeColumnRender'
import FunctionsLogsColumnRender from './LogColumnRenderers/FunctionsLogsColumnRender'
-import LogSelection from './LogSelection'
import type { LogData, LogQueryError, QueryType } from './Logs.types'
import { isDefaultLogPreviewFormat } from './Logs.utils'
+import LogSelection from './LogSelection'
import { DefaultErrorRenderer } from './LogsErrorRenderers/DefaultErrorRenderer'
import ResourcesExceededErrorRenderer from './LogsErrorRenderers/ResourcesExceededErrorRenderer'
import { LogsTableEmptyState } from './LogsTableEmptyState'
@@ -64,7 +64,7 @@ type LogMap = { [id: string]: LogData }
*
* When in custom data display mode, the side panel will not open when focusing on logs.
*/
-const LogTable = ({
+export const LogTable = ({
data = [],
queryType,
onHistogramToggle,
@@ -120,6 +120,9 @@ const LogTable = ({
const hasId = columnNames.includes('id')
const hasTimestamp = columnNames.includes('timestamp')
+ const panelContentMinSize = 40
+ const panelContentMaxSize = 60
+
const LOGS_EXPLORER_CONTEXT_MENU_ID = 'logs-explorer-context-menu'
const DEFAULT_COLUMNS = columnNames.map((v: keyof LogData, idx) => {
const column = `logs-column-${idx}`
@@ -127,7 +130,7 @@ const LogTable = ({
key: column,
name: v as string,
resizable: true,
- renderCell: ({ row }: any) => {
+ renderCell: ({ row }) => {
return (
{
@@ -140,7 +143,7 @@ const LogTable = ({
)
},
- renderHeaderCell: (props) => {
+ renderHeaderCell: () => {
return
{v}
},
minWidth: 128,
@@ -392,7 +395,13 @@ const LogTable = ({
{!queryType &&
}
-
+
-
-
{selectionOpen && (
-
- {
- onSelectedLogChange?.(null)
- setSelectionOpen(false)
- }}
- log={selectedLog}
- error={selectedLogError}
- queryType={queryType}
- />
-
+ <>
+
+
+ {
+ onSelectedLogChange?.(null)
+ setSelectionOpen(false)
+ }}
+ log={selectedLog}
+ error={selectedLogError}
+ queryType={queryType}
+ />
+
+ >
)}
)
}
-export default LogTable
diff --git a/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx b/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx
index 5b986b63fe624..77e05a6eed1c5 100644
--- a/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx
+++ b/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx
@@ -27,7 +27,7 @@ import {
import { DatePickerValue } from './Logs.DatePickers'
import type { Filters, LogSearchCallback, LogTemplate, QueryType } from './Logs.types'
import { maybeShowUpgradePromptIfNotEntitled } from './Logs.utils'
-import LogTable from './LogTable'
+import { LogTable } from './LogTable'
import UpgradePrompt from './UpgradePrompt'
/**
diff --git a/apps/studio/components/layouts/LogsLayout/LogsSidebarMenuV2.tsx b/apps/studio/components/layouts/LogsLayout/LogsSidebarMenuV2.tsx
index 2135799e473fc..412f796de34b0 100644
--- a/apps/studio/components/layouts/LogsLayout/LogsSidebarMenuV2.tsx
+++ b/apps/studio/components/layouts/LogsLayout/LogsSidebarMenuV2.tsx
@@ -1,8 +1,3 @@
-import { ChevronRight, CircleHelpIcon, Plus } from 'lucide-react'
-import Link from 'next/link'
-import { useRouter } from 'next/router'
-import React, { useState } from 'react'
-
import { IS_PLATFORM, useFlag, useParams } from 'common'
import {
useFeaturePreviewModal,
@@ -17,6 +12,10 @@ import { useContentQuery } from 'data/content/content-query'
import { useReplicationSourcesQuery } from 'data/replication/sources-query'
import { useCurrentOrgPlan } from 'hooks/misc/useCurrentOrgPlan'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
+import { ChevronRight, CircleHelpIcon, Plus } from 'lucide-react'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+import React, { useState } from 'react'
import {
Badge,
Button,
@@ -33,6 +32,7 @@ import {
InnerSideMenuItem,
} from 'ui-patterns/InnerSideMenu'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
+
import { FeaturePreviewSidebarPanel } from '../../ui/FeaturePreviewSidebarPanel'
const SupaIcon = ({ className }: { className?: string }) => {
@@ -368,7 +368,7 @@ export function LogsSidebarMenuV2() {
/>
)}
{savedQueries.map((query) => (
-
// kemal: i know, i know, temp any fix.
+
))}
@@ -381,7 +381,7 @@ export function LogsSidebarMenuV2() {
illustration={
{LOG_DRAIN_TYPES.map((type) =>
- React.cloneElement(type.icon, { height: 20, width: 20 })
+ React.cloneElement(type.icon, { key: type.name, height: 20, width: 20 })
)}
}
diff --git a/apps/studio/hooks/ui/useCsvFileDrop.ts b/apps/studio/hooks/ui/useCsvFileDrop.ts
index 2f2da36a1889f..26119d2313553 100644
--- a/apps/studio/hooks/ui/useCsvFileDrop.ts
+++ b/apps/studio/hooks/ui/useCsvFileDrop.ts
@@ -1,7 +1,6 @@
-import { type DragEvent, useCallback, useState } from 'react'
-
import { type ImportDataFileDroppedEvent } from 'common/telemetry-constants'
import { flagInvalidFileImport } from 'components/interfaces/TableGridEditor/SidePanelEditor/SpreadsheetImport/SpreadsheetImport.utils'
+import { useCallback, useState, type DragEvent } from 'react'
interface UseCsvFileDropOptions {
enabled: boolean
@@ -11,7 +10,6 @@ interface UseCsvFileDropOptions {
interface UseCsvFileDropReturn {
isDraggedOver: boolean
- isValidFile: boolean
onDragOver: (event: DragEvent
) => void
onFileDrop: (event: DragEvent) => void
}
@@ -22,7 +20,6 @@ export function useCsvFileDrop({
onTelemetryEvent,
}: UseCsvFileDropOptions): UseCsvFileDropReturn {
const [isDraggedOver, setIsDraggedOver] = useState(false)
- const [isValidFile, setIsValidFile] = useState(false)
const onDragOver = useCallback(
(event: DragEvent) => {
@@ -35,15 +32,13 @@ export function useCsvFileDrop({
if (event.type === 'dragover' && !isDraggedOver) {
setIsDraggedOver(true)
- setIsValidFile(item.type === 'text/csv')
} else if (event.type === 'dragleave' || event.type === 'drop') {
setIsDraggedOver(false)
- setIsValidFile(false)
}
event.stopPropagation()
event.preventDefault()
},
- [enabled, isDraggedOver, isValidFile]
+ [enabled, isDraggedOver]
)
const onFileDrop = useCallback(
@@ -68,7 +63,6 @@ export function useCsvFileDrop({
)
return {
- isValidFile: isValidFile && isDraggedOver,
isDraggedOver,
onDragOver,
onFileDrop,
diff --git a/apps/studio/instrumentation-client.ts b/apps/studio/instrumentation-client.ts
index 9bd34e8177f0b..5dd543ad6d3fd 100644
--- a/apps/studio/instrumentation-client.ts
+++ b/apps/studio/instrumentation-client.ts
@@ -57,6 +57,10 @@ Sentry.init({
}),
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
+
+ // Enable performance monitoring - Next.js routes and API calls are automatically instrumented
+ tracesSampleRate: 0.1, // Capture 10% of transactions for performance monitoring
+
// [Ali] Filter out browser extensions and user scripts (FE-2094)
// Using denyUrls to block known third-party script patterns
denyUrls: [/userscript/i],
diff --git a/apps/studio/pages/project/[ref]/logs/explorer/index.tsx b/apps/studio/pages/project/[ref]/logs/explorer/index.tsx
index 778e06362797e..93ca9663537bb 100644
--- a/apps/studio/pages/project/[ref]/logs/explorer/index.tsx
+++ b/apps/studio/pages/project/[ref]/logs/explorer/index.tsx
@@ -1,27 +1,24 @@
import { useMonaco } from '@monaco-editor/react'
import { useLocalStorage } from '@uidotdev/usehooks'
-import dayjs from 'dayjs'
-import type { editor } from 'monaco-editor'
-import { useRouter } from 'next/router'
-import { useEffect, useMemo, useRef, useState } from 'react'
-import { toast } from 'sonner'
-
import { IS_PLATFORM, LOCAL_STORAGE_KEYS, useParams } from 'common'
-
import {
EXPLORER_DATEPICKER_HELPERS,
+ getDefaultHelper,
LOGS_LARGE_DATE_RANGE_DAYS_THRESHOLD,
TEMPLATES,
- getDefaultHelper,
} from 'components/interfaces/Settings/Logs/Logs.constants'
-import { LogData, LogTemplate, LogsWarning } from 'components/interfaces/Settings/Logs/Logs.types'
import { DatePickerValue } from 'components/interfaces/Settings/Logs/Logs.DatePickers'
+import { LogData, LogsWarning, LogTemplate } from 'components/interfaces/Settings/Logs/Logs.types'
import {
maybeShowUpgradePromptIfNotEntitled,
useEditorHints,
} from 'components/interfaces/Settings/Logs/Logs.utils'
+import {
+ buildLogQueryParams,
+ resolveLogDateRange,
+} from 'components/interfaces/Settings/Logs/logsDateRange'
import LogsQueryPanel from 'components/interfaces/Settings/Logs/LogsQueryPanel'
-import LogTable from 'components/interfaces/Settings/Logs/LogTable'
+import { LogTable } from 'components/interfaces/Settings/Logs/LogTable'
import UpgradePrompt from 'components/interfaces/Settings/Logs/UpgradePrompt'
import DefaultLayout from 'components/layouts/DefaultLayout'
import LogsLayout from 'components/layouts/LogsLayout/LogsLayout'
@@ -33,6 +30,7 @@ import {
UpsertContentPayload,
useContentUpsertMutation,
} from 'data/content/content-upsert-mutation'
+import dayjs from 'dayjs'
import useLogsQuery from 'hooks/analytics/useLogsQuery'
import { useLogsUrlState } from 'hooks/analytics/useLogsUrlState'
import { useCustomContent } from 'hooks/custom-content/useCustomContent'
@@ -42,11 +40,11 @@ import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt'
import { uuidv4 } from 'lib/helpers'
import { useProfile } from 'lib/profile'
import { useTrack } from 'lib/telemetry/track'
+import type { editor } from 'monaco-editor'
+import { useRouter } from 'next/router'
+import { useEffect, useMemo, useRef, useState } from 'react'
+import { toast } from 'sonner'
import type { LogSqlSnippets, NextPageWithLayout } from 'types'
-import {
- buildLogQueryParams,
- resolveLogDateRange,
-} from 'components/interfaces/Settings/Logs/logsDateRange'
import {
Button,
Form,
diff --git a/apps/studio/sentry.edge.config.ts b/apps/studio/sentry.edge.config.ts
index c5db7e27ad95c..ad17e8b86a208 100644
--- a/apps/studio/sentry.edge.config.ts
+++ b/apps/studio/sentry.edge.config.ts
@@ -12,4 +12,7 @@ Sentry.init({
}),
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
+
+ // Enable performance monitoring
+ tracesSampleRate: 0.1, // Capture 10% of transactions for performance monitoring
})
diff --git a/apps/studio/sentry.server.config.ts b/apps/studio/sentry.server.config.ts
index dba6457bc5f2b..13d62e7bc317e 100644
--- a/apps/studio/sentry.server.config.ts
+++ b/apps/studio/sentry.server.config.ts
@@ -11,6 +11,9 @@ Sentry.init({
}),
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
+
+ // Enable performance monitoring
+ tracesSampleRate: 0.1, // Capture 10% of transactions for performance monitoring
ignoreErrors: [
// Used exclusively in Monaco Editor.
'ResizeObserver',
diff --git a/apps/studio/tests/features/logs/LogTable.test.tsx b/apps/studio/tests/features/logs/LogTable.test.tsx
index 73a85fdf1288c..d25554b3ad801 100644
--- a/apps/studio/tests/features/logs/LogTable.test.tsx
+++ b/apps/studio/tests/features/logs/LogTable.test.tsx
@@ -1,12 +1,13 @@
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import LogTable from 'components/interfaces/Settings/Logs/LogTable'
+import { LogTable } from 'components/interfaces/Settings/Logs/LogTable'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import relativeTime from 'dayjs/plugin/relativeTime'
import timezone from 'dayjs/plugin/timezone'
import utc from 'dayjs/plugin/utc'
import { beforeAll, expect, test, vi } from 'vitest'
+
import { render } from '../../helpers'
dayjs.extend(customParseFormat)
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 6fd37691c2d07..50db1b44ac93c 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -356,8 +356,8 @@ services:
container_name: supabase-analytics
image: supabase/logflare:1.30.3
restart: unless-stopped
- ports:
- - 4000:4000
+ # ports:
+ # - 4000:4000
# Uncomment to use Big Query backend for analytics
# volumes:
# - type: bind
@@ -459,7 +459,7 @@ services:
vector:
container_name: supabase-vector
- image: timberio/vector:0.28.1-alpine
+ image: timberio/vector:0.53.0-alpine
restart: unless-stopped
volumes:
- ./volumes/logs/vector.yml:/etc/vector/vector.yml:ro,z
diff --git a/docker/utils/generate-keys.sh b/docker/utils/generate-keys.sh
index e67c6957bc62b..d9a16395bf694 100644
--- a/docker/utils/generate-keys.sh
+++ b/docker/utils/generate-keys.sh
@@ -60,6 +60,8 @@ logflare_private_access_token=$(gen_base64 24)
s3_protocol_access_key_id=$(gen_hex 16)
s3_protocol_access_key_secret=$(gen_hex 32)
+minio_root_password=$(gen_hex 16)
+
echo ""
echo "JWT_SECRET=${jwt_secret}"
echo ""
@@ -75,6 +77,7 @@ echo "LOGFLARE_PUBLIC_ACCESS_TOKEN=${logflare_public_access_token}"
echo "LOGFLARE_PRIVATE_ACCESS_TOKEN=${logflare_private_access_token}"
echo "S3_PROTOCOL_ACCESS_KEY_ID=${s3_protocol_access_key_id}"
echo "S3_PROTOCOL_ACCESS_KEY_SECRET=${s3_protocol_access_key_secret}"
+echo "MINIO_ROOT_PASSWORD=${minio_root_password}"
echo ""
postgres_password=$(gen_hex 16)
@@ -114,6 +117,7 @@ sed \
-e "s|^LOGFLARE_PRIVATE_ACCESS_TOKEN=.*$|LOGFLARE_PRIVATE_ACCESS_TOKEN=${logflare_private_access_token}|" \
-e "s|^S3_PROTOCOL_ACCESS_KEY_ID=.*$|S3_PROTOCOL_ACCESS_KEY_ID=${s3_protocol_access_key_id}|" \
-e "s|^S3_PROTOCOL_ACCESS_KEY_SECRET=.*$|S3_PROTOCOL_ACCESS_KEY_SECRET=${s3_protocol_access_key_secret}|" \
+ -e "s|^MINIO_ROOT_PASSWORD=.*$|MINIO_ROOT_PASSWORD=${minio_root_password}|" \
-e "s|^POSTGRES_PASSWORD=.*$|POSTGRES_PASSWORD=${postgres_password}|" \
-e "s|^DASHBOARD_PASSWORD=.*$|DASHBOARD_PASSWORD=${dashboard_password}|" \
.env
diff --git a/docker/volumes/api/kong.yml b/docker/volumes/api/kong.yml
index 7441cd31285ab..ae69cec282421 100644
--- a/docker/volumes/api/kong.yml
+++ b/docker/volumes/api/kong.yml
@@ -197,29 +197,29 @@ services:
- name: cors
## Analytics routes
- - name: analytics-v1-api
- _comment: 'Analytics: /analytics/v1/api/endpoints/* -> http://logflare:4000/api/endpoints/*'
- url: http://analytics:4000/api/endpoints
- routes:
- - name: analytics-v1-api
- strip_path: true
- paths:
- - /analytics/v1/api/endpoints/
-
- # auth on analytics dashboard
- - name: analytics-v1
- _comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*'
- url: http://analytics:4000/
- routes:
- - name: dashboard-v1-all
- strip_path: true
- paths:
- - /analytics/v1
- plugins:
- - name: cors
- - name: basic-auth
- config:
- hide_credentials: true
+ ## Not used - Studio and Vector talk directly to analytics via Docker networking.
+ ## If external access is needed, add routes with key-auth matching Logflare's x-api-key auth.
+ # - name: analytics-v1-api
+ # _comment: 'Analytics: /analytics/v1/api/endpoints/* -> http://logflare:4000/api/endpoints/*'
+ # url: http://analytics:4000/api/endpoints
+ # routes:
+ # - name: analytics-v1-api
+ # strip_path: true
+ # paths:
+ # - /analytics/v1/api/endpoints/
+ # - name: analytics-v1
+ # _comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*'
+ # url: http://analytics:4000/
+ # routes:
+ # - name: dashboard-v1-all
+ # strip_path: true
+ # paths:
+ # - /analytics/v1
+ # plugins:
+ # - name: cors
+ # - name: basic-auth
+ # config:
+ # hide_credentials: true
## Secure Database routes
- name: meta
diff --git a/docker/volumes/logs/vector.yml b/docker/volumes/logs/vector.yml
index e79d7e8268570..d600bf2867795 100644
--- a/docker/volumes/logs/vector.yml
+++ b/docker/volumes/logs/vector.yml
@@ -49,10 +49,13 @@ transforms:
.metadata.request.headers.referer = req.referer
.metadata.request.headers.user_agent = req.agent
.metadata.request.headers.cf_connecting_ip = req.client
- .metadata.request.method = req.method
- .metadata.request.path = req.path
- .metadata.request.protocol = req.protocol
.metadata.response.status_code = req.status
+ url, split_err = split(req.request, " ")
+ if split_err == null {
+ .metadata.request.method = url[0]
+ .metadata.request.path = url[1]
+ .metadata.request.protocol = url[2]
+ }
}
if err != null {
abort
@@ -101,7 +104,7 @@ transforms:
parsed, err = parse_regex(.event_message, r'^(?P