Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/docs/content/guides/self-hosting/docker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
19 changes: 6 additions & 13 deletions apps/studio/.github/eslint-rule-baselines.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
76 changes: 31 additions & 45 deletions apps/studio/components/grid/components/grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -241,9 +236,7 @@ export const Grid = memo(
{(rows ?? []).length === 0 && (
<div
className={cn(
'absolute w-full inset-0 flex flex-col items-center justify-center p-2 z-[1] pointer-events-none',
isTableEmpty && isDraggedOver && 'border-2 border-dashed',
isValidFileDraggedOver ? 'border-brand-600' : 'border-destructive-600'
'absolute w-full inset-0 flex flex-col items-center justify-center p-2 z-[1] pointer-events-none'
)}
>
{isLoading && !isDisabled && (
Expand Down Expand Up @@ -272,18 +265,13 @@ export const Grid = memo(
</div>
</div>
) : (filters ?? []).length === 0 ? (
<div className="flex flex-col items-center justify-center">
<p className="text-sm text-light pointer-events-auto">
{isDraggedOver ? (
isValidFileDraggedOver ? (
'Drop your CSV file here'
) : (
<span className="text-destructive">Only CSV files are accepted</span>
)
) : (
'This table is empty'
)}
</p>
<div
className={cn(
'flex flex-col items-center justify-center w-full h-full mt-9 transition',
isTableEmpty && isDraggedOver && 'border-2 border-dashed border-brand'
)}
>
<p className="text-sm text-light pointer-events-auto">This table is empty</p>
{tableEntityType === ENTITY_TYPE.FOREIGN_TABLE ? (
<div className="flex items-center space-x-2 mt-4">
<p className="text-sm text-light pointer-events-auto">
Expand All @@ -292,30 +280,28 @@ export const Grid = memo(
</p>
</div>
) : (
!isDraggedOver && (
<div className="flex flex-col items-center gap-4 mt-4">
<Button
type="default"
className="pointer-events-auto"
onClick={() => {
tableEditorSnap.onImportData()
sendEvent({
action: 'import_data_button_clicked',
properties: { tableType: 'Existing Table' },
groups: {
project: project?.ref ?? 'Unknown',
organization: org?.slug ?? 'Unknown',
},
})
}}
>
Import data from CSV
</Button>
<p className="text-xs text-foreground-light pointer-events-auto">
or drag and drop a CSV file here
</p>
</div>
)
<div className="flex flex-col items-center gap-4 mt-4">
<Button
type="default"
className="pointer-events-auto"
onClick={() => {
tableEditorSnap.onImportData()
sendEvent({
action: 'import_data_button_clicked',
properties: { tableType: 'Existing Table' },
groups: {
project: project?.ref ?? 'Unknown',
organization: org?.slug ?? 'Unknown',
},
})
}}
>
Import data from CSV
</Button>
<p className="text-xs text-foreground-light pointer-events-auto">
or drag and drop a CSV file here
</p>
</div>
)}
</div>
) : (
Expand Down
75 changes: 45 additions & 30 deletions apps/studio/components/interfaces/Settings/Logs/LogTable.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
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'
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'
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -120,14 +120,17 @@ 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}`
const result: Column<LogData> = {
key: column,
name: v as string,
resizable: true,
renderCell: ({ row }: any) => {
renderCell: ({ row }) => {
return (
<span
onContextMenu={(e) => {
Expand All @@ -140,7 +143,7 @@ const LogTable = ({
</span>
)
},
renderHeaderCell: (props) => {
renderHeaderCell: () => {
return <div className="flex items-center">{v}</div>
},
minWidth: 128,
Expand Down Expand Up @@ -392,7 +395,13 @@ const LogTable = ({
{!queryType && <LogsExplorerTableHeader />}

<ResizablePanelGroup direction="horizontal">
<ResizablePanel defaultSize={selectedLog ? 60 : 100}>
<ResizablePanel
id="log-table-content"
order={1}
minSize={panelContentMinSize}
maxSize={panelContentMaxSize}
defaultSize={panelContentMaxSize}
>
<DataGrid
role="table"
style={{ height: '100%' }}
Expand Down Expand Up @@ -445,25 +454,31 @@ const LogTable = ({
)}
</ResizablePanel>

<ResizableHandle withHandle />

{selectionOpen && (
<ResizablePanel minSize={40} defaultSize={50}>
<LogSelection
isLoading={isSelectedLogLoading || false}
projectRef={projectRef}
onClose={() => {
onSelectedLogChange?.(null)
setSelectionOpen(false)
}}
log={selectedLog}
error={selectedLogError}
queryType={queryType}
/>
</ResizablePanel>
<>
<ResizableHandle withHandle />
<ResizablePanel
id="log-table-panel"
order={2}
minSize={100 - panelContentMaxSize}
maxSize={100 - panelContentMinSize}
defaultSize={100 - panelContentMaxSize}
>
<LogSelection
isLoading={isSelectedLogLoading || false}
projectRef={projectRef}
onClose={() => {
onSelectedLogChange?.(null)
setSelectionOpen(false)
}}
log={selectedLog}
error={selectedLogError}
queryType={queryType}
/>
</ResizablePanel>
</>
)}
</ResizablePanelGroup>
</section>
)
}
export default LogTable
Original file line number Diff line number Diff line change
Expand Up @@ -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'

/**
Expand Down
Loading
Loading