Skip to content

release: 7.7.0 — develop → main cut - #515

Merged
thekevinm merged 250 commits into
mainfrom
develop
Aug 13, 2026
Merged

release: 7.7.0 — develop → main cut#515
thekevinm merged 250 commits into
mainfrom
develop

Conversation

@thekevinm

Copy link
Copy Markdown
Contributor

7.7.0 release cut. Highlights: the 7.7 admin UI wave — design system + command palette, API Docs & API Builder workspaces, Agents/Alerts pages, chat suggestion chips, task cost estimator, real service health probes — plus the Silver paywall catalog for the AI types and a current dist build.

After merge, tag 1.7.7 on the merge commit (df-commercial's version refresh consumes the tags). Full release notes: see the 7.7.0 draft.

🤖 Generated with Claude Code

nicdavidson and others added 30 commits May 20, 2026 12:42
The April 2026 security update bumped swagger-ui 4.15.5 -> ^5.32.2
without migrating df-api-docs.component.ts to the v5 calling
convention. v5 introduced breaking changes in bundle layout and
internal call paths, causing every service's API docs to throw
"TypeError: o is not a function" from inside the swagger-ui bundle.

Pinning back to 4.15.5 restores the working UI as a stopgap. The
patched DOMPurify XSS / Handlebars JS injection CVEs return — low
practical risk for the admin UI (specs come from trusted backends),
but a proper v5 migration is still owed.

Rebuilt dist/ artifacts included.
The API Builder nav entries and breadcrumbs rendered raw transloco keys
(nav.api-builder.nav, nav.api-connections.api-types.api-builder.*, and the
missing api-types.header). Add the strings to en.json (source + runtime dist
copy). Translations are runtime-loaded JSON, so no JS rebuild is required.
Major rework of the API Builder admin UI (df-api-builder.component.ts):

UX:
- Replace the cramped 2-column workbench with a Swagger-style master-detail:
  API settings card (title, /api/v2/{base_path}, status, Save/Docs/Delete) +
  a method-colored endpoint accordion. Click a row to edit inline; Add Endpoint
  opens a new draft. Collapsed by default.
- Surface Endpoint Name/URL as primary fields; preserve user-entered identity
  (don't overwrite path/label/description once edited).
- Autocomplete source-API/table pickers; hide non-data service types from the
  source list; focus-to-show-full-list with deferred blur restore.

Behavior fixes:
- Preview/Test now execute (send dry_run:false + snake_case path_params); the
  Test runner response is shown verbatim.
- Re-introspect the source when loading a saved endpoint so Fields/Relationships
  render with saved selections (safe now that the CD-hang is fixed via trackBy).
- "Save the API first" hint when no API is saved yet.

Field/relationship renaming (output aliases):
- Per-field/relationship rename inputs -> flat alias map on the execution-plan
  step; backend applies a key-remap on fetched rows.

camelCase interceptor safety (shared utilities):
- case.ts: treat execution_plan/response_mapping VALUES as verbatim blobs (their
  inner keys are real field names + user aliases) — transform the envelope key
  only, both directions. Same pattern as the existing requestBody exclusion.
- case.interceptor.ts: skip response transform for /api_builder/test so the
  preview shows the real output keys the deployed endpoint returns.
- Add regression tests; existing case tests still pass.

Includes rebuilt dist/.
…crumb-header

Fix/api types breadcrumb header
…ship builder)

Workspace/relationship panel on the custom-API editor: pick backing services for the API and author cross-service relationships, with a live preview and per-type help text.

Endpoint source picker is scoped to the API's workspace and refreshes live when it changes. camelCase interceptor support for API Builder fields (case.ts). Rebuilt production dist.
Self-contained adf-agents component (mirrors adf-alerts): agent CRUD with
role + key TTL and revoke, approve/deny pending access requests, and an
activity view (last-active + recent agent alerts). Top-level 'agents' route +
nav label. Includes rebuilt dist.

Claude-Session: https://claude.ai/code/session_01TAqkbJ6Wpa9CX2sydcFeZu
…eguard

The global caseInterceptor converts /api responses to camelCase; the component
read snake_case so every field was undefined (toggle stuck off, blank cells,
edits not persisting). Rewrote to camelCase (alerts log stays snake — /_internal
is not under /api). Toggle now reverts to server truth on error. Rebuilt dist.

Claude-Session: https://claude.ai/code/session_01TAqkbJ6Wpa9CX2sydcFeZu
Drive the AI chat and AI Connections UIs off theme tokens instead of
hardcoded white text, so they are legible in light mode. Dark mode is
unchanged: the dark token values reproduce the original whites.

- AI chat: theme tokens for messages, tool-result cards, session list,
  and the chat shell; show the tool CALL (name + arguments), not just the
  result; move "Act as role" beside New chat; tighten height so the input
  stays in view.
- AI chat config: MCP servers + data services as selectable pickers.
- AI Connections config: theme tokens for allowed-roles, model-picker,
  and test-connection; fix df-role-scope wildcard callout.
- Hide API Builder / Alerts / Agents from the left nav (routes intact).
- Drop em-dashes from shipped picker and test-connection copy.
Snapshot of in-progress work found uncommitted in the tree: a new API
Builder preview component (+ specs), large reworks to the workspace and
main builder components, and small tweaks to Agents, event-script
details, welcome page, and the script editor. Committed to clean the
tree ahead of the UI-hardening branch; not reviewed.
…solved toward main's --df-ai-* pattern; dist kept ours, rebuilt next)
…d once on body

- styles.scss: --df-* token set, light on :root, dark under .dark-theme,
  dark values reproduce the pre-token hardcoded whites
- DfThemeService now stamps .dark-theme on <body> (single source of truth);
  color-scheme: dark for native controls
- component migration to tokens follows in stream1 sweep commits
thekevinm and others added 29 commits August 12, 2026 10:27
…tion-chips

AI Chat: follow-up suggestion chips from a trailing suggestions fence
…stimator

AI Usage: task-based what-if cost estimator (estimate → budget verdict → run & compare)
The Health chip flagged nearly every service as "Needs attention" with
"No API docs", but the API Docs page for those same services works.

The noDocs rule read the service_doc_by_service_id relation, which is
only populated when an admin uploads a *custom* OpenAPI override. Every
service gets a spec generated from its type at request time, so on a
healthy install that relation is empty for the whole catalog and the
rule fired on all of it. Neither is the presence of a doc a health
signal to begin with.

Dropped noRateLimit for the same reason: rate limiting is a licensed
feature and an install with no limits is the norm, so the rule warned
on every service without saying anything about its health.

Health now covers what actually makes a service unusable - no role
grants access (danger) and explicitly deprecated (danger). That also
takes the context down from three list reads to one.
Every detail route is keyed by id (/rate-limiting/7, /users/12,
/api-keys/3 ...), and the breadcrumb is generated straight from the URL,
so the page you are editing announced itself as a bare number. The one
place that already had a name to show - the Rate Limiting table - was
printing the raw service/role/user ids in its own columns too.

- Breadcrumb: the last crumb of a dynamic route now takes its label from
  the record the route's resolver already fetched, so no extra request.
  Only the crumb that *is* the identifier is renamed (a trailing static
  segment like :id/scope is left alone), and the raw segment stays when
  nothing names the record - a paywalled or failed resolve.
- Rate Limiting table: the user/service/role columns render the related
  record's name (already fetched via `related`), '-' when the limit is
  not scoped to one, instead of the foreign key.
- Dynamic crumbs render the whole segment. Splitting on '-' and keeping
  the tail turned a service named "my-mysql-db" into "db" in the
  breadcrumb on API Docs, Schema and Scripting pages.
On Home the "N services allow broad read and write access" strip was
drawn under the bottom of the four stat tiles.

df-stat-tile sets height:100% so the tiles fill their grid row at equal
height, but the app ships no global box-sizing reset, so the tiles
compute under content-box: the 16px padding on each side plus the 1px
borders are added *on top of* the row height, and every tile renders
34px taller than its own grid track. The overflow lands on whatever
follows .tile-grid in the column - here, the exposure strip. Measured in
Chromium: tile bottom 34px past the grid, 18px into the strip.

box-sizing: border-box keeps the padding inside the 100%. Scoped to the
tile rather than adding a global reset, which would move layout on every
other page.
The committed dist/ predated the merges of #509 (chat suggestion
chips) and #510 (task-based cost estimator), so neither feature was
present in the served admin UI. Rebuilt with ng build (Angular 16.1,
node 20) from develop @ 793c942; the new features' jest specs pass
(36 tests across df-chat-message.component.spec.ts and
task-estimate.spec.ts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Health chip on the Services table hides its reasons behind a menu.
That is fine for scanning a list and useless on the page where you would
actually act on them, so the service edit page now opens with the same
verdict spelled out: one row per failing rule, the consequence in plain
words, and a deep link to the config that clears it.

df-service-health-panel reuses DfServiceHealthService.derive() rather
than restating the rules, so the page and the table can never disagree,
and the context is already cached app-wide - opening a service costs no
extra request.

Placement and scope, given how far the service pages diverge below the
fold: top of the page for every service type in edit mode (create has
nothing to score yet), and never on the DreamFactory Platform APIs
route, whose services are not role-governed the way a user service is.
A passing service collapses to a single quiet line instead of a green
wall, so the panel does not compete with the config form.
…alth"

"Healthy" was reporting on the role graph and nothing else, so a service
whose credentials had rotted still read healthy - the chip never opens a
connection. Nothing else re-checks either: df-core's ServiceHealthChecker
fires only on static::created and persists no result, so a password that
broke after setup was invisible everywhere in the admin UI.

Two changes, matching the two things that were conflated:

- The service page's panel now probes the service live, using the same
  endpoints the API Docs page already checks (/_schema for a database, /
  for file storage, from healthCheckEndpointsInfo keyed by the route
  group). A dead connection is a danger finding that outranks anything
  derived. A type with no mapped endpoint says it was not checked rather
  than claiming health it cannot prove.
- The Services table column is renamed Access (services.access.chip.*),
  because that is all it measures. A live probe costs one request per
  service and the list would fire one per row on every visit, so the
  probe stays on the page for a single service.

The failed-probe row carries the normalized message plus df-error-detail
for status, request and the DSN-scrubbed raw body. The probe requests
JSON rather than text so DF's { error: { message } } envelope parses at
all - the API Docs probe asks for text, which collapses every failure
into the generic "errors.http5xx" string.
…on screen

Reverts the column back to Health and makes the name true, rather than
renaming around the problem: the list now probes each service on the
current page, so a database whose credentials broke reads "Action
required" in the catalog, not just on its own page.

Scope is the rendered page, never the catalog. The table pages
server-side, so dataSource.data is exactly what is on screen: cost
tracks page size, not install size. DfServiceProbeService caches each
verdict by service name, so paging back and forth re-opens nothing, and
the service page and the list now share one probe implementation.

A chip with no failing rule says which of two things it means: "Healthy"
only when a connection actually answered, "Not checked" for a type with
no defined probe (scripting, remote, auth), "Checking…" while in flight.
That distinction is the whole point - the old chip called all three
Healthy.

A failed probe becomes a cannotConnect rule via
DfServiceHealthService.withProbe(), so the existing chip and its "why"
menu render it with no special casing, and governance rules stay behind
it in the list. Composed rather than overwritten: the role-graph context
and the probe verdict land in either order.
The DreamFactory Platform APIs (system, files, logs, db, email, user)
are reached with an admin session, not through a role grant, so the
governance rule says nothing about them, and their route defines no
service group, so there is nothing to probe either. The column could
only ever read "Not checked" or a misleading "Action required".

Hidden rather than filled: the same reason the service page's health
panel already skips this route.
The page's copy was written against the light theme with fixed colours:
the subhead and the "Pick a SQL service above" empty state are
rgba(0,0,0,.6)/.5, i.e. black at low alpha, which all but disappears on
the dark ground.

Swapped for --df-text-muted, whose light value is rgba(0,0,0,.55) - so
light mode is unchanged - and which carries rgba(255,255,255,.55) in
dark and its own value in phosphor. Same swap for the other muted text
on the page (stat labels, table sub-labels, the muted lock icon), and
--df-danger / --df-accent for the drift and enforcement colours, which
were dark red and dark purple on a dark background.

Deliberately left: the rgba inside .badge-grey. That text sits on the
badge's own #f5f5f5 fill, not the page, so tokenising it would put
near-white text on near-white.
The three dialogs (table diff, snapshot history, OpenAPI) style
themselves from inline literals written against the light theme: muted
text as black-at-low-alpha, hairlines as rgba(0,0,0,.08), panels as
#f5f5f5/#fafafa/#fff. In dark mode the text all but disappears and the
panels are white slabs.

Everything now rides the same tokens the rest of the admin UI uses, so
all three themes repaint by construction:

  breaking            -> --df-danger(-soft)
  potentially breaking-> --df-warning(-soft)
  additive            -> --df-accent(-soft)
  cosmetic / neutral  -> --df-surface-2 + --df-text-muted
  locked / active     -> --df-success(-soft)
  OpenAPI draft blue  -> --df-tint-data-bg/fg

Severity border-lefts follow the same ladder. The status badges on the
page itself move with them - with the badge fill tokenised, the grey
badge's text can now be --df-text-muted too, which is what the earlier
pass had to leave as a literal.
…and-record-labels

Fix/service health and record labels
…erates

A {table_name} / {procedure_name} / {function_name} token always rendered
as a <select>, populated by one lookup whose failure is swallowed into an
empty list. When that list came back empty the operation became unrunnable:
a dropdown holding nothing but its disabled placeholder, and no way to type
a value.

Empty is not rare. The lookup 404s or 403s on RBAC, returns nothing for a
service with no stored procedures, and 500s outright on the Laravel 13
bundle, where cache.serializable_classes=false breaks GET /{service}/_table
for every service.

usePicker() keeps the dropdown while options exist - and while the request
is still in flight, so the control does not flip out from under the user -
and falls back to the free-text input the template already carries once the
list resolves empty.

Also repairs the suite, which failed 3/3 on 7.7 before this change: the
component gained a MatSnackBar injection and a route-snapshot read that the
TestBed never provided, and the swagger-ui host throws while jsdom tears the
fixture down.
…atures

Adds the three AI service types to SILVER_SERVICES so open-source
admin UIs show them in the service picker with the standard upgrade
paywall instead of omitting them entirely - matching how Active
Directory, SAML, and other paid connectors are presented. Dist rebuilt
from this branch head (includes the #513/#514 fixes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rebuild dist with suggestion chips and task cost estimator
@thekevinm
thekevinm merged commit aa94d10 into main Aug 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants