Skip to content

Commit aca7646

Browse files
committed
fix(computer-use): mount the device controls only once the permission group allows them
Their effects no longer call the native helper for loading or restricted members.
1 parent dc5a9df commit aca7646

2 files changed

Lines changed: 16 additions & 12 deletions

File tree

‎apps/sim/app/workspace/[workspaceId]/settings/components/desktop/computer-use.test.tsx‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
import { toast } from '@sim/emcn'
99
import { createDeferred } from '@sim/testing/helpers/deferred'
1010
import { libDesktopMock, libDesktopMockFns } from '@sim/testing/mocks/lib-desktop.mock'
11+
import { nextNavigationMockFns } from '@sim/testing/mocks/next-navigation.mock'
1112
import { createRoot, type Root } from 'react-dom/client'
1213
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
1314
import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
@@ -30,7 +31,10 @@ vi.mock('@/ee/access-control/hooks/permission-groups', () => ({
3031
? { isSuccess: true, data: { config: permission.config } }
3132
: { isSuccess: false, data: undefined },
3233
}))
33-
vi.mock('next/navigation', () => ({ useParams: () => ({ workspaceId: 'ws-1' }) }))
34+
vi.mock(
35+
'next/navigation',
36+
async () => (await import('@sim/testing/mocks/next-navigation.mock')).nextNavigationMock
37+
)
3438
vi.mock('@/lib/desktop', () => libDesktopMock)
3539

3640
const initialPermissions = [
@@ -46,6 +50,7 @@ let container: HTMLDivElement
4650
beforeEach(() => {
4751
permission.config = null
4852
permission.ready = true
53+
nextNavigationMockFns.mockUseParams.mockReturnValue({ workspaceId: 'ws-1' })
4954
permissions = [...initialPermissions]
5055
activity = null
5156
listeners = new Set()
@@ -98,6 +103,7 @@ it('withholds the device controls until the permission read succeeds', async ()
98103
await act(async () => renderSettings())
99104
expect(appRow('com.example.First')).toBeUndefined()
100105
expect(container.querySelector('[role="switch"]')).toBeNull()
106+
expect(native.listAppPermissions).not.toHaveBeenCalled()
101107
})
102108

103109
function appRow(bundleId: string) {

‎apps/sim/app/workspace/[workspaceId]/settings/components/desktop/computer-use.tsx‎

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,25 @@ import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/componen
1111
import { useUserPermissionConfig } from '@/ee/access-control/hooks/permission-groups'
1212
import { useComputerUseStatus } from '@/hooks/use-computer-use-status'
1313

14+
/** The activity stays visible so an in-flight action can be stopped; the device controls need the permission group's consent. */
1415
export function ComputerUseSettings() {
16+
const { workspaceId } = useParams<{ workspaceId: string }>()
17+
const permission = useUserPermissionConfig(workspaceId)
18+
const allowed =
19+
permission.isSuccess &&
20+
(permission.data.config === null ||
21+
!CAPABILITY_RULES['computer_use.use'].deniedBy(permission.data.config))
1522
return (
1623
<>
1724
<ComputerUseActivity />
18-
<ComputerUseSettingsControls />
25+
{allowed && <ComputerUseSettingsControls />}
1926
</>
2027
)
2128
}
2229

2330
function ComputerUseSettingsControls() {
2431
const requestVersion = useRef(0)
2532
const bridge = getDesktopBridge()?.computerUse
26-
const { workspaceId } = useParams<{ workspaceId: string }>()
27-
const permission = useUserPermissionConfig(workspaceId)
2833
const { status, setStatus, refresh, error } = useComputerUseStatus()
2934
const [apps, setApps] = useState<ComputerUseAppPermission[]>([])
3035
const [pending, setPending] = useState(false)
@@ -44,14 +49,7 @@ function ComputerUseSettingsControls() {
4449
requestVersion.current += 1
4550
}
4651
}, [refreshApps, status?.activeAction])
47-
if (
48-
!bridge ||
49-
!permission.isSuccess ||
50-
(permission.data.config !== null &&
51-
CAPABILITY_RULES['computer_use.use'].deniedBy(permission.data.config)) ||
52-
status?.supported === false
53-
)
54-
return null
52+
if (!bridge || status?.supported === false) return null
5553
const update = async (action: () => Promise<void>) => {
5654
setPending(true)
5755
try {

0 commit comments

Comments
 (0)