mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-09 23:36:02 +00:00
Fix/frontend optimizations (#2088)
* fix(web): auto-redirect to wizard on first visit and change sidebar icons to blue * refactor(wizard): use backend metadata table instead of localStorage for wizard completion state - Add wizard_completed field to system info API (read from metadata table) - Add POST /api/v1/system/wizard/completed endpoint to mark wizard done - Frontend home layout checks systemInfo.wizard_completed for auto-redirect - Wizard calls markWizardCompleted API on skip/finish - Ensures consistent behavior across all browsers on the same instance * fix(wizard): update systemInfo in memory before navigation to prevent redirect loop * fix(monitoring): prevent horizontal overflow and unify empty state styles * fix(wizard): use Object.assign for systemInfo and await wizard completion API - Replace systemInfo reassignment with Object.assign in all 3 locations to preserve object identity across module imports - Await markWizardCompleted() POST in wizard skip/finish handlers instead of fire-and-forget to ensure backend persistence - Always re-fetch systemInfo in home layout to get latest wizard_completed state from backend * fix(wizard): prevent redirect loop by blocking navigation on failed status save - Refactor wizard_completed (boolean) to wizard_status (string: none/skipped/completed) - Remove ALL localStorage usage from wizard page (form state persistence) - Replace AlertDialogAction with Button so skip dialog stays open during POST - Add loading spinners for skip and complete actions - If POST fails, show error toast and keep dialog/button active for retry - If POST succeeds, update in-memory state and navigate * fix(wizard): fix row[0].value bug causing GET /info to always return wizard_status=none conn.execute(select(Entity)) returns Row with raw column values, not ORM entities. row[0] is the key column (a string), so row[0].value raises AttributeError which was silently swallowed by except-pass, making the GET endpoint always return wizard_status=none regardless of DB state. * fix(wizard): replace AlertDialog with Dialog for skip confirmation to remove slide animation * chore: optimize toast in wizard * fix(wizard): set default token value for Telegram adapter and initialize adapter config in wizard * feat(web): move webhook URL to dynamic form system, add market category filter, fix layout overflow - Add 'webhook-url' dynamic form field type rendered as read-only input with copy button, defined in adapter YAML specs instead of hardcoded in BotForm. Supports show_if conditions for optional-webhook adapters. - Remove hardcoded webhook display logic from BotForm.tsx, pass webhook URLs via systemContext to DynamicFormComponent. - Fetch webhook URLs after bot creation in wizard and pass to Step 1. - Support ?category= query param on /home/market page for filtering by component type (mirrors langbot-space behavior). - Link 'install knowledge engine' hint to /home/market?category=KnowledgeEngine. - Fix SidebarInset missing min-w-0 causing content overflow when sidebar is expanded. - Add vertical divider between plugin detail config and readme panels. - Fix infinite re-render loop in DynamicFormComponent by memoizing editableItems array. * fix: lint * fix(web): change systemInfo to const to satisfy prefer-const lint rule * fix: update adapter descriptions for clarity and usage requirements
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import quart
|
||||
import sqlalchemy
|
||||
|
||||
from .. import group
|
||||
from .....utils import constants
|
||||
from .....entity.persistence.metadata import Metadata
|
||||
|
||||
|
||||
@group.group_class('system', '/api/v1/system')
|
||||
@@ -9,6 +11,19 @@ class SystemRouterGroup(group.RouterGroup):
|
||||
async def initialize(self) -> None:
|
||||
@self.route('/info', methods=['GET'], auth_type=group.AuthType.NONE)
|
||||
async def _() -> str:
|
||||
# Read wizard_status from metadata table
|
||||
# Possible values: 'skipped', 'completed'; absent key means 'none'
|
||||
wizard_status = 'none'
|
||||
try:
|
||||
result = await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.select(Metadata).where(Metadata.key == 'wizard_status')
|
||||
)
|
||||
row = result.first()
|
||||
if row:
|
||||
wizard_status = row.value
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return self.success(
|
||||
data={
|
||||
'version': constants.semantic_version,
|
||||
@@ -27,9 +42,38 @@ class SystemRouterGroup(group.RouterGroup):
|
||||
'disable_models_service', False
|
||||
),
|
||||
'limitation': self.ap.instance_config.data.get('system', {}).get('limitation', {}),
|
||||
'wizard_status': wizard_status,
|
||||
}
|
||||
)
|
||||
|
||||
@self.route('/wizard/completed', methods=['POST'], auth_type=group.AuthType.USER_TOKEN)
|
||||
async def _() -> str:
|
||||
"""Mark wizard status in metadata table.
|
||||
|
||||
Accepts JSON body: { "status": "skipped" | "completed" }
|
||||
"""
|
||||
data = await quart.request.get_json(silent=True) or {}
|
||||
status = data.get('status', 'completed')
|
||||
if status not in ('skipped', 'completed'):
|
||||
return self.http_status(400, 400, f'Invalid wizard status: {status}')
|
||||
|
||||
try:
|
||||
result = await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.select(Metadata).where(Metadata.key == 'wizard_status')
|
||||
)
|
||||
if result.first():
|
||||
await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.update(Metadata).where(Metadata.key == 'wizard_status').values(value=status)
|
||||
)
|
||||
else:
|
||||
await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.insert(Metadata).values(key='wizard_status', value=status)
|
||||
)
|
||||
except Exception as e:
|
||||
return self.http_status(500, 500, f'Failed to update wizard status: {e}')
|
||||
|
||||
return self.success(data={})
|
||||
|
||||
@self.route('/tasks', methods=['GET'], auth_type=group.AuthType.USER_TOKEN)
|
||||
async def _() -> str:
|
||||
task_type = quart.request.args.get('type')
|
||||
|
||||
Reference in New Issue
Block a user