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
80 changes: 80 additions & 0 deletions .github/workflows/studio-lint-ratchet-decrease.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Decrease studio lint ratchet baselines

on:
schedule:
- cron: '0 0 * * SUN'
workflow_dispatch:

permissions:
contents: write
pull-requests: write

jobs:
decrease-baselines:
runs-on: blacksmith-4vcpu-ubuntu-2404

steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
sparse-checkout: |
.github
apps/studio
packages

- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
name: Install pnpm
with:
run_install: false

- name: Use Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: '.nvmrc'
cache: 'pnpm'

- name: Install deps
run: pnpm install --frozen-lockfile

- name: Decrease ESLint ratchet baselines and open PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
set -eo pipefail
DEFAULT_BRANCH=${DEFAULT_BRANCH:-master}

BRANCH="bot/decrease-eslint-ratchet-baselines"

git fetch origin "$DEFAULT_BRANCH" --depth=1
if git ls-remote --exit-code --heads origin "$BRANCH" > /dev/null 2>&1; then
git fetch origin "$BRANCH":"$BRANCH" --depth=1
git switch "$BRANCH"
git reset --hard "origin/$DEFAULT_BRANCH"
else
git switch --create "$BRANCH" "origin/$DEFAULT_BRANCH"
fi

pnpm --filter studio run lint:ratchet --decrease-baselines

if git diff --quiet; then
echo "No baseline updates detected."
exit 0
fi

git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'

git add apps/studio/.github/eslint-rule-baselines.json
git commit --message "chore: decrease ESLint ratchet baselines"
git push --force origin "$BRANCH"

pr_url=$(gh pr list --state open --head "$BRANCH" --json url --jq '.[0].url // ""' 2>/dev/null || echo "")
if [ -z "$pr_url" ]; then
gh pr create \
--title "[bot] Decrease ESLint ratchet baselines" \
--body "Automated weekly decrease of ESLint ratchet baselines." \
--base "$DEFAULT_BRANCH" \
--head "$BRANCH"
else
gh pr comment "$pr_url" --body "Updated ESLint ratchet baselines with the latest weekly decreases."
fi
45 changes: 45 additions & 0 deletions .github/workflows/studio-lint-ratchet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Ratchet studio lint checks

on:
pull_request:
branches:
- master
paths:
- 'apps/studio/**'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
ratchet:
# Uses larger hosted runner as it significantly decreases build times
runs-on: blacksmith-4vcpu-ubuntu-2404

steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
sparse-checkout: |
.github
apps/studio
packages

- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
name: Install pnpm
with:
run_install: false

- name: Use Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: '.nvmrc'
cache: 'pnpm'

- name: Install deps
run: pnpm install --frozen-lockfile

- name: Run ratchet script
run: pnpm --filter studio run lint:ratchet
8 changes: 8 additions & 0 deletions apps/studio/.github/eslint-rule-baselines.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"rules": {
"react-hooks/exhaustive-deps": 238,
"import/no-anonymous-default-export": 62,
"@tanstack/query/exhaustive-deps": 19,
"@tanstack/query/no-deprecated-options": 2
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type { PostgresTable } from '@supabase/postgres-meta'
import { ArrowRight } from 'lucide-react'
import type { PropsWithChildren } from 'react'
import type { RenderCellProps } from 'react-data-grid'

import { convertByteaToHex } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
import { isTableLike } from 'data/table-editor/table-editor-types'
import { useTablesQuery } from 'data/tables/tables-query'
import { useTablesQuery as useTableRetrieveQuery } from 'data/tables/table-retrieve-query'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { Popover_Shadcn_, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_ } from 'ui'
import type { SupaRow } from '../../types'
Expand All @@ -21,7 +23,7 @@ export const ForeignKeyFormatter = (props: Props) => {
const { tableId, row, column } = props
const { data: project } = useSelectedProjectQuery()

const { data } = useTableEditorQuery({
const { data, isLoading } = useTableEditorQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
id: tableId,
Expand All @@ -35,17 +37,22 @@ export const ForeignKeyFormatter = (props: Props) => {
r.source_table_name === selectedTable?.name &&
r.source_column_name === column.name
)
const { data: tables } = useTablesQuery({
projectRef: project?.ref,
includeColumns: true,
connectionString: project?.connectionString,
schema: relationship?.target_table_schema,
})
const targetTable = tables?.find(
(table) =>
table.schema === relationship?.target_table_schema &&
table.name === relationship.target_table_name
)

const { data: targetTable, isLoading: isLoadingTargetTable } =
useTableRetrieveQuery<PostgresTable>(
{
projectRef: project?.ref,
connectionString: project?.connectionString,
schema: relationship?.target_table_schema ?? '',
name: relationship?.target_table_name ?? '',
},
{
enabled:
!!project?.ref &&
!!relationship?.target_table_schema &&
!!relationship?.target_table_name,
}
)

const value = row[column.key]
const formattedValue =
Expand All @@ -56,25 +63,39 @@ export const ForeignKeyFormatter = (props: Props) => {
<span className="sb-grid-foreign-key-formatter__text">
{formattedValue === null ? <NullValue /> : formattedValue}
</span>
{relationship !== undefined && targetTable !== undefined && formattedValue !== null && (
<Popover_Shadcn_>
<PopoverTrigger_Shadcn_ asChild>
<ButtonTooltip
type="default"
className="w-6 h-6"
icon={<ArrowRight />}
onClick={(e) => e.stopPropagation()}
tooltip={{ content: { side: 'bottom', text: 'View referencing record' } }}
/>
</PopoverTrigger_Shadcn_>
<PopoverContent_Shadcn_ portal align="end" className="p-0 w-96">
<ReferenceRecordPeek
table={targetTable}
column={relationship.target_column_name}
value={formattedValue}
/>
</PopoverContent_Shadcn_>
</Popover_Shadcn_>
{isLoading && formattedValue !== null && (
<div className="w-6 h-6 flex items-center justify-center">
<ShimmeringLoader className="w-4 h-4" />
</div>
)}
{!isLoading && relationship !== undefined && formattedValue !== null && (
<>
{isLoadingTargetTable && (
<div className="w-6 h-6 flex items-center justify-center">
<ShimmeringLoader className="w-4 h-4" />
</div>
)}
{!isLoadingTargetTable && targetTable !== undefined && (
<Popover_Shadcn_>
<PopoverTrigger_Shadcn_ asChild>
<ButtonTooltip
type="default"
className="w-6 h-6"
icon={<ArrowRight />}
onClick={(e) => e.stopPropagation()}
tooltip={{ content: { side: 'bottom', text: 'View referencing record' } }}
/>
</PopoverTrigger_Shadcn_>
<PopoverContent_Shadcn_ portal align="end" className="p-0 w-96">
<ReferenceRecordPeek
table={targetTable}
column={relationship.target_column_name}
value={formattedValue}
/>
</PopoverContent_Shadcn_>
</Popover_Shadcn_>
)}
</>
)}
</div>
)
Expand Down
29 changes: 22 additions & 7 deletions apps/studio/components/interfaces/Auth/Users/UserOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const UserOverview = ({ user, onDeleteSuccess }: UserOverviewProps) => {
const isEmailAuth = user.email !== null
const isPhoneAuth = user.phone !== null
const isBanned = user.banned_until !== null
const isVerified = user.confirmed_at != null

const { authenticationSignInProviders } = useIsFeatureEnabled([
'authentication:sign_in_providers',
Expand Down Expand Up @@ -110,10 +111,18 @@ export const UserOverview = ({ user, onDeleteSuccess }: UserOverviewProps) => {
const { mutate: sendMagicLink, isLoading: isSendingMagicLink } = useUserSendMagicLinkMutation({
onSuccess: (_, vars) => {
setSuccessAction('send_magic_link')
toast.success(`Sent magic link to ${vars.user.email}`)
toast.success(
isVerified
? `Sent magic link to ${vars.user.email}`
: `Sent confirmation email to ${vars.user.email}`
)
},
onError: (err) => {
toast.error(`Failed to send magic link: ${err.message}`)
toast.error(
isVerified
? `Failed to send magic link: ${err.message}`
: `Failed to send confirmation email: ${err.message}`
)
},
})
const { mutate: sendOTP, isLoading: isSendingOTP } = useUserSendOTPMutation({
Expand Down Expand Up @@ -294,11 +303,15 @@ export const UserOverview = ({ user, onDeleteSuccess }: UserOverviewProps) => {
}
/>
<RowAction
title="Send magic link"
description="Passwordless login via email for the user"
title={isVerified ? 'Send Magic Link' : 'Send confirmation email'}
description={
isVerified
? 'Passwordless login via email for the user'
: 'Send a confirmation email to the user'
}
button={{
icon: <Mail />,
text: 'Send magic link',
text: isVerified ? 'Send magic link' : 'Send confirmation email',
isLoading: isSendingMagicLink,
disabled: !canSendMagicLink,
onClick: () => {
Expand All @@ -308,8 +321,10 @@ export const UserOverview = ({ user, onDeleteSuccess }: UserOverviewProps) => {
success={
successAction === 'send_magic_link'
? {
title: 'Magic link sent',
description: `The link in the email is valid for ${formattedExpiry}`,
title: isVerified ? 'Magic link sent' : 'Confirmation email sent',
description: isVerified
? `The link in the email is valid for ${formattedExpiry}`
: 'The confirmation email has been sent to the user',
}
: undefined
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const ColumnForeignKey = ({
return {
id: c.id,
name: c.name,
format: column.format || c.format,
format: c.format || column.format,
isNewColumn: false,
}
})
Expand Down
Loading
Loading