mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 17:17:38 +00:00
* feat(file-drop): add element owner preparation plumbing * Fix terminal and chat file drop destination ownership * fix runtime terminal drop ownership and queued chat retries * fix(file-drop): preserve feedback acceptance and destination ordering * fix(file-drop): attach chat and composer files at the drop surface * fix(file-drop): preserve project destinations and live chat availability * fix(file-drop): keep path resolution in filesystem namespace * test(file-drop): use filesystem path bridge in PR3 fixtures * fix(file-drop): bind terminal drops to pane elements * fix(file-drop): compare terminal pane identity across public views * test(file-drop): align composer lifecycle with element-owned drops * Fix interrupted chat composition and refuse unused quick-create drops * Type the quick-create drop regression transfer * fix(file-drop): let the explorer, project sidebar, tab strip and editor own OS drops STA-6940 PR5. The file explorer tree, the project sidebar, each editor group's tab strip and its editor area now take OS file drops on their own element through the shared owner hook, with identity from their own render (the explorer's shown workspace and target row, the tab strip's and editor group's worktree and group) instead of the active worktree. The explorer and sidebar broadcast subscribers and their legacy drop markers are deleted; editor-open moves out of useGlobalFileDrop into editor-dropped-file-open, which the legacy unmarked-chrome route still uses until PR6. * fix(file-drop): keep editor delivery tied to its destination group * fix(file-drop): guard delayed opens and share floating ownership * fix(file-drop): remove legacy OS drop routing (STA-6940 PR6/6) * test(file-drop): finish owner test and comment cleanup * Clarify dropped-file default editor destination * Retain UI test namespace for terminal resume coverage
90 lines
2.9 KiB
TypeScript
90 lines
2.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
NATIVE_FILE_DROP_MAX_PATH_BYTES,
|
|
NATIVE_FILE_DROP_MAX_PATHS,
|
|
ORCA_INTERNAL_FILE_DRAG_TYPE,
|
|
createRejectedNativeFileDropPayload,
|
|
hasNativeFileDragTypes,
|
|
validateNativeFileDropPaths
|
|
} from './native-file-drop'
|
|
|
|
describe('hasNativeFileDragTypes', () => {
|
|
it('accepts native OS file drags', () => {
|
|
expect(hasNativeFileDragTypes(['Files'])).toBe(true)
|
|
})
|
|
|
|
it('rejects internal Orca file moves and URL/text drags', () => {
|
|
expect(hasNativeFileDragTypes(['Files', ORCA_INTERNAL_FILE_DRAG_TYPE])).toBe(false)
|
|
expect(hasNativeFileDragTypes(['text/uri-list'])).toBe(false)
|
|
expect(hasNativeFileDragTypes(['text/plain'])).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('validateNativeFileDropPaths', () => {
|
|
it('rejects native drops by file count before path byte accounting is needed', () => {
|
|
const paths = Array.from({ length: NATIVE_FILE_DROP_MAX_PATHS + 1 }, (_value, index) =>
|
|
['/tmp/file-', String(index)].join('')
|
|
)
|
|
|
|
expect(validateNativeFileDropPaths(paths)).toEqual({
|
|
byteLength: 0,
|
|
pathCount: NATIVE_FILE_DROP_MAX_PATHS + 1,
|
|
reason: 'too-many-paths',
|
|
status: 'rejected'
|
|
})
|
|
})
|
|
|
|
it('rejects native drops whose path list is too large without exposing paths', () => {
|
|
const validation = validateNativeFileDropPaths(['C:\\Users\\alice\\secret-token.txt'], {
|
|
maxPathBytes: 4
|
|
})
|
|
|
|
expect(validation).toEqual({
|
|
byteLength: 5,
|
|
pathCount: 1,
|
|
reason: 'paths-too-large',
|
|
status: 'rejected'
|
|
})
|
|
if (validation.status === 'rejected') {
|
|
const payload = createRejectedNativeFileDropPayload(validation)
|
|
expect(JSON.stringify(payload)).not.toContain('secret')
|
|
expect(JSON.stringify(payload)).not.toContain('alice')
|
|
}
|
|
})
|
|
|
|
it('accepts path payloads within the configured limits', () => {
|
|
expect(validateNativeFileDropPaths(['/tmp/a', '/tmp/b'])).toEqual({
|
|
byteLength: 12,
|
|
pathCount: 2,
|
|
status: 'accepted'
|
|
})
|
|
})
|
|
|
|
it('rejects multibyte native path lists with bounded byte accounting', () => {
|
|
expect(validateNativeFileDropPaths(['😀'.repeat(3)], { maxPathBytes: 5 })).toEqual({
|
|
byteLength: 8,
|
|
pathCount: 1,
|
|
reason: 'paths-too-large',
|
|
status: 'rejected'
|
|
})
|
|
})
|
|
|
|
it('enforces file count and byte limits at their boundaries', () => {
|
|
expect(
|
|
validateNativeFileDropPaths(Array.from({ length: NATIVE_FILE_DROP_MAX_PATHS }, () => '/a'))
|
|
.status
|
|
).toBe('accepted')
|
|
expect(
|
|
validateNativeFileDropPaths(
|
|
Array.from({ length: NATIVE_FILE_DROP_MAX_PATHS + 1 }, () => '/a')
|
|
).status
|
|
).toBe('rejected')
|
|
expect(validateNativeFileDropPaths(['a'.repeat(NATIVE_FILE_DROP_MAX_PATH_BYTES)]).status).toBe(
|
|
'accepted'
|
|
)
|
|
expect(
|
|
validateNativeFileDropPaths(['a'.repeat(NATIVE_FILE_DROP_MAX_PATH_BYTES + 1)]).status
|
|
).toBe('rejected')
|
|
})
|
|
})
|