chore: Remove dangling dependencies and files (#19785)

* Delete probably unneeded files.

* Remove unused deps.
This commit is contained in:
Ivan Vasilov authored and GitHub committed 2023-12-18 12:11:15 +00:00
1 parent b5b26fc110
commit 563ef1cff2
48 files changed
+1 -3492

No files matched your search

@@ -1,165 +0,0 @@
// [Joshen] Maybe shift this into shared-types repo or something?
// This isn't typed completely properly as I'm not too sure myself
export interface AuthConfig {
id: number
project_id: number
updated_at: string
DISABLE_SIGNUP: boolean
SECURITY_MANUAL_LINKING_ENABLED: boolean
EXTERNAL_EMAIL_ENABLED: boolean
EXTERNAL_PHONE_ENABLED: boolean
EXTERNAL_APPLE_ENABLED: boolean
EXTERNAL_APPLE_CLIENT_ID: string | null
EXTERNAL_APPLE_SECRET: string | null
EXTERNAL_AZURE_ENABLED: boolean
EXTERNAL_AZURE_URL: string | null
EXTERNAL_AZURE_CLIENT_ID: string | null
EXTERNAL_AZURE_SECRET: string | null
EXTERNAL_BITBUCKET_ENABLED: boolean
EXTERNAL_BITBUCKET_CLIENT_ID: string | null
EXTERNAL_BITBUCKET_SECRET: string | null
EXTERNAL_DISCORD_ENABLED: boolean
EXTERNAL_DISCORD_CLIENT_ID: string | null
EXTERNAL_DISCORD_SECRET: string | null
EXTERNAL_FACEBOOK_ENABLED: boolean
EXTERNAL_FACEBOOK_CLIENT_ID: string | null
EXTERNAL_FACEBOOK_SECRET: string | null
EXTERNAL_FIGMA_ENABLED: boolean
EXTERNAL_FIGMA_CLIENT_ID: string | null
EXTERNAL_FIGMA_SECRET: string | null
EXTERNAL_GITHUB_ENABLED: false
EXTERNAL_GITHUB_CLIENT_ID: string | null
EXTERNAL_GITHUB_SECRET: string | null
EXTERNAL_GITLAB_ENABLED: boolean
EXTERNAL_GITLAB_CLIENT_ID: string | null
EXTERNAL_GITLAB_REDIRECT_URI: string | null
EXTERNAL_GITLAB_SECRET: string | null
EXTERNAL_GOOGLE_ENABLED: boolean
EXTERNAL_GOOGLE_CLIENT_ID: string | null
EXTERNAL_GOOGLE_SECRET: string | null
EXTERNAL_KEYCLOAK_ENABLED: boolean
EXTERNAL_KEYCLOAK_CLIENT_ID: string | null
EXTERNAL_KEYCLOAK_SECRET: string | null
EXTERNAL_KEYCLOAK_URL: string | null
EXTERNAL_LINKEDIN_ENABLED: boolean
EXTERNAL_LINKEDIN_CLIENT_ID: string | null
EXTERNAL_LINKEDIN_SECRET: string | null
EXTERNAL_LINKEDIN_OIDC_ENABLED: boolean
EXTERNAL_LINKEDIN_OIDC_CLIENT_ID: string | null
EXTERNAL_LINKEDIN_OIDC_SECRET: string | null
EXTERNAL_NOTION_ENABLED: boolean
EXTERNAL_NOTION_CLIENT_ID: string | null
EXTERNAL_NOTION_SECRET: string | null
EXTERNAL_SLACK_ENABLED: boolean
EXTERNAL_SLACK_CLIENT_ID: string | null
EXTERNAL_SLACK_SECRET: string | null
EXTERNAL_SPOTIFY_ENABLED: boolean
EXTERNAL_SPOTIFY_CLIENT_ID: string | null
EXTERNAL_SPOTIFY_SECRET: string | null
EXTERNAL_TWITCH_ENABLED: boolean
EXTERNAL_TWITCH_CLIENT_ID: string | null
EXTERNAL_TWITCH_SECRET: string | null
EXTERNAL_TWITTER_ENABLED: boolean
EXTERNAL_TWITTER_CLIENT_ID: string | null
EXTERNAL_TWITTER_SECRET: string | null
EXTERNAL_WORKOS_ENABLED: boolean
EXTERNAL_WORKOS_CLIENT_ID: string | null
EXTERNAL_WORKOS_SECRET: string | null
EXTERNAL_WORKOS_URL: string | null
EXTERNAL_ZOOM_ENABLED: boolean
EXTERNAL_ZOOM_CLIENT_ID: string | null
EXTERNAL_ZOOM_SECRET: string | null
JWT_AUD: 'authenticated' | string
JWT_DEFAULT_GROUP_NAME: 'authenticated' | string
JWT_EXP: number
MAILER_AUTOCONFIRM: boolean
MAILER_OTP_EXP: number
MAILER_SECURE_EMAIL_CHANGE_ENABLED: boolean
MAILER_SUBJECTS_CONFIRMATION: string
MAILER_SUBJECTS_EMAIL_CHANGE: string
MAILER_SUBJECTS_INVITE: string
MAILER_SUBJECTS_MAGIC_LINK: string
MAILER_SUBJECTS_RECOVERY: string
MAILER_TEMPLATES_CONFIRMATION: string | null
MAILER_TEMPLATES_CONFIRMATION_CONTENT: string
MAILER_TEMPLATES_EMAIL_CHANGE: string | null
MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT: string
MAILER_TEMPLATES_INVITE: string | null
MAILER_TEMPLATES_INVITE_CONTENT: string
MAILER_TEMPLATES_MAGIC_LINK: string | null
MAILER_TEMPLATES_MAGIC_LINK_CONTENT: string
MAILER_TEMPLATES_RECOVERY: string | null
MAILER_TEMPLATES_RECOVERY_CONTENT: string
MAILER_URLPATHS_CONFIRMATION: string
MAILER_URLPATHS_EMAIL_CHANGE: string
MAILER_URLPATHS_INVITE: string
MAILER_URLPATHS_RECOVERY: string
OPERATOR_TOKEN: string | null
PASSWORD_MIN_LENGTH: number
RATE_LIMIT_EMAIL_SENT: number
RATE_LIMIT_SMS_SENT: number
RATE_LIMIT_HEADER: string | null
RATE_LIMIT_TOKEN_REFRESH: number
RATE_LIMIT_VERIFY: number
REFRESH_TOKEN_ROTATION_ENABLED: boolean
SECURITY_CAPTCHA_ENABLED: boolean
SECURITY_CAPTCHA_PROVIDER: 'hcaptcha' | 'turnstile' | string
SECURITY_CAPTCHA_SECRET: string
SECURITY_REFRESH_TOKEN_REUSE_INTERVAL: number
SECURITY_UPDATE_PASSWORD_REQUIRE_REAUTHENTICATION: boolean
SITE_URL: string
SMS_AUTOCONFIRM: boolean
SMS_MAX_FREQUENCY: number
SMS_MESSAGEBIRD_ACCESS_KEY: string
SMS_MESSAGEBIRD_ORIGINATOR: string
SMS_OTP_EXP: number
SMS_OTP_LENGTH: number
SMS_PROVIDER: 'twilio' | string
SMS_TEMPLATE: string
SMS_TEXTLOCAL_API_KEY: string
SMS_TEXTLOCAL_SENDER: string
SMS_TWILIO_ACCOUNT_SID: string
SMS_TWILIO_AUTH_TOKEN: string
SMS_TWILIO_CONTENT_SID: string
SMS_TWILIO_MESSAGE_SERVICE_SID: string
SMS_TWILIO_VERIFY_ACCOUNT_SID: string
SMS_TWILIO_VERIFY_AUTH_TOKEN: string
SMS_TWILIO_VERIFY_MESSAGE_SERVICE_SID: string
SMS_VONAGE_API_KEY: string
SMS_VONAGE_API_SECRET: string
SMS_VONAGE_FROM: string
SMTP_ADMIN_EMAIL: string | null
SMTP_HOST: string | null
SMTP_MAX_FREQUENCY: number
SMTP_PASS: string | null
SMTP_PASS_ENCRYPTED: string | null
SMTP_PORT: number | string | null
SMTP_SENDER_NAME: string | null
SMTP_USER: string | null
URI_ALLOW_LIST: string
}
@@ -1,105 +0,0 @@
// [Joshen] Probably need to centralize this value somewhere as it needs to be used
// by email notifications as well
export const USAGE_APPROACHING_THRESHOLD = 0.8
export const BILLING_BREAKDOWN_METRICS = [
{
key: 'db_size',
name: 'Database space',
units: 'bytes',
anchor: 'dbSize',
metric: 'DATABASE_SIZE',
category: 'Database',
unitName: 'GB',
},
{
key: 'db_egress',
name: 'Database egress',
units: 'bytes',
anchor: 'egress',
metric: 'DATABASE_EGRESS',
category: 'Database',
unitName: 'GB',
},
{
key: 'monthly_active_users',
name: 'Active users',
units: 'absolute',
anchor: 'mau',
metric: 'MONTHLY_ACTIVE_USERS',
category: 'Authentication',
unitName: 'MAU',
},
{
key: 'monthly_active_sso_users',
name: 'Active SSO users',
units: 'absolute',
anchor: 'mauSso',
metric: 'MONTHLY_ACTIVE_SSO_USERS',
category: 'Authentication',
unitName: 'MAU',
},
{
key: 'storage_size',
name: 'Storage space',
units: 'bytes',
anchor: 'storageSize',
metric: 'STORAGE_SIZE',
category: 'Storage',
unitName: 'GB',
},
{
key: 'storage_egress',
name: 'Storage egress',
units: 'bytes',
anchor: 'storageEgress',
metric: 'STORAGE_EGRESS',
category: 'Storage',
unitName: 'GB',
},
{
key: 'storage_image_render_count',
name: 'Storage Image Transformations',
units: 'absolute',
anchor: 'storageImageTransformations',
metric: 'STORAGE_IMAGES_TRANSFORMED',
category: 'Storage',
unitName: 'image',
},
{
key: 'realtime_peak_connection',
name: 'Realtime peak connections',
units: 'absolute',
anchor: 'realtimePeakConnections',
metric: 'REALTIME_PEAK_CONNECTIONS',
category: 'Realtime',
unitName: 'connection',
},
{
key: 'realtime_message_count',
name: 'Realtime messages',
units: 'absolute',
anchor: 'realtimeMessageCount',
metric: 'REALTIME_MESSAGE_COUNT',
category: 'Realtime',
unitName: 'message',
},
{
key: 'func_invocations',
name: 'Edge Function invocations',
units: 'absolute',
anchor: 'funcInvocations',
metric: 'FUNCTION_INVOCATIONS',
category: 'Edge Functions',
unitName: 'invocation',
},
{
key: 'func_count',
name: 'Edge Functions',
units: 'absolute',
anchor: 'funcCount',
metric: 'FUNCTION_COUNT',
category: 'Edge Functions',
unitName: 'function',
},
] as const
@@ -1,30 +0,0 @@
// Converts a list of single object, into a single object
// e.g [{ name: 'name1', value: 'value1' }, { name: 'name2', value: 'value2' }]
// -> { name1: 'value1', name2: 'value2' }
export const formatArguments = (args: { name: string; value: string }[]) => {
const res: any = {}
args.forEach((args) => {
res[args.name] = args.value
})
return JSON.stringify(res)
}
/**
* convert "{\"Content-type\":\"application/json\"}"
* to {value: [{name: 'search_path', value: 'auth, public'}]}
*/
export const convertKeyValue = (value: string) => {
const temp = []
if (value) {
const obj = JSON.parse(value)
for (var key in obj) {
temp.push({ name: key, value: obj[key] })
}
}
return { value: temp }
}
export const hasWhitespace = (value: string) => {
return /\s/.test(value)
}
@@ -1,11 +0,0 @@
const NoDescription = () => {
return (
<p className="text-gray-300 text-sm">
No description provided.
<br />
Hint: you can create a custom description by adding a "comment" to this item in your database.
</p>
)
}
export default NoDescription
@@ -1,326 +0,0 @@
export const LOGS_DATA = [
{
id: 1,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 256,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 2,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 256,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 3,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 512,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 3,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 512,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 3,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 512,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 3,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 512,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 3,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 512,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 3,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 512,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
{
id: 3,
url: '/readededeaded/functions/hello-world',
method: 'POST',
runtime: 'Node14',
memory: 512,
created_at: 1646524256,
user_agent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
memory_used: '113',
init_duration: '431.44',
duration: '1394.57 ms',
edge_status: '200',
function_status: '200',
},
]
export const REQUEST_SAMPLE = {
custom_fields: {
'0': {
name: 'Project name',
value: '1a1a1a1a1a1a1a1a1a1a1a',
},
},
}
export const RESPONSE_SAMPLE = [
{
id: 'in_1a1a1a1a1a1a1a1a1a1a1a',
object: '1a1a1a1a1a1a1a1a1a1a1a',
account_country: 'US',
account_name: '1a1a1a1a1a1a1a1a1a1a1a',
account_tax_ids: null,
amount_due: 0,
amount_paid: 0,
amount_remaining: 0,
application_fee_amount: null,
attempt_count: 0,
attempted: false,
auto_advance: true,
automatic_tax: {
enabled: false,
status: null,
},
billing_reason: '1a1a1a1a1a1a1a1a1a1a1a',
charge: null,
collection_method: 'charge_automatically',
created: 1646526032,
currency: 'usd',
custom_fields: [
{
name: 'Project name',
value: '1a1a1a1a1a1a1a1a1a1a1a',
},
],
customer: 'cus_in_1a1a1a1a1a1a1a1a1a1a1a',
customer_address: null,
customer_email: 'in_1a1a1a1a1a1a1a1a1a1a1a@gmail.com',
customer_name: null,
customer_phone: null,
customer_shipping: null,
customer_tax_exempt: 'none',
customer_tax_ids: [],
default_payment_method: null,
default_source: null,
default_tax_rates: [],
description: null,
discount: null,
discounts: [],
due_date: null,
ending_balance: null,
footer: null,
hosted_invoice_url: null,
invoice_pdf: null,
last_finalization_error: null,
lines: {
object: 'list',
data: [
{
id: 'il_in_1a1a1a1a1a1a1a1a1a1a1a',
object: 'line_item',
amount: 0,
currency: 'usd',
description: '1 × Free tier (at $0.00 / month)',
discount_amounts: [],
discountable: true,
discounts: [],
livemode: true,
metadata: {
project_id: '29167',
project_ref: '1a1a1a1a1a1a1a1a1a1a1a',
project_name: '1a1a1a1a1a1a1a1a1a1a1a',
organization_id: '1a1a1a1a1a1a1a1a1a1a1a',
organization_slug:
'1a1a1a1a1a1a1a1a1a1a1a-1a1a1a1a1a1a1a1a1a1a1a-1a1a1a1a1a1a1a1a1a1a1a',
},
period: {
end: 1649204401,
start: 1646526001,
},
plan: {
id: 'price_1a1a1a1a1a1a1a1a1a1a1a',
object: 'plan',
active: true,
aggregate_usage: null,
amount: 0,
amount_decimal: '0',
billing_scheme: 'per_unit',
created: 1615645622,
currency: 'usd',
interval: 'month',
interval_count: 1,
livemode: true,
metadata: {
price: '0000',
},
nickname: null,
product: 'prod_1a1a1a1a1a1a1a1a1a1a1a',
tiers_mode: null,
transform_usage: null,
trial_period_days: null,
usage_type: 'licensed',
},
price: {
id: 'price_1a1a1a1a1a1a1a1a1a1a1a',
object: 'price',
active: true,
billing_scheme: 'per_unit',
created: 1615645622,
currency: 'usd',
livemode: true,
lookup_key: null,
metadata: {
price: '0000',
},
nickname: null,
product: 'prod_1a1a1a1a1a1a1a1a1a1a1a',
recurring: {
aggregate_usage: null,
interval: 'month',
interval_count: 1,
trial_period_days: null,
usage_type: 'licensed',
},
tax_behavior: 'unspecified',
tiers_mode: null,
transform_quantity: null,
type: 'recurring',
unit_amount: 0,
unit_amount_decimal: '0',
},
proration: false,
proration_details: {
credited_items: null,
},
quantity: 1,
subscription: 'sub_1a1a1a1a1a1a1a1a1a1a1a',
subscription_item: 'si_1a1a1a1a1a1a1a1a1a1a1a',
tax_amounts: [],
tax_rates: [],
type: 'subscription',
},
],
has_more: false,
total_count: 1,
url: '/v1/invoices/in_1a1a1a1a1a1a1a1a1a1a1a/lines',
},
livemode: true,
metadata: {},
next_payment_attempt: 1646529632,
number: null,
on_behalf_of: null,
paid: false,
paid_out_of_band: false,
payment_intent: null,
payment_settings: {
payment_method_options: null,
payment_method_types: null,
},
period_end: 1646526001,
period_start: 1644106801,
post_payment_credit_notes_amount: 0,
pre_payment_credit_notes_amount: 0,
quote: null,
receipt_number: null,
starting_balance: 0,
statement_descriptor: null,
status: 'draft',
status_transitions: {
finalized_at: null,
marked_uncollectible_at: null,
paid_at: null,
voided_at: null,
},
subscription: 'sub_1a1a1a1a1a1a1a1a1a1a1a',
subtotal: 0,
tax: null,
test_clock: null,
total: 0,
total_discount_amounts: [],
total_tax_amounts: [],
transfer_data: null,
webhooks_delivered_at: null,
},
]
@@ -1,4 +0,0 @@
export interface EndpointResponse<T> {
result: Array<T>
error: Object
}
@@ -1,50 +0,0 @@
import { noop } from 'lodash'
import { Badge, Button } from 'ui'
import { Project } from 'types'
interface PausedProjectCardProps {
project: Project
onSelectRestore: () => void
onSelectDelete: () => void
}
const PausedProjectCard = ({
project,
onSelectRestore = noop,
onSelectDelete = noop,
}: PausedProjectCardProps) => {
return (
<li className="col-span-1 flex rounded-md shadow-sm">
<a className="col-span-3 w-full md:col-span-1 ">
<div
className={[
'bg-surface-100',
'hover:bg-background',
'border border-strong',
'hover:border-stronger',
'h-32 rounded p-4',
'flex flex-col justify-between transition duration-150 ease-in-out',
].join(' ')}
>
<div className="flex items-center justify-between space-x-2">
<h5 className="m-0 truncate">{project.name}</h5>
<Badge color="yellow" dot>
Paused
</Badge>
</div>
<div className="flex items-center space-x-2">
<Button size="tiny" onClick={() => onSelectRestore()}>
Restore
</Button>
<Button size="tiny" type="outline" onClick={() => onSelectDelete()}>
Delete
</Button>
</div>
</div>
</a>
</li>
)
}
export default PausedProjectCard
@@ -1,348 +0,0 @@
import * as Tooltip from '@radix-ui/react-tooltip'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { useState } from 'react'
import {
Alert,
Badge,
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
IconCreditCard,
IconMoreHorizontal,
IconPlus,
IconX,
Input,
Modal,
} from 'ui'
import AlertError from 'components/ui/AlertError'
import NoPermission from 'components/ui/NoPermission'
import Panel from 'components/ui/Panel'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useOrganizationCustomerProfileQuery } from 'data/organizations/organization-customer-profile-query'
import { useOrganizationCustomerProfileUpdateMutation } from 'data/organizations/organization-customer-profile-update-mutation'
import { useOrganizationPaymentMethodDeleteMutation } from 'data/organizations/organization-payment-method-delete-mutation'
import { useOrganizationPaymentMethodsQuery } from 'data/organizations/organization-payment-methods-query'
import { useCheckPermissions, useStore } from 'hooks'
import { BASE_PATH } from 'lib/constants'
import { getURL } from 'lib/helpers'
import AddNewPaymentMethodModal from 'components/interfaces/Billing/Payment/AddNewPaymentMethodModal'
const PaymentMethods = () => {
const { ui } = useStore()
const { slug } = useParams()
const [selectedMethodForDefault, setSelectedMethodForDefault] = useState<any>()
const [selectedMethodToDelete, setSelectedMethodToDelete] = useState<any>()
const [showAddPaymentMethodModal, setShowAddPaymentMethodModal] = useState(false)
const { mutate: updateCustomerProfile, isLoading: isUpdating } =
useOrganizationCustomerProfileUpdateMutation({
onSuccess: (updatedCustomer) => {
setSelectedMethodForDefault(undefined)
ui.setNotification({
category: 'success',
message: 'Successfully updated default payment method',
})
},
onError: (error) => {
ui.setNotification({
category: 'error',
message: `Failed to make payment method default: ${error.message}`,
})
},
})
const { mutate: deletePaymentMethod, isLoading: isDeleting } =
useOrganizationPaymentMethodDeleteMutation({
onSuccess: () => {
setSelectedMethodToDelete(undefined)
ui.setNotification({ category: 'success', message: 'Successfully deleted payment method' })
},
})
const { data: customer } = useOrganizationCustomerProfileQuery({ slug })
const {
data,
error: paymentMethodsError,
refetch: refetchPaymentMethods,
isLoading: isLoadingPaymentMethods,
isError: isErrorPaymentMethods,
isSuccess: isSuccessPaymentMethods,
} = useOrganizationPaymentMethodsQuery({ slug })
const paymentMethods = data || []
const defaultPaymentMethod = customer?.invoice_settings?.default_payment_method ?? ''
const canReadPaymentMethods = useCheckPermissions(
PermissionAction.BILLING_READ,
'stripe.payment_methods'
)
const canUpdatePaymentMethods = useCheckPermissions(
PermissionAction.BILLING_WRITE,
'stripe.payment_methods'
)
const onConfirmMakeDefaultPaymentMethod = () => {
if (!slug) return console.error('Slug is required')
updateCustomerProfile({
slug,
invoice_settings: {
default_payment_method: selectedMethodForDefault.id,
},
})
}
const onConfirmDetachPaymentMethod = () => {
if (!slug) return console.error('Slug is required')
deletePaymentMethod({ slug, cardId: selectedMethodToDelete.id })
}
const onLocalPaymentMethodAdded = () => {
setShowAddPaymentMethodModal(false)
ui.setNotification({ category: 'success', message: 'Successfully added new payment method' })
return refetchPaymentMethods()
}
return (
<>
<div className="space-y-2 -mb-8">
<div>
<h4>Payment methods</h4>
<p className="text-sm opacity-50">
When adding a new payment method, either remove the old one or go to your projects'
subscription to explicitly update the payment method. Marking a payment method as
"default" is only relevant for new projects or if there are no other payment methods on
your account.
</p>
</div>
{!isLoadingPaymentMethods && !canReadPaymentMethods && (
<Panel>
<NoPermission resourceText="view this organization's payment methods" />
</Panel>
)}
{isLoadingPaymentMethods && <GenericSkeletonLoader />}
{isErrorPaymentMethods && (
<AlertError error={paymentMethodsError} subject="Failed to retrieve payment methods" />
)}
{isSuccessPaymentMethods && (
<Panel
footer={
<div className="flex w-full justify-between">
{!canUpdatePaymentMethods ? (
<p className="text-sm text-foreground-light">
You need additional permissions to manage this organization's payment methods
</p>
) : (
<div />
)}
<div>
<Button
key="panel-footer"
type="default"
icon={<IconPlus />}
disabled={!canUpdatePaymentMethods}
onClick={() => setShowAddPaymentMethodModal(true)}
>
Add new card
</Button>
</div>
</div>
}
>
{paymentMethods.length >= 1 ? (
<Panel.Content>
<div className="space-y-2">
{paymentMethods.map((paymentMethod: any) => {
const isDefault = paymentMethod.id === defaultPaymentMethod
return (
<div key={paymentMethod.id} className="flex items-center justify-between">
<div className="flex items-center space-x-8">
<img
alt="Credit card brand"
src={`${BASE_PATH}/img/payment-methods/${paymentMethod.card.brand
.replace(' ', '-')
.toLowerCase()}.png`}
width="32"
/>
<Input
readOnly
className="w-64"
size="small"
value={`•••• •••• •••• ${paymentMethod.card.last4}`}
/>
{isDefault ? (
<Badge color="gray">Default</Badge>
) : (
<div className="opacity-0">
<Badge color="gray">Default</Badge>
</div>
)}
<p className="text-sm tabular-nums">
Expires: {paymentMethod.card.exp_month}/{paymentMethod.card.exp_year}
</p>
</div>
{canUpdatePaymentMethods && (
<>
{isDefault ? (
<Tooltip.Root delayDuration={0}>
<Tooltip.Trigger asChild>
<Button disabled type="outline" icon={<IconX />} />
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content side="bottom">
<Tooltip.Arrow className="radix-tooltip-arrow" />
<div
className={[
'rounded bg-alternative py-1 px-2 leading-none shadow', // background
'w-48 border border-background text-center', //border
].join(' ')}
>
<span className="text-xs text-foreground">
Your default payment method cannot be deleted
</span>
</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
) : (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="outline"
loading={isLoadingPaymentMethods}
className="hover:border-gray-500"
>
<IconMoreHorizontal />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
key="make-default"
onClick={() => setSelectedMethodForDefault(paymentMethod)}
>
<p>Make default</p>
</DropdownMenuItem>
<DropdownMenuItem
key="delete-method"
onClick={() => setSelectedMethodToDelete(paymentMethod)}
>
<p>Delete</p>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
</>
)}
</div>
)
})}
</div>
</Panel.Content>
) : (
<Panel.Content>
<div className="flex items-center space-x-2 opacity-50">
<IconCreditCard />
<p className="text-sm">No payment methods</p>
</div>
</Panel.Content>
)}
</Panel>
)}
</div>
<AddNewPaymentMethodModal
visible={showAddPaymentMethodModal}
returnUrl={`${getURL()}/org/${slug}/billing`}
onCancel={() => setShowAddPaymentMethodModal(false)}
onConfirm={() => onLocalPaymentMethodAdded()}
/>
<Modal
visible={selectedMethodForDefault !== undefined}
size="small"
header="Set payment method as default"
onCancel={() => setSelectedMethodForDefault(undefined)}
customFooter={
<div className="flex items-center gap-2">
<Button
type="default"
disabled={isUpdating}
onClick={() => setSelectedMethodForDefault(undefined)}
>
Cancel
</Button>
<Button
type="primary"
disabled={isUpdating}
loading={isUpdating}
onClick={onConfirmMakeDefaultPaymentMethod}
>
Confirm
</Button>
</div>
}
>
<div className="py-4">
<Modal.Content>
<p className="text-sm">
Confirm to set selected payment method (Ending with{' '}
{selectedMethodForDefault?.card?.last4 ?? ''}) as the default?
</p>
</Modal.Content>
</div>
</Modal>
<Modal
visible={selectedMethodToDelete !== undefined}
size="medium"
header="Delete payment method"
onCancel={() => setSelectedMethodToDelete(undefined)}
customFooter={
<div className="flex items-center gap-2">
<Button
type="default"
disabled={isDeleting}
onClick={() => setSelectedMethodToDelete(undefined)}
>
Cancel
</Button>
<Button
type="primary"
disabled={isDeleting}
loading={isDeleting}
onClick={onConfirmDetachPaymentMethod}
>
Confirm
</Button>
</div>
}
>
<div className="py-4">
<Modal.Content>
<Alert
withIcon
variant="warning"
title="This will permanently delete your payment method."
>
<p className="">
Any subscription currently charging this payment method will start charging your
default payment method.
</p>
</Alert>
</Modal.Content>
</div>
</Modal>
</>
)
}
export default PaymentMethods
@@ -1,55 +0,0 @@
import { useParams } from 'common'
import { Markdown } from 'components/interfaces/Markdown'
// import { useIntegrationsQuery } from 'data/integrations/integrations-query-org-only'
import { useStore } from 'hooks'
import { observer } from 'mobx-react-lite'
import { IconGitHub, IconSearch, Input, Select, SidePanel } from 'ui'
// TO DO
const GitHubRepoSelection = () => {
const { ui } = useStore()
const { slug } = useParams()
// const { data } = useIntegrationsQuery({ orgSlug: slug })
return (
<SidePanel
header={'Add GitHub repository'}
size="large"
visible={false}
// visible={githubConnectionConfigPanelSnapshot.visible}
// onCancel={() => githubConnectionConfigPanelSnapshot.setVisible(false)}
>
<div className="my-10 flex flex-col gap-6">
<SidePanel.Content>
<Markdown
content={`
### Choose repository to connect to
Check the details below before proceeding
`}
/>
</SidePanel.Content>
<SidePanel.Content className="flex flex-col gap-2">
<label className="text-sm text-foreground-lighter">GitHub scope / organization</label>
<div className="flex gap-3 w-full">
<Select icon={<IconGitHub />} className="w-full">
<Select.Option value="mildtomato">MildTomato</Select.Option>
<Select.Option value="supabase">Supabase</Select.Option>
</Select>
<Input autoFocus icon={<IconSearch />} className="w-full" placeholder="Search..." />
</div>
</SidePanel.Content>
<SidePanel.Content>
<ul>
<li className="border px-10">
{/* <IntegrationConnectionOption connection={githubIntegrations[0]} /> */}
</li>
</ul>
</SidePanel.Content>
</div>
</SidePanel>
)
}
export default observer(GitHubRepoSelection)
@@ -1,57 +0,0 @@
import Sparkline from 'components/ui/Charts/Sparkline'
import React from 'react'
interface Props {
value: string | number
startingValue?: string | number
prefix?: string
suffix?: string
valueFormatter?: (value: Props['value']) => string
sparklineData?: any
sparklineXAxis?: string
sparklineYAxis?: string
}
const Statistic: React.FC<Props> = ({
prefix,
suffix,
value,
startingValue,
sparklineData,
sparklineXAxis,
sparklineYAxis,
}) => {
const isNumber = typeof value === 'number' && !Number.isNaN(value)
const percentageChange =
startingValue && isNumber ? Number(startingValue) / Number(value) - 1 : null
const showSparkline = sparklineData && sparklineXAxis && sparklineYAxis
return (
<div className="w-full">
<div className="flex flex-row justify-center">
<span>{prefix}</span>
<span className="text-3xl text-foreground">{value}</span>
<span>{suffix}</span>
</div>
{startingValue && (
<div>
{isNumber && percentageChange !== null && (
<span>
{Number(percentageChange * 100).toFixed(1)}
{percentageChange > 0 ? 'increase' : 'decrease'}
</span>
)}
</div>
)}
{showSparkline && (
<Sparkline
data={sparklineData}
xAxisKey={sparklineXAxis}
yAxisKey={sparklineYAxis}
size="small"
/>
)}
</div>
)
}
export default Statistic
@@ -1,102 +0,0 @@
import { editor } from 'monaco-editor'
import { PropsWithChildren, useEffect, useMemo } from 'react'
import { createPortal } from 'react-dom'
export interface InlineWidgetProps {
/**
* The Monaco editor instance.
*/
editor: editor.IStandaloneCodeEditor
/**
* ID used by Monaco to reference this widget
*/
id: string
/**
* The line number after which this zone should appear.
* Use 0 to place a view zone before the first line number.
*/
afterLineNumber: number
/**
* The height in lines of the view zone.
* @default 1
*/
heightInLines?: number
}
/**
* Adds an inline widget to a Monaco editor instance. Acts as a
* container for custom widgets that are rendered inline.
*
* Implemented using the same techniques VS Code uses for their inline
* widgets (such as "Go to References"), but built for React.
* Uses a combination of a view zone and overlay widget.
*/
const InlineWidget = ({
children,
editor,
id,
afterLineNumber,
heightInLines = 1,
}: PropsWithChildren<InlineWidgetProps>) => {
const key = `${id}-${afterLineNumber.toString()}`
const containerElement = useMemo(() => document.createElement('div'), [])
useEffect(() => {
let zoneId: string
let viewZoneTop = 0
let viewZoneHeight = 0
const overlayWidget: editor.IOverlayWidget = {
getId: () => id,
getDomNode: () => containerElement,
getPosition: () => null,
}
const recalculateLayout = () => {
const layoutInfo = editor.getLayoutInfo()
if (!layoutInfo) {
return
}
containerElement.style.left = `${layoutInfo.contentLeft}px`
containerElement.style.top = `${viewZoneTop}px`
containerElement.style.width = `${layoutInfo.width - layoutInfo.contentLeft}px`
containerElement.style.height = `${viewZoneHeight}px`
}
editor.changeViewZones((accessor) => {
zoneId = accessor.addZone({
afterLineNumber,
heightInLines,
domNode: document.createElement('div'),
onDomNodeTop: (top) => {
viewZoneTop = top
recalculateLayout()
},
onComputedHeight: (height) => {
viewZoneHeight = height
recalculateLayout()
},
})
editor.addOverlayWidget(overlayWidget)
})
// Remove the view zone & overlay widget on unmount
return () => {
editor.changeViewZones((accessor) => {
accessor.removeZone(zoneId)
editor.removeOverlayWidget(overlayWidget)
})
}
}, [editor, id, afterLineNumber, heightInLines, containerElement])
return createPortal(children, containerElement, key)
}
export default InlineWidget
@@ -1,58 +0,0 @@
import DataGrid, { Row } from 'react-data-grid'
interface ResultsPaneProps {
results: any
}
const ResultsPane = ({ results }: ResultsPaneProps) => {
if (results.length === 0) {
return (
<div className="p-5 flex items-center space-x-2 bg-alternative">
<p>Success. No rows returned.</p>
</div>
)
}
const columns = Object.keys(results[0]).map((key) => ({
key,
name: key,
width: 120,
resizable: true,
headerRenderer: () => columnRender(key),
formatter: ({ row }: { row: any }) => formatter(key, row),
}))
const formatter = (column: any, row: any) => {
return <span className="font-mono text-xs">{row[column] + ''}</span>
}
const columnRender = (name: string) => {
return (
<div className="flex items-center justify-center h-full">
<p className="text-sm font-mono">{name}</p>
</div>
)
}
const rowRenderer = (props: any) => {
const { row, viewportColumns: columns } = props
columns.forEach((col: any) => {
if (row[col.key] != null && typeof row[col.key] === 'object') {
row[col.key] = JSON.stringify(row[col.key])
}
})
return <Row {...props} />
}
return (
<div className="flex-grow">
<DataGrid
columns={columns}
rows={results}
renderers={{ renderRow: rowRenderer }}
style={{ height: '100%' }}
/>
</div>
)
}
export default ResultsPane
@@ -1,69 +0,0 @@
import * as Tooltip from '@radix-ui/react-tooltip'
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
import { Button, IconMaximize2, IconMinimize2 } from 'ui'
export interface SizeToggleButton {
id: string
}
const SizeToggleButton = ({ id }: SizeToggleButton) => {
const snap = useSqlEditorStateSnapshot()
const snippet = snap.snippets[id]
const isUtilityPanelCollapsed = (snippet?.splitSizes?.[1] ?? 0) === 0
const maximizeEditor = () => snap.collapseUtilityPanel(id)
const restorePanelSize = () => snap.restoreUtilityPanel(id)
if (!snippet) return null
return isUtilityPanelCollapsed ? (
<Tooltip.Root delayDuration={0}>
<Tooltip.Trigger asChild>
<Button
type="text"
size="tiny"
onClick={restorePanelSize}
icon={<IconMaximize2 className="text-gray-1100" size="tiny" strokeWidth={2} />}
/>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content side="bottom">
<Tooltip.Arrow className="radix-tooltip-arrow" />
<div
className={[
'rounded bg-alternative py-1 px-2 leading-none shadow',
'border border-background',
].join(' ')}
>
<span className="text-xs text-foreground">Show results</span>
</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
) : (
<Tooltip.Root delayDuration={0}>
<Tooltip.Trigger asChild>
<Button
type="text"
size="tiny"
onClick={maximizeEditor}
icon={<IconMinimize2 className="text-gray-1100" size="tiny" strokeWidth={2} />}
/>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content side="bottom">
<Tooltip.Arrow className="radix-tooltip-arrow" />
<div
className={[
'rounded bg-alternative py-1 px-2 leading-none shadow',
'border border-background',
].join(' ')}
>
<span className="text-xs text-foreground">Collapse results</span>
</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
)
}
export default SizeToggleButton
@@ -1,15 +0,0 @@
// [Joshen] TODO: Change the keys to enums from shared-types when ready
export const BREAKING_CHANGES = {
'postgrest-v10': {
title: 'Postgrest will be upgraded to v11',
url: 'https://postgrest.org/en/stable/releases/v10.0.0.html#breaking-changes',
},
}
export const MANUAL_INTERVENTIONS = {
project_unsupported_too_old: {
title: 'Project is too old',
description: '',
},
}
@@ -1,5 +0,0 @@
const InstanceResizeModal = () => {
return <div>Hello</div>
}
export default InstanceResizeModal
@@ -1,84 +0,0 @@
import { useParams } from 'common'
import { useEffect, useState } from 'react'
import { Listbox, SidePanel } from 'ui'
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
import { AVAILABLE_REPLICA_REGIONS } from './InstanceConfiguration.constants'
import { AWS_REGIONS, AWS_REGIONS_DEFAULT, AWS_REGIONS_KEYS, BASE_PATH } from 'lib/constants'
import { Database } from 'data/read-replicas/replicas-query'
// [Joshen] FYI this is purely for AWS only, need to update to support Fly eventually
interface ResizeReplicaPanelProps {
visible: boolean
selectedReplica?: Database
onClose: () => void
}
const ResizeReplicaPanel = ({ visible, selectedReplica, onClose }: ResizeReplicaPanelProps) => {
const { ref: projectRef } = useParams()
const { data: addons, isSuccess } = useProjectAddonsQuery({ projectRef })
const computeAddons =
addons?.available_addons.find((addon) => addon.type === 'compute_instance')?.variants ?? []
const defaultCompute = computeAddons.find((option) => option.name === 'Small')?.identifier
const [selectedCompute, setSelectedCompute] = useState(defaultCompute)
const selectedComputeMeta = computeAddons.find((addon) => addon.identifier === selectedCompute)
const replicaRegion = AVAILABLE_REPLICA_REGIONS.find((r) =>
selectedReplica?.region.includes(r.region)
)
const onSubmit = async () => {
console.log('Resize', { selectedCompute })
onClose()
}
useEffect(() => {
if (visible && isSuccess) {
}
}, [visible, isSuccess])
return (
<SidePanel
visible={visible}
onCancel={onClose}
onConfirm={() => onSubmit()}
header={`Resize read replica (ID: ${selectedReplica?.identifier})`}
>
<SidePanel.Content className="flex flex-col py-4 gap-y-8">
<div className="flex flex-col gap-y-1">
<p className="text-sm text-foreground-light">Replica is currently deployed in</p>
<div className="flex items-center gap-x-2">
<img
alt="region icon"
className="w-7 rounded-sm"
src={`${BASE_PATH}/img/regions/${replicaRegion?.key}.svg`}
/>
<p>{replicaRegion?.name}</p>
</div>
</div>
<Listbox
size="small"
id="compute"
name="compute"
value={selectedCompute}
onChange={setSelectedCompute}
label="Select the instance size for your read replica"
>
{computeAddons.map((option) => (
<Listbox.Option key={option.identifier} label={option.name} value={option.identifier}>
{option.name}
</Listbox.Option>
))}
</Listbox>
<p className="text-xs text-foreground-light">
Show some preview info on cost for deploying this replica here
</p>
</SidePanel.Content>
</SidePanel>
)
}
export default ResizeReplicaPanel
@@ -1,13 +0,0 @@
import { QueryType } from './Logs.types'
const SelectionRenderHandler = ({ type }: { type: QueryType }) => {
switch (type) {
case 'api':
break
default:
break
}
}
export default SelectionRenderHandler
@@ -1,71 +0,0 @@
import { noop } from 'lodash'
import Link from 'next/link'
import { IconArrowUpRight, IconLogOut, Menu } from 'ui'
interface SidebarItemProps {
id: any
label: string
href?: string
isActive?: boolean
isSubitem?: boolean
isExternal?: boolean
onClick?: () => void
}
const SidebarItem = ({
id,
label,
href,
isActive = false,
isSubitem = false,
isExternal = false,
onClick = noop,
}: SidebarItemProps) => {
if (href === undefined) {
const icon = isExternal ? (
<IconArrowUpRight size="tiny" />
) : label === 'Logout' ? (
<IconLogOut size="tiny" />
) : undefined
return (
<Menu.Item
rounded
key={id}
style={{ marginLeft: isSubitem ? '.5rem' : '0' }}
active={isActive}
onClick={onClick}
icon={icon}
>
{isSubitem ? <p className="text-sm">{label}</p> : label}
</Menu.Item>
)
}
return (
<Link href={href || ''} className="block" target={isExternal ? '_blank' : '_self'}>
<button
className={[
'group border-default ring-foreground group-hover:border-foreground-muted',
'flex max-w-full cursor-pointer items-center space-x-2 py-1 font-normal',
'outline-none focus-visible:z-10 focus-visible:ring-1',
].join(' ')}
onClick={onClick}
>
{isExternal && (
<span className="truncate text-sm text-foreground-lighter transition group-hover:text-foreground-light">
<IconArrowUpRight size="tiny" />
</span>
)}
<span
title={label}
className="w-full truncate text-sm text-foreground-light transition group-hover:text-foreground"
>
{isSubitem ? <p>{label}</p> : label}
</span>
</button>
</Link>
)
}
export default SidebarItem
@@ -1,45 +0,0 @@
import { useParams } from 'common'
import { Badge, Button, Modal } from 'ui'
import { Integration } from 'data/integrations/integrations.types'
import Link from 'next/link'
interface VercelProjectSelectionProps {
integration?: Integration
}
const VercelProjectSelection = ({ integration }: VercelProjectSelectionProps) => {
const { ref } = useParams()
const vercelProjectIntegration = integration?.connections.find(
(connection) => connection.supabase_project_ref === ref
)
return (
<Modal.Content>
<div className="space-y-1 py-6">
<div className="flex items-center space-x-2">
<p>Frontend Cloud Previews</p>
<Badge color="gray">Optional</Badge>
</div>
<p className="text-sm text-foreground-light">
Previews can be available by connecting your Supabase project to a Vercel project.
</p>
{!integration && (
<Button asChild type="default" className="!mt-3">
<Link
href="https://vercel.com/integrations/supabase-v2-local"
target="_blank"
rel="noreferrer"
>
Install Vercel Integration
</Link>
</Button>
)}
{integration && !vercelProjectIntegration && <div>Connect project</div>}
{integration && vercelProjectIntegration && <div>Select project</div>}
</div>
</Modal.Content>
)
}
export default VercelProjectSelection
@@ -1,61 +0,0 @@
import { useRouter } from 'next/router'
import {
AccordionContent_Shadcn_,
AccordionItem_Shadcn_,
AccordionTrigger_Shadcn_,
IconChevronRight,
} from 'ui'
import { Project } from 'types'
import SettingsMenuItem from './SettingsMenuItem'
interface ProjectSettingsMenuItemProps {
project: Project
}
const ProjectSettingsMenuItem = ({ project }: ProjectSettingsMenuItemProps) => {
const router = useRouter()
// [Joshen] Links need to be updated once we start implementing these
const projectSettings = [
{ label: 'General', pathname: `/project/[ref]/settings/general` },
{ label: 'Infrastructure', pathname: `/project/[ref]/settings/infrastructure` },
{ label: 'Add Ons', pathname: `/project/[ref]/settings/addons` },
]
return (
<AccordionItem_Shadcn_ value={project.ref} className="!border-none">
<AccordionTrigger_Shadcn_
hideIcon
className="py-1.5 hover:!no-underline [&[data-state=open]>div>svg]:!rotate-90 [&[data-state=open]>div>p]:text-foreground"
>
<div className="flex items-center space-x-2">
<IconChevronRight
className="h-4 w-4 transition-transform duration-200"
strokeWidth={1.5}
/>
<p className="text-foreground-light text-sm font-normal transition duration-200">
{project.name}
</p>
</div>
</AccordionTrigger_Shadcn_>
<AccordionContent_Shadcn_>
<div className="space-y-2 pl-6 mt-1">
{projectSettings.map((link) => {
const href = link.pathname.replace('[ref]', project.ref)
return (
<SettingsMenuItem
key={link.label}
label={link.label}
href={href}
isActive={href === router.asPath}
/>
)
})}
</div>
</AccordionContent_Shadcn_>
</AccordionItem_Shadcn_>
)
}
export default ProjectSettingsMenuItem
@@ -1,37 +0,0 @@
import { SupaTable } from 'components/grid'
import { formatFilterURLParams, formatSortURLParams } from 'components/grid/SupabaseGrid.utils'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import { useTableRowsPrefetch as _useTableRowsPrefetch } from 'data/table-rows/table-rows-query'
import { useUrlState } from 'hooks'
import { useCallback } from 'react'
/**
* useTableRowsPrefetchWrapper is a wrapper around the base useTableRowsPrefetch that prefills the sort and filter params
*/
function useTableRowsPrefetchWrapper() {
const [{ sort, filter }] = useUrlState({
arrayKeys: ['sort', 'filter'],
})
const sorts = formatSortURLParams(sort as string[])
const filters = formatFilterURLParams(filter as string[])
const { project } = useProjectContext()
const prefetch = _useTableRowsPrefetch()
return useCallback(
(table: SupaTable) =>
prefetch({
queryKey: [table.schema, table.name],
projectRef: project?.ref,
connectionString: project?.connectionString,
table,
sorts,
filters,
page: 1,
limit: 100,
}),
[project, sorts, filters]
)
}
export default useTableRowsPrefetchWrapper
@@ -1,63 +0,0 @@
import React, { forwardRef } from 'react'
const FormField = forwardRef(
(
{
id,
label,
type,
description,
placeholder,
errorMessage,
wrapperClasses,
children,
value,
onChange,
checked,
choices,
autoFocus,
},
ref
) => {
let options =
type === 'select'
? Object.keys(choices).map((choice) => {
return (
<option key={choices[choice]} value={choices[choice]}>
{choices[choice]}
</option>
)
})
: null
return (
<div className={`form-group ${wrapperClasses ? wrapperClasses : ''}`}>
<label htmlFor={id}>{label}</label>
{children ? (
<div className="form-control inline-block p-3">{children}</div>
) : type === 'select' ? (
<select id={id} onChange={onChange} defaultValue={value} className="form-control">
{options}
</select>
) : (
<input
id={id}
name={id}
className="form-control text-base"
ref={ref}
type={type}
value={value || ''}
onChange={onChange}
placeholder={placeholder}
checked={checked}
autoFocus={autoFocus}
/>
)}
{errorMessage && errorMessage != '' && <p className="form-error">{errorMessage}</p>}
{description && <div className="form-text form-help">{description}</div>}
</div>
)
}
)
export default FormField
@@ -1,69 +0,0 @@
import Ajv from 'ajv'
import { PropsWithChildren } from 'react'
import { AutoForm } from 'uniforms-bootstrap4'
import { JSONSchemaBridge } from 'uniforms-bridge-json-schema'
interface SchemaFormProps
extends PropsWithChildren<{
schema: any
model: any
disabled: boolean
formRef: any
onSubmit: any
onChangeModel: any
}> {}
const SchemaForm = ({
schema,
model,
disabled = false,
children,
formRef,
onSubmit,
onChangeModel = () => {},
}: SchemaFormProps) => {
const validatedSchema = new JSONSchemaBridge(schema, createValidator(schema))
return (
<AutoForm
disabled={disabled}
onChangeModel={onChangeModel}
ref={formRef}
schema={validatedSchema}
onSubmit={onSubmit}
submitField={() => <></>}
model={model}
>
{children}
</AutoForm>
)
}
export default SchemaForm
let ajv = new Ajv({ strict: false, allErrors: true, useDefaults: true })
ajv = ajv.addFormat('absolute-url', '^(http://|https://)')
const createValidator = (schema: any) => {
const validator = ajv.compile(schema)
return (model: any) => {
let cleansedModel = { ...model }
Object.entries(cleansedModel).map(([k, v]) => {
const isRequired = schema.required.indexOf(k) != -1
// only do nullifyStringIfEmpty if it's a required string property
if (typeof v === 'string' && isRequired) cleansedModel[k] = nullifyStringIfEmpty(v)
else cleansedModel[k] = v
})
validator(cleansedModel)
if (validator.errors && validator.errors.length) {
return { details: validator.errors }
}
}
}
/**
* JSON Schema doesn't support validation for empty strings.
* We want to convert all empty strings to NULL to ensure they get validated
*/
const nullifyStringIfEmpty = (data: any) => {
if (data.trim() === '') return null
else return data
}
@@ -1,105 +0,0 @@
import { useState } from 'react'
import { Button } from 'ui'
import SchemaForm from './SchemaForm'
export default function SchemaFormPanel({
schema,
title,
model,
children,
onChangeModel = () => {},
onReset = () => {},
onSubmit,
loading,
submitLabel = 'Save',
cancelLabel = 'Cancel',
message = '',
disabled = false,
disabledMessage = '',
}: any) {
let formRef: any
const [submitButtonLoading, setSubmitButtonLoading] = useState(false)
const [hasChanged, setHasChanged] = useState(false)
const isLoading = loading !== undefined ? loading : submitButtonLoading
function onClickCancel() {
formRef.reset()
setSubmitButtonLoading(false)
setHasChanged(false)
if (onReset) onReset()
}
const onClickSubmit = () => {
formRef
.submit()
.then(() => {
setSubmitButtonLoading(true)
})
.catch((error: any) => {
console.error('Error on submitting', error)
})
}
return (
<section className="section-block mb-8">
<div
className="
flex h-12
items-center overflow-hidden
border-b px-6
border-overlay bg-surface-100
"
>
<div className="flex-1 text-left">
<h6>{title || ''}</h6>
</div>
{disabled && disabledMessage ? (
<p className="text-sm text-foreground-light">{disabledMessage}</p>
) : (
<div
className={`flex transition duration-150 ${
hasChanged ? 'opacity-100' : 'cursor-default opacity-0'
}`}
>
<Button onClick={onClickCancel} type="default" disabled={!hasChanged || isLoading}>
{cancelLabel || 'Cancel'}
</Button>
<Button
onClick={onClickSubmit}
loading={isLoading}
disabled={disabled || !hasChanged || isLoading}
type="primary"
className="ml-2 hover:border-green-500"
>
{submitLabel || 'Save'}
</Button>
</div>
)}
<span className="text-sm text-foreground-lighter">{message}</span>
</div>
<div className="Form section-block--body px-6 py-3">
<SchemaForm
disabled={disabled}
onChangeModel={(model: any) => {
setHasChanged(true)
if (onChangeModel) onChangeModel(model)
}}
formRef={(ref: any) => (formRef = ref)}
schema={schema}
model={model}
onSubmit={async (args: any) => {
onSubmit(args)
.then(() => {
setSubmitButtonLoading(false)
setHasChanged(false)
})
.catch(() => setSubmitButtonLoading(false))
}}
>
{children}
</SchemaForm>
</div>
</section>
)
}
@@ -1,53 +0,0 @@
import * as React from 'react'
import { IconEye, IconEyeOff } from 'ui'
import { connectField, filterDOMProps } from 'uniforms'
const SecretField: React.FC = (props: any) => {
const { disabled, id, inputRef, label, name, onChange, value, help, error, errorMessage } = props
const [text, setText] = React.useState(value)
const [visible, setVisible] = React.useState(false)
React.useEffect(() => {
setText(value)
}, [value])
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const newValue = e.target.value
setText(newValue)
onChange(newValue)
}
function onToggleVisible() {
setVisible(!visible)
}
return (
<div className="form-group" {...filterDOMProps(props)}>
{label && <label htmlFor={id}>{label}</label>}
<div className="form-control flex flex-col">
<div className="inline-flex items-center">
<input
disabled={disabled}
id={id}
name={name}
ref={inputRef}
value={text}
onChange={handleChange}
type={visible ? 'text' : 'password'}
/>
<div className="px-2" onClick={onToggleVisible}>
{visible ? (
<IconEye className="text-foreground-lighter" />
) : (
<IconEyeOff className="text-foreground-lighter" />
)}
</div>
</div>
</div>
{error && <span className="form-text text-muted">{errorMessage ?? error.message}</span>}
{help && <span className="form-text text-muted">{help}</span>}
</div>
)
}
export default connectField(SecretField, { kind: 'leaf' })
@@ -1,42 +0,0 @@
const sizes = {
md: {
slider: 'h-5 w-5',
toggleOn: 'translate-x-5',
toggleOff: 'translate-x-0',
background: 'h-6 w-11 border-2',
},
sm: {
slider: 'h-4 w-4',
toggleOn: 'translate-x-3',
toggleOff: 'translate-x-0',
background: 'h-5 w-9 border-2',
},
}
export default function Toggle({
isOn = true,
size = 'md',
onToggle = (value) => {},
isDisabled = false,
}) {
const toggleSizes = sizes[size]
return (
<span
role="checkbox"
aria-checked="false"
onClick={!isDisabled ? () => onToggle(!isOn) : () => {}}
className={`${isOn ? 'bg-green-500' : 'bg-gray-200'} ${toggleSizes.background} ${
isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'
} relative inline-block flex-shrink-0 border-transparent rounded-full transition-colors ease-in-out duration-200 focus:outline-none focus:ring `}
>
<span
aria-hidden="true"
className={`${isOn ? toggleSizes.toggleOn : toggleSizes.toggleOff} ${
isDisabled ? 'cursor-not-allowed bg-white' : 'cursor-pointer bg-white'
} ${
toggleSizes.slider
} inline-block rounded-full shadow transform transition ease-in-out duration-200`}
></span>
</span>
)
}
@@ -1,50 +0,0 @@
import React, { useEffect, useState } from 'react'
import { connectField, filterDOMProps } from 'uniforms'
import { Toggle } from 'ui'
function ToggleField({
disabled,
id,
inputRef,
label,
name,
onChange,
value,
help,
addOns,
...props
}) {
const [enabled, setEnable] = useState(false)
useEffect(() => {
setEnable(value)
}, [value])
function onToggle() {
const newValue = !enabled
setEnable(newValue)
onChange(newValue)
}
return (
<div className="form-group items-center" {...filterDOMProps(props)}>
<input
disabled={disabled}
id={id}
name={name}
ref={inputRef}
type="checkbox"
style={{ display: 'none' }}
/>
{label && <label htmlFor={id}>{label}</label>}
<div className="form-control flex items-center">
<Toggle onChange={disabled ? undefined : onToggle} checked={enabled} />
{addOns && addOns}
</div>
{help && <span className="form-text text-muted">{help}</span>}
</div>
)
}
export default connectField(ToggleField, { kind: 'leaf' })
-13
View File
@@ -1,13 +0,0 @@
import { Button, IconArrowLeft } from 'ui'
export function BackButton({ onClick }: { onClick: () => void }) {
return (
<div className="-ml-2 2xl:absolute 2xl:top-[2px] 2xl:left-0">
<Button type="text" icon={<IconArrowLeft />} onClick={onClick}>
Back
</Button>
</div>
)
}
export default BackButton
@@ -1,34 +0,0 @@
import Link from 'next/link'
import { Button, IconAlertCircle } from 'ui'
export interface ClientLoadingErrorProps {
projectRef: string
description: string
}
const ClientLoadingError = ({
projectRef,
description = 'An error has occurred',
}: ClientLoadingErrorProps) => {
return (
<div className="px-6 py-4 bg-surface-200 border border-overlay rounded flex justify-between items-center">
<div className="flex space-x-4">
<IconAlertCircle strokeWidth={1.5} className="text-foreground-light" />
<div className="space-y-1">
<p className="text-sm text-foreground">{description}</p>
<p className="text-sm text-foreground-light">
Try refreshing your browser. However, if this issue persists, please reach out to us via
support.
</p>
</div>
</div>
<Button asChild>
<Link href={`/support/new?ref=${projectRef}`} target="_blank" rel="noreferrer">
Contact support
</Link>
</Button>
</div>
)
}
export default ClientLoadingError
@@ -1,19 +0,0 @@
export default function DividerSlash() {
return (
<span className="text-foreground-lighter">
<svg
viewBox="0 0 24 24"
width="14"
height="14"
stroke="currentColor"
strokeWidth="1"
strokeLinecap="round"
strokeLinejoin="round"
fill="none"
shapeRendering="geometricPrecision"
>
<path d="M16 3.549L7.12 20.600"></path>
</svg>
</span>
)
}
@@ -1,19 +0,0 @@
import { IconAlertCircle } from 'ui'
const WarningBanner = ({ title, description }: { title: string; description?: string }) => {
return (
<div className="rounded bg-warning-200 px-6 py-3">
<div className="flex flex-row gap-4">
<div className="mt-1 text-warning">
<IconAlertCircle size={14} strokeWidth={2} />
</div>
<div className="flex flex-col items-start gap-x-3 xl:flex-row xl:items-center">
<h2 className="text-sm text-foreground">{title}</h2>
{description && <p className="text-xs text-warning">{description}</p>}
</div>
</div>
</div>
)
}
export default WarningBanner
-124
View File
@@ -1,124 +0,0 @@
const Base64 = {
// private property
_keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
// public method for encoding
encode: function (input: string) {
var output = ''
var chr1, chr2, chr3, enc1, enc2, enc3, enc4
var i = 0
input = Base64._utf8_encode(input)
while (i < input.length) {
chr1 = input.charCodeAt(i++)
chr2 = input.charCodeAt(i++)
chr3 = input.charCodeAt(i++)
enc1 = chr1 >> 2
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4)
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6)
enc4 = chr3 & 63
if (isNaN(chr2)) {
enc3 = enc4 = 64
} else if (isNaN(chr3)) {
enc4 = 64
}
output =
output +
Base64._keyStr.charAt(enc1) +
Base64._keyStr.charAt(enc2) +
Base64._keyStr.charAt(enc3) +
Base64._keyStr.charAt(enc4)
}
return output
},
// public method for decoding
decode: function (input: string) {
var output = ''
var chr1, chr2, chr3
var enc1, enc2, enc3, enc4
var i = 0
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '')
while (i < input.length) {
enc1 = Base64._keyStr.indexOf(input.charAt(i++))
enc2 = Base64._keyStr.indexOf(input.charAt(i++))
enc3 = Base64._keyStr.indexOf(input.charAt(i++))
enc4 = Base64._keyStr.indexOf(input.charAt(i++))
chr1 = (enc1 << 2) | (enc2 >> 4)
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2)
chr3 = ((enc3 & 3) << 6) | enc4
output = output + String.fromCharCode(chr1)
if (enc3 != 64) {
output = output + String.fromCharCode(chr2)
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3)
}
}
output = Base64._utf8_decode(output)
return output
},
// private method for UTF-8 encoding
_utf8_encode: function (string: string) {
string = string.replace(/\r\n/g, '\n')
var utftext = ''
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n)
if (c < 128) {
utftext += String.fromCharCode(c)
} else if (c > 127 && c < 2048) {
utftext += String.fromCharCode((c >> 6) | 192)
utftext += String.fromCharCode((c & 63) | 128)
} else {
utftext += String.fromCharCode((c >> 12) | 224)
utftext += String.fromCharCode(((c >> 6) & 63) | 128)
utftext += String.fromCharCode((c & 63) | 128)
}
}
return utftext
},
// private method for UTF-8 decoding
_utf8_decode: function (utftext: string) {
var string = ''
var i = 0
var c = 0,
c1 = 0,
c2 = 0
while (i < utftext.length) {
c = utftext.charCodeAt(i)
if (c < 128) {
string += String.fromCharCode(c)
i++
} else if (c > 191 && c < 224) {
c1 = utftext.charCodeAt(i + 1)
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63))
i += 2
} else {
c1 = utftext.charCodeAt(i + 1)
c2 = utftext.charCodeAt(i + 2)
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63))
i += 3
}
}
return string
},
}
export default Base64
@@ -12,7 +12,7 @@ import {
STORAGE_ROW_TYPES,
STORAGE_SORT_BY,
STORAGE_VIEWS,
} from 'components/to-be-cleaned/Storage/Storage.constants.ts'
} from 'components/to-be-cleaned/Storage/Storage.constants'
import { useStore } from 'hooks'
import { delete_, post } from 'lib/common/fetch'
import { API_URL, IS_PLATFORM } from 'lib/constants'
-3
View File
@@ -39,7 +39,6 @@
"@uidotdev/usehooks": "^2.4.1",
"@zip.js/zip.js": "^2.7.29",
"ai": "^2.2.26",
"ajv": "^8.6.3",
"awesome-debounce-promise": "^2.1.0",
"blueimp-md5": "^2.19.0",
"clsx": "^1.2.1",
@@ -100,8 +99,6 @@
"sql-formatter": "^12.2.0",
"sqlstring": "^2.3.2",
"ui": "*",
"uniforms-bootstrap4": "^3.6.2",
"uniforms-bridge-json-schema": "^3.6.2",
"uuid": "^9.0.1",
"valtio": "^1.11.2",
"yup": "^0.32.11",
@@ -1,30 +0,0 @@
{
"type": "object",
"required": ["id", "inserted_at", "updated_at", "api_key", "key_name", "project_id"],
"properties": {
"api_key": {
"title": "Api Key",
"type": "string"
},
"id": {
"title": "Id",
"type": "number"
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"key_name": {
"title": "Key Name",
"type": "string"
},
"project_id": {
"title": "Project Id",
"type": "number"
},
"updated_at": {
"title": "Updated At",
"type": "string"
}
}
}
-30
View File
@@ -1,30 +0,0 @@
{
"type": "object",
"required": ["id", "inserted_at", "updated_at", "name"],
"properties": {
"config_schema": {
"title": "Config Schema",
"type": "object"
},
"description": {
"title": "Description",
"type": "string"
},
"id": {
"title": "Id",
"type": "number"
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"updated_at": {
"title": "Updated At",
"type": "string"
}
}
}
@@ -1,616 +0,0 @@
{
"type": "object",
"required": [
"SITE_URL",
"DISABLE_SIGNUP",
"SECURITY_MANUAL_LINKING_ENABLED",
"JWT_EXP",
"JWT_AUD",
"JWT_DEFAULT_GROUP_NAME",
"SECURITY_UPDATE_PASSWORD_REQUIRE_REAUTHENTICATION",
"EXTERNAL_EMAIL_ENABLED",
"EXTERNAL_PHONE_ENABLED",
"EXTERNAL_APPLE_ENABLED",
"EXTERNAL_AZURE_ENABLED",
"EXTERNAL_BITBUCKET_ENABLED",
"EXTERNAL_DISCORD_ENABLED",
"EXTERNAL_FACEBOOK_ENABLED",
"EXTERNAL_GITHUB_ENABLED",
"EXTERNAL_GITLAB_ENABLED",
"EXTERNAL_GOOGLE_ENABLED",
"EXTERNAL_KAKAO_ENABLED",
"EXTERNAL_KEYCLOAK_ENABLED",
"EXTERNAL_LINKEDIN_ENABLED",
"EXTERNAL_NOTION_ENABLED",
"EXTERNAL_TWITCH_ENABLED",
"EXTERNAL_TWITTER_ENABLED",
"EXTERNAL_SLACK_ENABLED",
"EXTERNAL_SPOTIFY_ENABLED",
"EXTERNAL_WORKOS_ENABLED",
"EXTERNAL_ZOOM_ENABLED",
"SMS_AUTOCONFIRM",
"SMS_MAX_FREQUENCY",
"SMS_OTP_EXP",
"SMS_OTP_LENGTH",
"SMS_PROVIDER",
"SMS_TEMPLATE",
"MAILER_AUTOCONFIRM",
"MAILER_OTP_EXP",
"MAILER_URLPATHS_INVITE",
"MAILER_URLPATHS_CONFIRMATION",
"MAILER_URLPATHS_RECOVERY",
"MAILER_URLPATHS_EMAIL_CHANGE",
"MAILER_SUBJECTS_INVITE",
"MAILER_SUBJECTS_CONFIRMATION",
"MAILER_SUBJECTS_RECOVERY",
"MAILER_SUBJECTS_MAGIC_LINK",
"MAILER_SUBJECTS_EMAIL_CHANGE",
"MAILER_TEMPLATES_INVITE_CONTENT",
"MAILER_TEMPLATES_CONFIRMATION_CONTENT",
"MAILER_TEMPLATES_RECOVERY_CONTENT",
"MAILER_TEMPLATES_MAGIC_LINK_CONTENT",
"MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT"
],
"properties": {
"SITE_URL": {
"title": "Site URL",
"type": "string",
"help": "The base URL of your website. Used as an allow-list for redirects and for constructing URLs used in emails."
},
"URI_ALLOW_LIST": {
"title": "Additional redirect URLs",
"type": "string",
"help": "A comma separated list of URLs that auth providers are permitted to redirect to post authentication. Wildcards allowed (e.g. https://*.domain.com)"
},
"DISABLE_SIGNUP": {
"title": "Disable signup",
"type": "boolean",
"help": "Allow/disallow new user signups for your project."
},
"SECURITY_MANUAL_LINKING_ENABLED": {
"title": "Enable Manual Linking",
"type": "boolean",
"help": "Enable manual linking APIs for your project"
},
"EXTERNAL_EMAIL_ENABLED": {
"title": "Enable email signup",
"type": "boolean",
"help": "Allow/disallow new user signups via email to your project."
},
"EXTERNAL_PHONE_ENABLED": {
"title": "Enable phone signup",
"type": "boolean",
"help": "Allow/disallow new user signups via phone to your project."
},
"JWT_EXP": {
"title": "JWT expiry",
"type": "integer",
"help": "How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one week).",
"minimum": 1,
"maximum": 604800,
"multipleof": 1
},
"JWT_AUD": {
"title": "JWT audience",
"type": "string"
},
"JWT_DEFAULT_GROUP_NAME": {
"title": "Default user group",
"type": "string"
},
"EXTERNAL_APPLE_ENABLED": {
"title": "Apple enabled",
"type": "boolean"
},
"EXTERNAL_APPLE_CLIENT_ID": {
"title": "Apple client ID",
"type": "string"
},
"EXTERNAL_APPLE_SECRET": {
"title": "Apple secret",
"type": "string"
},
"EXTERNAL_AZURE_ENABLED": {
"title": "Azure enabled",
"type": "boolean"
},
"EXTERNAL_AZURE_CLIENT_ID": {
"title": "Azure client ID",
"type": "string"
},
"EXTERNAL_AZURE_SECRET": {
"title": "Azure secret",
"type": "string",
"help": "Enter the data from Value, not the Secret ID."
},
"EXTERNAL_AZURE_URL": {
"title": "Azure tenant URL",
"type": "string"
},
"EXTERNAL_BITBUCKET_ENABLED": {
"title": "Bitbucket enabled",
"type": "boolean"
},
"EXTERNAL_BITBUCKET_CLIENT_ID": {
"title": "Bitbucket client ID",
"type": "string"
},
"EXTERNAL_BITBUCKET_SECRET": {
"title": "Bitbucket secret",
"type": "string"
},
"EXTERNAL_DISCORD_ENABLED": {
"title": "Discord enabled",
"type": "boolean"
},
"EXTERNAL_DISCORD_CLIENT_ID": {
"title": "Discord client ID",
"type": "string"
},
"EXTERNAL_DISCORD_SECRET": {
"title": "Discord secret",
"type": "string"
},
"EXTERNAL_FACEBOOK_ENABLED": {
"title": "Facebook enabled",
"type": "boolean"
},
"EXTERNAL_FACEBOOK_CLIENT_ID": {
"title": "Facebook client ID",
"type": "string"
},
"EXTERNAL_FACEBOOK_SECRET": {
"title": "Facebook secret",
"type": "string"
},
"EXTERNAL_FIGMA_ENABLED": {
"title": "Figma enabled",
"type": "boolean"
},
"EXTERNAL_FIGMA_CLIENT_ID": {
"title": "Figma client ID",
"type": "string"
},
"EXTERNAL_FIGMA_SECRET": {
"title": "Figma secret",
"type": "string"
},
"EXTERNAL_GITHUB_ENABLED": {
"title": "GitHub enabled",
"type": "boolean"
},
"EXTERNAL_GITHUB_CLIENT_ID": {
"title": "GitHub client ID",
"type": "string"
},
"EXTERNAL_GITHUB_SECRET": {
"title": "GitHub secret",
"type": "string"
},
"EXTERNAL_GITLAB_ENABLED": {
"title": "GitLab enabled",
"type": "boolean"
},
"EXTERNAL_GITLAB_CLIENT_ID": {
"title": "GitLab client ID",
"type": "string"
},
"EXTERNAL_GITLAB_SECRET": {
"title": "Gitlab secret",
"type": "string"
},
"EXTERNAL_GITLAB_URL": {
"title": "The base URL used for constructing the URLs to request authorization and access tokens.",
"type": "string"
},
"EXTERNAL_GOOGLE_ENABLED": {
"title": "Google enabled",
"type": "boolean"
},
"EXTERNAL_GOOGLE_CLIENT_ID": {
"title": "Google client ID",
"type": "string"
},
"EXTERNAL_GOOGLE_SECRET": {
"title": "Google secret",
"type": "string"
},
"EXTERNAL_KAKAO_ENABLED": {
"title": "Kakao enabled",
"type": "boolean"
},
"EXTERNAL_KAKAO_CLIENT_ID": {
"title": "Kakao client ID",
"type": "string"
},
"EXTERNAL_KAKAO_SECRET": {
"title": "Kakao secret",
"type": "string"
},
"EXTERNAL_KEYCLOAK_ENABLED": {
"title": "Keycloak enabled",
"type": "boolean"
},
"EXTERNAL_KEYCLOAK_CLIENT_ID": {
"title": "Keycloak client ID",
"type": "string"
},
"EXTERNAL_KEYCLOAK_SECRET": {
"title": "Keycloak secret",
"type": "string"
},
"EXTERNAL_KEYCLOAK_URL": {
"title": "Keycloak URL",
"type": "string"
},
"EXTERNAL_LINKEDIN_ENABLED": {
"title": "Linkedin enabled",
"type": "boolean"
},
"EXTERNAL_LINKEDIN_CLIENT_ID": {
"title": "Linkedin client ID",
"type": "string"
},
"EXTERNAL_LINKEDIN_SECRET": {
"title": "Linkedin secret",
"type": "string"
},
"EXTERNAL_LINKEDIN_OIDC_ENABLED": {
"title": "LinkedIn enabled",
"type": "boolean"
},
"EXTERNAL_LINKEDIN_OIDC_CLIENT_ID": {
"title": "LinkedIn client ID",
"type": "string"
},
"EXTERNAL_LINKEDIN_OIDC_SECRET": {
"title": "LinkedIn secret",
"type": "string"
},
"EXTERNAL_NOTION_ENABLED": {
"title": "Notion enabled",
"type": "boolean"
},
"EXTERNAL_NOTION_CLIENT_ID": {
"title": "Notion client ID",
"type": "string"
},
"EXTERNAL_NOTION_SECRET": {
"title": "Notion secret",
"type": "string"
},
"EXTERNAL_TWITCH_ENABLED": {
"title": "Twitch enabled",
"type": "boolean"
},
"EXTERNAL_TWITCH_CLIENT_ID": {
"title": "Twitch client ID",
"type": "string"
},
"EXTERNAL_TWITCH_SECRET": {
"title": "Twitch secret",
"type": "string"
},
"EXTERNAL_TWITTER_ENABLED": {
"title": "Twitter enabled",
"type": "boolean"
},
"EXTERNAL_TWITTER_CLIENT_ID": {
"title": "Twitter client ID",
"type": "string"
},
"EXTERNAL_TWITTER_SECRET": {
"title": "Twitter secret",
"type": "string"
},
"EXTERNAL_SLACK_ENABLED": {
"title": "Slack enabled",
"type": "boolean"
},
"EXTERNAL_SLACK_CLIENT_ID": {
"title": "Slack client ID",
"type": "string"
},
"EXTERNAL_SLACK_SECRET": {
"title": "Slack secret",
"type": "string"
},
"EXTERNAL_SPOTIFY_ENABLED": {
"title": "Spotify enabled",
"type": "boolean"
},
"EXTERNAL_SPOTIFY_CLIENT_ID": {
"title": "Spotify client ID",
"type": "string"
},
"EXTERNAL_SPOTIFY_SECRET": {
"title": "Spotify secret",
"type": "string"
},
"EXTERNAL_WORKOS_ENABLED": {
"title": "WorkOS enabled",
"type": "boolean"
},
"EXTERNAL_WORKOS_CLIENT_ID": {
"title": "WorkOS client ID",
"type": "string"
},
"EXTERNAL_WORKOS_SECRET": {
"title": "WorkOS secret",
"type": "string"
},
"EXTERNAL_WORKOS_URL": {
"title": "WorkOS URL",
"type": "string"
},
"EXTERNAL_ZOOM_ENABLED": {
"title": "Zoom enabled",
"type": "boolean"
},
"EXTERNAL_ZOOM_CLIENT_ID": {
"title": "Zoom client ID",
"type": "string"
},
"EXTERNAL_ZOOM_SECRET": {
"title": "Zoom secret",
"type": "string"
},
"SMTP_ADMIN_EMAIL": {
"title": "SMTP admin email",
"type": "string"
},
"SMTP_HOST": {
"title": "SMTP host",
"type": "string"
},
"SMTP_PORT": {
"title": "SMTP port",
"type": "string"
},
"SMTP_USER": {
"title": "SMTP user",
"type": "string"
},
"SMTP_PASS": {
"title": "SMTP password",
"type": "string"
},
"SMTP_PASS_ENCRYPTED": {
"title": "SMTP password",
"type": "string"
},
"SMTP_SENDER_NAME": {
"title": "SMTP sender name",
"type": "string"
},
"RATE_LIMIT_EMAIL_SENT": {
"title": "Rate limit",
"type": "number",
"help": "Maximum number of emails sent per hour (Default: 30, Max: 32,767)",
"minimum": 1,
"maximum": 32767,
"multipleof": 1
},
"RATE_LIMIT_SMS_SENT": {
"title": "Rate limit",
"type": "number",
"help": "Maximum number of SMS messages sent per hour (Default: 30, Max: 32,767)",
"minimum": 1,
"maximum": 32767,
"multipleof": 1
},
"MAILER_SECURE_EMAIL_CHANGE_ENABLED": {
"title": "Double confirm email changes",
"type": "boolean",
"help": "If enabled, a user will be required to confirm any email change on both the old, and new email addresses. If disabled, only the new email is required to confirm"
},
"MAILER_AUTOCONFIRM": {
"title": "Enable email confirmations",
"type": "boolean",
"help": "If enabled, users need to confirm their email address before signing in."
},
"MAILER_URLPATHS_INVITE": {
"title": "Confirmation URL",
"type": "string"
},
"MAILER_URLPATHS_CONFIRMATION": {
"title": "Path",
"type": "string"
},
"MAILER_URLPATHS_RECOVERY": {
"title": "Confirmation URL",
"type": "string"
},
"MAILER_URLPATHS_EMAIL_CHANGE": {
"title": "Confirmation URL",
"type": "string"
},
"MAILER_SUBJECTS_INVITE": {
"title": "Subject",
"type": "string"
},
"MAILER_OTP_EXP": {
"title": "Mailer Otp Expiration",
"type": "integer",
"help": "Duration before an email otp / link expires."
},
"MAILER_SUBJECTS_CONFIRMATION": {
"title": "Subject",
"type": "string"
},
"MAILER_SUBJECTS_MAGIC_LINK": {
"title": "Subject",
"type": "string"
},
"MAILER_SUBJECTS_RECOVERY": {
"title": "Subject",
"type": "string"
},
"MAILER_SUBJECTS_EMAIL_CHANGE": {
"title": "Subject",
"type": "string"
},
"MAILER_TEMPLATES_INVITE": {
"type": "string"
},
"MAILER_TEMPLATES_INVITE_CONTENT": {
"title": "Body",
"type": "string"
},
"MAILER_TEMPLATES_CONFIRMATION": {
"type": "string"
},
"MAILER_TEMPLATES_CONFIRMATION_CONTENT": {
"title": "Body",
"type": "string"
},
"MAILER_TEMPLATES_RECOVERY": {
"type": "string"
},
"MAILER_TEMPLATES_MAGIC_LINK": {
"type": "string"
},
"MAILER_TEMPLATES_RECOVERY_CONTENT": {
"title": "Body",
"type": "string"
},
"MAILER_TEMPLATES_MAGIC_LINK_CONTENT": {
"title": "Body",
"type": "string"
},
"MAILER_TEMPLATES_EMAIL_CHANGE": {
"type": "string"
},
"MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT": {
"title": "Body",
"type": "string"
},
"MFA_MAX_ENROLLED_FACTORS": {
"title": "Maximum enrolled factors",
"type": "integer"
},
"PASSWORD_MIN_LENGTH": {
"title": "Minimum password length",
"type": "integer"
},
"SECURITY_CAPTCHA_ENABLED": {
"title": "hCaptcha protection",
"type": "boolean",
"help": "Enables hCaptcha protection on all auth endpoints."
},
"SECURITY_CAPTCHA_SECRET": {
"title": "hCaptcha sitekey",
"type": "string",
"help": "Secret (sitekey) used to verify hCaptcha challenges."
},
"SECURITY_UPDATE_PASSWORD_REQUIRE_REAUTHENTICATION": {
"title": "Enable strict password updates",
"type": "boolean",
"help": "If enabled, users need to reauthenticate via email or phone before updating their passwords."
},
"SECURITY_REFRESH_TOKEN_REUSE_INTERVAL": {
"title": "Reuse Interval",
"type": "integer",
"help": "Time interval where the same refresh token can be used to request for an access token."
},
"SMS_AUTOCONFIRM": {
"title": "Enable phone confirmations",
"type": "boolean",
"help": "If enabled, users need to confirm their phone number before signing in."
},
"SMS_OTP_EXP": {
"title": "Sms Otp Expiration",
"type": "integer",
"help": "Duration before an sms otp expires."
},
"SMS_OTP_LENGTH": {
"title": "Sms Otp Length",
"type": "integer",
"help": "Number of digits in otp."
},
"SMS_PROVIDER": {
"title": "Sms provider",
"type": "string",
"options": [
{
"value": "twilio",
"label": "Twilio"
},
{
"value": "messagebird",
"label": "Messagebird"
},
{
"value": "vonage",
"label": "Vonage"
},
{
"value": "textlocal",
"label": "Textlocal"
}
]
},
"SMS_TEXTLOCAL_API_KEY": {
"title": "Textlocal API key",
"type": "string"
},
"SMS_TEXTLOCAL_SENDER": {
"title": "Textlocal sender",
"type": "string",
"help": "Textlocal sender phone number"
},
"SMS_TWILIO_ACCOUNT_SID": {
"title": "Twilio account SID",
"type": "string"
},
"SMS_TWILIO_AUTH_TOKEN": {
"title": "Twilio auth token",
"type": "string"
},
"SMS_TWILIO_MESSAGE_SERVICE_SID": {
"title": "Twilio message service SID",
"type": "string",
"help": "Twilio message service SID or twilio phone number"
},
"SMS_TWILIO_VERIFY_ACCOUNT_SID": {
"title": "Twilio account SID",
"type": "string"
},
"SMS_TWILIO_VERIFY_AUTH_TOKEN": {
"title": "Twilio Verify auth token",
"type": "string"
},
"SMS_TWILIO_VERIFY_MESSAGE_SERVICE_SID": {
"title": "Twilio Verify service SID",
"type": "string",
"help": "Twilio Verify service SID"
},
"SMS_MESSAGEBIRD_ACCESS_KEY": {
"title": "Messagebird access key",
"type": "string"
},
"SMS_MESSAGEBIRD_ORIGINATOR": {
"title": "Messagebird originator",
"type": "string",
"help": "Messagebird sender name or phone number"
},
"SMS_VONAGE_API_KEY": {
"title": "Vonage API key",
"type": "string"
},
"SMS_VONAGE_API_SECRET": {
"title": "Vonage API secret",
"type": "string"
},
"SMS_VONAGE_FROM": {
"title": "Vonage sender",
"type": "string",
"help": "Vonage sender phone number"
},
"SMS_TEMPLATE": {
"title": "Body",
"type": "string"
}
}
}
-25
View File
@@ -1,25 +0,0 @@
import api_keys from './api_keys'
import apps from './apps'
import infrastructure from './infrastructure'
import members from './members'
import organizations from './organizations'
import products from './products'
import projects from './projects'
import schema_migrations from './schema_migrations'
import services from './services'
import users from './users'
import authConfig from './auth_gotrue_config'
export {
api_keys,
apps,
infrastructure,
members,
organizations,
products,
projects,
schema_migrations,
services,
users,
authConfig,
}
@@ -1,64 +0,0 @@
{
"type": "object",
"required": [
"id",
"inserted_at",
"updated_at",
"infrastructure_type",
"status",
"provider_reference",
"provider"
],
"properties": {
"id": {
"title": "Id",
"type": "number"
},
"infrastructure_type": {
"title": "Infrastructure Type",
"type": "string",
"enum": ["DATABASE", "WEB_SERVER"]
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"ipv4_address": {
"title": "Ipv4 Address",
"type": "string"
},
"provider": {
"title": "Provider",
"type": "string"
},
"provider_reference": {
"title": "Provider Reference",
"type": "string"
},
"service_id": {
"title": "Service Id",
"type": "number"
},
"status": {
"title": "Status",
"type": "string",
"enum": [
"INACTIVE",
"ACTIVE_HEALTHY",
"ACTIVE_UNHEALTHY",
"COMING_UP",
"UNKNOWN",
"GOING_DOWN",
"REMOVED"
]
},
"updated_at": {
"title": "Updated At",
"type": "string"
},
"url": {
"title": "Url",
"type": "string"
}
}
}
@@ -1,22 +0,0 @@
{
"type": "object",
"required": ["id", "is_owner"],
"properties": {
"id": {
"title": "Id",
"type": "number"
},
"is_owner": {
"title": "Is Owner",
"type": "boolean"
},
"organization_id": {
"title": "Organization Id",
"type": "number"
},
"user_id": {
"title": "User Id",
"type": "number"
}
}
}
@@ -1,94 +0,0 @@
{
"type": "object",
"required": ["id", "inserted_at", "updated_at", "slug", "name"],
"properties": {
"badge": {
"title": "Badge",
"type": "string"
},
"billing_address_line_1": {
"title": "Billing Address Line 1",
"type": "string"
},
"billing_address_line_2": {
"title": "Billing Address Line 2",
"type": "string"
},
"billing_city": {
"title": "Billing City",
"type": "string"
},
"billing_country": {
"title": "Billing Country",
"type": "string"
},
"billing_email": {
"title": "Billing Email",
"type": "string"
},
"billing_expiry": {
"title": "Billing Expiry",
"type": "string"
},
"billing_phone": {
"title": "Billing Phone",
"type": "string"
},
"billing_postal_code": {
"title": "Billing Postal Code",
"type": "string"
},
"billing_state": {
"title": "Billing State",
"type": "string"
},
"credit_card_last_four_digits": {
"title": "Credit Card Last Four Digits",
"type": "string"
},
"email": {
"title": "Email",
"type": "string"
},
"id": {
"title": "Id",
"type": "number"
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"phone": {
"title": "Phone",
"type": "string"
},
"slug": {
"title": "Slug",
"type": "string"
},
"stripe_customer_id": {
"title": "Stripe Customer Id",
"type": "string"
},
"stripe_monthly_subscription_id": {
"title": "Stripe Monthly Subscription Id",
"type": "string"
},
"stripe_payment_method_id": {
"title": "Stripe Payment Method Id",
"type": "string"
},
"stripe_yearly_subscription_id": {
"title": "Stripe Yearly Subscription Id",
"type": "string"
},
"updated_at": {
"title": "Updated At",
"type": "string"
}
}
}
@@ -1,47 +0,0 @@
{
"type": "object",
"required": ["id", "inserted_at", "updated_at", "name"],
"properties": {
"feature_rights": {
"title": "Feature Rights",
"type": "object"
},
"id": {
"title": "Id",
"type": "number"
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"product_config": {
"title": "Product Config",
"type": "string"
},
"product_type": {
"title": "Product Type",
"type": "string",
"enum": ["API", "CDC"]
},
"stripe_monthly_plan_id": {
"title": "Stripe Monthly Plan Id",
"type": "string"
},
"stripe_product_id": {
"title": "Stripe Product Id",
"type": "string"
},
"stripe_yearly_plan_id": {
"title": "Stripe Yearly Plan Id",
"type": "string"
},
"updated_at": {
"title": "Updated At",
"type": "string"
}
}
}
@@ -1,83 +0,0 @@
{
"type": "object",
"required": [
"id",
"inserted_at",
"updated_at",
"organization_id",
"name",
"db_host",
"db_name",
"db_user",
"db_pass",
"db_port",
"db_ssl",
"ref"
],
"properties": {
"badge": {
"title": "Badge",
"type": "string"
},
"db_host": {
"title": "Db Host",
"type": "string"
},
"db_name": {
"title": "Db Name",
"type": "string"
},
"db_pass": {
"title": "Db Pass",
"type": "string"
},
"db_port": {
"title": "Db Port",
"type": "number"
},
"db_schema": {
"title": "Db Schema",
"type": "string"
},
"db_ssl": {
"title": "Db Ssl",
"type": "boolean"
},
"db_user": {
"title": "Db User",
"type": "string"
},
"id": {
"title": "Id",
"type": "number"
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"organization_id": {
"title": "Organization Id",
"type": "number"
},
"ref": {
"title": "Ref",
"type": "string"
},
"stripe_subscription_id": {
"title": "Stripe Subscription Id",
"type": "string"
},
"supabase_url": {
"title": "Supabase Url",
"type": "string"
},
"updated_at": {
"title": "Updated At",
"type": "string"
}
}
}
@@ -1,10 +0,0 @@
{
"type": "object",
"required": ["version"],
"properties": {
"version": {
"title": "Version",
"type": "string"
}
}
}
@@ -1,48 +0,0 @@
{
"type": "object",
"required": ["id", "inserted_at", "updated_at", "status", "version"],
"properties": {
"app_id": {
"title": "App Id",
"type": "number"
},
"config": {
"title": "Config",
"type": "object"
},
"id": {
"title": "Id",
"type": "number"
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"project_id": {
"title": "Project Id",
"type": "number"
},
"status": {
"title": "Status",
"type": "string",
"enum": [
"INACTIVE",
"ACTIVE_HEALTHY",
"ACTIVE_UNHEALTHY",
"COMING_UP",
"UNKNOWN",
"GOING_DOWN",
"INIT_FAILED",
"REMOVED"
]
},
"updated_at": {
"title": "Updated At",
"type": "string"
},
"version": {
"title": "Version",
"type": "string"
}
}
}
-50
View File
@@ -1,50 +0,0 @@
{
"type": "object",
"required": ["id", "auth0_id", "inserted_at", "updated_at", "username", "is_alpha_user"],
"properties": {
"auth0_id": {
"title": "Auth0 Id",
"type": "string"
},
"data": {
"title": "Data",
"type": "object"
},
"first_name": {
"title": "First Name",
"type": "string"
},
"id": {
"title": "Id",
"type": "number"
},
"inserted_at": {
"title": "Inserted At",
"type": "string"
},
"is_alpha_user": {
"title": "Is Alpha User",
"type": "boolean"
},
"last_name": {
"title": "Last Name",
"type": "string"
},
"mobile": {
"title": "Mobile",
"type": "string"
},
"primary_email": {
"title": "Primary Email",
"type": "string"
},
"updated_at": {
"title": "Updated At",
"type": "string"
},
"username": {
"title": "Username",
"type": "string"
}
}
}
-67
View File
@@ -727,7 +727,6 @@
"@uidotdev/usehooks": "^2.4.1",
"@zip.js/zip.js": "^2.7.29",
"ai": "^2.2.26",
"ajv": "^8.6.3",
"awesome-debounce-promise": "^2.1.0",
"blueimp-md5": "^2.19.0",
"clsx": "^1.2.1",
@@ -788,8 +787,6 @@
"sql-formatter": "^12.2.0",
"sqlstring": "^2.3.2",
"ui": "*",
"uniforms-bootstrap4": "^3.6.2",
"uniforms-bridge-json-schema": "^3.6.2",
"uuid": "^9.0.1",
"valtio": "^1.11.2",
"yup": "^0.32.11",
@@ -853,20 +850,6 @@
"glob": "7.1.7"
}
},
"apps/studio/node_modules/ajv": {
"version": "8.12.0",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"apps/studio/node_modules/argparse": {
"version": "2.0.1",
"license": "Python-2.0"
@@ -979,10 +962,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"apps/studio/node_modules/json-schema-traverse": {
"version": "1.0.0",
"license": "MIT"
},
"apps/studio/node_modules/resolve": {
"version": "2.0.0-next.5",
"dev": true,
@@ -33588,52 +33567,6 @@
"node": ">=4"
}
},
"node_modules/uniforms": {
"version": "3.10.2",
"license": "MIT",
"dependencies": {
"invariant": "^2.0.0",
"lodash": "^4.0.0",
"tslib": "^2.2.0"
},
"funding": {
"url": "https://github.com/vazco/uniforms?sponsor=1"
},
"peerDependencies": {
"react": "^18.0.0 || ^17.0.0 || ^16.8.0"
}
},
"node_modules/uniforms-bootstrap4": {
"version": "3.10.2",
"license": "MIT",
"dependencies": {
"classnames": "^2.0.0",
"invariant": "^2.0.0",
"lodash": "^4.0.0",
"tslib": "^2.2.0",
"uniforms": "^3.10.2",
"warning": "^4.0.0"
},
"funding": {
"url": "https://github.com/vazco/uniforms?sponsor=1"
},
"peerDependencies": {
"react": "^18.0.0 || ^17.0.0 || ^16.8.0"
}
},
"node_modules/uniforms-bridge-json-schema": {
"version": "3.10.2",
"license": "MIT",
"dependencies": {
"invariant": "^2.0.0",
"lodash": "^4.0.0",
"tslib": "^2.2.0",
"uniforms": "^3.10.2"
},
"funding": {
"url": "https://github.com/vazco/uniforms?sponsor=1"
}
},
"node_modules/unique-filename": {
"version": "1.1.1",
"license": "ISC",