fix: open the selected channel settings
This commit is contained in:
@@ -2709,6 +2709,13 @@ describe('App', () => {
|
|||||||
])
|
])
|
||||||
)
|
)
|
||||||
expect(screen.getAllByText('尚无远程会话').length).toBeGreaterThan(0)
|
expect(screen.getAllByText('尚无远程会话').length).toBeGreaterThan(0)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: '打开设置' }))
|
||||||
|
|
||||||
|
const channelSettingsTab = await screen.findByRole('tab', {
|
||||||
|
name: '消息通道'
|
||||||
|
})
|
||||||
|
expect(channelSettingsTab).toHaveAttribute('aria-selected', 'true')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows client-created remote conversations without obsolete approval copy', async () => {
|
it('shows client-created remote conversations without obsolete approval copy', async () => {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ import type {
|
|||||||
ConversationToolActivity,
|
ConversationToolActivity,
|
||||||
ProjectCreateInput,
|
ProjectCreateInput,
|
||||||
InteractiveWorkMode,
|
InteractiveWorkMode,
|
||||||
|
ProjectChannel,
|
||||||
WorkspaceChanges
|
WorkspaceChanges
|
||||||
} from '../../shared/assistant-contracts'
|
} from '../../shared/assistant-contracts'
|
||||||
import {
|
import {
|
||||||
@@ -132,6 +133,7 @@ import {
|
|||||||
type SidebarArtifact
|
type SidebarArtifact
|
||||||
} from './RightAssistantSidebar'
|
} from './RightAssistantSidebar'
|
||||||
import { SettingsPanel } from './SettingsPanel'
|
import { SettingsPanel } from './SettingsPanel'
|
||||||
|
import type { SettingsCategoryId } from './settings-categories'
|
||||||
import goodbuddyDarkIcon from './assets/goodbuddy-dark.png'
|
import goodbuddyDarkIcon from './assets/goodbuddy-dark.png'
|
||||||
import goodbuddyLightIcon from './assets/goodbuddy-light.png'
|
import goodbuddyLightIcon from './assets/goodbuddy-light.png'
|
||||||
import {
|
import {
|
||||||
@@ -1448,6 +1450,10 @@ function App(): React.JSX.Element {
|
|||||||
Record<string, BrowserLiveState>
|
Record<string, BrowserLiveState>
|
||||||
>({})
|
>({})
|
||||||
const [view, setView] = useState<WorkspaceView>('chat')
|
const [view, setView] = useState<WorkspaceView>('chat')
|
||||||
|
const [settingsInitialCategory, setSettingsInitialCategory] =
|
||||||
|
useState<SettingsCategoryId>()
|
||||||
|
const [settingsInitialChannel, setSettingsInitialChannel] =
|
||||||
|
useState<ProjectChannel>()
|
||||||
const [magicNotesEnabled, setMagicNotesEnabled] = useState(false)
|
const [magicNotesEnabled, setMagicNotesEnabled] = useState(false)
|
||||||
const [searchQuery, setSearchQuery] = useState('')
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
const [conversationActionsId, setConversationActionsId] = useState('')
|
const [conversationActionsId, setConversationActionsId] = useState('')
|
||||||
@@ -5204,7 +5210,11 @@ function App(): React.JSX.Element {
|
|||||||
action={
|
action={
|
||||||
<button
|
<button
|
||||||
className="secondary-button"
|
className="secondary-button"
|
||||||
onClick={() => setView('settings')}
|
onClick={() => {
|
||||||
|
setSettingsInitialCategory('channels')
|
||||||
|
setSettingsInitialChannel(activeProject.channel)
|
||||||
|
setView('settings')
|
||||||
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
{t('chat.remote.openSettings')}
|
{t('chat.remote.openSettings')}
|
||||||
@@ -6773,10 +6783,16 @@ function App(): React.JSX.Element {
|
|||||||
<SettingsPanel
|
<SettingsPanel
|
||||||
appearanceTheme={appearanceTheme}
|
appearanceTheme={appearanceTheme}
|
||||||
heartbeats={assistantHeartbeats}
|
heartbeats={assistantHeartbeats}
|
||||||
|
initialCategory={settingsInitialCategory}
|
||||||
|
initialChannel={settingsInitialChannel}
|
||||||
magicNotesEnabled={magicNotesEnabled}
|
magicNotesEnabled={magicNotesEnabled}
|
||||||
onAppearanceThemeChange={setAppearanceTheme}
|
onAppearanceThemeChange={setAppearanceTheme}
|
||||||
onClearLocalData={clearLocalData}
|
onClearLocalData={clearLocalData}
|
||||||
onClose={() => setView('chat')}
|
onClose={() => {
|
||||||
|
setSettingsInitialCategory(undefined)
|
||||||
|
setSettingsInitialChannel(undefined)
|
||||||
|
setView('chat')
|
||||||
|
}}
|
||||||
onCreateHeartbeat={createHeartbeat}
|
onCreateHeartbeat={createHeartbeat}
|
||||||
onExpertsChanged={(experts) => {
|
onExpertsChanged={(experts) => {
|
||||||
setAssistantExperts(experts)
|
setAssistantExperts(experts)
|
||||||
|
|||||||
@@ -616,6 +616,35 @@ describe('ChannelSettingsSection', () => {
|
|||||||
).toBeInTheDocument()
|
).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('opens the requested channel configuration', async () => {
|
||||||
|
Object.defineProperty(window, 'goodbuddy', {
|
||||||
|
configurable: true,
|
||||||
|
value: {
|
||||||
|
channels: {
|
||||||
|
...bindingApi(),
|
||||||
|
getSnapshot: vi.fn(async () => snapshot),
|
||||||
|
apply: vi.fn(),
|
||||||
|
testConnection: vi.fn()
|
||||||
|
},
|
||||||
|
projects: {
|
||||||
|
list: vi.fn(async () => projects),
|
||||||
|
update: vi.fn()
|
||||||
|
},
|
||||||
|
settings: settingsApi()
|
||||||
|
} as unknown as DesktopApi
|
||||||
|
})
|
||||||
|
|
||||||
|
render(<ChannelSettingsSection initialChannel="wecom" />)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByRole('tab', { name: '企业微信' })
|
||||||
|
).toHaveAttribute('aria-selected', 'true')
|
||||||
|
expect(screen.getByRole('tabpanel')).toHaveAttribute(
|
||||||
|
'aria-labelledby',
|
||||||
|
'channel-settings-tab-wecom'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('renders English channel copy while preserving project data', async () => {
|
it('renders English channel copy while preserving project data', async () => {
|
||||||
Object.defineProperty(window, 'goodbuddy', {
|
Object.defineProperty(window, 'goodbuddy', {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
|
|||||||
@@ -972,8 +972,10 @@ function WeixinChannelEditor({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ChannelSettingsSection({
|
export function ChannelSettingsSection({
|
||||||
|
initialChannel = 'weixin',
|
||||||
onNotify = () => undefined
|
onNotify = () => undefined
|
||||||
}: {
|
}: {
|
||||||
|
initialChannel?: ProjectChannel
|
||||||
onNotify?: (notification: AppNotificationInput) => void
|
onNotify?: (notification: AppNotificationInput) => void
|
||||||
}): React.JSX.Element {
|
}): React.JSX.Element {
|
||||||
const { t } = useTranslation('integrations')
|
const { t } = useTranslation('integrations')
|
||||||
@@ -999,7 +1001,7 @@ export function ChannelSettingsSection({
|
|||||||
const [bindingOpen, setBindingOpen] = useState(false)
|
const [bindingOpen, setBindingOpen] = useState(false)
|
||||||
const [bindingError, setBindingError] = useState<string>()
|
const [bindingError, setBindingError] = useState<string>()
|
||||||
const [activeChannel, setActiveChannel] =
|
const [activeChannel, setActiveChannel] =
|
||||||
useState<ProjectChannel>('weixin')
|
useState<ProjectChannel>(initialChannel)
|
||||||
const [drafts, setDrafts] = useState<
|
const [drafts, setDrafts] = useState<
|
||||||
Record<CredentialChannel, ChannelDraft>
|
Record<CredentialChannel, ChannelDraft>
|
||||||
>({
|
>({
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import type {
|
import type {
|
||||||
AssistantExpert,
|
AssistantExpert,
|
||||||
AssistantHeartbeatConfig,
|
AssistantHeartbeatConfig,
|
||||||
HeartbeatCreateInput
|
HeartbeatCreateInput,
|
||||||
|
ProjectChannel
|
||||||
} from '../../shared/assistant-contracts'
|
} from '../../shared/assistant-contracts'
|
||||||
import type {
|
import type {
|
||||||
AgentRuntimeDetection,
|
AgentRuntimeDetection,
|
||||||
@@ -70,6 +71,8 @@ const settingsTabs = settingsCategoryList.map(({ id }) => id)
|
|||||||
type SettingsPanelProps = {
|
type SettingsPanelProps = {
|
||||||
open: boolean
|
open: boolean
|
||||||
presentation?: 'modal' | 'page'
|
presentation?: 'modal' | 'page'
|
||||||
|
initialCategory?: SettingsCategoryId
|
||||||
|
initialChannel?: ProjectChannel
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
onSaved: (settings: RuntimeSettings) => void
|
onSaved: (settings: RuntimeSettings) => void
|
||||||
onNotify?: (notification: AppNotificationInput) => void
|
onNotify?: (notification: AppNotificationInput) => void
|
||||||
@@ -351,6 +354,8 @@ function RuntimeConfigCard({
|
|||||||
export function SettingsPanel({
|
export function SettingsPanel({
|
||||||
open,
|
open,
|
||||||
presentation = 'modal',
|
presentation = 'modal',
|
||||||
|
initialCategory,
|
||||||
|
initialChannel,
|
||||||
onClose,
|
onClose,
|
||||||
onSaved,
|
onSaved,
|
||||||
onNotify = () => {},
|
onNotify = () => {},
|
||||||
@@ -461,7 +466,7 @@ export function SettingsPanel({
|
|||||||
const [detection, setDetection] = useState<AgentRuntimeDetection>()
|
const [detection, setDetection] = useState<AgentRuntimeDetection>()
|
||||||
const [detecting, setDetecting] = useState(false)
|
const [detecting, setDetecting] = useState(false)
|
||||||
const [activeTab, setActiveTab] =
|
const [activeTab, setActiveTab] =
|
||||||
useState<SettingsCategoryId>('runtime')
|
useState<SettingsCategoryId>(initialCategory ?? 'runtime')
|
||||||
const [modelType, setModelType] = useState<ModelType>('llm')
|
const [modelType, setModelType] = useState<ModelType>('llm')
|
||||||
const [speechModelDraftId, setSpeechModelDraftId] = useState<
|
const [speechModelDraftId, setSpeechModelDraftId] = useState<
|
||||||
string | null | undefined
|
string | null | undefined
|
||||||
@@ -2610,7 +2615,10 @@ export function SettingsPanel({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{activeTab === 'channels' && (
|
{activeTab === 'channels' && (
|
||||||
<ChannelSettingsSection onNotify={onNotify} />
|
<ChannelSettingsSection
|
||||||
|
initialChannel={initialChannel}
|
||||||
|
onNotify={onNotify}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{activeTab === 'roles' && (
|
{activeTab === 'roles' && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
Reference in New Issue
Block a user