fix: simplify code navigation and support Gazebo XML files
Remove redundant code-view cancellation and align button labels. Restore module scrollbar thickness while preserving workspace colors, and support config, SDF and world text files locally and remotely.
This commit is contained in:
@@ -71,7 +71,7 @@ test('does not decorate another file, a hidden/diff editor, stale scope or unrea
|
||||
|
||||
const hookSource = ts.createSourceFile('useAiAgent.ts', fs.readFileSync(require.resolve('../src/renderer/src/features/workspace/useAiAgent.ts'), 'utf8'), ts.ScriptTarget.Latest, true)
|
||||
const hook = hookSource.statements.find(node => ts.isFunctionDeclaration(node) && node.name?.text === 'useAiAgent')
|
||||
const functions = hook.body.statements.filter(node => ts.isVariableStatement(node) && ['openCodeReference', 'cancelCodeReference'].includes(node.declarationList.declarations[0].name.getText(hookSource)))
|
||||
const functions = hook.body.statements.filter(node => ts.isVariableStatement(node) && node.declarationList.declarations[0].name.getText(hookSource) === 'openCodeReference')
|
||||
function consentHarness() {
|
||||
const session = {}
|
||||
const messageStateRef = { current: { session, messages: [{ id: 'answer', role: 'assistant', plan: { codeReferences: [reference] } }] } }
|
||||
@@ -79,19 +79,23 @@ function consentHarness() {
|
||||
return { ...compile(functions.map(node => `export ${node.getText(hookSource)}`).join('\n'), globals), globals, message: () => messageStateRef.current.messages[0] }
|
||||
}
|
||||
|
||||
test('opening requires explicit approval, cancellation never opens or applies anything', async () => {
|
||||
test('code navigation opens only when the user selects View in editor', async () => {
|
||||
const h = consentHarness()
|
||||
let opened = 0
|
||||
const open = async () => { opened++ }
|
||||
assert.equal(opened, 0)
|
||||
h.cancelCodeReference('answer', 'location')
|
||||
await h.openCodeReference('answer', 'location', open)
|
||||
assert.equal(opened, 0)
|
||||
assert.equal(h.message().codeReferenceStates.location.status, 'cancelled')
|
||||
const approved = consentHarness()
|
||||
await approved.openCodeReference('answer', 'location', async ref => { assert.equal(ref.path, reference.path); opened++ })
|
||||
assert.equal(opened, 1)
|
||||
assert.equal(approved.message().codeReferenceStates.location.status, 'opened')
|
||||
assert.equal(h.message().codeReferenceStates.location.status, 'opened')
|
||||
})
|
||||
|
||||
test('legacy cancelled references can be opened with the same read-only navigation action', async () => {
|
||||
const h = consentHarness()
|
||||
h.message().codeReferenceStates = { location: { status: 'cancelled' } }
|
||||
let opened = 0
|
||||
await h.openCodeReference('answer', 'location', async ref => { assert.equal(ref.path, reference.path); opened++ })
|
||||
assert.equal(opened, 1)
|
||||
assert.equal(h.message().codeReferenceStates.location.status, 'opened')
|
||||
})
|
||||
|
||||
test('duplicate clicks, invalid IDs and busy tasks do not open more files', async () => {
|
||||
@@ -99,8 +103,6 @@ test('duplicate clicks, invalid IDs and busy tasks do not open more files', asyn
|
||||
let finish, opened = 0
|
||||
const first = h.openCodeReference('answer', 'location', () => { opened++; return new Promise(resolve => { finish = resolve }) })
|
||||
assert.equal(h.message().codeReferenceStates.location.status, 'opening')
|
||||
h.cancelCodeReference('answer', 'location')
|
||||
assert.equal(h.message().codeReferenceStates.location.status, 'opening')
|
||||
await h.openCodeReference('answer', 'location', async () => { opened++ })
|
||||
finish()
|
||||
await first
|
||||
@@ -158,15 +160,23 @@ function text(tree) {
|
||||
return typeof tree === 'string' ? tree : React.isValidElement(tree) ? React.Children.toArray(tree.props.children).map(text).join('') : ''
|
||||
}
|
||||
const render = compile(fs.readFileSync(require.resolve('../src/renderer/src/components/AgentCodeReferences.tsx'), 'utf8'), {}, name => name.endsWith('/i18n') ? { t: key => key, useLocaleRender() {} } : require(name)).AgentCodeReferences
|
||||
for (const dark of [true, false]) test(`consent controls use cancel-left/open-right and preserve states (${dark})`, () => {
|
||||
for (const dark of [true, false]) test(`code navigation has only a vertically aligned View in editor button (${dark})`, () => {
|
||||
const clicked = []
|
||||
const props = { dark, references: [reference], onOpen: id => clicked.push(`open:${id}`), onCancel: id => clicked.push(`cancel:${id}`) }
|
||||
const props = { dark, references: [reference], onOpen: id => clicked.push(`open:${id}`) }
|
||||
const buttons = elements(render(props), element => element.type === 'button')
|
||||
assert.equal(clicked.length, 0)
|
||||
assert.deepEqual(buttons.map(text), ['취소', '코드에서 보기'])
|
||||
buttons[1].props.onClick()
|
||||
assert.deepEqual(buttons.map(text), ['코드에서 보기'])
|
||||
const label = elements(buttons[0], element => element.type === 'span')[0]
|
||||
assert.match(buttons[0].props.className, /items-center.*leading-none/)
|
||||
assert.match(label.props.className, /top-px leading-none/)
|
||||
buttons[0].props.onClick()
|
||||
assert.deepEqual(clicked, ['open:location'])
|
||||
for (const button of elements(render({ ...props, busy: true }), element => element.type === 'button')) assert.equal(button.props.disabled, true)
|
||||
assert.equal(elements(render({ ...props, states: { location: { status: 'cancelled' } } }), element => element.type === 'button').length, 0)
|
||||
for (const status of ['cancelled', 'opened', 'error']) {
|
||||
assert.deepEqual(elements(render({ ...props, states: { location: { status } } }), element => element.type === 'button').map(text), ['코드에서 보기'])
|
||||
}
|
||||
const opening = elements(render({ ...props, states: { location: { status: 'opening' } } }), element => element.type === 'button')[0]
|
||||
assert.equal(opening.props.disabled, true)
|
||||
assert.equal(text(opening), '파일 여는 중...')
|
||||
assert.equal(elements(render({ ...props, states: { location: { status: 'error', error: 'missing' } } }), element => element.props.role === 'alert').length, 1)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user