refactor(ui): redesign frontend UX + chat/endpoint improvements#156
Merged
Conversation
- 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
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.
# 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
shubham3121
reviewed
Jun 3, 2026
Member
There was a problem hiding this comment.
This seems duplicate now, with the existing Payment Ledger, LedgerEntry and User Balance entities and services.
# Conflicts: # backend/syft_space/components/policy_types/prepaid/__init__.py # frontend/src/components/AddPricingRuleDialog.vue
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.
Summary
Long-running
redesign_uxbranch covering a frontend UX overhaul and supporting backend/feature work:AppTopbar, extractedSidebarNavItem, removed inbox and mock-data dead codeLocalChatHandlerwith timeouts and error classification, improved data-only/combined endpoint flowsystem_promptin endpoint responses, error-classification extraction in chat100 files changed, +7604 / −4563.
Test plan
cd frontend && bun run typecheck && bun run lintcd frontend && bun run test:unit