Skip to content

Commit

Permalink
feat(react-components): upload instance with PoI (#4918)
Browse files Browse the repository at this point in the history
* feat(react-components): upload instance with PoI

* fix: upload function

* chore: lint fix
  • Loading branch information
haakonflatval-cognite authored Dec 2, 2024
1 parent cfc58e4 commit fc44c35
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ export abstract class BaseTool extends RenderTargetCommand {
}

this._renderTarget.contextMenuController.contextMenuPositionData = {
clickEvent: event,
position: new Vector2(event.layerX, event.layerY),
intersection
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ContextMenuUpdater } from '../reactUpdaters/ContextMenuUpdater';
import { type Vector2 } from 'three';

export type ContextMenuData = {
clickEvent: PointerEvent;
position: Vector2;
intersection: AnyIntersection | undefined;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { type Vector3 } from 'three';
import { PointsOfInterestDomainObject } from './PointsOfInterestDomainObject';
import { type TranslationInput } from '../../base/utilities/TranslateInput';
import { createPointsOfInterestPropertiesFromPointAndTitle } from './types';
import { type DmsUniqueIdentifier } from '../../../data-providers';
import { type InstanceReference, type DmsUniqueIdentifier } from '../../../data-providers';

import {
CustomBaseInputCommand,
type FieldContent
Expand All @@ -15,6 +16,8 @@ export class CreatePointsOfInterestWithDescriptionCommand extends CustomBaseInpu
private readonly _point: Vector3;
private readonly _scene: DmsUniqueIdentifier;

private _associatedInstance: InstanceReference | undefined;

private readonly poisPlaceholders: TranslationInput[] = [
{ key: 'NAME' },
{ key: 'POINT_OF_INTEREST_DESCRIPTION_PLACEHOLDER' }
Expand All @@ -34,6 +37,14 @@ export class CreatePointsOfInterestWithDescriptionCommand extends CustomBaseInpu
this._contents = this.poiContents;
}

public get associatedInstance(): InstanceReference | undefined {
return this._associatedInstance;
}

public set associatedInstance(instance: InstanceReference | undefined) {
this._associatedInstance = instance;
}

public override getPostButtonLabel(): TranslationInput {
return { key: 'CREATE' };
}
Expand Down Expand Up @@ -71,7 +82,8 @@ export class CreatePointsOfInterestWithDescriptionCommand extends CustomBaseInpu
createPointsOfInterestPropertiesFromPointAndTitle(
this._point,
this._scene,
this._contents.map((content) => content.content)
this._contents.map((content) => content.content),
this._associatedInstance
)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import { PointsOfInterestTool } from './PointsOfInterestTool';

export class InitiatePointsOfInterestCommand extends RenderTargetCommand {
private readonly _position: Vector3;
private readonly _pointerEvent: PointerEvent;

constructor(position: Vector3) {
constructor(position: Vector3, clickEvent: PointerEvent) {
super();
this._position = position;
this._pointerEvent = clickEvent;
}

public override get hasData(): boolean {
Expand All @@ -35,7 +37,7 @@ export class InitiatePointsOfInterestCommand extends RenderTargetCommand {
}

this.renderTarget.commandsController.setActiveTool(poiTool);
poiTool.openCreateCommandDialog(this._position);
poiTool.openCreateCommandDialog(this._position, this._pointerEvent);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export class PointsOfInterestTool<PoiIdType> extends BaseEditTool {
AnchoredDialogUpdater.update();
}

public openCreateCommandDialog(position: Vector3): void {
public openCreateCommandDialog(position: Vector3, clickEvent: PointerEvent): void {
const poiObject = this.getPointsOfInterestDomainObject();

const scene = poiObject?.getScene();
Expand Down Expand Up @@ -184,6 +184,15 @@ export class PointsOfInterestTool<PoiIdType> extends BaseEditTool {
onCloseCallback: onCancelCallback,
customListeners
});

void getInstancesFromClick(this.renderTarget, clickEvent).then((instances) => {
if (instances !== undefined && instances.length !== 0) {
const selectedInstance = instances[0];

this.setAssignedInstance(selectedInstance);
createPointCommand.associatedInstance = selectedInstance;
}
});
}

public closeCreateCommandDialog(): void {
Expand All @@ -209,12 +218,6 @@ export class PointsOfInterestTool<PoiIdType> extends BaseEditTool {
return;
}

this.openCreateCommandDialog(intersection.point);

const instances = await getInstancesFromClick(this.renderTarget, event);

if (instances !== undefined && instances.length !== 0) {
this.setAssignedInstance(instances[0]);
}
this.openCreateCommandDialog(intersection.point, event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ import { type CommentProperties, type PointsOfInterestInstance } from '../models
import { type PointsOfInterestProvider } from '../PointsOfInterestProvider';

import { v4 as uuid } from 'uuid';
import { type PoiItem } from './types';
import {
type PoiExternalAssetRef,
type PoiExternalDMRef,
type PoiExternalInstanceRef,
type PoiItem
} from './types';
import { isDefined } from '../../../../utilities/isDefined';
import { uniq } from 'lodash';
import { createUpsertRequestFromPois } from './createUpsertRequestFromPois';
import { type InstanceReference } from '../../../../data-providers';

/**
* A PoI provider using the Cognite Application Data Storage service as backing storage
Expand Down Expand Up @@ -166,7 +172,34 @@ function poiItemToInstance(item: PoiItem): PointsOfInterestInstance<ExternalId>
externalId: item.sceneExternalId ?? 'dummy-scene-external-id',
space: item.sceneSpace ?? 'dummy-scene-space'
},
instanceRef: poiExternalInstanceRefToInstanceReference(item?.assetRef),
sceneState: item.sceneState
}
};
}

function poiExternalInstanceRefToInstanceReference(
instance: PoiExternalInstanceRef | undefined
): InstanceReference | undefined {
if (instance === undefined) {
return undefined;
}

if (isPoiAssetRef(instance)) {
return { assetId: instance.id };
} else if (isPoiDMRef(instance)) {
return { externalId: instance.externalId, space: instance.instanceSpace };
}
throw Error('Unrecognized PoI external reference type');
}

function isPoiAssetRef(instance: PoiExternalInstanceRef): instance is PoiExternalAssetRef {
return (instance as PoiExternalAssetRef).id !== undefined;
}

function isPoiDMRef(instance: PoiExternalInstanceRef): instance is PoiExternalDMRef {
return (
(instance as PoiExternalDMRef).externalId !== undefined &&
(instance as PoiExternalDMRef).instanceSpace !== undefined
);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/*!
* Copyright 2024 Cognite AS
*/
import { type DmsUniqueIdentifier } from '../../../../data-providers';
import { type InstanceReference, type DmsUniqueIdentifier } from '../../../../data-providers';
import { type ExternalId } from '../../../../data-providers/FdmSDK';
import { isAssetInstance } from '../../../../data-providers/types';
import { type PointsOfInterestInstance, type PoiVisibility, type SceneState } from '../models';
import { type PoiExternalInstanceRef } from './types';

type PoiUpsertObject = {
externalId: ExternalId;
Expand All @@ -13,6 +15,7 @@ type PoiUpsertObject = {
sceneState: SceneState;
scene: DmsUniqueIdentifier;
visibility: PoiVisibility;
assetRef?: PoiExternalInstanceRef;
};

type PoiUpsertRequest = {
Expand All @@ -30,7 +33,22 @@ export function createUpsertRequestFromPois(
position: [poi.positionX, poi.positionY, poi.positionZ],
sceneState: {},
scene: poi.scene,
visibility: poi.visibility ?? 'PRIVATE'
visibility: poi.visibility ?? 'PRIVATE',
assetRef: instanceReferenceToPoiExternalInstanceReference(poi.instanceRef)
}))
};
}

function instanceReferenceToPoiExternalInstanceReference(
instanceRef: InstanceReference | undefined
): PoiExternalInstanceRef | undefined {
if (instanceRef === undefined) {
return undefined;
}

if (isAssetInstance(instanceRef)) {
return { id: instanceRef.assetId };
} else {
return { externalId: instanceRef.externalId, instanceSpace: instanceRef.space };
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
/*!
* Copyright 2024 Cognite AS
*/
import { type InternalId } from '@cognite/sdk';
import { type DmsUniqueIdentifier } from '../../../../data-providers';
import { type Space, type ExternalId } from '../../../../data-providers/FdmSDK';

export type PoiExternalAssetRef = { id: number };
export type PoiExternalDMRef = { externalId: ExternalId; instanceSpace: Space };
export type PoiExternalInstanceRef = PoiExternalAssetRef | PoiExternalDMRef;

export type PoiUpsertRequestPayload = {
externalId: ExternalId;
name: string;
description?: string;
position: Vec3;
sceneState: PoiSceneState;
screenshotFile: InternalId;
screenshotFile: number;
scene: DmsUniqueIdentifier;
assetRef: { id: InternalId } | DmsUniqueIdentifier;
assetRef: PoiExternalInstanceRef;
visibility: PoiVisibility;
};

Expand All @@ -26,7 +29,7 @@ export type PoiItem = {
sceneExternalId?: ExternalId;
sceneSpace?: Space;
sceneState: PoiSceneState;
assetRef: DmsUniqueIdentifier;
assetRef?: PoiExternalInstanceRef;
visibility: PoiVisibility;
createdTime: number;
lastUpdatedTime: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright 2024 Cognite AS
*/

import { type DmsUniqueIdentifier } from '../../../data-providers';
import { type InstanceReference, type DmsUniqueIdentifier } from '../../../data-providers';

export type PoiVisibility = 'PUBLIC' | 'PRIVATE';

Expand Down Expand Up @@ -30,7 +30,6 @@ export type PointsOfInterestProperties = {
// "The status of the observation (draft, completed, sent)"
// status?: string;
// "External ID of the associated CDF Asset"
// asset?: DmsUniqueIdentifier;
// "List of associated files"
// files?: DmsUniqueIdentifier[];
// "description of how the observation was troubleshooted"
Expand All @@ -44,6 +43,7 @@ export type PointsOfInterestProperties = {
positionY: number;
positionZ: number;
scene: DmsUniqueIdentifier;
instanceRef?: InstanceReference;
// "Comments"
// comments?: CommentProperties[];
sceneState: SceneState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { type PointsOfInterestProperties } from './models';
import { type Vector3 } from 'three';
import { type DomainObjectIntersection } from '../../base/domainObjectsHelpers/DomainObjectIntersection';
import { type PointsOfInterestDomainObject } from './PointsOfInterestDomainObject';
import { type DmsUniqueIdentifier } from '../../../data-providers';
import { type InstanceReference, type DmsUniqueIdentifier } from '../../../data-providers';

export enum PointsOfInterestStatus {
Default,
Expand All @@ -27,7 +27,8 @@ export type PointOfInterest<IdType> = {
export function createPointsOfInterestPropertiesFromPointAndTitle(
point: Vector3,
scene: DmsUniqueIdentifier,
contents: string[]
contents: string[],
associatedInstance: InstanceReference | undefined
): PointsOfInterestProperties {
const cdfPosition = point.clone().applyMatrix4(CDF_TO_VIEWER_TRANSFORMATION.clone().invert());
return {
Expand All @@ -37,7 +38,8 @@ export function createPointsOfInterestPropertiesFromPointAndTitle(
scene,
sceneState: {},
name: contents[0],
description: contents[1]
description: contents[1],
instanceRef: associatedInstance
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,13 @@ export class RevealButtons {
static PointsOfInterest = (prop: ButtonProp): ReactElement =>
createButtonFromCommandConstructor(() => new PointsOfInterestTool(), prop);

static PointsOfInterestInitiateCreation = (prop: { point: Vector3 } & ButtonProp): ReactElement =>
createButtonFromCommandConstructor(() => new InitiatePointsOfInterestCommand(prop.point), prop);
static PointsOfInterestInitiateCreation = (
prop: { point: Vector3; clickEvent: PointerEvent } & ButtonProp
): ReactElement =>
createButtonFromCommandConstructor(
() => new InitiatePointsOfInterestCommand(prop.point, prop.clickEvent),
prop
);

static DeleteSelectedPointOfInterest = (prop: ButtonProp): ReactElement =>
createButtonFromCommandConstructor(() => new DeleteSelectedPointsOfInterestCommand(), prop);
Expand Down
7 changes: 6 additions & 1 deletion react-components/stories/Architecture.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ const ContextMenuContent = ({
return (
<Menu>
<ActionList>
{point !== undefined && <RevealButtons.PointsOfInterestInitiateCreation point={point} />}
{point !== undefined && (
<RevealButtons.PointsOfInterestInitiateCreation
point={point}
clickEvent={contextMenuData.clickEvent}
/>
)}
</ActionList>
</Menu>
);
Expand Down
10 changes: 2 additions & 8 deletions react-components/stories/HighlightNode.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
useClickedNodeData,
useCameraNavigation,
type AddResourceOptions,
type FdmAssetStylingGroup,
RevealContext
} from '../src';
import { Color } from 'three';
Expand All @@ -19,10 +18,7 @@ import { type CadIntersection, DefaultNodeAppearance } from '@cognite/reveal';
import { createSdkByUrlToken } from './utilities/createSdkByUrlToken';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { RevealResourcesFitCameraOnLoad } from './utilities/with3dResoursesFitCameraOnLoad';
import {
type Image360AssetStylingGroup,
type AssetStylingGroup
} from '../src/components/Reveal3DResources/types';
import { type InstanceStylingGroup } from '../src/components/Reveal3DResources/types';
import { type AnnotationsCogniteAnnotationTypesImagesAssetLink } from '@cognite/sdk';

const meta = {
Expand Down Expand Up @@ -82,9 +78,7 @@ export const Main: Story = {
};

const StoryContent = ({ resources }: { resources: AddResourceOptions[] }): ReactElement => {
const [stylingGroups, setStylingGroups] = useState<
Array<FdmAssetStylingGroup | AssetStylingGroup | Image360AssetStylingGroup>
>([]);
const [stylingGroups, setStylingGroups] = useState<InstanceStylingGroup[]>([]);
const cameraNavigation = useCameraNavigation();
const nodeData = useClickedNodeData();

Expand Down

0 comments on commit fc44c35

Please sign in to comment.