Skip to content

refactor(ui): redesign frontend UX + chat/endpoint improvements#156

Merged
itstauq merged 35 commits into
mainfrom
redesign_ux
Jun 5, 2026
Merged

refactor(ui): redesign frontend UX + chat/endpoint improvements#156
itstauq merged 35 commits into
mainfrom
redesign_ux

Conversation

@IonesioJunior

Copy link
Copy Markdown
Member

Summary

Long-running redesign_ux branch covering a frontend UX overhaul and supporting backend/feature work:

  • UX redesign: refreshed home dashboard, unified page widths, restructured endpoint/dataset/model detail pages, moved resource search from sidebar into new AppTopbar, extracted SidebarNavItem, removed inbox and mock-data dead code
  • Endpoints: slug-based routing, API type badges, per-endpoint system-prompt override (OME-235), endpoints store with freshness caching + dedup + invalidation
  • Chat: endpoint-based preview replacing local chat, markdown rendering for assistant responses, system-prompt passthrough, no-models empty state + submit shortcut (OME-…), hardened LocalChatHandler with timeouts and error classification, improved data-only/combined endpoint flow
  • Policies: end-to-end PII filter policy (OME-234) — backend regex replaced with AI-model-powered redaction; PII Filter toggle in publish wizard
  • Datasets: block deletion when in use by an endpoint
  • Backend: concurrent-safe prepaid quota decrement + tenant-scoped purges, async parallelism in endpoints, system_prompt in endpoint responses, error-classification extraction in chat

100 files changed, +7604 / −4563.

Test plan

  • cd frontend && bun run typecheck && bun run lint
  • cd frontend && bun run test:unit
  • Home dashboard: verify first-time vs returning user states render correctly
  • Endpoints: create / publish / edit / delete; verify slug routing, system-prompt override persists
  • Chat: data-only, model-only, and combined endpoints; markdown rendering; PII filter masks expected fields
  • Datasets: deletion blocked when referenced by an endpoint
  • Topbar resource search: dataset / model / endpoint lookups + keyboard nav
  • Backend: prepaid quota decrement under concurrent requests stays consistent

IrinaMBejan and others added 30 commits April 10, 2026 08:35
- Restyle homepage with gradient hero, stat cards, and quick-nav buttons
- Unify resource listing pages (Data Sources, Models, APIs) with consistent card styling
- Consolidate Go Live into a single "Publish" flow supporting data, model, or both
- Add inline create modals for data sources and models within the publish form
- Redesign endpoint detail policies tab with stacked layout replacing card grid
- Rename "Live" to "APIs", "Go Live" to "Publish", "Authorization" to "Access Control",
  "Rate Limiter" to "Usage Limits", and "endpoint" to "resource" in user-facing text
- Add sidebar navigation with collapsible layout and sheet component
- Simplify create dataset/model dialogs with clearer terminology
- Add AI response configuration with prompt presets (summarise & cite/filter)
- Rename Analytics tab to Progress on dataset detail page

Made-with: Cursor
…in UI

Add a Local Chat page (backend + frontend) that lets users select a model
and optionally a data source to test their resources in a multi-turn
conversation without publishing an endpoint. Includes collapsible
references panel for validating data source search results.

Also rename user-facing "endpoint" terminology to "API" across all pages,
components, dialogs, toasts, and mock data for consistency with the
sidebar navigation label.

Made-with: Cursor
…scope labels

Add a toggleable PII Filter card in the Configure step with info tooltip
and review summary. Update rate limit scope options to "Per User" / "Per
Full API" for clarity.

Made-with: Cursor
…n, tests (OME-233) (#136)

LocalChatHandler previously had no upstream timeout — a hung model call
would block the request indefinitely — and both _search_dataset and
_chat_with_model classified every upstream failure as a bare HTTP 500,
hiding the real cause. It also had zero test coverage.

This change:
- Wraps dataset search and model chat invocations in asyncio.wait_for
  using a new configurable CHAT_TIMEOUT_SECONDS setting (default 60s).
- Classifies exceptions at each call site:
  * asyncio.TimeoutError   -> 504 "Chat/dataset request timed out"
  * httpx.HTTPError / ConnectionError -> 502 "upstream error: ..."
  * KeyError on type registry -> 400 "type not registered"
    (previously 500 for models, now matches dataset path)
  * Existing 404 for missing model/dataset preserved
  * Unknown errors -> 500, full traceback still logged
- Fixes a latent bug: Context.sender is an EmailStr, so the hardcoded
  "local-chat" sender would ValidationError on every real request.
  Replaced with a synthetic but valid placeholder email constant.
- Adds a hermetic pytest suite (14 tests) covering happy paths, timeout
  classification, upstream error classification, missing/unregistered
  model+dataset, empty model responses, unexpected errors, and tenant
  isolation for both model and dataset lookups. All mocks — no network.

Public chat() signature and route contract are unchanged.
Adds a regex-based pii_filter policy type that redacts email, phone,
SSN, and credit card PII from endpoint responses in the post_hook
phase. Credit card matches are validated with Luhn to avoid redacting
arbitrary digit runs. JSON structure is preserved — only string leaves
are mutated.

Wires the existing "PII Filter" toggle in the publish wizard through
useGoLive so flipping it produces a real pii_filter policy with the
default category set on publish. Also adds the plumbing (types,
validation, transform, form dialog branch) for pii_filter rules in the
shared policy creation composable so future UIs can configure it.
#137)

* feat(endpoints): persist per-endpoint system prompt override (OME-235)

Add a nullable system_prompt column on Endpoint and, at query time,
inject it into the messages passed to model_instance.chat so it takes
precedence over the model's default system prompt. If the caller already
supplied a leading system message, replace its content; otherwise insert
a new one. Wire the field through CreateEndpointRequest,
UpdateEndpointRequest, and EndpointResponse, the repository update path,
and the frontend CreateEndpointRequest / useModelEndpointCreation flow.

Reversible Alembic migration adds the column; unit tests cover insert,
replace, and pass-through cases.

* fix(endpoints): wire systemPrompt through useGoLive.createEndpoint (OME-235)

The Go-Live wizard already collected systemPrompt but never forwarded it
to the endpoint create request. Pass it through so the new endpoint
system_prompt column actually gets populated from the redesigned publish
flow.
- Surface load failures via vue-sonner toast + console.error instead of
  silently swallowing errors; retain non-fatal behavior so the UI keeps
  rendering.
- Expand the client-side filter to match name, summary, and tags (tags
  normalized via parseTags so comma-separated strings and arrays both
  work).
- Add keyboard navigation: ArrowUp/ArrowDown move a highlighted index
  through the filtered results, Enter navigates, Escape clears and
  blurs; highlight resets to 0 whenever the filtered results change.
- Expose combobox/listbox ARIA roles and aria-activedescendant so
  assistive tech can follow the highlighted option.
- Replace the route-path watcher with a 30s TTL on the cached resource
  list (plus an in-flight de-dupe promise) so the dropdown freshens
  without re-fetching on every keystroke or unrelated navigation.
- Reuse useNavigation route helpers, fixing the broken dataset/model
  detail params (now passes slug instead of name).
…ME-233) (#134)

Fill missing UX edges in ChatPage.vue:
- Render a shadcn Alert with an "Add a model" CTA linking to the models
  page when the user has zero models loaded.
- Submit on Ctrl/Cmd+Enter from the textarea (Shift+Enter still inserts a
  newline); guard against firing while a modal dialog is open.
- Rename canSend to canSubmit and ensure the submit button is disabled
  when the input is empty, no model is selected, or a request is in flight.
- Add optional system_prompt field to LocalChatRequest; prepended as first
  system message before any references context
- Extract duplicated timeout/upstream/generic catch blocks into a single
  _classify_upstream_errors async context manager (504/502/500 classification)
- Tighten ChatMessage.role to Literal["user","assistant","system"]
- Add two tests: system prompt prepended first, system prompt precedes
  references context
- Switch publish, unpublish, and checkSlugAvailability from sequential for
  loops to asyncio.gather
- Add system_prompt field to EndpointDetailResponse schema
…chase lookup

- Rewrite decrement_quota as a single UPDATE ... WHERE remaining_quota > 0 —
  concurrent-safe, returns bool indicating whether a row was updated
- post_hook uses max(before - 1, 0) when decremented; avoids going negative
- get_purchase_by_id accepts tenant_id, returns None on mismatch (removes
  separate fetch + tenant check in handler)
- Parallel asyncio.gather for subscriber + purchase lookups in handlers
- Condense verbose module/class docstrings
…lidate

- EndpointItem gains modelId, datasetId, systemPrompt fields from API response
- 30s freshness window + in-flight dedup so components can call fetchEndpoints
  freely without hammering the API
- Add invalidate() helper; called after endpoint creation (data/model flows)
  and after deletion
…+ AbortController

- ChatPage selects published APIs from endpoints store instead of raw
  models/datasets; surfaces modelId/datasetId/systemPrompt from the endpoint
- useLocalChat.sendMessage takes SendMessageOptions object, drops reactive
  modelId/datasetId refs
- AbortController cancels in-flight requests on new send and on unmount
- chatApi.send accepts { signal } option
- Empty state updated: "No APIs with a model" pointing to GoLive
- Enter key submits without requiring Ctrl/Cmd modifier
…rage

- Extract ~150 lines of repeated collapsed/expanded button+tooltip markup
  into SidebarNavItem.vue
- Resolve nav items once via computed() instead of re-evaluating per render
- Replace manual localStorage + watch in useSidebar with useStorage from
  vueuse/core
- Clear blur timer on unmount with onBeforeUnmount
…cleanup

- Remove inline dataset/model creation from GoLive; createDatasetIfNeeded
  and createModelIfNeeded and their newDataSource/newModel inputs dropped
- aiModelName becomes a computed from the already-loaded models list, removing
  a watch + extra API call
- Policy creation parallelized with Promise.all; endpoint_id assigned before
  passing to create (fixes PII filter bug where endpoint_id was empty string)
- openAiConfigDialog called with mode.id instead of hardcoded 'both'
- Switch uses v-model instead of :checked + @update:checked
- nameDebounce cleared on unmount; errors logged in catch blocks
- useNavigation stripped of ~80 lines of dead route helpers
- Endpoints store invalidated after publish
- Delete mock stores: mockEndpoints.ts, models.ts
- Delete unused create-resource components: CreateDatasetDialog.vue,
  CreateEndpointModal.vue, CreateModelDialog.vue, CreateResourceDialog.vue
- Delete unused composables: useCreateEndpointForm.ts, useDashboardStats.ts
- Remove ~280 lines of hardcoded mock inbox items from inbox store
…cleanup

- Extract getInboxSourceIcon/getInboxSourceColor into lib/inboxFormatters.ts,
  removing duplicate implementations in HomePage and InboxPage
- Fix slug availability check: use m.available !== false so a null marketplace
  status doesn't falsely block publication (CreateDataEndpointPage,
  CreateModelEndpointPage, GoLivePage)
- DatasetDetailPage: parallelize type info + ingestion data load with
  Promise.all
- markdown.ts: remove inline Tailwind styles from regex replacements
- policyTypes.ts: replace deprecated substr with slice
Endpoint detail navigation was broken for endpoints with spaces or
special characters in their names because router.push was passing
endpoint.name ("Legal Q&A") instead of endpoint.slug ("legal-qa").
The detail page queries by slug, so all such endpoints returned 404.

Also adds inline "Data API" (blue) and "Model API" (purple) badges
next to endpoint names so users can distinguish endpoint archetypes
at a glance.
Backend now raises HTTP 409 Conflict when a delete is attempted on a
dataset that is attached to one or more endpoints, returning the names
of the blocking APIs in the error detail.

Frontend replaces the previous cascade-delete checkbox flow with a
hard block: when dependencies exist the Delete button is hidden and an
amber warning panel lists which APIs must be removed first.
Go Live wizard: data-only endpoints published with raw response mode
now show a blue "search-only" info callout in step 2 and an "API Type"
field in the review summary, making it clear they won't appear in the
Chat model selector.

Chat page: fix dataApis filter to exclude combined endpoints (they
already contribute their dataset via the model selector), add a context
fallback so combined endpoint datasets are used automatically, and show
"Override context" as the placeholder when a combined endpoint is
selected.
…ix model id type

- chat/handlers: remove [:3] slice so all retrieved documents are
  included in the context window, not just the first three
- chromadb_type + weaviate_type: use `is not None` for similarity
  threshold comparison to correctly handle a threshold of 0.0
- models/repository: fix get_by_id signature from int to UUID to match
  the actual id type used across the schema
Remove the standalone local chat module and replace it with chat routed
through the published endpoint pipeline.  The owner now tests their API
via POST /{slug}/preview — identical to /query but authenticated with the
admin key — so they see exactly what external users experience: policies,
filters, rate limits, and all.

- Delete backend chat component (handlers, routes, schemas, tests)
- Add POST /{slug}/preview route (admin-auth wrapper around /query)
- Return (summary, model_instance, model_id) from _chat_with_model so
  post-hook policies (e.g. pii_filter) can access the live model
- Fix stop_sequences default to [] (was ["\n"])
- Delete frontend chat.ts API module; add endpointsApi.query()
- Rename useLocalChat → useEndpointChat, rewrite to send via slug
- Simplify ChatPage to a single endpoint selector (all endpoint types)
…tion

The previous implementation used hardcoded regex patterns per category
(email, phone, SSN, credit card).  This replaces it with a post-hook that
sends the model's own response back to the model with a redaction prompt,
letting the model identify and replace PII with [REDACTED] contextually.

Backend:
- Rewrite PiiFilterPolicyType to use model_instance from policy context
- Skip silently on data-only endpoints (no model_instance available)
- Update tests to match new model-delegation approach

Frontend:
- Remove category checkboxes and replacement-token input — zero config
- Restrict PII filter toggle to model endpoints only (GoLivePage)
- Auto-disable PII filter when model is deselected
- Update policy summary label and descriptions throughout
Key integration points:
- Accept EndpointHandler split (CRUD/QueryEndpointHandler/PublishEndpointHandler)
- Apply model-instance context passing to QueryEndpointHandler._chat_with_model
  so PiiFilterType post-hook can access the live model for AI-powered redaction
- Keep POST /{slug}/preview route (wired to QueryEndpointHandler)
- Register both PiiFilterType and XenditAccountingPolicy in policy registry
- Add system_prompt field back to create_endpoint
- Keep go-live route; add earnings route alongside it
- Expand useNavigation with new helper functions from main
- Accept origin/main's simplified AppNavbar and SettingsPage
- Accept origin/main's EndpointDetailPage access tab (card grid + pricing summary)
- Merge usePolicyCreation pricing config (mpp_accounting vs xendit split + pii_filter empty config)
Remove InboxPage, inbox store, inbox formatters, sidebar nav entry,
navbar badge, router route, and all related imports and dialog logic
from HomePage.
Reworks layout, navigation, and detail pages on the redesign_ux branch:
move resource search from sidebar to new AppTopbar, unify page widths,
streamline endpoint/dataset/model detail pages, and refresh home dashboard.

Includes simplify pass: drop dead try/catch in HomePage formatTxTime,
fold EndpointDetailPage status-label switches into a lookup table, and
index ingestion jobs once for getStatsForPath (O(P*J) -> O(P+J)).
Fan out /preview calls to selected data source endpoints in parallel,
merge their references with provenance, and inject the merged docs as
a system message before invoking the model endpoint /preview.

- useEndpointChat: parallel data-source fan-out + merge + augmented model call
- Partial fan-out failures surface as a non-fatal warning, not a destructive error
- ChatPage: pass selected data sources, show source-name badge per doc
- ChatDocumentResponse: optional source_endpoint_slug/name (client-stamped)
- EndpointQueryMessage.role: widened to include 'system'
- Delete unused lib/markdown.ts and lib/mappers.ts (zero imports;
  ChatPage uses vue-markdown-render directly, mappers held mock names).
- Add parseTags helper to lib/formatters.ts; consume from AppTopbar and
  the endpoints store, replacing two inline implementations.
- stores/endpoints.ts: drop price/languages/mcpCompatible/domains from
  EndpointItem — never read by any consumer.
- usePolicyCreation: hoist helpers to module scope, drop unused exports
  (createAuthorizationPolicy/createRateLimitPolicy/etc., processUserList,
  generatePolicyName, validate* sub-forms, reset). Public surface is
  now just createPolicy, transformPolicyRules, validatePolicyForm.
- useNavigation: remove liveDetail (identical to endpointDetail); update
  AppTopbar caller.
- useEndpointChat.clearChat now aborts in-flight requests and resets
  loading — previously a late response could land on an empty turn list.
- Strip narration comments across EditEndpointDialog, CreateDataset/Model
  DialogSimple, PolicyFormDialog, AddPricingRuleDialog per the explicit
  "NEVER leave historical comments" rule in frontend/CLAUDE.md.

This comment was marked as spam.

# Conflicts:
#	backend/syft_space/components/endpoints/query_handler.py
#	backend/syft_space/components/policy_types/__init__.py
#	frontend/bun.lockb
#	frontend/src/composables/useNavigation.ts
#	frontend/src/composables/usePolicyCreation.ts
#	frontend/src/pages/AnalyticsPage.vue
#	frontend/src/pages/EarningsPage.vue
#	frontend/src/pages/EndpointDetailPage.vue
#	frontend/src/router/index.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems duplicate now, with the existing Payment Ledger, LedgerEntry and User Balance entities and services.

itstauq added 2 commits June 5, 2026 15:18
# Conflicts:
#	backend/syft_space/components/policy_types/prepaid/__init__.py
#	frontend/src/components/AddPricingRuleDialog.vue
@itstauq itstauq merged commit 092d1a8 into main Jun 5, 2026
2 checks passed
@itstauq itstauq deleted the redesign_ux branch June 5, 2026 13:14
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.

5 participants