Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(react-components): functionality surrounding Points of interest and bump to 0.67.0 #4866

Merged
merged 16 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import { AnnotationsCreateTool } from '../annotations/commands/AnnotationsCreate
import { AnnotationsShowCommand } from '../annotations/commands/AnnotationsShowCommand';
import { AnnotationsShowOnTopCommand } from '../annotations/commands/AnnotationsShowOnTopCommand';
import { AnnotationsSelectTool } from '../annotations/commands/AnnotationsSelectTool';
import { type DmsUniqueIdentifier } from '../../../data-providers';
import { PointsOfInterestTool } from '../pointsOfInterest/PointsOfInterestTool';
import { Image360ActionCommand } from '../../base/concreteCommands/image360Collection/Image360ActionCommand';
import { Image360Action } from '@cognite/reveal';
import { type ExternalId } from '../../../data-providers/FdmSDK';

export class StoryBookConfig extends BaseRevealConfig {
// ==================================================
Expand Down Expand Up @@ -63,7 +63,10 @@ export class StoryBookConfig extends BaseRevealConfig {
undefined,
new MeasurementTool(),
new ClipTool(),
new PointsOfInterestTool<DmsUniqueIdentifier>(),
new PointsOfInterestTool<ExternalId>(),
undefined,
new MockSettingsCommand(),
new MockFilterCommand(),
undefined,
new MockSettingsCommand(),
new MockFilterCommand(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*!
* Copyright 2024 Cognite AS
*/
import { BaseInputCommand } from '../../base/commands/BaseInputCommand';
import { Changes } from '../../base/domainObjectsHelpers/Changes';
import { type TranslateDelegate } from '../../base/utilities/TranslateKey';
import { PointsOfInterestDomainObject } from './PointsOfInterestDomainObject';
import { type PointOfInterest } from './types';

export class CreatePoICommentCommand extends BaseInputCommand {
private readonly _poi: PointOfInterest<unknown>;

constructor(poi: PointOfInterest<unknown>) {
super();

this._poi = poi;
}

public override get hasData(): true {
return true;
}

public override getPostButtonLabel(t: TranslateDelegate): string | undefined {
return t('SEND', 'Send');
}

public override getCancelButtonLabel(t: TranslateDelegate): string | undefined {
return t('CANCEL', 'Cancel');
}

public override getPlaceholder(t: TranslateDelegate): string | undefined {
return t('COMMENT_PLACEHOLDER', 'Write a comment');
}
danpriori marked this conversation as resolved.
Show resolved Hide resolved

public override invokeCore(): boolean {
if (this._content === undefined) {
return false;
}

const domainObject = this.rootDomainObject.getDescendantByType(PointsOfInterestDomainObject);
void domainObject?.postCommentForPoi(this._poi, this._content);
domainObject?.notify(Changes.addedPart);
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*!
* Copyright 2024 Cognite AS
*/
import { type Vector3 } from 'three';
import { BaseInputCommand } from '../../base/commands/BaseInputCommand';
import { PointsOfInterestDomainObject } from './PointsOfInterestDomainObject';
import { type TranslateDelegate } from '../../base/utilities/TranslateKey';
import { createPointsOfInterestPropertiesFromPointAndTitle } from './types';

export class CreatePointsOfInterestWithDescriptionCommand extends BaseInputCommand {
private readonly _point: Vector3;

constructor(position: Vector3) {
super();

this._point = position;
}

public override getPostButtonLabel(t: TranslateDelegate): string | undefined {
return t('CREATE', 'Create');
}

public override getCancelButtonLabel(t: TranslateDelegate): string | undefined {
return t('CANCEL', 'Cancel');
}

public override getPlaceholder(t: TranslateDelegate): string | undefined {
return t('POI_DESCRIPTION_PLACEHOLDER', 'Write a points of interest description');
}

public override get hasData(): true {
return true;
}

public override invokeCore(): boolean {
if (this._content === undefined) {
return false;
}

const domainObject = this.renderTarget.rootDomainObject.getDescendantByType(
PointsOfInterestDomainObject
);
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved

if (domainObject === undefined) {
return false;
}

const poi = domainObject.addPendingPointsOfInterest(
createPointsOfInterestPropertiesFromPointAndTitle(this._point, this._content)
);

void domainObject.save();
domainObject.setSelectedPointOfInterest(poi);

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class DeletePointsOfInterestCommand<PoIIdType> extends PointsOfInterestCo
}

pois.removePointsOfInterest(selectedOverlay);
pois.setSelectedPointsOfInterest(undefined);
pois.setSelectedPointOfInterest(undefined);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*!
* Copyright 2024 Cognite AS
*/
import { type Vector3 } from 'three';
import { type IconName } from '../../base/utilities/IconName';
import { type TranslateDelegate, type TranslateKey } from '../../base/utilities/TranslateKey';
import { RenderTargetCommand } from '../../base/commands/RenderTargetCommand';
import { PointsOfInterestTool } from './PointsOfInterestTool';
import { CreatePointsOfInterestWithDescriptionCommand } from './CreatePointsOfInterestWithDescriptionCommand';

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

constructor(position: Vector3) {
super();
this._position = position;
}

public override get isEnabled(): boolean {
return this._position !== undefined;
}

public override get icon(): IconName {
return 'Waypoint';
}

public override get tooltip(): TranslateKey {
return { key: 'CREATE_POI', fallback: 'Create point of interest' };
danpriori marked this conversation as resolved.
Show resolved Hide resolved
}

public override getLabel(t: TranslateDelegate): string {
return t('CREATE_POI', 'Create point of interest');
}

public override get hasData(): boolean {
return true;
}

protected override invokeCore(): boolean {
if (this._position === undefined) {
return false;
}

const poiTool = this.renderTarget.commandsController.getToolByType(PointsOfInterestTool);

if (poiTool === undefined) {
return false;
}

const previousTool = this.renderTarget.commandsController.activeTool;
this.renderTarget.commandsController.setActiveTool(poiTool);
const createPointCommand = new CreatePointsOfInterestWithDescriptionCommand(this._position);

const onFinishCallback = (): void => {
poiTool.setAnchoredDialogContent(undefined);
};

const onCancelCallback = (): void => {
this.renderTarget.commandsController.setActiveTool(previousTool);
onFinishCallback();
};

createPointCommand.onFinish = onFinishCallback;
createPointCommand.onCancel = onCancelCallback;

poiTool.setAnchoredDialogContent({
contentCommands: [createPointCommand],
position: this._position,
onCloseCallback: onCancelCallback
});

return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/*!
* Copyright 2024 Cognite AS
*/
import { type PointsOfInterestInstance, type PointsOfInterestProperties } from './models';
import {
type CommentProperties,
type PointsOfInterestInstance,
type PointsOfInterestProperties
} from './models';
import { type PointsOfInterestProvider } from './PointsOfInterestProvider';

/**
Expand All @@ -12,11 +16,43 @@ export class PointsOfInterestCache<PoIId> {
private readonly _loadedPromise: Promise<Array<PointsOfInterestInstance<PoIId>>>;
private readonly _poiProvider: PointsOfInterestProvider<PoIId>;

private readonly _poiCommentCache = new Map<string, CommentProperties[]>();

constructor(poiProvider: PointsOfInterestProvider<PoIId>) {
this._poiProvider = poiProvider;
this._loadedPromise = poiProvider.fetchAllPointsOfInterest();
}

public async getPoiCommentsForPoi(id: PoIId): Promise<CommentProperties[]> {
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
const hashKey = createHashKey(id);

const cacheElement = this._poiCommentCache.get(hashKey);

if (cacheElement !== undefined) {
return cacheElement;
}

const comments = await this._poiProvider.getPointsOfInterestComments(id);
this._poiCommentCache.set(hashKey, comments);

return comments;
}

public async postCommentForPoi(id: PoIId, content: string): Promise<CommentProperties> {
const comment = await this._poiProvider.postPointsOfInterestComment(id, content);

const hashKey = createHashKey(id);
const cacheElement = this._poiCommentCache.get(hashKey);

if (cacheElement !== undefined) {
cacheElement.push(comment);
} else {
this._poiCommentCache.set(hashKey, [comment]);
}

return comment;
}

public async getFinishedOriginalLoadingPromise(): Promise<
Array<PointsOfInterestInstance<PoIId>>
> {
Expand All @@ -41,3 +77,11 @@ export class PointsOfInterestCache<PoIId> {
return await this._poiProvider.createPointsOfInterest(pois);
}
}

function createHashKey(id: any): string {
if (typeof id === 'string') {
return id;
}

return JSON.stringify(id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,32 @@ import { type TranslateKey } from '../../base/utilities/TranslateKey';
import { Changes } from '../../base/domainObjectsHelpers/Changes';
import { PointsOfInterestCache } from './PointsOfInterestCache';
import { PanelInfo } from '../../base/domainObjectsHelpers/PanelInfo';
import { type PointsOfInterest, PointsOfInterestStatus } from './types';
import { type PointOfInterest, PointsOfInterestStatus } from './types';
import { partition, remove } from 'lodash';
import { type PointsOfInterestProperties } from './models';
import { type CommentProperties, type PointsOfInterestProperties } from './models';
import { Quantity } from '../../base/domainObjectsHelpers/Quantity';
import { type PointsOfInterestProvider } from './PointsOfInterestProvider';
import { isDefined } from '../../../utilities/isDefined';

export class PointsOfInterestDomainObject<PoIIdType> extends VisualDomainObject {
private _selectedPointsOfInterest: PointsOfInterest<PoIIdType> | undefined;
private _selectedPointsOfInterest: PointOfInterest<PoIIdType> | undefined;
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
private readonly _poisCache: PointsOfInterestCache<PoIIdType>;

private _pointsOfInterest: Array<PointsOfInterest<PoIIdType>> = [];
private _pointsOfInterest: Array<PointOfInterest<PoIIdType>> = [];

constructor(poiProvider: PointsOfInterestProvider<PoIIdType>) {
super();

this._poisCache = new PointsOfInterestCache<PoIIdType>(poiProvider);
void this._poisCache.getFinishedOriginalLoadingPromise().then((pois) => {
this._pointsOfInterest = pois.map((poi) => ({
id: poi.id,
properties: poi.properties,
status: PointsOfInterestStatus.Default
}));
this._pointsOfInterest = [
...pois.map((poi) => ({
id: poi.id,
properties: poi.properties,
status: PointsOfInterestStatus.Default
})),
...this._pointsOfInterest
];
this.notify(Changes.geometry);
});
}
Expand Down Expand Up @@ -72,7 +75,7 @@ export class PointsOfInterestDomainObject<PoIIdType> extends VisualDomainObject

public addPendingPointsOfInterest(
poiData: PointsOfInterestProperties
): PointsOfInterest<PoIIdType> {
): PointOfInterest<PoIIdType> {
const newPointsOfInterest = {
properties: poiData,
status: PointsOfInterestStatus.PendingCreation
Expand All @@ -85,7 +88,7 @@ export class PointsOfInterestDomainObject<PoIIdType> extends VisualDomainObject
return newPointsOfInterest;
}

public removePointsOfInterest(poiToDelete: PointsOfInterest<PoIIdType>): void {
public removePointsOfInterest(poiToDelete: PointOfInterest<PoIIdType>): void {
if (poiToDelete.status === PointsOfInterestStatus.PendingCreation) {
remove(this._pointsOfInterest, (poi) => poiToDelete === poi);
} else if (this._pointsOfInterest.includes(poiToDelete)) {
Expand All @@ -95,11 +98,11 @@ export class PointsOfInterestDomainObject<PoIIdType> extends VisualDomainObject
this.notify(Changes.geometry);
}

public get pois(): Array<PointsOfInterest<PoIIdType>> {
public get pointsOfInterest(): Array<PointOfInterest<PoIIdType>> {
return this._pointsOfInterest;
}

public get selectedPointsOfInterest(): PointsOfInterest<PoIIdType> | undefined {
public get selectedPointsOfInterest(): PointOfInterest<PoIIdType> | undefined {
return this._selectedPointsOfInterest;
}

Expand All @@ -114,7 +117,7 @@ export class PointsOfInterestDomainObject<PoIIdType> extends VisualDomainObject
(this._selectedPointsOfInterest.status === PointsOfInterestStatus.PendingCreation ||
this._selectedPointsOfInterest.status === PointsOfInterestStatus.PendingDeletion)
) {
this.setSelectedPointsOfInterest(undefined);
this.setSelectedPointOfInterest(undefined);
}

const [toRemove, notToRemove] = partition(
Expand Down Expand Up @@ -148,12 +151,30 @@ export class PointsOfInterestDomainObject<PoIIdType> extends VisualDomainObject
this.notify(Changes.geometry);
}

public setSelectedPointsOfInterest(poi: PointsOfInterest<PoIIdType> | undefined): void {
public setSelectedPointOfInterest(poi: PointOfInterest<PoIIdType> | undefined): void {
this._selectedPointsOfInterest = poi;

this.notify(Changes.selected);
}

public async postCommentForPoi(
poi: PointOfInterest<PoIIdType>,
content: string
): Promise<CommentProperties | undefined> {
if (poi.id === undefined) {
return undefined;
}

return await this._poisCache.postCommentForPoi(poi.id, content);
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
}

public async getCommentsForPoi(poi: PointOfInterest<PoIIdType>): Promise<CommentProperties[]> {
if (poi.id === undefined) {
return [];
}
return await this._poisCache.getPoiCommentsForPoi(poi.id);
}

public hasPendingPointsOfInterest(): boolean {
return this._pointsOfInterest.some(
(poi) => poi.status === PointsOfInterestStatus.PendingCreation
Expand Down
Loading