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
17 changes: 17 additions & 0 deletions .github/workflows/trigger-nimbus-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Trigger Nimbus Sync

on:
push:
branches: [master]
workflow_dispatch: # Allow manual triggering

jobs:
trigger-nimbus-sync:
runs-on: ubuntu-latest
steps:
- name: Trigger sync in supabase-nimbus
uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.NIMBUS_SYNC_TOKEN }}
repository: supabase/supabase-nimbus
event-type: sync_from_upstream
7 changes: 5 additions & 2 deletions apps/studio/components/grid/SupabaseGrid.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ export function loadTableEditorStateFromLocalStorage(
schema?: string | null
): SavedState | undefined {
const storageKey = getStorageKey(STORAGE_KEY_PREFIX, projectRef)
const jsonStr = localStorage.getItem(storageKey)
// Prefer sessionStorage (scoped to current tab) over localStorage
const jsonStr = sessionStorage.getItem(storageKey) ?? localStorage.getItem(storageKey)
if (!jsonStr) return
const json = JSON.parse(jsonStr)
const tableKey = !schema || schema == 'public' ? tableName : `${schema}.${tableName}`
Expand All @@ -154,7 +155,7 @@ export function saveTableEditorStateToLocalStorage({
filters?: string[]
}) {
const storageKey = getStorageKey(STORAGE_KEY_PREFIX, projectRef)
const savedStr = localStorage.getItem(storageKey)
const savedStr = sessionStorage.getItem(storageKey) ?? localStorage.getItem(storageKey)
const tableKey = !schema || schema == 'public' ? tableName : `${schema}.${tableName}`

const config = {
Expand All @@ -171,7 +172,9 @@ export function saveTableEditorStateToLocalStorage({
} else {
savedJson = { [tableKey]: config }
}
// Save to both localStorage and sessionStorage so it's consistent to current tab
localStorage.setItem(storageKey, JSON.stringify(savedJson))
sessionStorage.setItem(storageKey, JSON.stringify(savedJson))
}

export const saveTableEditorStateToLocalStorageDebounced = AwesomeDebouncePromise(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export const RedirectUrlList = ({
<div
className={[
'flex items-center border-overlay bg-studio text-foreground',
'justify-center gap-2 rounded border px-6 py-8 text-sm',
'justify-center gap-2 rounded-b border px-6 py-8 text-sm',
].join(' ')}
>
<EmptyListState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,15 +270,6 @@ export const SessionsAuthSettingsForm = () => {
>
<Card>
<CardContent>
{promptProPlanUpgrade && (
<div className="mb-4">
<UpgradeToPro
primaryText="Upgrade to Pro"
secondaryText="Configuring user sessions requires the Pro Plan."
/>
</div>
)}

<FormField_Shadcn_
control={userSessionsForm.control}
name="SESSIONS_SINGLE_PER_USER"
Expand Down Expand Up @@ -352,6 +343,15 @@ export const SessionsAuthSettingsForm = () => {
)}
/>
</CardContent>

{promptProPlanUpgrade && (
<UpgradeToPro
fullWidth
primaryText="Configuring user sessions is only available on the Pro Plan and above"
secondaryText="Upgrade to the Pro plan to configure settings for user sessions"
/>
)}

<CardFooter className="justify-end space-x-2">
{userSessionsForm.formState.isDirty && (
<Button type="default" onClick={() => userSessionsForm.reset()}>
Expand Down
8 changes: 5 additions & 3 deletions apps/studio/components/interfaces/Auth/Users/Users.utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
copyToClipboard,
} from 'ui'
import { PROVIDERS_SCHEMAS } from '../AuthProvidersFormValidation'
import { ColumnConfiguration, USERS_TABLE_COLUMNS } from './Users.constants'
import { ColumnConfiguration, UsersTableColumn } from './Users.constants'
import { HeaderCell } from './UsersGridComponents'

const GITHUB_AVATAR_URL = 'https://avatars.githubusercontent.com'
Expand Down Expand Up @@ -250,21 +250,23 @@ export function getAvatarUrl(user: User): string | undefined {
}

export const formatUserColumns = ({
columns,
config,
users,
visibleColumns = [],
setSortByValue,
onSelectDeleteUser,
}: {
columns: UsersTableColumn[]
config: ColumnConfiguration[]
users: User[]
visibleColumns?: string[]
setSortByValue: (val: string) => void
onSelectDeleteUser: (user: User) => void
}) => {
const columnOrder = config.map((c) => c.id) ?? USERS_TABLE_COLUMNS.map((c) => c.id)
const columnOrder = config.map((c) => c.id) ?? columns.map((c) => c.id)

let gridColumns = USERS_TABLE_COLUMNS.map((col) => {
let gridColumns = columns.map((col) => {
const savedConfig = config.find((c) => c.id === col.id)
const res: Column<any> = {
key: col.id,
Expand Down
22 changes: 18 additions & 4 deletions apps/studio/components/interfaces/Auth/Users/UsersV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,25 @@ export const UsersV2 = () => {
authenticationShowSortByEmail: showSortByEmail,
authenticationShowSortByPhone: showSortByPhone,
authenticationShowUserTypeFilter: showUserTypeFilter,
authenticationShowEmailPhoneColumns: showEmailPhoneColumns,
} = useIsFeatureEnabled([
'authentication:show_provider_filter',
'authentication:show_sort_by_email',
'authentication:show_sort_by_phone',
'authentication:show_user_type_filter',
'authentication:show_email_phone_columns',
])

const userTableColumns = useMemo(() => {
if (showEmailPhoneColumns) return USERS_TABLE_COLUMNS
else {
return USERS_TABLE_COLUMNS.filter((col) => {
if (col.id === 'email' || col.id === 'phone') return false
return true
})
}
}, [showEmailPhoneColumns])

const [columns, setColumns] = useState<Column<any>[]>([])
const [search, setSearch] = useState('')
const [filter, setFilter] = useState<Filter>('all')
Expand Down Expand Up @@ -265,14 +277,15 @@ export const UsersV2 = () => {
(isErrorStorage && (errorStorage as Error).message.includes('data is undefined')))
) {
const columns = formatUserColumns({
columns: userTableColumns,
config: columnConfiguration ?? [],
users: users ?? [],
visibleColumns: selectedColumns,
setSortByValue,
onSelectDeleteUser: setSelectedUserToDelete,
})
setColumns(columns)
if (columns.length < USERS_TABLE_COLUMNS.length) {
if (columns.length < userTableColumns.length) {
setSelectedColumns(columns.filter((col) => col.key !== 'img').map((col) => col.key))
}
}
Expand Down Expand Up @@ -386,7 +399,7 @@ export const UsersV2 = () => {
name={selectedColumns.length === 0 ? 'All columns' : 'Columns'}
title="Select columns to show"
buttonType={selectedColumns.length === 0 ? 'dashed' : 'default'}
options={USERS_TABLE_COLUMNS.slice(1)} // Ignore user image column
options={userTableColumns.slice(1)} // Ignore user image column
labelKey="name"
valueKey="id"
labelClass="text-xs"
Expand All @@ -401,19 +414,20 @@ export const UsersV2 = () => {

let updatedConfig = (columnConfiguration ?? []).slice()
if (value.length === 0) {
updatedConfig = USERS_TABLE_COLUMNS.map((c) => ({ id: c.id, width: c.width }))
updatedConfig = userTableColumns.map((c) => ({ id: c.id, width: c.width }))
} else {
value.forEach((col) => {
const hasExisting = updatedConfig.find((c) => c.id === col)
if (!hasExisting)
updatedConfig.push({
id: col,
width: USERS_TABLE_COLUMNS.find((c) => c.id === col)?.width,
width: userTableColumns.find((c) => c.id === col)?.width,
})
})
}

const updatedColumns = formatUserColumns({
columns: userTableColumns,
config: updatedConfig,
users: users ?? [],
visibleColumns: value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const CurrentPaymentMethod = () => {
<Button type="outline" asChild>
{subscription?.payment_method_type === 'invoice' ? (
<Link
href={`/support/new?slug=${slug}&ref=no-project&message=${encodeURIComponent('I would like to change my payment method')}&category=${SupportCategories.BILLING}`}
href={`/support/new?slug=${slug}&projectRef=no-project&message=${encodeURIComponent('I would like to change my payment method')}&category=${SupportCategories.BILLING}`}
>
Contact support
</Link>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Link from 'next/link'

import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { Badge, NavMenu, NavMenuItem } from 'ui'

Expand All @@ -9,6 +10,7 @@ type Props = {

function DatabaseBackupsNav({ active }: Props) {
const { ref, cloud_provider } = useSelectedProjectQuery()?.data || {}
const { databaseRestoreToNewProject } = useIsFeatureEnabled(['database:restore_to_new_project'])

const navMenuItems = [
{
Expand All @@ -24,7 +26,7 @@ function DatabaseBackupsNav({ active }: Props) {
href: `/project/${ref}/database/backups/pitr`,
},
{
enabled: cloud_provider !== 'FLY',
enabled: databaseRestoreToNewProject && cloud_provider !== 'FLY',
id: 'rtnp',
label: (
<div className="flex items-center gap-1">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ChevronRightIcon } from 'lucide-react'
import Link from 'next/link'

import { CloneStatus } from 'data/projects/clone-status-query'
import { TimestampInfo } from 'ui-patterns'
import { StatusBadge } from './StatusBadge'

export const PreviousRestoreItem = ({
clone,
}: {
clone: NonNullable<CloneStatus['clones']>[number]
}) => {
if (clone.status === 'REMOVED') {
return (
<div className="grid grid-cols-4 gap-2 text-sm p-4 group">
<div className="min-w-24 truncate">{(clone.target_project as any).name}</div>
<div>
<StatusBadge status={clone.status} />
</div>
<div>
<TimestampInfo
className="font-mono text-xs text-foreground-lighter"
utcTimestamp={clone.inserted_at ?? ''}
/>
</div>
</div>
)
} else {
return (
<Link
href={`/project/${clone.target_project.ref}`}
className="grid grid-cols-4 gap-2 text-sm p-4 group"
>
<div className="min-w-24 truncate">{(clone.target_project as any).name}</div>
<div>
<StatusBadge status={clone.status} />
</div>
<div>
<TimestampInfo
className="font-mono text-xs text-foreground-lighter"
utcTimestamp={clone.inserted_at ?? ''}
/>
</div>
<div className="flex items-center justify-end text-foreground-lighter group-hover:text-foreground">
<ChevronRightIcon className="w-4 h-4" />
</div>
</Link>
)
}
}
Loading
Loading