Files
speckle-server/packages/server/modules/comments/services/data.ts
T
Kristaps Fabians Geikins 6d08889a79 fix(fe2): various minor regressions (#1622)
* fix(server): viewerState sometimes reporting wrong isOrthoProjection value

* feat: more resilient viewerState read/write

* feat: more resilient viewerState read/write

* fix(fe2): dashboard not showing empty state properly

* fix(fe2): weird thread opening/closing behaviour

* feat(cli): specifying token for commit download

* fix(fe2): selection not being set for opened threads
2023-06-13 13:55:55 +03:00

175 lines
4.8 KiB
TypeScript

import { CommentRecord } from '@/modules/comments/helpers/types'
import { LegacyCommentViewerData } from '@/modules/core/graph/generated/graphql'
import {
getViewerResourcesForComments,
viewerResourcesToString
} from '@/modules/core/services/commit/viewerResources'
import { Nullable, SpeckleViewer } from '@speckle/shared'
import { has, get, intersection, isObjectLike } from 'lodash'
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: state.ui.sectionBox,
propertyInfoKey: state.ui.filters.propertyFilter.key
},
location: {
x: selectionLocation[0] || 0,
y: selectionLocation[1] || 0,
z: selectionLocation[2] || 0
},
sectionBox: state.ui.sectionBox,
selection: null
}
return ret
}
export async function convertLegacyDataToState(
data: LegacyData,
comment: CommentRecord
): Promise<SerializedViewerState> {
const resources = await 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 || [],
selectedObjectIds: [],
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
},
sectionBox: sectionBox
? {
min: (sectionBox.min as number[]) || [0, 0, 0],
max: (sectionBox.max as number[]) || [0, 0, 0]
}
: 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
}
}
}
return ret
}