mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
## What kind of change does this PR introduce? UI improvements. Resolves DEPR-419. ## What is the current behavior? - `ColumnList` splits type information across separate `Data Type` and `Format` columns, which makes scanning less efficient - The list only surfaces a limited subset of column metadata up front, so key structural information like primary keys, foreign keys, uniqueness, and identity is not easy to scan - Constraint and nullability affordances are not aligned with the visual language already used in the Table Editor and Schema Visualiser ## What is the new behavior? - `ColumnList` now shows a leading type affordance icon, while keeping the exact Postgres type visible in the `Type` column - The standalone `Data Type` column is removed, and `format` is now the primary textual type shown in the table - The `Constraints` column now surfaces explicit icon-plus-label tokens for: - `Primary` - `Foreign key` - `Unique` - `Identity` - `Nullable` / `Non-nullable` - Constraint tokens use a purpose-built segmented style based on `ComputeBadge`, including a green primary variant for primary keys - Nullability now matches Schema Visualiser semantics exactly: outlined diamond for nullable, filled diamond for non-nullable - Existing search, descriptions, row actions, and permission gating are preserved --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import { POSTGRES_DATA_TYPE_OPTIONS } from 'components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.constants'
|
|
|
|
type TableConstraintSource = {
|
|
schema: string
|
|
name: string
|
|
primary_keys: ReadonlyArray<{ name: string }>
|
|
relationships: ReadonlyArray<{
|
|
source_schema: string
|
|
source_table_name: string
|
|
source_column_name: string
|
|
}>
|
|
unique_indexes?: ReadonlyArray<{ columns: ReadonlyArray<string> }>
|
|
}
|
|
|
|
export type ColumnAffordanceKind = 'number' | 'time' | 'text' | 'json' | 'bool' | 'other'
|
|
|
|
export interface ColumnTypeAffordance {
|
|
kind: ColumnAffordanceKind
|
|
label: string
|
|
}
|
|
|
|
const COLUMN_AFFORDANCE_LABELS: Record<ColumnAffordanceKind, string> = {
|
|
number: 'Numeric',
|
|
time: 'Date / time',
|
|
text: 'Text',
|
|
json: 'JSON',
|
|
bool: 'Boolean',
|
|
other: 'Other',
|
|
}
|
|
|
|
const normalizeColumnFormat = (format: string) => format.replaceAll('"', '').replace(/\[\]$/, '')
|
|
|
|
export function getColumnTypeAffordance(format: string): ColumnTypeAffordance {
|
|
const normalizedFormat = normalizeColumnFormat(format)
|
|
const optionType = POSTGRES_DATA_TYPE_OPTIONS.find(
|
|
(option) => option.name === normalizedFormat
|
|
)?.type
|
|
|
|
switch (optionType) {
|
|
case 'number':
|
|
case 'time':
|
|
case 'text':
|
|
case 'json':
|
|
case 'bool':
|
|
return { kind: optionType, label: COLUMN_AFFORDANCE_LABELS[optionType] }
|
|
default:
|
|
return { kind: 'other', label: COLUMN_AFFORDANCE_LABELS.other }
|
|
}
|
|
}
|
|
|
|
export function getPrimaryKeyColumnNames(table?: TableConstraintSource) {
|
|
return new Set(table?.primary_keys.map((primaryKey) => primaryKey.name) ?? [])
|
|
}
|
|
|
|
export function getForeignKeyColumnNames(table?: TableConstraintSource) {
|
|
if (!table) {
|
|
return new Set<string>()
|
|
}
|
|
|
|
const { schema, name, relationships } = table
|
|
|
|
return new Set(
|
|
relationships
|
|
.filter(
|
|
(relationship) =>
|
|
relationship.source_schema === schema && relationship.source_table_name === name
|
|
)
|
|
.map((relationship) => relationship.source_column_name)
|
|
)
|
|
}
|
|
|
|
export function getUniqueIndexColumnNames(table?: TableConstraintSource) {
|
|
return new Set(
|
|
table?.unique_indexes
|
|
?.filter((uniqueIndex) => uniqueIndex.columns.length === 1)
|
|
.flatMap((uniqueIndex) => uniqueIndex.columns) ?? []
|
|
)
|
|
}
|