Files
windmill/frontend/src/lib/utils/postgresConnectionString.ts
T
Guilhem Lemouel cd4ecbe52a feat(frontend): rebuild data table setup around a read-only row
The wizard gathers intent over two steps, reviews it on a third and writes nothing
until Finish, so a billable Supabase project is created only once the user has seen
what will happen. runSetup is also the retry: every step probes for its own result
before doing anything, so running it again on a half-finished data table resumes
instead of duplicating. Its steps are keyed rather than dispatched on their titles,
where rewording one changed what it did.

The settings row stops being an editable form with a dirty/save cycle. It carries the
name, where the database came from, a health dot and two actions; everything rare
moved into the gear panel, which also offers Finish setup for a data table whose
wizard never completed. Manage is ExploreAssetButton, the control the ducklake list
already uses, and the row and panel both link out to the underlying resource.

supabaseResourceValue no longer assembles the pooler host from the region.
aws-0-<region>.pooler.supabase.com is wrong for any project Supabase allocated
elsewhere, so the host, user and port come from the pooler config endpoint.

Two data tables sharing one database also share _wm_migrations, which is probed
unqualified, so the review step warns when the database being connected is already
behind another data table.

SupabaseConnect is deleted. The resource drawer uses the shared project step
restricted to existing projects: creating one is a billed action and belongs in the
wizard, which has somewhere to report what it did. The kitchen_sink checklist
playground goes with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 10:15:15 +02:00

37 lines
1.1 KiB
TypeScript

/**
* Parsing for `postgres://user:password@host:5432/dbname?sslmode=require`.
*
* Shared by the resource form and the data table wizard: both turn a pasted
* connection string into a `postgresql` resource value, and the two drifting
* apart would mean the same string produced two different resources.
*/
const CONNECTION_STRING =
/postgres(?:ql)?:\/\/(?<user>[^:@]+)(?::(?<password>[^@]+))?@(?<host>[^:\/?]+)(?::(?<port>\d+))?\/(?<dbname>[^\?]+)?(?:\?.*sslmode=(?<sslmode>[^&]+))?/
export type PostgresConnectionParts = {
user: string
password?: string
host: string
port?: number
dbname?: string
sslmode?: string
}
/** Undefined when the string is not a postgres URI. */
export function parsePostgresConnectionString(
connectionString: string
): PostgresConnectionParts | undefined {
const match = connectionString.match(CONNECTION_STRING)
if (!match?.groups) return undefined
const { user, password, host, port, dbname, sslmode } = match.groups
return {
user,
password: password || undefined,
host,
port: port ? Number(port) : undefined,
dbname: dbname || undefined,
sslmode: sslmode || undefined
}
}