Skip to content

Searchable pickers (#534), event-script name picker fix, presentation mode - #537

Open
nicdavidson wants to merge 17 commits into
developfrom
feat/searchable-pickers-presentation-mode
Open

nicdavidson wants to merge 17 commits into
developfrom
feat/searchable-pickers-presentation-mode

Conversation

@nicdavidson

Copy link
Copy Markdown
Contributor

Closes #534. Supersedes #533 (presentation mode), which is included here.

The branch starts from the current main (1a8d68b3, #535 Docker trial). This diff against develop therefore also contains #535's commits, because develop has not been updated since 9/24.

Searchable pickers (#534)

  • Shared df-select-search + dfSearch pipe. A search box at the top of a single-select mat-select panel.
    • Arrow keys and Enter select; Esc clears the search, then closes.
    • Text typed on a closed or still-opening select goes to the search box instead of mat-select's jump-to-option type-ahead.
  • Role-Based Access
    • The Service picker is searchable.
    • The Component picker has a Type dropdown, built from each component's first path segment (Schema / Table / Function / Procedure, and admin, role, … for system and file services), plus search.
    • Within a type, only that type's own wildcards (_table/, _table/*) stay visible. '' and * appear under All.
  • Users / Admins: the app and role autocompletes now narrow as you type. They filter on the typed text, because requireSelection keeps that text out of the form control until an option is picked.
  • Event Scripts: the service, script type, method and table pickers are searchable.
  • API Docs
    • Operation nav search.
    • The {table} / {field} / relation / proc / func path-token pickers are now searchable mat-selects.
    • The filter-builder Field picker and Try-it's "Test as" picker are searchable.
  • No payload change. Saved roles and apps are identical.

Event Scripts fix (broken on main today)

/system/event is exempt from the case interceptor (7f0747ba), so event parameters arrive as table_name / procedure_name / function_name. The component only matched the camelCase keys, so the Table / Procedure / Function Name picker never appeared, and you could not script a single table (e.g. a pre_process on driver).

  • Both key spellings are now accepted.
  • When a service has none (the API sends parameter: null), the picker is derived from the {…_name} placeholder and still shown. A typed name can be used, so you can script ahead of creating the function.

Presentation mode (from #533)

  • Mask API keys and tokens for screensharing (df-secret, top-bar toggle).
  • Fix: unmasked keys in the API Keys table were wrapping one character per line. They now show on one line, ellipsized at 180px.

Testing

  • npm run test -- -c jest.config.ci.js: 34 suites / 292 tests pass. New specs:
    • df-select-search.spec.ts
    • scriptEventParameter cases in df-script-details.submit.spec.ts
  • Browser-checked against a live 7.x instance (df-dev) with Playwright:
    • Role component picker: Table + "invoice" → _table/chinook_invoice/.
    • Users app and role pickers.
    • Event Scripts: logistics → _table.{table_name} → get.pre_process → driver. Also functions with none defined.
    • API Docs token, Field and "Test as" pickers.
    • API Keys table with presentation mode on and off.
  • The remaining non-CI Jest failures (roles, filter-builder, try-it) also fail on clean main. They are the known transloco ESM issue noted in jest.config.ci.js.

Follow-up

Kevin McGahey and others added 14 commits October 3, 2026 23:13
…d interceptor

Implements TRIAL-DESIGN.md section 5 for the on-prem 30-day Docker trial.
Dormant unless /api/v2/system/environment carries the df-trial block.

- Types: TrialInfo (camelCase of the 4.4 wire block) on platform.trial and
  top-level trial (pre-login); platform.installType.
- DfTrialService: trial$ from environment$, lock$/expired$/isLocked with
  reason + context, markLocked()/clearLock(), remaining$ 1 s countdown from
  expiresAt corrected by the server-reported secondsRemaining, severity
  info > warnDays warning > criticalDays critical.
- DfTrialBannerComponent: fixed-top + spacer (same pattern as the engagement
  banner, which now hides on trial instances), section-9 copy with pluralised
  units, mailto + demo CTAs, --df-accent/--df-warning/--df-danger tokens,
  visible pre-login, hidden while locked.
- DfTrialExpiredComponent (route trial-expired): "Thank you for testing
  DreamFactory." + ended-on date for TRIAL_EXPIRED, token-required variant
  with portal CTA for TRIAL_TOKEN_INVALID; tokenized, offline-safe. The shell
  drops side-nav/toolbar while locked (extends the disableUi branch).
- errorInterceptor: 402/403 with context.reason TRIAL_EXPIRED |
  TRIAL_TOKEN_INVALID -> markLocked + navigate, checked before the 401 branch
  and for silent requests too; never clears the token. AppError now carries
  the envelope context.
- trialGuard first on every guarded route (+ auth, license-expired):
  locked -> trial-expired, active on trial-expired -> home.
- APP_INITIALIZER resolves on a locked instance (addendum 12.5); no retry of
  a deterministic lock. Browser-side updates.dreamfactory.com check and the
  red subscription strip are skipped when trial info is present.
- System Info: install type, trial status/started/expires/days/id.
- i18n trial.* keys; jest specs (85 tests) added to the CI list.

Claude-Session: https://claude.ai/code/session_01FptG8FPhcAoo6yqakZwqUf
Production build (ng build --configuration production, Angular 16) of the
trial banner / lockout changes; served to the host app via the committed
dist/ convention.

Claude-Session: https://claude.ai/code/session_01FptG8FPhcAoo6yqakZwqUf
feat(trial): self-service Docker trial banner, lockout page, guard and interceptor
Screensharing the admin UI puts live API keys on someone else's monitor.
One toggle in the top bar now covers every credential the UI renders, with
a per-field eye to reveal one on demand.

Display and clipboard are deliberately separate paths: df-try-it renders
displaySnippet and copies snippet, df-mcp-connect renders
maskIfPresenting(x) and copies x. A masked curl command still pastes into
Postman and works.

The value leaves the DOM rather than being blurred — a CSS blur stays
selectable and recoverable from a screenshot.

Service-config secrets key off the field name, not the schema type:
oidc.client_secret ships as `text` and mcp.oauth_client_secret as
`string`, so both render as plain visible inputs. `_id` is excluded so
client_id stays readable during OAuth setup.

This is not a security boundary — the key still arrives in the API
response and is visible in devtools. It addresses screenshare exposure.

Covered by 34 unit tests (registered in jest.config.ci.js) and
e2e/presentation-mode.spec.ts, which asserts the clipboard still carries
the exact unmasked command and sweeps the leaking routes, failing loudly
if a swept route has no credential left to hide.
…s table

overflow-wrap: anywhere let the auto-layout table shrink the API key
column to a single character, stacking the 64-char key vertically.
Show it on one line, capped at 180px with an ellipsis instead.
Shared df-select-search header + dfSearch pipe. Role-Based Access service
and component pickers get type-to-search; the component picker also gets
All/Schema/Table/Function/Procedure toggles. Wildcards stay selectable
while filtering. Users/Admins app+role autocompletes now narrow as you
type; Event Scripts pickers and the API Docs operation nav are searchable.
Saved payloads are unchanged.

Closes #534
… wildcards

Replace the Schema/Table/Function/Procedure toggles with a compact Type
select derived from each component's first path segment, so file and
system services get types too. Within a type only that type's own
wildcards are kept; the query matches the part after the prefix.
Keys typed on a focused-but-closed select, or before the panel finished
opening, hit mat-select's jump-to-option typeahead instead of filtering.
The request builder's {table}/{field}/relation token pickers become
mat-selects with the shared search, as do the filter builder's Field
picker and Try-it's Identity picker. Register the dfSearch spec in the
CI jest config.
requireSelection keeps typed text out of the form control until an
option is picked, so the filter read a stale value and never narrowed.
/system/event is exempt from the case interceptor, so event parameters
arrive as table_name / procedure_name / function_name. The component only
matched the camelCase keys, so the name picker never appeared and a
script could not target one table (e.g. a pre_process on driver).
A service with no stored functions/procedures sends parameter: null, which
hid the picker and left the script name with a literal {function_name}.
Derive the kind from the event's placeholder instead, show an empty
picker, and let a typed name be used (script ahead of creating it).
nicdavidson and others added 3 commits October 9, 2026 11:38
Changing the admin password blacklists the current session token. If the
dead token stays in the cookie, every page load sends it with the bootstrap
GET /system/environment and DF answers 403 "The token has been blacklisted:
Session terminated. Please re-login". The error interceptor only cleared
the token on 401, and returned early for silent requests (the environment
call is silent), so the login page never rendered until the user cleared
browser storage by hand.

- errorInterceptor: a 401/403 whose message says the token was blacklisted,
  terminated or expired, on a request that carried a session token, now
  clears the token, routes to login, and retries the request once without
  the token. This runs before the silent opt-out, so bootstrap recovers.
- normalizeError: such 403s normalize to kind auth instead of forbidden.
- DfPasswordService.updatePassword: only store a session token the server
  actually returned.
- Tests cover the bootstrap recovery, the single retry, plain 403s, plain
  401s, and staying put on the login page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ckers-presentation-mode

Brings the dead-session recovery into the branch df-dev runs. Conflict in
error.interceptor.ts resolved by keeping the trial-lock branch first (it
must win over the dead-session check, and still applies to silent
requests), then the dead-session clear-and-retry, then the existing
severity routing. error.interceptor.spec.ts now holds both the trial-lock
and the dead-session suites. dist rebuilt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants