Files
upstream-tldraw/templates/agent/client/parts/UserActionHistoryPartUtil.ts
upstream-mirror a774ac673a
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
2026-09-23 16:12:52 +05:00

111 lines
3.3 KiB
TypeScript

import { squashRecordDiffs } from 'tldraw'
import {
convertTldrawIdToSimpleId,
convertTldrawShapeToFocusedShape,
convertTldrawShapeToFocusedType,
} from '../../shared/format/convertTldrawShapeToFocusedShape'
import { FocusedShape } from '../../shared/format/FocusedShape'
import { UserActionHistoryPart } from '../../shared/schema/PromptPartDefinitions'
import { AgentRequest } from '../../shared/types/AgentRequest'
import { AgentHelpers } from '../AgentHelpers'
import { PromptPartUtil, registerPromptPartUtil } from './PromptPartUtil'
export const UserActionHistoryPartUtil = registerPromptPartUtil(
class UserActionHistoryPartUtil extends PromptPartUtil<UserActionHistoryPart> {
static override type = 'userActionHistory' as const
override getPart(_request: AgentRequest, helpers: AgentHelpers): UserActionHistoryPart {
const { editor, agent } = helpers
// Get the action history and clear it so that we can start tracking changes for the next request
const diffs = agent.userAction.getHistory()
agent.userAction.clearHistory()
const part: UserActionHistoryPart = {
type: 'userActionHistory',
added: [],
removed: [],
updated: [],
}
const squashedDiff = squashRecordDiffs(diffs)
const { added, updated, removed } = squashedDiff
// Collect user-added shapes
for (const shape of Object.values(added)) {
if (shape.typeName !== 'shape') continue
part.added.push({
shapeId: convertTldrawIdToSimpleId(shape.id),
type: convertTldrawShapeToFocusedType(shape),
})
}
// Collect user-removed shapes
for (const shape of Object.values(removed)) {
if (shape.typeName !== 'shape') continue
const focusedShape = convertTldrawShapeToFocusedShape(editor, shape)
part.removed.push({
shapeId: focusedShape.shapeId,
type: focusedShape._type,
})
}
// Collect user-updated shapes
for (const [from, to] of Object.values(updated)) {
if (from.typeName !== 'shape' || to.typeName !== 'shape') continue
const fromFocusedShape = convertTldrawShapeToFocusedShape(editor, from)
const toFocusedShape = convertTldrawShapeToFocusedShape(editor, to)
const changeFocusedShape = getFocusedShapeChange(fromFocusedShape, toFocusedShape)
if (!changeFocusedShape) continue
const before = helpers.applyOffsetToShapePartial(changeFocusedShape.from)
const after = helpers.applyOffsetToShapePartial(changeFocusedShape.to)
part.updated.push({
shapeId: toFocusedShape.shapeId,
type: toFocusedShape._type,
before: helpers.roundShapePartial(before),
after: helpers.roundShapePartial(after),
})
}
return part
}
}
)
/**
* Get any changed properties between two focused shapes.
* @param from - The original shape.
* @param to - The new shape.
* @returns The changed properties.
*/
function getFocusedShapeChange<T extends FocusedShape['_type']>(
from: FocusedShape & { _type: T },
to: FocusedShape & { _type: T }
) {
if (from._type !== to._type) {
return null
}
const change: {
from: Partial<FocusedShape>
to: Partial<FocusedShape>
} = {
from: {},
to: {},
}
for (const key in to) {
const fromValue = from[key]
const toValue = to[key]
if (fromValue === toValue) {
continue
}
;(change.from as any)[key] = fromValue
;(change.to as any)[key] = toValue
}
return change
}