Files
speckle-server/packages/server/modules/comments/services/data.ts
T
Kristaps Fabians Geikins bde148f286 chore(server): migrating fully to ESM (#5042)
* wip

* some extra fixes

* stuff kinda works?

* need to figure out mocks

* need to figure out mocks

* fix db listener

* gqlgen fix

* minor gqlgen watch adjustment

* lint fixes

* delete old codegen file

* converting migrations to ESM

* getModuleDIrectory

* vitest sort of works

* added back ts-vitest

* resolve gql double load

* fixing test timeout configs

* TSC lint fix

* fix automate tests

* moar debugging

* debugging

* more debugging

* codegen update

* server works

* yargs migrated

* chore(server): getting rid of global mocks for Server ESM (#5046)

* got rid of email mock

* got rid of comment mocks

* got rid of multi region mocks

* got rid of stripe mock

* admin override mock updated

* removed final mock

* fixing import.meta.resolve calls

* another import.meta.resolve fix

* added requested test

* nyc ESM fix

* removed unneeded deps + linting

* yarn lock forgot to commit

* tryna fix flakyness

* email capture util fix

* sendEmail fix

* fix TSX check

* sender transporter fix + CR comments

* merge main fix

* test fixx

* circleci fix

* gqlgen bigint fix

* error formatter fix

* more error formatting improvements

* esmloader added to Dockerfile

* more dockerfile fixes

* bg jobs fix
2025-07-14 10:26:19 +03:00

200 lines
5.8 KiB
TypeScript

import {
ConvertLegacyDataToState,
GetViewerResourcesForComments
} from '@/modules/comments/domain/operations'
import { LegacyCommentViewerData } from '@/modules/core/graph/generated/graphql'
import { viewerResourcesToString } from '@/modules/core/services/commit/viewerResources'
import { Nullable, SpeckleViewer } from '@speckle/shared'
import { has, get, intersection, isObjectLike } from 'lodash-es'
type SerializedViewerState = SpeckleViewer.ViewerState.SerializedViewerState
export type LegacyData = Partial<LegacyCommentViewerData>
export type DataStruct = {
version: number
state: SerializedViewerState
}
export function inputToDataStruct(
inputSerializedViewerState: unknown
): Nullable<DataStruct> {
const state = SpeckleViewer.ViewerState.isSerializedViewerState(
inputSerializedViewerState
)
? inputSerializedViewerState
: null
if (!state) return null
return {
version: SpeckleViewer.ViewerState.SERIALIZED_VIEWER_STATE_VERSION,
state
}
}
export function isDataStruct(data: unknown): data is DataStruct {
if (!data) return false
if (!has(data, 'version')) return false
const stateRaw = get(data, 'state')
return SpeckleViewer.ViewerState.isSerializedViewerState(stateRaw)
}
export const formatSerializedViewerState =
SpeckleViewer.ViewerState.formatSerializedViewerState
export function isLegacyData(data: unknown): data is LegacyData {
if (!data) return false
const keys: Array<keyof LegacyData> = [
'camPos',
'filters',
'location',
'sectionBox',
'selection'
]
if (!isObjectLike(data)) return false
const valKeys = Object.keys(data as Record<string, unknown>)
if (intersection(valKeys, keys).length !== keys.length) return false
return true
}
export function convertStateToLegacyData(state: SerializedViewerState): LegacyData {
const camPos = state.ui.camera.position
const camTarget = state.ui.camera.target
const zoom = state.ui.camera.zoom
const isOrtho = state.ui.camera.isOrthoProjection
const selection = state.ui.selection
const selectionLocation = selection || camTarget
const ret: LegacyData = {
camPos: [
camPos[0] || 0,
camPos[1] || 0,
camPos[2] || 0,
camTarget[0] || 0,
camTarget[1] || 0,
camTarget[2] || 0,
zoom || 1,
isOrtho ? 1 : 0
],
filters: {
passMin: state.viewer.metadata.filteringState?.passMin || null,
passMax: state.viewer.metadata.filteringState?.passMax || null,
hiddenIds: state.ui.filters.hiddenObjectIds.slice(),
isolatedIds: state.ui.filters.isolatedObjectIds.slice(),
sectionBox: {
min: (state.ui?.sectionBox?.min as number[]) || [0, 0, 0],
max: (state.ui?.sectionBox?.max as number[]) || [0, 0, 0],
rotation: (state.ui?.sectionBox?.rotation as number[]) || [
1, 0, 0, 0, 1, 0, 0, 0, 1
]
},
propertyInfoKey: state.ui.filters.propertyFilter.key
},
location: {
x: selectionLocation[0] || 0,
y: selectionLocation[1] || 0,
z: selectionLocation[2] || 0
},
sectionBox: {
min: (state.ui?.sectionBox?.min as number[]) || [0, 0, 0],
max: (state.ui?.sectionBox?.max as number[]) || [0, 0, 0],
rotation: (state.ui?.sectionBox?.rotation as number[]) || [
1, 0, 0, 0, 1, 0, 0, 0, 1
]
},
selection: null
}
return ret
}
export const convertLegacyDataToStateFactory =
(deps: {
getViewerResourcesForComments: GetViewerResourcesForComments
}): ConvertLegacyDataToState =>
async (data, comment) => {
const resources = await deps.getViewerResourcesForComments(comment.streamId, [
comment.id
])
const sectionBox = data.filters?.sectionBox || data.sectionBox
const ret: SerializedViewerState = {
projectId: comment.streamId,
sessionId: 'legacy-sessionId',
viewer: {
metadata: {
filteringState: {
passMax: data.filters?.passMax,
passMin: data.filters?.passMin
}
}
},
resources: {
request: {
resourceIdString: viewerResourcesToString(resources),
threadFilters: {
includeArchived: false,
loadedVersionsOnly: false
}
}
},
ui: {
threads: {
openThread: {
threadId: null,
isTyping: false,
newThreadEditor: true
}
},
spotlightUserSessionId: null,
explodeFactor: 0,
filters: {
isolatedObjectIds: data.filters?.isolatedIds || [],
hiddenObjectIds: data.filters?.hiddenIds || [],
selectedObjectApplicationIds: {},
propertyFilter: {
key: data.filters?.propertyInfoKey || null,
isApplied: true
}
},
camera: {
position: [
data.camPos?.[0] || 0,
data.camPos?.[1] || 0,
data.camPos?.[2] || 0
],
target: [data.camPos?.[3] || 0, data.camPos?.[4] || 0, data.camPos?.[5] || 0],
isOrthoProjection: !!data.camPos?.[6],
zoom: data.camPos?.[7] || 1
},
viewMode: 0,
sectionBox: sectionBox
? {
min: (sectionBox.min as number[]) || [0, 0, 0],
max: (sectionBox.max as number[]) || [0, 0, 0],
rotation: (sectionBox.rotation as number[]) || [1, 0, 0, 0, 1, 0, 0, 0, 1]
}
: null,
lightConfig: {},
selection: data.location
? [
data.location.x as number,
data.location.y as number,
data.location.z as number
]
: null,
diff: {
command: null,
mode: 1,
time: 0.5
},
measurement: {
enabled: false,
options: null
}
}
}
return ret
}