Sync BIM attachment versions from viewer storage

This commit is contained in:
DCCONSTRUCTIONS
2026-06-23 11:32:49 +03:00
parent 4ed460ae45
commit df4767a085
4 changed files with 105 additions and 8 deletions
+64 -3
View File
@@ -21,9 +21,12 @@ export type TBeamModelVersionRecord = {
downloadUrl: string;
originalFilename: string;
previewAvailable: boolean;
projectId?: string;
sha256?: string;
size: number;
sourceSrc?: string;
src: string;
status?: string;
type: string;
uploadedBy?: string;
uploadedAt: string;
@@ -39,6 +42,7 @@ export type TBeamViewerAttachment = {
downloadUrl: string;
originalFilename: string;
previewAvailable: boolean;
projectId?: string;
sha256?: string;
src: string;
type: string;
@@ -72,6 +76,16 @@ export type TBeamConversionStatus = {
versionId?: string;
};
export type TBeamVersionHistoryResponse = {
assetId?: string;
currentVersion?: number;
currentVersionId?: string;
ok: boolean;
projectId?: string;
updatedAt?: string;
versions: TBeamModelVersionRecord[];
};
export const BEAM_VIEWER_OPEN_EVENT = "nodedc:beam-viewer-open";
export type TBeamViewerOpenEventDetail = {
@@ -192,7 +206,7 @@ export const getBeamViewerAttachment = (attachment: TIssueAttachment | undefined
};
const getAttachmentVersionNumber = (attachment: TIssueAttachment | undefined): number => {
const rawVersion = attachment?.attributes.version;
const rawVersion = (attachment?.attributes as { version?: number | string } | undefined)?.version;
if (typeof rawVersion === "number" && Number.isFinite(rawVersion)) return rawVersion;
if (typeof rawVersion === "string") {
const parsed = Number.parseInt(rawVersion.replace(/^v/i, ""), 10);
@@ -222,9 +236,12 @@ export const createBeamModelVersionRecord = (
downloadUrl: beamViewer.downloadUrl,
originalFilename: beamViewer.originalFilename,
previewAvailable: beamViewer.previewAvailable,
projectId: beamViewer.projectId,
sha256: beamViewer.sha256,
size: options.size ?? beamViewer.conversion?.size ?? Number(options.attachment?.attributes.size ?? 0),
sourceSrc: beamViewer.conversion?.sourceSrc || beamViewer.src,
src: beamViewer.src,
status: beamViewer.conversion?.status || "ready",
type: beamViewer.type,
uploadedBy: beamViewer.uploadedBy || options.uploadedBy || options.attachment?.created_by,
uploadedAt: beamViewer.uploadedAt,
@@ -251,7 +268,7 @@ export const getBeamModelVersionRecords = (
return versions
.filter((version) => typeof version?.version === "number" && Number.isFinite(version.version))
.toSorted((first, second) => first.version - second.version);
.sort((first, second) => first.version - second.version);
};
export const mergeBeamModelVersionRecords = (
@@ -268,11 +285,26 @@ export const mergeBeamModelVersionRecords = (
) ||
nextBeamViewer.versions?.[0] ||
createBeamModelVersionRecord(nextBeamViewer);
return [...previousVersions.filter((version) => !isSameBeamVersionRecord(version, nextRecord)), nextRecord].toSorted(
return [...previousVersions.filter((version) => !isSameBeamVersionRecord(version, nextRecord)), nextRecord].sort(
(first, second) => first.version - second.version
);
};
export const mergeBeamModelVersionRecordLists = (
firstVersions: TBeamModelVersionRecord[] = [],
secondVersions: TBeamModelVersionRecord[] = []
): TBeamModelVersionRecord[] => {
const byKey = new Map<string, TBeamModelVersionRecord>();
[...firstVersions, ...secondVersions].forEach((version) => {
const key = version.versionId || `version-${version.version}`;
const previous = byKey.get(key);
byKey.set(key, { ...(previous || {}), ...version });
});
return [...byKey.values()]
.filter((version) => typeof version?.version === "number" && Number.isFinite(version.version))
.sort((first, second) => first.version - second.version);
};
export const syncCurrentBeamVersionRecord = (
beamViewer: TBeamViewerAttachment,
attachment?: TIssueAttachment
@@ -287,6 +319,14 @@ export const syncCurrentBeamVersionRecord = (
export const getBeamVersionViewerUrl = (version: TBeamModelVersionRecord): string | undefined => {
if (version.viewerUrl) return version.viewerUrl;
if (!version.conversion && version.previewAvailable && version.src) {
return buildBeamViewerUrl({
name: version.originalFilename,
settingsSrc: version.sourceSrc || version.src,
src: version.src,
type: version.type,
});
}
if (version.conversion?.status !== "ready" || !version.conversion.artifactSrc) return undefined;
const artifactType = version.conversion.artifactType || version.conversion.targetFormat || "gltf";
return buildBeamViewerUrl({
@@ -315,6 +355,25 @@ export const fetchBeamConversionStatus = async (beamViewer: TBeamViewerAttachmen
};
};
export const fetchBeamModelVersions = async (
beamViewer: TBeamViewerAttachment
): Promise<TBeamVersionHistoryResponse> => {
const versionsUrl = new URL("/api/uploads/versions", `${getBeamApiBaseUrl()}/`);
if (beamViewer.projectId && beamViewer.assetId) {
versionsUrl.searchParams.set("projectId", beamViewer.projectId);
versionsUrl.searchParams.set("assetId", beamViewer.assetId);
} else {
versionsUrl.searchParams.set("src", toBeamRelativeUploadSrc(beamViewer.src));
}
const response = await fetch(versionsUrl.toString(), { credentials: "include" });
if (!response.ok) {
throw new Error(`BIM version history failed: HTTP ${response.status}`);
}
return (await response.json()) as TBeamVersionHistoryResponse;
};
export const uploadBeamModelFile = (
file: File,
options: {
@@ -369,6 +428,7 @@ export const uploadBeamModelFile = (
assetId?: string;
conversion?: TBeamViewerAttachment["conversion"];
originalFilename?: string;
projectId?: string;
sha256?: string;
src?: string;
uploadedAt?: string;
@@ -387,6 +447,7 @@ export const uploadBeamModelFile = (
downloadUrl: downloadUrl.toString(),
originalFilename: response.originalFilename || file.name,
previewAvailable: !!directViewerType,
projectId: response.projectId,
sha256: response.sha256,
src: downloadUrl.toString(),
type,