@nextclaw/ui 0.12.9 → 0.12.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/dist/assets/ChannelsList-SQ7Oxotv.js +8 -0
- package/dist/assets/DocBrowser-BCO2k6XD.js +1 -0
- package/dist/assets/{DocBrowser-6ReNjvzF.js → DocBrowser-rDOjI3ga.js} +1 -1
- package/dist/assets/{DocBrowserContext-B6SpA7Qs.js → DocBrowserContext-BUq3Wo8O.js} +1 -1
- package/dist/assets/{LogoBadge-ByNLYg65.js → LogoBadge-DP8Ye7wJ.js} +1 -1
- package/dist/assets/ModelConfig-C77Ae9ru.js +1 -0
- package/dist/assets/ProviderScopedModelInput-CEnK61uo.js +1 -0
- package/dist/assets/ProvidersList-BCupBayq.js +1 -0
- package/dist/assets/RuntimeConfig-Ad-CAcmy.js +1 -0
- package/dist/assets/SearchConfig-BfCz4wJ4.js +1 -0
- package/dist/assets/SecretsConfig-DjmBIhyy.js +3 -0
- package/dist/assets/{SessionsConfig-ChHQ7M5c.js → SessionsConfig-CvjxU40H.js} +2 -2
- package/dist/assets/{book-open-BdcxxoQu.js → book-open-BE8M56IM.js} +1 -1
- package/dist/assets/chat-page-JKC6ln-y.js +58 -0
- package/dist/assets/chat-session-display-YcRMrAMa.js +1 -0
- package/dist/assets/{chunk-JZWAC4HX-DK5HPmIK.js → chunk-JZWAC4HX-erTUn3b8.js} +1 -1
- package/dist/assets/client-CszWMVKi.js +7 -0
- package/dist/assets/config-split-page-BAGSzUR3.js +1 -0
- package/dist/assets/{createLucideIcon-BSeTgkZW.js → createLucideIcon-CCiTGX8L.js} +1 -1
- package/dist/assets/desktop-DfkLlkG2.js +1 -0
- package/dist/assets/desktop-update-config-BXeGlqHD.js +1 -0
- package/dist/assets/dialog-BghZFPch.js +5 -0
- package/dist/assets/{dist-6TrrnPCR.js → dist-Dd9cr-kz.js} +1 -1
- package/dist/assets/dist-ZwoAXs46.js +9 -0
- package/dist/assets/{download-BhDxnyvU.js → download-D7LOizcW.js} +1 -1
- package/dist/assets/es2015-CEAreese.js +41 -0
- package/dist/assets/{external-link-BgErLCNT.js → external-link-qsnCMhw1.js} +1 -1
- package/dist/assets/{hash-Bl7dr_UG.js → hash-0zjWsNl-.js} +1 -1
- package/dist/assets/{i18n-eDHeDY0n.js → i18n-DvzXOGQX.js} +1 -1
- package/dist/assets/index-DvVTC9FF.css +1 -0
- package/dist/assets/index-lr6rQUSd.js +2 -0
- package/dist/assets/key-round-BLe9D8ND.js +1 -0
- package/dist/assets/loader-circle-wj7kARHv.js +1 -0
- package/dist/assets/{logos-x89HbrZ4.js → logos-_v5b2SdG.js} +1 -1
- package/dist/assets/marketplace-page-CAAk1Khc.js +1 -0
- package/dist/assets/marketplace-page-CfCiq90S.js +49 -0
- package/dist/assets/mcp-marketplace-page-D0Pp9Hs-.js +40 -0
- package/dist/assets/play-o6NmwGTi.js +1 -0
- package/dist/assets/plus-I9pBS4Fl.js +1 -0
- package/dist/assets/{refresh-cw-C47QSEwg.js → refresh-cw-MNqgR3LZ.js} +1 -1
- package/dist/assets/remote-C9fXm4V5.js +1 -0
- package/dist/assets/{save-3S6-H3Xw.js → save-D4bObrmH.js} +1 -1
- package/dist/assets/search-DxmL3IWE.js +1 -0
- package/dist/assets/security-config-BUm6FFfl.js +1 -0
- package/dist/assets/select-BILPf7zs.js +1 -0
- package/dist/assets/setting-row-BATDgg4r.js +1 -0
- package/dist/assets/skeleton-COKMAnJy.js +1 -0
- package/dist/assets/{switch-BsLtHOH-.js → switch-CBOzecWS.js} +1 -1
- package/dist/assets/{tabs-custom-D3HYMt6k.js → tabs-custom-Bx3cNhD-.js} +1 -1
- package/dist/assets/tag-chip-zUaDE2-H.js +1 -0
- package/dist/assets/{trash-2-G48scll7.js → trash-2-CQUgYyRn.js} +1 -1
- package/dist/assets/use-infinite-scroll-loader-B5V2Klve.js +1 -0
- package/dist/assets/useConfirmDialog-patAnl1g.js +1 -0
- package/dist/assets/{useMutation-CBWjE2uj.js → useMutation-__AYv-Pz.js} +1 -1
- package/dist/assets/x-BHUGQIUv.js +1 -0
- package/dist/index.html +22 -22
- package/dist/runtime-icons/claude.ico +0 -0
- package/dist/runtime-icons/codex-openai.svg +6 -0
- package/dist/runtime-icons/hermes-agent.png +0 -0
- package/module-structure.config.json +7 -0
- package/package.json +6 -6
- package/public/runtime-icons/claude.ico +0 -0
- package/public/runtime-icons/codex-openai.svg +6 -0
- package/public/runtime-icons/hermes-agent.png +0 -0
- package/src/api/chat-session-type.types.ts +7 -0
- package/src/api/config.ts +10 -0
- package/src/api/raw-client.test.ts +1 -1
- package/src/api/{raw-client.ts → raw-client.utils.ts} +2 -0
- package/src/api/runtime-control.types.ts +8 -0
- package/src/api/types.ts +48 -0
- package/src/app/components/app-manager-provider.tsx +20 -0
- package/src/app/managers/app.manager.ts +12 -0
- package/src/app.tsx +223 -59
- package/src/components/agents/agent-dialogs.tsx +499 -0
- package/src/components/agents/agents-page.test.tsx +238 -0
- package/src/components/agents/agents-page.tsx +435 -0
- package/src/components/chat/chat-conversation-panel.test.tsx +30 -0
- package/src/components/chat/chat-conversation-panel.tsx +83 -13
- package/src/components/chat/chat-input/ncp-chat-input-availability.utils.test.ts +92 -0
- package/src/components/chat/chat-input/ncp-chat-input-availability.utils.ts +45 -0
- package/src/components/chat/chat-page-shell.tsx +19 -13
- package/src/components/chat/chat-session-type-option-item.test.tsx +46 -0
- package/src/components/chat/chat-session-type-option-item.tsx +68 -0
- package/src/components/chat/chat-session-workspace-file-preview.test.tsx +87 -0
- package/src/components/chat/chat-session-workspace-file-preview.tsx +14 -43
- package/src/components/chat/chat-session-workspace-panel-nav.tsx +8 -2
- package/src/components/chat/chat-sidebar-project-groups.tsx +11 -36
- package/src/components/chat/containers/chat-input-bar.container.tsx +24 -12
- package/src/components/chat/{ChatSidebar.test.tsx → containers/chat-sidebar.test.tsx} +5 -4
- package/src/components/chat/{ChatSidebar.tsx → containers/chat-sidebar.tsx} +24 -72
- package/src/components/chat/hooks/use-chat-sidebar-session-label-editor.ts +49 -0
- package/src/components/chat/ncp/__tests__/ncp-session-adapter.cancelled-tool.test.ts +77 -0
- package/src/components/chat/ncp/ncp-app-client-fetch.ts +3 -0
- package/src/components/chat/ncp/ncp-chat-input.manager.ts +13 -5
- package/src/components/chat/ncp/ncp-chat-page.tsx +23 -2
- package/src/components/chat/ncp/ncp-session-adapter.test.ts +1 -0
- package/src/components/chat/ncp/ncp-session-adapter.ts +3 -0
- package/src/components/chat/ncp/page/ncp-chat-derived-state.ts +10 -4
- package/src/components/chat/ncp/session-conversation/use-ncp-session-conversation.test.tsx +48 -4
- package/src/components/chat/ncp/session-conversation/use-ncp-session-conversation.ts +43 -5
- package/src/components/chat/ncp/tests/ncp-chat-input.manager.test.ts +51 -1
- package/src/components/chat/stores/chat-input.store.ts +2 -1
- package/src/components/chat/stores/chat-thread.store.ts +3 -1
- package/src/components/chat/useChatSessionTypeState.ts +10 -1
- package/src/components/chat/workspace/chat-session-workspace-file-breadcrumbs.tsx +86 -0
- package/src/components/common/BrandHeader.tsx +3 -1
- package/src/components/common/session-context-icon.tsx +15 -2
- package/src/components/common/{TagInput.tsx → tag-input.tsx} +25 -17
- package/src/components/config/ChannelForm.test.tsx +89 -3
- package/src/components/config/ChannelForm.tsx +157 -188
- package/src/components/config/ChannelsList.test.tsx +163 -119
- package/src/components/config/ChannelsList.tsx +90 -101
- package/src/components/config/ProviderForm.tsx +108 -146
- package/src/components/config/ProvidersList.tsx +100 -123
- package/src/components/config/SearchConfig.tsx +423 -393
- package/src/components/config/channel-form-fields-section.tsx +70 -37
- package/src/components/config/config-split-page.tsx +109 -0
- package/src/components/config/desktop-update-config.test.tsx +10 -4
- package/src/components/config/desktop-update-config.tsx +5 -3
- package/src/components/config/provider-enabled-field.tsx +17 -10
- package/src/components/config/runtime-control-card.test.tsx +136 -158
- package/src/components/config/runtime-control-card.tsx +43 -68
- package/src/components/config/runtime-presence-card.test.tsx +10 -14
- package/src/components/config/runtime-presence-card.tsx +97 -81
- package/src/components/layout/AppLayout.tsx +25 -37
- package/src/components/layout/Sidebar.tsx +4 -4
- package/src/components/layout/app-layout.test.tsx +46 -14
- package/src/components/layout/runtime-status-entry.test.tsx +101 -0
- package/src/components/layout/runtime-status-entry.tsx +95 -0
- package/src/components/layout/sidebar.layout.test.tsx +11 -5
- package/src/components/marketplace/marketplace-detail-doc.ts +93 -0
- package/src/components/marketplace/marketplace-list-card.tsx +288 -0
- package/src/components/marketplace/marketplace-page-data.ts +129 -0
- package/src/components/marketplace/marketplace-page.test.tsx +339 -0
- package/src/components/marketplace/marketplace-page.tsx +596 -0
- package/src/components/marketplace/mcp/mcp-marketplace-card.tsx +128 -0
- package/src/components/marketplace/mcp/mcp-marketplace-dialogs.tsx +191 -0
- package/src/components/marketplace/mcp/mcp-marketplace-doc.ts +152 -0
- package/src/components/marketplace/mcp/mcp-marketplace-page.test.tsx +223 -0
- package/src/components/marketplace/mcp/mcp-marketplace-page.tsx +414 -0
- package/src/components/ui/notice-card.tsx +129 -0
- package/src/components/ui/setting-row.tsx +51 -0
- package/src/components/ui/tag-chip.tsx +39 -0
- package/src/components/ui/textarea.tsx +19 -0
- package/src/features/account/components/account-panel.tsx +255 -0
- package/src/features/account/index.ts +6 -0
- package/src/{account → features/account}/managers/account.manager.ts +6 -5
- package/src/features/remote/components/remote-access-page.test.tsx +104 -0
- package/src/features/remote/components/remote-access-page.tsx +250 -0
- package/src/{hooks/useRemoteAccess.ts → features/remote/hooks/use-remote-access.ts} +1 -1
- package/src/features/remote/index.ts +27 -0
- package/src/{remote → features/remote}/managers/remote-access.manager.ts +3 -4
- package/src/{remote → features/remote/services}/remote-access-feedback.service.test.ts +1 -1
- package/src/features/system-status/hooks/use-system-status.ts +104 -0
- package/src/features/system-status/index.ts +12 -0
- package/src/features/system-status/managers/system-status.manager.bootstrap-polling.test.ts +126 -0
- package/src/features/system-status/managers/system-status.manager.test.ts +142 -0
- package/src/features/system-status/managers/system-status.manager.ts +511 -0
- package/src/features/system-status/stores/system-status.store.ts +32 -0
- package/src/features/system-status/types/system-status.types.ts +73 -0
- package/src/features/system-status/utils/system-status.utils.test.ts +132 -0
- package/src/features/system-status/utils/system-status.utils.ts +202 -0
- package/src/hooks/use-realtime-query-bridge.ts +34 -18
- package/src/hooks/useConfig.ts +2 -1
- package/src/index.css +24 -0
- package/src/lib/app-resource-uri.test.ts +20 -0
- package/src/lib/app-resource-uri.ts +29 -0
- package/src/lib/i18n.chat.ts +8 -0
- package/src/lib/i18n.remote.ts +1 -1
- package/src/lib/i18n.runtime-control.ts +31 -0
- package/src/lib/i18n.ts +5 -8
- package/src/lib/session-context.utils.test.ts +71 -0
- package/src/lib/session-context.utils.ts +28 -3
- package/src/lib/session-project/workspace-file-breadcrumb.test.ts +83 -0
- package/src/lib/session-project/workspace-file-breadcrumb.ts +188 -0
- package/src/platforms/desktop/index.ts +20 -0
- package/src/{desktop → platforms/desktop}/managers/desktop-presence.manager.ts +2 -2
- package/src/{desktop → platforms/desktop}/managers/desktop-update.manager.ts +2 -2
- package/src/{desktop → platforms/desktop}/stores/desktop-presence.store.ts +1 -1
- package/src/{desktop → platforms/desktop}/stores/desktop-update.store.ts +1 -1
- package/src/stores/ui.store.ts +0 -9
- package/src/transport/{app-client.ts → app-client.service.ts} +9 -9
- package/src/transport/app-client.test.ts +9 -5
- package/src/transport/index.ts +1 -1
- package/src/transport/{local.transport.ts → local-transport.service.ts} +14 -12
- package/dist/assets/ChannelsList-Ita2Zm1_.js +0 -8
- package/dist/assets/DocBrowser-BNwbPHf4.js +0 -1
- package/dist/assets/MarketplacePage-CjX2MWww.js +0 -1
- package/dist/assets/MarketplacePage-D0sDlYX4.js +0 -49
- package/dist/assets/McpMarketplacePage-BGKJm1sJ.js +0 -40
- package/dist/assets/ModelConfig-BzZenCH-.js +0 -1
- package/dist/assets/ProviderScopedModelInput-Da7khnBA.js +0 -1
- package/dist/assets/ProvidersList-BbVzRxjY.js +0 -1
- package/dist/assets/RemoteAccessPage-BaDH_X1Q.js +0 -1
- package/dist/assets/RuntimeConfig-F_XKGgLm.js +0 -1
- package/dist/assets/SearchConfig-BGkzXQP-.js +0 -1
- package/dist/assets/SecretsConfig-D281Rotl.js +0 -3
- package/dist/assets/app-query-client-VnFElj4E.js +0 -1
- package/dist/assets/chat-page-Doe0yTtB.js +0 -58
- package/dist/assets/chat-session-display-cw78aiI_.js +0 -1
- package/dist/assets/client-_i4MU2bB.js +0 -7
- package/dist/assets/config-DtIQwrHF.js +0 -1
- package/dist/assets/config-layout-CHs0mAaR.js +0 -1
- package/dist/assets/desktop-update-config-Dpcf4BKG.js +0 -1
- package/dist/assets/dist-ccBFUi-o.js +0 -9
- package/dist/assets/index-CF9xve0E.js +0 -6
- package/dist/assets/index-FgA52VBt.css +0 -1
- package/dist/assets/infiniteQueryBehavior-ZDS92Qpp.js +0 -1
- package/dist/assets/loader-circle-ACM1s51e.js +0 -1
- package/dist/assets/page-layout-vZnghcFy.js +0 -1
- package/dist/assets/play-CFUwCA2E.js +0 -1
- package/dist/assets/plus-rYsv72JG.js +0 -1
- package/dist/assets/popover-Bg1VoTZ6.js +0 -1
- package/dist/assets/refresh-ccw-DT98i__E.js +0 -1
- package/dist/assets/rotate-cw-JtFzpNn6.js +0 -1
- package/dist/assets/search-3kFR_zh9.js +0 -1
- package/dist/assets/security-config-BWaiARNk.js +0 -1
- package/dist/assets/select-DJ2MUjBB.js +0 -41
- package/dist/assets/skeleton-ByQepn0M.js +0 -1
- package/dist/assets/status-dot-vbanNPFU.js +0 -1
- package/dist/assets/use-infinite-scroll-loader-DkNhD-42.js +0 -1
- package/dist/assets/useConfirmDialog-BkvTN-vd.js +0 -1
- package/dist/assets/x-ByDbItbq.js +0 -1
- package/src/account/components/account-panel.tsx +0 -135
- package/src/components/agents/AgentDialogs.tsx +0 -400
- package/src/components/agents/AgentsPage.test.tsx +0 -217
- package/src/components/agents/AgentsPage.tsx +0 -352
- package/src/components/config/config-layout.ts +0 -10
- package/src/components/marketplace/MarketplacePage.test.tsx +0 -322
- package/src/components/marketplace/MarketplacePage.tsx +0 -827
- package/src/components/marketplace/mcp/McpMarketplacePage.test.tsx +0 -208
- package/src/components/marketplace/mcp/McpMarketplacePage.tsx +0 -580
- package/src/components/remote/RemoteAccessPage.test.tsx +0 -103
- package/src/components/remote/RemoteAccessPage.tsx +0 -144
- package/src/hooks/use-runtime-control.ts +0 -24
- package/src/presenter/app-presenter-context.tsx +0 -20
- package/src/presenter/app.presenter.ts +0 -12
- package/src/runtime-control/runtime-control.manager.ts +0 -118
- /package/dist/assets/{config-hints-BhTmc9P1.js → config-hints-DSQQbeOA.js} +0 -0
- /package/src/{account → features/account}/stores/account.store.ts +0 -0
- /package/src/{remote → features/remote/services}/remote-access-feedback.service.ts +0 -0
- /package/src/{remote/remote-access.query.ts → features/remote/services/remote-access-query.service.ts} +0 -0
- /package/src/{remote → features/remote}/stores/remote-access.store.ts +0 -0
- /package/src/{desktop → platforms/desktop/types}/desktop-update.types.ts +0 -0
|
@@ -1,17 +1,44 @@
|
|
|
1
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
2
1
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
2
|
import userEvent from '@testing-library/user-event';
|
|
4
|
-
import type { ReactNode } from 'react';
|
|
5
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
4
|
import { toast } from 'sonner';
|
|
7
5
|
import { RuntimeControlCard } from '@/components/config/runtime-control-card';
|
|
8
6
|
import { setLanguage } from '@/lib/i18n';
|
|
9
7
|
|
|
8
|
+
const baseControlView = {
|
|
9
|
+
environment: 'managed-local-service' as const,
|
|
10
|
+
lifecycle: 'healthy' as const,
|
|
11
|
+
serviceState: 'running' as const,
|
|
12
|
+
message: 'runtime healthy',
|
|
13
|
+
pendingRestart: null,
|
|
14
|
+
canStartService: {
|
|
15
|
+
available: false,
|
|
16
|
+
requiresConfirmation: false,
|
|
17
|
+
impact: 'brief-ui-disconnect' as const,
|
|
18
|
+
reasonIfUnavailable: '当前页面已经由运行中的本地服务托管。',
|
|
19
|
+
},
|
|
20
|
+
canRestartService: {
|
|
21
|
+
available: true,
|
|
22
|
+
requiresConfirmation: false,
|
|
23
|
+
impact: 'brief-ui-disconnect' as const,
|
|
24
|
+
},
|
|
25
|
+
canStopService: {
|
|
26
|
+
available: true,
|
|
27
|
+
requiresConfirmation: true,
|
|
28
|
+
impact: 'brief-ui-disconnect' as const,
|
|
29
|
+
},
|
|
30
|
+
canRestartApp: {
|
|
31
|
+
available: false,
|
|
32
|
+
requiresConfirmation: true,
|
|
33
|
+
impact: 'full-app-relaunch' as const,
|
|
34
|
+
reasonIfUnavailable: 'desktop only',
|
|
35
|
+
},
|
|
36
|
+
managementHint: 'This page is served by the running local service.',
|
|
37
|
+
};
|
|
38
|
+
|
|
10
39
|
const mocks = vi.hoisted(() => ({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
waitForRecovery: vi.fn(),
|
|
14
|
-
restartApp: vi.fn(),
|
|
40
|
+
useRuntimeControlPanelView: vi.fn(),
|
|
41
|
+
runRuntimeControlAction: vi.fn(),
|
|
15
42
|
}));
|
|
16
43
|
|
|
17
44
|
vi.mock('sonner', () => ({
|
|
@@ -21,104 +48,28 @@ vi.mock('sonner', () => ({
|
|
|
21
48
|
},
|
|
22
49
|
}));
|
|
23
50
|
|
|
24
|
-
vi.mock('@/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
runtimeControlManager: {
|
|
31
|
-
waitForRecovery: (...args: unknown[]) => mocks.waitForRecovery(...args),
|
|
32
|
-
restartApp: (...args: unknown[]) => mocks.restartApp(...args),
|
|
51
|
+
vi.mock('@/features/system-status', () => ({
|
|
52
|
+
useRuntimeControlPanelView: (...args: unknown[]) =>
|
|
53
|
+
mocks.useRuntimeControlPanelView(...args),
|
|
54
|
+
systemStatusManager: {
|
|
55
|
+
runRuntimeControlAction: (...args: unknown[]) =>
|
|
56
|
+
mocks.runRuntimeControlAction(...args),
|
|
33
57
|
},
|
|
34
58
|
}));
|
|
35
59
|
|
|
36
|
-
function createWrapper(queryClient: QueryClient) {
|
|
37
|
-
return function Wrapper({ children }: { children: ReactNode }) {
|
|
38
|
-
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
60
|
describe('RuntimeControlCard', () => {
|
|
43
61
|
beforeEach(() => {
|
|
44
62
|
setLanguage('zh');
|
|
45
63
|
vi.clearAllMocks();
|
|
46
|
-
mocks.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
impact: 'brief-ui-disconnect',
|
|
56
|
-
reasonIfUnavailable: '当前页面已经由运行中的本地服务托管。'
|
|
57
|
-
},
|
|
58
|
-
canRestartService: {
|
|
59
|
-
available: true,
|
|
60
|
-
requiresConfirmation: false,
|
|
61
|
-
impact: 'brief-ui-disconnect',
|
|
62
|
-
},
|
|
63
|
-
canStopService: {
|
|
64
|
-
available: true,
|
|
65
|
-
requiresConfirmation: true,
|
|
66
|
-
impact: 'brief-ui-disconnect',
|
|
67
|
-
},
|
|
68
|
-
canRestartApp: {
|
|
69
|
-
available: false,
|
|
70
|
-
requiresConfirmation: true,
|
|
71
|
-
impact: 'full-app-relaunch',
|
|
72
|
-
reasonIfUnavailable: 'desktop only',
|
|
73
|
-
},
|
|
74
|
-
managementHint: 'This page is served by the running local service.'
|
|
75
|
-
},
|
|
76
|
-
isError: false,
|
|
77
|
-
error: null,
|
|
78
|
-
});
|
|
79
|
-
mocks.useRuntimeServiceAction.mockReturnValue({
|
|
80
|
-
mutateAsync: vi.fn().mockResolvedValue({
|
|
81
|
-
accepted: true,
|
|
82
|
-
action: 'restart-service',
|
|
83
|
-
lifecycle: 'restarting-service',
|
|
84
|
-
message: 'Restart scheduled. This page may disconnect for a few seconds.',
|
|
85
|
-
}),
|
|
86
|
-
isPending: false,
|
|
87
|
-
});
|
|
88
|
-
mocks.waitForRecovery.mockResolvedValue({
|
|
89
|
-
environment: 'managed-local-service',
|
|
90
|
-
lifecycle: 'healthy',
|
|
91
|
-
serviceState: 'running',
|
|
92
|
-
message: 'runtime healthy',
|
|
93
|
-
canStartService: {
|
|
94
|
-
available: false,
|
|
95
|
-
requiresConfirmation: false,
|
|
96
|
-
impact: 'brief-ui-disconnect',
|
|
97
|
-
reasonIfUnavailable: '当前页面已经由运行中的本地服务托管。'
|
|
98
|
-
},
|
|
99
|
-
canRestartService: {
|
|
100
|
-
available: true,
|
|
101
|
-
requiresConfirmation: false,
|
|
102
|
-
impact: 'brief-ui-disconnect',
|
|
103
|
-
},
|
|
104
|
-
canStopService: {
|
|
105
|
-
available: true,
|
|
106
|
-
requiresConfirmation: true,
|
|
107
|
-
impact: 'brief-ui-disconnect',
|
|
108
|
-
},
|
|
109
|
-
canRestartApp: {
|
|
110
|
-
available: false,
|
|
111
|
-
requiresConfirmation: true,
|
|
112
|
-
impact: 'full-app-relaunch',
|
|
113
|
-
reasonIfUnavailable: 'desktop only',
|
|
114
|
-
},
|
|
115
|
-
managementHint: 'This page is served by the running local service.'
|
|
116
|
-
});
|
|
117
|
-
mocks.restartApp.mockResolvedValue({
|
|
118
|
-
accepted: true,
|
|
119
|
-
action: 'restart-app',
|
|
120
|
-
lifecycle: 'restarting-app',
|
|
121
|
-
message: 'NextClaw app restart scheduled.',
|
|
64
|
+
mocks.useRuntimeControlPanelView.mockReturnValue({
|
|
65
|
+
controlView: baseControlView,
|
|
66
|
+
visibleLifecycle: 'healthy',
|
|
67
|
+
visibleServiceState: 'running',
|
|
68
|
+
visibleMessage: 'runtime healthy',
|
|
69
|
+
busyAction: null,
|
|
70
|
+
busy: false,
|
|
71
|
+
pendingRestart: null,
|
|
72
|
+
errorMessage: null,
|
|
122
73
|
});
|
|
123
74
|
});
|
|
124
75
|
|
|
@@ -127,14 +78,15 @@ describe('RuntimeControlCard', () => {
|
|
|
127
78
|
});
|
|
128
79
|
|
|
129
80
|
it('renders service management actions from the current capability view', () => {
|
|
130
|
-
|
|
81
|
+
render(<RuntimeControlCard />);
|
|
131
82
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
});
|
|
83
|
+
const startButton = screen.getByRole('button', {
|
|
84
|
+
name: '启动服务',
|
|
85
|
+
}) as HTMLButtonElement;
|
|
86
|
+
const restartAppButton = screen.getByRole('button', {
|
|
87
|
+
name: '重启应用',
|
|
88
|
+
}) as HTMLButtonElement;
|
|
135
89
|
|
|
136
|
-
const startButton = screen.getByRole('button', { name: '启动服务' }) as HTMLButtonElement;
|
|
137
|
-
const restartAppButton = screen.getByRole('button', { name: '重启应用' }) as HTMLButtonElement;
|
|
138
90
|
expect(screen.getByText('服务管理')).toBeTruthy();
|
|
139
91
|
expect(screen.getByText('服务运行中')).toBeTruthy();
|
|
140
92
|
expect(screen.getByRole('button', { name: '重启服务' })).toBeTruthy();
|
|
@@ -144,84 +96,61 @@ describe('RuntimeControlCard', () => {
|
|
|
144
96
|
expect(screen.getByText('desktop only')).toBeTruthy();
|
|
145
97
|
});
|
|
146
98
|
|
|
147
|
-
it('runs the restart service flow
|
|
148
|
-
const queryClient = new QueryClient();
|
|
99
|
+
it('runs the restart service flow through the system status manager', async () => {
|
|
149
100
|
const user = userEvent.setup();
|
|
150
|
-
|
|
151
|
-
const mutateAsync = vi.fn().mockResolvedValue({
|
|
101
|
+
mocks.runRuntimeControlAction.mockResolvedValue({
|
|
152
102
|
accepted: true,
|
|
153
103
|
action: 'restart-service',
|
|
154
104
|
lifecycle: 'restarting-service',
|
|
155
105
|
message: 'Restart scheduled. This page may disconnect for a few seconds.',
|
|
156
106
|
});
|
|
157
|
-
mocks.useRuntimeServiceAction.mockReturnValue({
|
|
158
|
-
mutateAsync,
|
|
159
|
-
isPending: false,
|
|
160
|
-
});
|
|
161
107
|
|
|
162
|
-
render(<RuntimeControlCard
|
|
163
|
-
wrapper: createWrapper(queryClient),
|
|
164
|
-
});
|
|
108
|
+
render(<RuntimeControlCard />);
|
|
165
109
|
|
|
166
110
|
await user.click(screen.getByRole('button', { name: '重启服务' }));
|
|
167
111
|
|
|
168
112
|
await waitFor(() => {
|
|
169
|
-
expect(
|
|
170
|
-
|
|
113
|
+
expect(mocks.runRuntimeControlAction).toHaveBeenCalledWith(
|
|
114
|
+
'restart-service'
|
|
115
|
+
);
|
|
171
116
|
});
|
|
172
|
-
expect(toast.success).toHaveBeenCalledWith(
|
|
173
|
-
|
|
117
|
+
expect(toast.success).toHaveBeenCalledWith(
|
|
118
|
+
'Restart scheduled. This page may disconnect for a few seconds.'
|
|
119
|
+
);
|
|
174
120
|
});
|
|
175
121
|
|
|
176
122
|
it('runs the stop service flow after confirmation', async () => {
|
|
177
|
-
const queryClient = new QueryClient();
|
|
178
123
|
const user = userEvent.setup();
|
|
179
|
-
const
|
|
124
|
+
const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
125
|
+
mocks.runRuntimeControlAction.mockResolvedValue({
|
|
180
126
|
accepted: true,
|
|
181
127
|
action: 'stop-service',
|
|
182
128
|
lifecycle: 'stopping-service',
|
|
183
129
|
message: 'Stop scheduled. This page will disconnect shortly.',
|
|
184
130
|
});
|
|
185
|
-
mocks.useRuntimeServiceAction.mockReturnValue({
|
|
186
|
-
mutateAsync,
|
|
187
|
-
isPending: false,
|
|
188
|
-
});
|
|
189
|
-
const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
190
131
|
|
|
191
|
-
render(<RuntimeControlCard
|
|
192
|
-
wrapper: createWrapper(queryClient),
|
|
193
|
-
});
|
|
132
|
+
render(<RuntimeControlCard />);
|
|
194
133
|
|
|
195
134
|
await user.click(screen.getByRole('button', { name: '停止服务' }));
|
|
196
135
|
|
|
197
136
|
await waitFor(() => {
|
|
198
137
|
expect(confirmSpy).toHaveBeenCalledTimes(1);
|
|
199
|
-
expect(
|
|
138
|
+
expect(mocks.runRuntimeControlAction).toHaveBeenCalledWith(
|
|
139
|
+
'stop-service'
|
|
140
|
+
);
|
|
200
141
|
});
|
|
201
|
-
expect(
|
|
202
|
-
|
|
142
|
+
expect(toast.success).toHaveBeenCalledWith(
|
|
143
|
+
'Stop scheduled. This page will disconnect shortly.'
|
|
144
|
+
);
|
|
203
145
|
});
|
|
204
146
|
|
|
205
147
|
it('runs the desktop restart app flow after confirmation', async () => {
|
|
206
|
-
const queryClient = new QueryClient();
|
|
207
148
|
const user = userEvent.setup();
|
|
208
|
-
|
|
209
|
-
mocks.
|
|
210
|
-
|
|
149
|
+
const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
150
|
+
mocks.useRuntimeControlPanelView.mockReturnValue({
|
|
151
|
+
controlView: {
|
|
152
|
+
...baseControlView,
|
|
211
153
|
environment: 'desktop-embedded',
|
|
212
|
-
lifecycle: 'healthy',
|
|
213
|
-
serviceState: 'running',
|
|
214
|
-
message: 'runtime healthy',
|
|
215
|
-
canStartService: {
|
|
216
|
-
available: false,
|
|
217
|
-
requiresConfirmation: false,
|
|
218
|
-
impact: 'none',
|
|
219
|
-
},
|
|
220
|
-
canRestartService: {
|
|
221
|
-
available: true,
|
|
222
|
-
requiresConfirmation: false,
|
|
223
|
-
impact: 'brief-ui-disconnect',
|
|
224
|
-
},
|
|
225
154
|
canStopService: {
|
|
226
155
|
available: false,
|
|
227
156
|
requiresConfirmation: true,
|
|
@@ -232,24 +161,73 @@ describe('RuntimeControlCard', () => {
|
|
|
232
161
|
requiresConfirmation: true,
|
|
233
162
|
impact: 'full-app-relaunch',
|
|
234
163
|
},
|
|
235
|
-
managementHint: 'desktop launcher hint'
|
|
164
|
+
managementHint: 'desktop launcher hint',
|
|
236
165
|
},
|
|
237
|
-
|
|
238
|
-
|
|
166
|
+
visibleLifecycle: 'healthy',
|
|
167
|
+
visibleServiceState: 'running',
|
|
168
|
+
visibleMessage: 'runtime healthy',
|
|
169
|
+
busyAction: null,
|
|
170
|
+
busy: false,
|
|
171
|
+
pendingRestart: null,
|
|
172
|
+
errorMessage: null,
|
|
173
|
+
});
|
|
174
|
+
mocks.runRuntimeControlAction.mockResolvedValue({
|
|
175
|
+
accepted: true,
|
|
176
|
+
action: 'restart-app',
|
|
177
|
+
lifecycle: 'restarting-app',
|
|
178
|
+
message: 'NextClaw app restart scheduled.',
|
|
239
179
|
});
|
|
240
180
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
render(<RuntimeControlCard />, {
|
|
244
|
-
wrapper: createWrapper(queryClient),
|
|
245
|
-
});
|
|
181
|
+
render(<RuntimeControlCard />);
|
|
246
182
|
|
|
247
183
|
await user.click(screen.getByRole('button', { name: '重启应用' }));
|
|
248
184
|
|
|
249
185
|
await waitFor(() => {
|
|
250
186
|
expect(confirmSpy).toHaveBeenCalledTimes(1);
|
|
251
|
-
expect(mocks.
|
|
187
|
+
expect(mocks.runRuntimeControlAction).toHaveBeenCalledWith(
|
|
188
|
+
'restart-app'
|
|
189
|
+
);
|
|
252
190
|
});
|
|
253
|
-
expect(toast.success).toHaveBeenCalledWith(
|
|
191
|
+
expect(toast.success).toHaveBeenCalledWith(
|
|
192
|
+
'NextClaw app restart scheduled.'
|
|
193
|
+
);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('shows a pending restart notice instead of auto-applying hidden restarts', () => {
|
|
197
|
+
mocks.useRuntimeControlPanelView.mockReturnValue({
|
|
198
|
+
controlView: {
|
|
199
|
+
...baseControlView,
|
|
200
|
+
message: 'Saved changes are waiting for a manual restart.',
|
|
201
|
+
pendingRestart: {
|
|
202
|
+
changedPaths: ['plugins', 'ui'],
|
|
203
|
+
message: 'Saved changes are waiting for a manual restart.',
|
|
204
|
+
reasons: ['config reload requires restart: plugins, ui'],
|
|
205
|
+
requestedAt: '2026-04-17T10:00:00.000Z',
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
visibleLifecycle: 'healthy',
|
|
209
|
+
visibleServiceState: 'running',
|
|
210
|
+
visibleMessage: 'Saved changes are waiting for a manual restart.',
|
|
211
|
+
busyAction: null,
|
|
212
|
+
busy: false,
|
|
213
|
+
pendingRestart: {
|
|
214
|
+
changedPaths: ['plugins', 'ui'],
|
|
215
|
+
message: 'Saved changes are waiting for a manual restart.',
|
|
216
|
+
reasons: ['config reload requires restart: plugins, ui'],
|
|
217
|
+
requestedAt: '2026-04-17T10:00:00.000Z',
|
|
218
|
+
},
|
|
219
|
+
errorMessage: null,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
render(<RuntimeControlCard />);
|
|
223
|
+
|
|
224
|
+
expect(screen.getByText('待重启')).toBeTruthy();
|
|
225
|
+
expect(
|
|
226
|
+
screen.getByText(
|
|
227
|
+
'这次改动已经保存,但系统不会自动重启。请在你方便的时候手动重启,重启完成后该提示会自动清空。'
|
|
228
|
+
)
|
|
229
|
+
).toBeTruthy();
|
|
230
|
+
expect(screen.getByText('plugins')).toBeTruthy();
|
|
231
|
+
expect(screen.getByText('ui')).toBeTruthy();
|
|
254
232
|
});
|
|
255
233
|
});
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { useQueryClient } from '@tanstack/react-query';
|
|
3
1
|
import type {
|
|
4
2
|
RuntimeActionCapability,
|
|
5
3
|
RuntimeControlAction,
|
|
@@ -9,9 +7,11 @@ import type {
|
|
|
9
7
|
} from '@/api/runtime-control.types';
|
|
10
8
|
import { Button } from '@/components/ui/button';
|
|
11
9
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
12
|
-
import { useRuntimeControl, useRuntimeServiceAction } from '@/hooks/use-runtime-control';
|
|
13
10
|
import { t } from '@/lib/i18n';
|
|
14
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
useRuntimeControlPanelView,
|
|
13
|
+
systemStatusManager,
|
|
14
|
+
} from '@/features/system-status';
|
|
15
15
|
import { Loader2, RotateCw, Square, Play } from 'lucide-react';
|
|
16
16
|
import { toast } from 'sonner';
|
|
17
17
|
|
|
@@ -117,19 +117,6 @@ function resolveVisibleActions(controlView: RuntimeControlView | undefined): Vis
|
|
|
117
117
|
return actions.filter((item) => item.capability.available || Boolean(item.capability.reasonIfUnavailable));
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
function resolveActionHelp(action: RuntimeControlAction): string {
|
|
121
|
-
if (action === 'start-service') {
|
|
122
|
-
return t('runtimeControlStartingServiceHelp');
|
|
123
|
-
}
|
|
124
|
-
if (action === 'restart-service') {
|
|
125
|
-
return t('runtimeControlRestartingServiceHelp');
|
|
126
|
-
}
|
|
127
|
-
if (action === 'stop-service') {
|
|
128
|
-
return t('runtimeControlStoppingServiceHelp');
|
|
129
|
-
}
|
|
130
|
-
return t('runtimeControlRestartingAppHelp');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
120
|
function RuntimeActionIcon(props: { icon: VisibleRuntimeAction['icon']; busy: boolean }) {
|
|
134
121
|
const { busy, icon } = props;
|
|
135
122
|
if (busy) {
|
|
@@ -145,27 +132,17 @@ function RuntimeActionIcon(props: { icon: VisibleRuntimeAction['icon']; busy: bo
|
|
|
145
132
|
}
|
|
146
133
|
|
|
147
134
|
export function RuntimeControlCard() {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
const displayedMessage = localMessage ?? controlView?.message ?? t('runtimeControlDescription');
|
|
160
|
-
const busy = serviceActionMutation.isPending || busyAction !== null || displayedLifecycle === 'recovering';
|
|
161
|
-
const visibleActions = resolveVisibleActions(controlView);
|
|
162
|
-
|
|
163
|
-
const resetLocalState = () => {
|
|
164
|
-
setLocalLifecycle(null);
|
|
165
|
-
setLocalServiceState(null);
|
|
166
|
-
setLocalMessage(null);
|
|
167
|
-
setBusyAction(null);
|
|
168
|
-
};
|
|
135
|
+
const {
|
|
136
|
+
busy,
|
|
137
|
+
busyAction,
|
|
138
|
+
controlView,
|
|
139
|
+
errorMessage,
|
|
140
|
+
pendingRestart,
|
|
141
|
+
visibleLifecycle: displayedLifecycle,
|
|
142
|
+
visibleMessage: displayedMessage,
|
|
143
|
+
visibleServiceState: displayedServiceState,
|
|
144
|
+
} = useRuntimeControlPanelView();
|
|
145
|
+
const visibleActions = resolveVisibleActions(controlView ?? undefined);
|
|
169
146
|
|
|
170
147
|
const handleServiceAction = async (action: Extract<RuntimeControlAction, 'start-service' | 'restart-service' | 'stop-service'>) => {
|
|
171
148
|
const capability = action === 'start-service'
|
|
@@ -182,30 +159,11 @@ export function RuntimeControlCard() {
|
|
|
182
159
|
return;
|
|
183
160
|
}
|
|
184
161
|
|
|
185
|
-
setBusyAction(action);
|
|
186
|
-
setLocalLifecycle(action === 'start-service' ? 'starting-service' : action === 'stop-service' ? 'stopping-service' : 'restarting-service');
|
|
187
|
-
setLocalServiceState(action === 'start-service' ? 'starting' : action === 'stop-service' ? 'stopping' : 'restarting');
|
|
188
|
-
setLocalMessage(resolveActionHelp(action));
|
|
189
|
-
|
|
190
162
|
try {
|
|
191
|
-
const result = await
|
|
163
|
+
const result = await systemStatusManager.runRuntimeControlAction(action);
|
|
192
164
|
toast.success(result.message);
|
|
193
|
-
if (action === 'stop-service') {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
setLocalLifecycle('recovering');
|
|
197
|
-
setLocalMessage(t('runtimeControlRecoveringHelp'));
|
|
198
|
-
const recoveredView = await runtimeControlManager.waitForRecovery();
|
|
199
|
-
queryClient.setQueryData(['runtime-control'], recoveredView);
|
|
200
|
-
await queryClient.invalidateQueries({ queryKey: ['runtime-control'] });
|
|
201
|
-
resetLocalState();
|
|
202
|
-
toast.success(t('runtimeControlRecovered'));
|
|
203
165
|
} catch (error) {
|
|
204
166
|
const message = error instanceof Error ? error.message : t('runtimeControlActionFailed');
|
|
205
|
-
setLocalLifecycle('failed');
|
|
206
|
-
setLocalServiceState(action === 'stop-service' ? 'running' : 'unknown');
|
|
207
|
-
setLocalMessage(message);
|
|
208
|
-
setBusyAction(null);
|
|
209
167
|
toast.error(`${t('runtimeControlActionFailed')}: ${message}`);
|
|
210
168
|
}
|
|
211
169
|
};
|
|
@@ -219,18 +177,11 @@ export function RuntimeControlCard() {
|
|
|
219
177
|
return;
|
|
220
178
|
}
|
|
221
179
|
|
|
222
|
-
setBusyAction('restart-app');
|
|
223
|
-
setLocalLifecycle('restarting-app');
|
|
224
|
-
setLocalMessage(t('runtimeControlRestartingAppHelp'));
|
|
225
|
-
|
|
226
180
|
try {
|
|
227
|
-
const result = await
|
|
181
|
+
const result = await systemStatusManager.runRuntimeControlAction('restart-app');
|
|
228
182
|
toast.success(result.message);
|
|
229
183
|
} catch (error) {
|
|
230
184
|
const message = error instanceof Error ? error.message : t('runtimeControlActionFailed');
|
|
231
|
-
setLocalLifecycle('failed');
|
|
232
|
-
setLocalMessage(message);
|
|
233
|
-
setBusyAction(null);
|
|
234
185
|
toast.error(`${t('runtimeControlActionFailed')}: ${message}`);
|
|
235
186
|
}
|
|
236
187
|
};
|
|
@@ -254,13 +205,37 @@ export function RuntimeControlCard() {
|
|
|
254
205
|
{controlView?.managementHint ? (
|
|
255
206
|
<p className="text-xs text-gray-500">{controlView.managementHint}</p>
|
|
256
207
|
) : null}
|
|
257
|
-
{
|
|
208
|
+
{errorMessage && !busy ? (
|
|
258
209
|
<p className="text-sm text-amber-700">
|
|
259
|
-
{
|
|
210
|
+
{errorMessage}
|
|
260
211
|
</p>
|
|
261
212
|
) : null}
|
|
262
213
|
</div>
|
|
263
214
|
|
|
215
|
+
{pendingRestart ? (
|
|
216
|
+
<div className="rounded-xl border border-amber-200 bg-amber-50 p-4 space-y-3">
|
|
217
|
+
<div className="text-sm font-medium text-amber-900">{t('runtimeControlPendingRestartTitle')}</div>
|
|
218
|
+
<p className="text-sm text-amber-800">{t('runtimeControlPendingRestartDescription')}</p>
|
|
219
|
+
{pendingRestart.changedPaths.length > 0 ? (
|
|
220
|
+
<div className="space-y-2">
|
|
221
|
+
<div className="text-xs font-medium uppercase tracking-[0.08em] text-amber-700">
|
|
222
|
+
{t('runtimeControlPendingRestartPaths')}
|
|
223
|
+
</div>
|
|
224
|
+
<div className="flex flex-wrap gap-2">
|
|
225
|
+
{pendingRestart.changedPaths.map((path: string) => (
|
|
226
|
+
<span
|
|
227
|
+
key={path}
|
|
228
|
+
className="rounded-full border border-amber-200 bg-white px-2.5 py-1 text-xs text-amber-800"
|
|
229
|
+
>
|
|
230
|
+
{path}
|
|
231
|
+
</span>
|
|
232
|
+
))}
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
) : null}
|
|
236
|
+
</div>
|
|
237
|
+
) : null}
|
|
238
|
+
|
|
264
239
|
<div className="flex flex-col gap-3 md:flex-row md:flex-wrap">
|
|
265
240
|
{visibleActions.map((item) => {
|
|
266
241
|
const isBusyAction = busyAction === item.action;
|
|
@@ -2,17 +2,17 @@ import { render, screen, waitFor } from '@testing-library/react';
|
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
import { RuntimePresenceCard } from '@/components/config/runtime-presence-card';
|
|
5
|
-
import { useDesktopPresenceStore } from '@/desktop/stores/desktop-presence.store';
|
|
6
5
|
import { setLanguage } from '@/lib/i18n';
|
|
6
|
+
import { useDesktopPresenceStore } from '@/platforms/desktop';
|
|
7
7
|
|
|
8
8
|
const mocks = vi.hoisted(() => ({
|
|
9
|
-
|
|
9
|
+
useSystemStatus: vi.fn(),
|
|
10
10
|
toastSuccess: vi.fn(),
|
|
11
11
|
toastError: vi.fn()
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
-
vi.mock('@/
|
|
15
|
-
|
|
14
|
+
vi.mock('@/features/system-status', () => ({
|
|
15
|
+
useSystemStatus: (...args: unknown[]) => mocks.useSystemStatus(...args)
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
18
|
vi.mock('sonner', () => ({
|
|
@@ -32,8 +32,8 @@ describe('RuntimePresenceCard', () => {
|
|
|
32
32
|
busyAction: null,
|
|
33
33
|
snapshot: null
|
|
34
34
|
});
|
|
35
|
-
mocks.
|
|
36
|
-
|
|
35
|
+
mocks.useSystemStatus.mockReturnValue({
|
|
36
|
+
runtimeControlView: {
|
|
37
37
|
environment: 'managed-local-service',
|
|
38
38
|
lifecycle: 'healthy',
|
|
39
39
|
serviceState: 'running',
|
|
@@ -61,9 +61,7 @@ describe('RuntimePresenceCard', () => {
|
|
|
61
61
|
reasonIfUnavailable: 'desktop only'
|
|
62
62
|
},
|
|
63
63
|
managementHint: 'managed service hint'
|
|
64
|
-
}
|
|
65
|
-
isError: false,
|
|
66
|
-
error: null
|
|
64
|
+
}
|
|
67
65
|
});
|
|
68
66
|
window.nextclawDesktop = undefined;
|
|
69
67
|
});
|
|
@@ -106,8 +104,8 @@ describe('RuntimePresenceCard', () => {
|
|
|
106
104
|
onUpdateStateChanged: vi.fn(() => () => {})
|
|
107
105
|
};
|
|
108
106
|
|
|
109
|
-
mocks.
|
|
110
|
-
|
|
107
|
+
mocks.useSystemStatus.mockReturnValue({
|
|
108
|
+
runtimeControlView: {
|
|
111
109
|
environment: 'desktop-embedded',
|
|
112
110
|
lifecycle: 'healthy',
|
|
113
111
|
serviceState: 'running',
|
|
@@ -133,9 +131,7 @@ describe('RuntimePresenceCard', () => {
|
|
|
133
131
|
impact: 'full-app-relaunch'
|
|
134
132
|
},
|
|
135
133
|
managementHint: 'desktop hint'
|
|
136
|
-
}
|
|
137
|
-
isError: false,
|
|
138
|
-
error: null
|
|
134
|
+
}
|
|
139
135
|
});
|
|
140
136
|
|
|
141
137
|
render(<RuntimePresenceCard />);
|