Skip to content

fix(ui): align button states and action roles with UIKit #6250

fix(ui): align button states and action roles with UIKit

fix(ui): align button states and action roles with UIKit #6250

Triggered via pull request September 8, 2026 12:03
Status Cancelled
Total duration 26m 3s
Artifacts –

ci.yml

on: pull_request
Build Impact
24s
Build Impact
Shell Deploy Scripts
12s
Shell Deploy Scripts
Matrix: cli-test
Matrix: Impact-selected Linux / Relay Contract / build
Waiting for pending jobs
Matrix: rust-build-check
DSH Profile Packaging (windows-latest)
0s
DSH Profile Packaging (windows-latest)
Frontend Build
8m 14s
Frontend Build
Rust / CLI Validation
6s
Rust / CLI Validation
Fit to window
Zoom out
Zoom in

Annotations

11 errors and 11 warnings
Frontend Build
Process completed with exit code 1.
src/app/scenes/profile/views/AssistantCard.test.tsx > AssistantCard actions > disables session actions while a new session is starting: src/web-ui/src/app/scenes/profile/views/AssistantCard.test.tsx#L160
TypeError: Cannot read properties of null (reading 'disabled') ❯ src/app/scenes/profile/views/AssistantCard.test.tsx:160:23
src/app/scenes/profile/views/AssistantCard.test.tsx > AssistantCard actions > disables card actions while setting the primary assistant: src/web-ui/src/app/scenes/profile/views/AssistantCard.test.tsx#L137
TypeError: Cannot read properties of null (reading 'disabled') ❯ src/app/scenes/profile/views/AssistantCard.test.tsx:137:23
src/app/scenes/profile/views/AssistantCard.test.tsx > AssistantCard actions > keeps configuration and new-session actions distinct: src/web-ui/src/app/scenes/profile/views/AssistantCard.test.tsx#L101
TypeError: Cannot read properties of null (reading 'click') ❯ src/app/scenes/profile/views/AssistantCard.test.tsx:101:26 ❯ Proxy.act ../../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.development.js:2512:16 ❯ src/app/scenes/profile/views/AssistantCard.test.tsx:101:5
src/infrastructure/config/components/VoiceInputConfig.presentation.test.ts > VoiceInputConfig status presentation > renders setup and ready states as compact body copy: src/web-ui/src/infrastructure/config/components/VoiceInputConfig.presentation.test.ts#L29
AssertionError: expected 'import { Button, Input, Select, type …' to contain 'variant={status === \'setup\' ? \'fil…' - Expected + Received - variant={status === 'setup' ? 'fill' : 'outline'} + import { Button, Input, Select, type SelectOption, StatusPill, type StatusPillTone, Switch } from '@openbitfun/ui'; + import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; + import { Trans, useTranslation } from 'react-i18next'; + import { CloudOff, HardDrive } from 'lucide-react'; + import { + LOCAL_SENSEVOICE_SMALL_INT8_MODEL_ID, + speechAPI, + type SpeechModelStatus, + type SpeechRealtimeConfig, + } from '@/infrastructure/api'; + import { isTauriRuntime } from '@/infrastructure/runtime'; + import { notificationService } from '@/shared/notification-system'; + import { createLogger } from '@/shared/utils/logger'; + import { useAIExperienceSettings } from '../hooks'; + import { aiExperienceConfigService } from '../services/AIExperienceConfigService'; + import type { VoiceInputSettings } from '../types'; + import LocalVoiceModelsConfig from './LocalVoiceModelsConfig'; + import { VoiceInputDiagnostics } from './VoiceInputDiagnostics'; + import { + ConfigPageContent, + ConfigPageHeader, + ConfigPageLayout, + ConfigLoadingState, + ConfigMessage, + ConfigPageRow, + ConfigPageSection, + ConfigRetryState, + } from './common'; + import './VoiceInputConfig.scss'; + + const log = createLogger('VoiceInputConfig'); + const DEFAULT_LOCAL_VOICE_MODEL_ID = LOCAL_SENSEVOICE_SMALL_INT8_MODEL_ID; + + function formatBytes(bytes: number): string { + if (!Number.isFinite(bytes) || bytes <= 0) return '0 B'; + const units = ['B', 'KiB', 'MiB', 'GiB']; + let value = bytes; + let unitIndex = 0; + while (value >= 1024 && unitIndex < units.length - 1) { + value /= 1024; + unitIndex += 1; + } + const digits = value >= 10 || unitIndex === 0 ? 0 : 1; + return `${value.toFixed(digits)} ${units[unitIndex]}`; + } + + type VoiceInputStatus = + | 'ready' + | 'setup' + | 'downloading' + | 'verifying' + | 'deleting' + | 'unavailable' + | 'error'; + + function statusBadgeVariant(status: VoiceInputStatus): StatusPillTone { + switch (status) { + case 'ready': + return 'success'; + case 'downloading': + case 'verifying': + return 'info'; + case 'unavailable': + case 'error': + return 'danger'; + default: + return 'neutral'; + } + } + + function statusActionKey(status: VoiceInputStatus): string { + switch (status) { + case 'setup': + return 'status.downloadModel'; + case 'downloading': + case 'verifying': + case 'deleting': + return 'status.viewDetails'; + case 'error': + return 'status.repair'; + default: + return 'status.manageModels'; + } + } + + const VoiceInputConfig: React.FC = () => { + const { t } = useTranslation('settings/voice-input'); + const speechRuntimeSupported = isTauriRuntime(); + const { + settings, + isLoading: settingsLoading, + error: settingsError, + reload: reloadSettings, + } = useAIExperienceSettings(); + const [models, setModels] = useState<SpeechModelStatus[]>([]); + const [modelsLoading, setModelsLoading] = useState(speechRuntimeSupported); + const [modelsLoadFailed, setModelsLoadFailed] = useState(false); + const [voiceInputSaving, setVoiceInputSaving] = useState(false); + const [busyAction, setBusyAction] = useState<string | null>(null); + const [localModelsOpen, setLocalModelsOpen] = useState(false); + const [voiceCallDraft, setVoiceCallDraft] = useState<SpeechRealtimeConfig | null>(null); + const voiceCallConfigRef = useRef<SpeechRealtimeConfig | null>(null); + const persistedVoiceCallConfigRef = useRef<SpeechRealtimeConfig | null>(null); + const [voiceCallLoading, setVoiceCallLoading] = useState(speechRuntimeSupported); + const [voiceCallLoadFailed, setVoiceCallLoadFailed] = useState(false); + const [voiceCallSaveError, setVoiceCallSaveError] = useState<string | null>(null); + const voiceCallR
src/infrastructure/config/components/ModelSettingsDialog.presentation.test.ts > ModelSettingsPage dialog presentation > keeps model configuration editors at a moderate responsive size: src/web-ui/src/infrastructure/config/components/ModelSettingsDialog.presentation.test.ts#L33
AssertionError: expected 'open={isEditing && !!editingConfig}\n…' to contain '<Button variant="outline" size="sm" o…' - Expected + Received - <Button variant="outline" size="sm" onClick={requestCloseEditingModal} disabled={isEditorSaving}> + open={isEditing && !!editingConfig} + onOpenChange={(nextOpen) => { + if (!nextOpen && !isEditorSaving) { + if (reasoningPanelDraft) finishReasoningPanel(); + else requestCloseEditingModal(); + } + }} + className="openbitfun-model-settings__editor-dialog" + size="xl" + > + <DialogHeader> + <DialogHeading> + <DialogTitle>{reasoningPanelDraft + ? t('reasoningPresets.dialogTitle', { + provider: editingConfig?.name?.trim() + || currentTemplate?.name + || editingConfig?.provider + || '', + model: reasoningPanelDraft.modelName, + }) + : editingConfig?.id + ? t('editModel') + : (getProviderInstanceId(editingConfig) + ? t('editProvider') + : (currentTemplate ? `${t('newProvider')} - ${currentTemplate.name}` : t('newProvider')))}</DialogTitle> + </DialogHeading> + <DialogClose disabled={isEditorSaving} /> + </DialogHeader> + <DialogBody + inset="none" + aria-busy={isEditorSaving} + {...(isEditorSaving ? { inert: '' } : {})} + > + {reasoningPanelDraft ? ( + <ReasoningConfigPanel + key={reasoningPanelDraft.key} + value={reasoningPanelDraft.reasoning} + generatedProjection={reasoningPanelProjection} + modelsDevReasoningCatalog={modelCatalog?.models_dev_reasoning_catalog} + projectionRequest={reasoningPanelProjectionRequest} + requestFormatLabel={reasoningPanelProjectionRequest + ? requestFormatLabelMap[reasoningPanelProjectionRequest.provider] + || reasoningPanelProjectionRequest.provider + : undefined} + onCancel={cancelReasoningPanel} + onDraftChange={updateReasoningPanelDraft} + onApply={(result: ReasoningConfigApplyResult) => { + updateReasoningPanelDraft(result); + finishReasoningPanel(); + }} + /> + ) : renderEditingForm()} + </DialogBody> + {!reasoningPanelDraft && ( + <DialogFooter> + <Button variant="fill" size="sm" onClick={requestCloseEditingModal} disabled={isEditorSaving}> + {t('actions.cancel')} + </Button> + <Button + data-testid="settings-model-save-btn" + variant="primary" + size="sm" + onClick={() => void handleSave()} + loading={isEditorSaving} + > + {t('actions.save')} + </Button> + </DialogFooter> + )} + </Dialog> + ❯ src/infrastructure/config/components/ModelSettingsDialog.presentation.test.ts:33:26
src/tools/generative-widget/appearancePayload.test.ts > generated widget appearance payload contract > derives its complete host payload allowlist from the canonical theme package: src/web-ui/src/tools/generative-widget/appearancePayload.test.ts#L67
AssertionError: expected { count: 140, …(3) } to deeply equal { count: 127, …(3) } - Expected + Received { - "count": 127, + "count": 140, "first": "--openbitfun-color-accent-border", - "hash": "e80ebcdf9452a0b5f8ab26d9b41cb81c4e74d75451e4402f99afc68af3c13f42", + "hash": "b9e8ed7d5fdc8a39768649aaf3643f7a6bef1d79c08b3f969f1798016f2d44ae", "last": "--openbitfun-shadow-xs", } ❯ src/tools/generative-widget/appearancePayload.test.ts:67:8
Rust Build Check (windows-latest)
Canceling since a higher priority waiting request for ci-refs/pull/2901/merge exists
Rust Build Check (windows-latest)
The operation was canceled.
Rust / CLI Validation
Process completed with exit code 1.
CI
Canceling since a higher priority waiting request for ci-refs/pull/2901/merge exists
Frontend Build: src/web-ui/src/shared/announcement-system/components/ReleaseLetterModal.tsx#L22
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/flow_chat/tool-cards/AgentWaitToolCard.tsx#L17
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/flow_chat/components/voice/RealtimeVoiceCallContext.tsx#L32
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/flow_chat/components/voice/RealtimeVoiceCallContext.tsx#L23
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/flow_chat/components/modern/MessageReferenceCapsule.tsx#L29
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/flow_chat/components/modern/MessageReferenceCapsule.tsx#L7
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/flow_chat/components/ReasoningPresetSelector.tsx#L112
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/flow_chat/components/ReasoningPresetSelector.tsx#L36
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/app/components/SceneTopBar/SceneChrome.tsx#L121
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Frontend Build: src/web-ui/src/app/components/NavPanel/components/DeviceArtwork.tsx#L6
Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Tauri Windows test-loader limitation
The desktop test harness hit upstream Tauri issue #13419 before any Rust test ran. Compilation and the cross-platform product-control contracts remain blocking.