Rebuild dist with suggestion chips and task cost estimator - #512
Merged
Conversation
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
# Conflicts: # dist/index.html
…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.
…typing Fix/api docs token typing
…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>
Contributor
Author
|
Commercial-packaging follow-up pushed: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
develop's committed
dist/predates the #509/#510 merges, so the chips and task estimator exist insrc/but not in any served JS chunk — users of a develop-pinned install don't see either feature. This rebuildsdist/from develop @ 793c942 (ng build, Angular 16.1 / node 20). Verified the new chunks contain the feature code, and the two new jest suites pass (36 tests).The develop-pinned Laravel 13 engineer bundle pins this branch until it merges, so test instances ship the current UI.
🤖 Generated with Claude Code