Skip to content

Commit

Permalink
fix: user selects none; location disappears correctly (#1155)
Browse files Browse the repository at this point in the history
* feat: dynamic location picker for entities

* feat: added translation, corrected some params

* feat: moving changes to a separate PR

* feat: updated tests

* fix: update package lock

* fix: get location items more flexible

* fix: suggested change from tom

* fix: updated tests, added to get type from entity

* fix: made edit test more meaningful

* fix: improving if statement

* fix: simplified logic w tom

* fix: updated tests
  • Loading branch information
abp6318 authored Aug 14, 2023
1 parent 798e2f6 commit 3a13434
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 24 deletions.
48 changes: 30 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion packages/common/src/content/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
getItem,
removeItem,
} from "@esri/arcgis-rest-portal";
import { IHubContent, IHubContentEditor, IHubEditableContent } from "../core";
import { IHubContentEditor, IHubEditableContent } from "../core";

// Note - we separate these imports so we can cleanly spy on things in tests
import {
Expand All @@ -20,6 +20,7 @@ import { getPropertyMap } from "./_internal/getPropertyMap";
import { cloneObject } from "../util";
import { IModel } from "../types";
import { computeProps } from "./_internal/computeProps";
import { getProp } from "../objects/get-prop";

// TODO: move this to defaults?
const DEFAULT_CONTENT_MODEL: IModel = {
Expand Down Expand Up @@ -104,6 +105,12 @@ export async function updateContent(
// we are not attempting to handle "concurrent edit" conflict resolution
// but this is where we would apply that sort of logic
const modelToUpdate = mapper.entityToStore(content, model);

// prevent map from displaying when boundary is 'none'
const locationType = getProp(modelToUpdate, "item.properties.location.type");
modelToUpdate.item.properties.boundary =
locationType === "none" ? "none" : "item";

// TODO: if we have resources disconnect them from the model for now.
// if (modelToUpdate.resources) {
// resources = configureBaseResources(
Expand Down
3 changes: 3 additions & 0 deletions packages/common/src/core/getTypeFromEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export function getTypeFromEntity(
case "Group":
type = "group";
break;
case "Hub Content":
type = "content";
break;
default:
// TODO: other families go here? feedback? solution? template?
const contentFamilies = ["app", "content", "dataset", "document", "map"];
Expand Down
69 changes: 66 additions & 3 deletions packages/common/src/core/schemas/internal/getLocationOptions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { extentToBBox, getGeographicOrgExtent } from "../../../extent";
import {
bBoxToExtent,
extentToBBox,
getGeographicOrgExtent,
isBBox,
} from "../../../extent";
import { IHubRequestOptions } from "../../../types";
import { getTypeFromEntity } from "../../getTypeFromEntity";

import { ConfigurableEntity } from "./ConfigurableEntity";
import { IHubLocation, IHubLocationOption } from "../../types/IHubLocation";
import { IExtent } from "@esri/arcgis-rest-types";

const getItemExtent = (itemExtent: number[][]): IExtent => {
return isBBox(itemExtent)
? ({ ...bBoxToExtent(itemExtent), type: "extent" } as unknown as IExtent)
: undefined;
};

/**
* Construct the dynamic location picker options with the entity's
Expand All @@ -22,9 +34,58 @@ export async function getLocationOptions(
portalName: string,
hubRequestOptions: IHubRequestOptions
): Promise<IHubLocationOption[]> {
const defaultExtent = await getGeographicOrgExtent(hubRequestOptions);
const location: IHubLocation = entity.location;
const typeFromEntity = getTypeFromEntity(entity);

switch (typeFromEntity) {
case "content":
return getContentLocationOptions(entity);
default:
return getDefaultLocationOptions(entity, portalName, hubRequestOptions);
}
}

// TODO: Refactor parameters, they are icky gross
// TODO: Maybe move these to outside of core and into respective entities

export async function getContentLocationOptions(
entity: ConfigurableEntity
): Promise<IHubLocationOption[]> {
const defaultExtent: IExtent = getItemExtent(entity.extent);
const defaultExtentIsBBox = isBBox(entity.extent);
const boundary = entity.boundary;
const isNone = boundary === "none";
return [
{
label: "{{shared.fields.location.none:translate}}",
location: { type: "none" },
selected: isNone,
},
{
label: "{{shared.fields.location.itemExtent:translate}}",
entityType: "content",
selected: !isNone,
location: {
type: "custom",
// TODO: Add custom bbox option here
// TODO: Remove "Add another location?" notification that appears when selecting a location
extent: defaultExtentIsBBox ? extentToBBox(defaultExtent) : undefined,
spatialReference: defaultExtentIsBBox
? defaultExtent.spatialReference
: undefined,
},
},
] as IHubLocationOption[];
}

export async function getDefaultLocationOptions(
entity: ConfigurableEntity,
portalName: string,
hubRequestOptions: IHubRequestOptions
): Promise<IHubLocationOption[]> {
const defaultExtent: IExtent = await getGeographicOrgExtent(
hubRequestOptions
);
const location: IHubLocation = entity.location;
return (
[
{
Expand Down Expand Up @@ -64,3 +125,5 @@ export async function getLocationOptions(
return option;
});
}

// TODO: Add other location options here
48 changes: 48 additions & 0 deletions packages/common/test/content/edit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ describe("content editing:", () => {
schemaVersion: 1,
canEdit: false,
canDelete: false,
location: { type: "none" },
};
const chk = await updateContent(content, { authentication: MOCK_AUTH });
expect(chk.id).toBe(GUID);
Expand All @@ -79,6 +80,53 @@ describe("content editing:", () => {
expect(updateModelSpy.calls.count()).toBe(1);
const modelToUpdate = updateModelSpy.calls.argsFor(0)[0];
expect(modelToUpdate.item.description).toBe(content.description);
expect(modelToUpdate.item.properties.boundary).toBe("none");
});
});
describe("update content with location:", () => {
it("converts to a model and updates the item", async () => {
const getItemSpy = spyOn(portalModule, "getItem").and.returnValue(
Promise.resolve({
item: {
typeKeywords: [],
},
})
);
const updateModelSpy = spyOn(modelUtils, "updateModel").and.callFake(
(m: IModel) => {
return Promise.resolve(m);
}
);
const content: IHubEditableContent = {
itemControl: "edit",
id: GUID,
name: "Hello World",
tags: ["Transportation"],
description: "Some longer description",
slug: "dcdev-wat-blarg",
orgUrlKey: "dcdev",
owner: "dcdev_dude",
type: "Hub Initiative",
createdDate: new Date(1595878748000),
createdDateSource: "item.created",
updatedDate: new Date(1595878750000),
updatedDateSource: "item.modified",
thumbnailUrl: "",
permissions: [],
schemaVersion: 1,
canEdit: false,
canDelete: false,
location: { type: "item" },
};
const chk = await updateContent(content, { authentication: MOCK_AUTH });
expect(chk.id).toBe(GUID);
expect(chk.name).toBe("Hello World");
expect(chk.description).toBe("Some longer description");
expect(getItemSpy.calls.count()).toBe(1);
expect(updateModelSpy.calls.count()).toBe(1);
const modelToUpdate = updateModelSpy.calls.argsFor(0)[0];
expect(modelToUpdate.item.description).toBe(content.description);
expect(modelToUpdate.item.properties.boundary).toBe("item");
});
});
describe("delete content", () => {
Expand Down
Loading

0 comments on commit 3a13434

Please sign in to comment.