feat(uat-batch): Group Q — platform refactors

Q58, Q59, Q61 from the 2026-05-21 plan. Q57 + Q60 (sweep-scope) parked.

Shipped:
  Q58  SelectTrigger size variant. <SelectTrigger> now accepts
       `size?: 'default' | 'sm'`. Default = `h-11` so the trigger
       matches <Input>'s h-11 default and the 8px height mismatch
       called out in the UAT vanishes platform-wide. Existing call
       sites that need the legacy compact look (FilterBar, dense
       table headers) opt back in via `size="sm"`. Nothing breaks —
       the default render flips height without touching any other
       styling.
  Q59  Table density min-widths + nowrap. DataTable cells now
       default to `whitespace-nowrap` so long values (URLs, names,
       addresses) don't wrap into 4-5 lines and inflate row height.
       Columns that need wrapping override via the column def's
       `meta.wrap = true`. Min-width comes from
       `column.getSize?.()` when set so a column doesn't shrink-
       wrap below readability — opt-in per column rather than a
       sweeping width change.
  Q61  Error message audit foundation — Documenso 401/403 path
       enriched. <PortDocumensoConfig> gains `apiKeySource` +
       `apiUrlSource` ('port' | 'global' | 'env' | 'default' |
       'none'). `getPortDocumensoConfig` populates them based on
       which layer of the resolver chain produced the value.
       documenso-client's <ResolvedCreds> exposes the source flags;
       the 401/403 branch surfaces them in the
       `DOCUMENSO_AUTH_FAILURE` internalMessage so operators see
       "api key source: env, port: <id>" instead of the prior
       generic `path → 401` body. Solves the Documenso diagnosis
       loop that prompted the platform-wide error audit. Same
       pattern can extend to other integration error paths in
       follow-ups (S3, Redis, IMAP) — the resolver-source helper
       lives on PortConfig now.
  Q60  Tooltip audit primitive already shipped — <FieldLabel> in
       `ui/field-label.tsx` is the canonical surface with an Info
       icon + Tooltip slot. One adopter live (custom-field-form);
       remaining admin-form sweep is the lift that's parked.

Deferred:
  Q57  recharts → ECharts migration (6-10h). Pure visual port of
       8 chart components; safer as a focused session with
       per-chart visual review. Pre-reqs (ECharts deps + the
       transpilePackages config + the d3-geo install) are in place
       so the migration can be picked up cleanly.

Verified: tsc clean, vitest 1454/1454.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 23:49:22 +02:00
parent 0ed03fcd7f
commit c14f80a4f7
5 changed files with 71 additions and 10 deletions

View File

@@ -12,7 +12,15 @@ interface DocumensoCreds {
apiVersion: DocumensoApiVersion;
}
async function resolveCreds(portId?: string): Promise<DocumensoCreds> {
interface ResolvedCreds extends DocumensoCreds {
/** Provenance of the API key — surfaces in error messages so an
* operator can tell at a glance whether a 401 is the env fallback's
* stale key vs. a per-port admin entry. */
apiKeySource: 'port' | 'global' | 'env' | 'default' | 'none';
apiUrlSource: 'port' | 'global' | 'env' | 'default' | 'none';
}
async function resolveCreds(portId?: string): Promise<ResolvedCreds> {
// env.DOCUMENSO_API_URL / env.DOCUMENSO_API_KEY are now optional — the
// canonical config lives in admin settings. Empty fallbacks let the call
// proceed; if both env + admin are blank, the downstream fetch hits an
@@ -23,6 +31,8 @@ async function resolveCreds(portId?: string): Promise<DocumensoCreds> {
baseUrl: env.DOCUMENSO_API_URL ?? '',
apiKey: env.DOCUMENSO_API_KEY ?? '',
apiVersion: env.DOCUMENSO_API_VERSION,
apiKeySource: env.DOCUMENSO_API_KEY ? 'env' : 'none',
apiUrlSource: env.DOCUMENSO_API_URL ? 'env' : 'none',
};
}
const cfg = await getPortDocumensoConfig(portId);
@@ -30,6 +40,8 @@ async function resolveCreds(portId?: string): Promise<DocumensoCreds> {
baseUrl: cfg.apiUrl ?? '',
apiKey: cfg.apiKey ?? '',
apiVersion: cfg.apiVersion,
apiKeySource: cfg.apiKeySource ?? (cfg.apiKey ? 'env' : 'none'),
apiUrlSource: cfg.apiUrlSource ?? (cfg.apiUrl ? 'env' : 'none'),
};
}
@@ -64,9 +76,13 @@ async function documensoFetchOnce(
logger.error({ path, status: res.status, err, portId }, 'Documenso API error');
if (res.status === 401 || res.status === 403) {
// Auth failures are not retryable — wrong key won't fix itself.
// Surface the resolver source in the error message so the operator
// sees "key resolved from env fallback" vs "per-port override" and
// knows whether to edit the deploy env or the port admin row.
const { apiKeySource, apiUrlSource } = await resolveCreds(portId);
throw new AbortError(
new CodedError('DOCUMENSO_AUTH_FAILURE', {
internalMessage: `${path}${res.status}`,
internalMessage: `${path}${res.status} (api key source: ${apiKeySource}, api url source: ${apiUrlSource}, port: ${portId ?? 'global'})`,
}),
);
}