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: add links hash for project, initiative, and group entities #1226

Merged
merged 12 commits into from
Sep 28, 2023
63 changes: 34 additions & 29 deletions packages/common/src/core/types/IHubEntityBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,39 @@ export interface ILink {
[key: string]: string;
}

/**
* Interface for entity links
*/
export interface IHubEntityLinks {
/**
* Url to Thumbnail. May not include a token
* TODO: Why should we not include the token?
*/
thumbnail?: string;
/**
* Url to the entities canonical "self"
* For Items/Groups/Users, this will be the Home App url
* For other entities, it will be the canonical url
*/
self: string;
/**
* Relative url of the entity, within a site
*/
siteRelative?: string;
/**
* Relative workspace url of the entity, within a site
*/
workspaceRelative?: string;
/**
* Relative url to the entity's layout editing experience
*/
layoutRelative?: string;
/**
* Additional urls
*/
[key: string]: string | ILink;
}

/**
* Base properties for Hub Entities
* This includes a subset of `IItem`, that can apply to
Expand Down Expand Up @@ -68,33 +101,5 @@ export interface IHubEntityBase {
/**
* Links to related things
*/
links?: {
/**
* Url to Thumbnail. May not include a token
* TODO: Why should we not include the token?
*/
thumbnail?: string;
/**
* Url to the entities canonical "self"
* For Items/Groups/Users, this will be the Home App url
* For other entities, it will be the canonical url
*/
self: string;
/**
* Relative url of the entity, within a site
*/
siteRelative?: string;
/**
* Relative workspace url of the entity, within a site
*/
workspaceRelative?: string;
/**
* Relative url to the entity's layout editing experience
*/
layoutRelative?: string;
/**
* Additional urls
*/
[key: string]: string | ILink;
};
links?: IHubEntityLinks;
}
9 changes: 2 additions & 7 deletions packages/common/src/groups/HubGroups.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { IGroup } from "@esri/arcgis-rest-types";
import { fetchGroupEnrichments } from "./_internal/enrichments";
import { getProp, setProp } from "../objects";
import { getGroupThumbnailUrl } from "../search/utils";
import { parseInclude } from "../search/_internal/parseInclude";
import { IHubRequestOptions } from "../types";
import { getGroupHomeUrl } from "../urls";
import { unique } from "../util";
import { mapBy } from "../utils";
import {
Expand All @@ -19,8 +17,8 @@ import { IUserRequestOptions } from "@esri/arcgis-rest-auth";
import { DEFAULT_GROUP } from "./defaults";
import { convertHubGroupToGroup } from "./_internal/convertHubGroupToGroup";
import { convertGroupToHubGroup } from "./_internal/convertGroupToHubGroup";
import { getRelativeWorkspaceUrl } from "../core/getRelativeWorkspaceUrl";
import { IHubSearchResult } from "../search/types/IHubSearchResult";
import { computeLinks } from "./_internal/computeLinks";

/**
* Enrich a generic search result
Expand Down Expand Up @@ -83,10 +81,7 @@ export async function enrichGroupSearchResult(
});

// Handle links
result.links.thumbnail = getGroupThumbnailUrl(requestOptions.portal, group);
result.links.self = getGroupHomeUrl(result.id, requestOptions);
result.links.siteRelative = `/teams/${result.id}`;
result.links.workspaceRelative = getRelativeWorkspaceUrl("Group", result.id);
result.links = { ...computeLinks(group, requestOptions) };

return result;
}
Expand Down
32 changes: 32 additions & 0 deletions packages/common/src/groups/_internal/computeLinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { IGroup } from "@esri/arcgis-rest-types";
import { IRequestOptions } from "@esri/arcgis-rest-request";
import { UserSession } from "@esri/arcgis-rest-auth";
import { IHubEntityLinks } from "../../core/types";
import { getRelativeWorkspaceUrl } from "../../core/getRelativeWorkspaceUrl";
import { getGroupHomeUrl } from "../../urls/getGroupHomeUrl";
import { getGroupThumbnailUrl } from "../../search/utils";

/**
* Compute the links that get appended to a Hub Group
* search result and entity
*
* @param group
* @param requestOptions
*/
export function computeLinks(
group: IGroup,
requestOptions: IRequestOptions
): IHubEntityLinks {
let token: string;
if (requestOptions.authentication) {
const session: UserSession = requestOptions.authentication as UserSession;
token = session.token;
}

return {
self: getGroupHomeUrl(group.id, requestOptions),
siteRelative: `/teams/${group.id}`,
workspaceRelative: getRelativeWorkspaceUrl("Group", group.id),
thumbnail: getGroupThumbnailUrl(requestOptions.portal, group, token),
};
}
5 changes: 5 additions & 0 deletions packages/common/src/groups/_internal/computeProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { IHubGroup } from "../../core/types/IHubGroup";
import { IGroup } from "@esri/arcgis-rest-types";
import { isDiscussable } from "../../discussions";
import { getGroupThumbnailUrl } from "../../search/utils";
import { getRelativeWorkspaceUrl } from "../../core";
import { getGroupHomeUrl } from "../../urls";
juliannemarik marked this conversation as resolved.
Show resolved Hide resolved
import { computeLinks } from "./computeLinks";

/**
* Given a model and a group, set various computed properties that can't be directly mapped
Expand Down Expand Up @@ -62,6 +65,8 @@ export function computeProps(
group.userMembership?.memberType === "admin";
hubGroup.canDelete = hubGroup.canEdit;

hubGroup.links = computeLinks(group, requestOptions);
dbouwman marked this conversation as resolved.
Show resolved Hide resolved

// cast b/c this takes a partial but returns a full group
return hubGroup as IHubGroup;
}
28 changes: 6 additions & 22 deletions packages/common/src/initiatives/HubInitiatives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ import {
import {
isGuid,
cloneObject,
getItemThumbnailUrl,
unique,
mapBy,
getProp,
getFamily,
IHubRequestOptions,
getItemHomeUrl,
setDiscussableKeyword,
IModel,
} from "../index";
Expand All @@ -41,17 +39,16 @@ import { IEntityInfo, IHubInitiative } from "../core/types";
import { IHubSearchResult } from "../search";
import { parseInclude } from "../search/_internal/parseInclude";
import { fetchItemEnrichments } from "../items/_enrichments";
import { getHubRelativeUrl } from "../content/_internal/internalContentUtils";
import { DEFAULT_INITIATIVE, DEFAULT_INITIATIVE_MODEL } from "./defaults";
import { getPropertyMap } from "./_internal/getPropertyMap";
import { computeProps } from "./_internal/computeProps";
import { applyInitiativeMigrations } from "./_internal/applyInitiativeMigrations";
import { getRelativeWorkspaceUrl } from "../core/getRelativeWorkspaceUrl";
import { combineQueries } from "../search/_internal/combineQueries";
import { portalSearchItemsAsItems } from "../search/_internal/portalSearchItems";
import { getTypeWithKeywordQuery } from "../associations/internal/getTypeWithKeywordQuery";
import { getTypeWithoutKeywordQuery } from "../associations/internal/getTypeWithoutKeywordQuery";
import { negateGroupPredicates } from "../search/_internal/negateGroupPredicates";
import { computeLinks } from "./_internal/computeLinks";
import { getHubRelativeUrl } from "../content/_internal/internalContentUtils";

/**
* @private
Expand Down Expand Up @@ -260,23 +257,10 @@ export async function enrichInitiativeSearchResult(

// Handle links
// TODO: Link handling should be an enrichment
result.links.thumbnail = getItemThumbnailUrl(item, requestOptions);
result.links.self = getItemHomeUrl(result.id, requestOptions);
const identifier = item.id;
// Until the new initiatives route is in place we need to
// route using the id. Once the route is in place we can
// un-comment this
// const identifier = getItemIdentifier(item);

result.links.siteRelative = getHubRelativeUrl(
result.type,
identifier,
item.typeKeywords
);
result.links.workspaceRelative = getRelativeWorkspaceUrl(
result.type,
identifier
);
result.links = { ...computeLinks(item, requestOptions) };
// TODO: remove once sites are separated from initiatives and
// the initiatives view route is released
result.links.siteRelative = getHubRelativeUrl(result.type, result.id);

return result;
}
Expand Down
39 changes: 39 additions & 0 deletions packages/common/src/initiatives/_internal/computeLinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { IItem } from "@esri/arcgis-rest-types";
import { IRequestOptions } from "@esri/arcgis-rest-request";
import { UserSession } from "@esri/arcgis-rest-auth";
import { getItemHomeUrl } from "../../urls";
import { IHubEntityLinks } from "../../core/types";
import { getItemIdentifier } from "../../items";
import { getRelativeWorkspaceUrl } from "../../core/getRelativeWorkspaceUrl";
import { getItemThumbnailUrl } from "../../resources/get-item-thumbnail-url";

/**
* Compute the links that get appended to a Hub Initiative
* search result and entity
*
* @param item
* @param requestOptions
*/
export function computeLinks(
item: IItem,
requestOptions: IRequestOptions
): IHubEntityLinks {
let token: string;
if (requestOptions.authentication) {
const session: UserSession = requestOptions.authentication as UserSession;
token = session.token;
}

return {
self: getItemHomeUrl(item.id, requestOptions),
// TODO: once the initiative view is moved to initiatives/:id,
// update and leverage the getHubRelativeUrl util to construct
// this url. For now, we hard-code to the initiatives2/:id route
siteRelative: `/initiatives2/${getItemIdentifier(item)}`,
workspaceRelative: getRelativeWorkspaceUrl(
item.type,
getItemIdentifier(item)
),
thumbnail: getItemThumbnailUrl(item, requestOptions, token),
};
}
3 changes: 3 additions & 0 deletions packages/common/src/initiatives/_internal/computeProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IHubInitiative } from "../../core";
import { isDiscussable } from "../../discussions";
import { processEntityFeatures } from "../../permissions/_internal/processEntityFeatures";
import { InitiativeDefaultFeatures } from "./InitiativeBusinessRules";
import { computeLinks } from "./computeLinks";

/**
* Given a model and an Initiative, set various computed properties that can't be directly mapped
Expand Down Expand Up @@ -49,6 +50,8 @@ export function computeProps(
InitiativeDefaultFeatures
);

initiative.links = computeLinks(model.item, requestOptions);

// cast b/c this takes a partial but returns a full object
return initiative as IHubInitiative;
}
37 changes: 37 additions & 0 deletions packages/common/src/projects/_internal/computeLinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { IItem } from "@esri/arcgis-rest-types";
import { IRequestOptions } from "@esri/arcgis-rest-request";
import { UserSession } from "@esri/arcgis-rest-auth";
import { getItemHomeUrl } from "../../urls";
import { IHubEntityLinks } from "../../core/types";
import { getItemIdentifier } from "../../items";
import { getHubRelativeUrl } from "../../content/_internal/internalContentUtils";
import { getRelativeWorkspaceUrl } from "../../core/getRelativeWorkspaceUrl";
import { getItemThumbnailUrl } from "../../resources/get-item-thumbnail-url";

/**
* Compute the links that get appended to a Hub Project
* search result and entity
*
* @param item
* @param requestOptions
*/
export function computeLinks(
item: IItem,
requestOptions: IRequestOptions
): IHubEntityLinks {
let token: string;
if (requestOptions.authentication) {
const session: UserSession = requestOptions.authentication as UserSession;
token = session.token;
}

return {
self: getItemHomeUrl(item.id, requestOptions),
siteRelative: getHubRelativeUrl(item.type, getItemIdentifier(item)),
workspaceRelative: getRelativeWorkspaceUrl(
item.type,
getItemIdentifier(item)
),
thumbnail: getItemThumbnailUrl(item, requestOptions, token),
};
}
4 changes: 3 additions & 1 deletion packages/common/src/projects/_internal/computeProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { UserSession } from "@esri/arcgis-rest-auth";
import { getItemThumbnailUrl } from "../../resources";
import { IHubProject } from "../../core";
import { IModel } from "../../types";

import { isDiscussable } from "../../discussions";
import { processEntityFeatures } from "../../permissions/_internal/processEntityFeatures";
import { ProjectDefaultFeatures } from "./ProjectBusinessRules";
import { computeLinks } from "./computeLinks";

/**
* Given a model and a project, set various computed properties that can't be directly mapped
Expand Down Expand Up @@ -44,6 +44,8 @@ export function computeProps(
ProjectDefaultFeatures
);

project.links = computeLinks(model.item, requestOptions);

// cast b/c this takes a partial but returns a full project
return project as IHubProject;
}
19 changes: 2 additions & 17 deletions packages/common/src/projects/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { IRequestOptions } from "@esri/arcgis-rest-request";
import { getItem, IItem } from "@esri/arcgis-rest-portal";

import { getFamily } from "../content/get-family";
import { getHubRelativeUrl } from "../content/_internal/internalContentUtils";
import { IHubProject } from "../core/types";
import { PropertyMapper } from "../core/_internal/PropertyMapper";
import { getItemBySlug } from "../items/slugs";
Expand All @@ -18,12 +17,9 @@ import { computeProps } from "./_internal/computeProps";
import { getPropertyMap } from "./_internal/getPropertyMap";
import { unique } from "../util";
import { getProp } from "../objects/get-prop";
import { getItemThumbnailUrl } from "../resources/get-item-thumbnail-url";
import { getItemHomeUrl } from "../urls/get-item-home-url";
import { getItemIdentifier } from "../items";
import { getRelativeWorkspaceUrl } from "../core/getRelativeWorkspaceUrl";
import { listAssociations } from "../associations";
import { getTypeByIdsQuery } from "../associations/internal/getTypeByIdsQuery";
import { computeLinks } from "./_internal/computeLinks";

/**
* @private
Expand Down Expand Up @@ -127,18 +123,7 @@ export async function enrichProjectSearchResult(

// Handle links
// TODO: Link handling should be an enrichment
result.links.thumbnail = getItemThumbnailUrl(item, requestOptions);
result.links.self = getItemHomeUrl(result.id, requestOptions);
const identifier = getItemIdentifier(item);
result.links.siteRelative = getHubRelativeUrl(
result.type,
identifier,
item.typeKeywords
);
result.links.workspaceRelative = getRelativeWorkspaceUrl(
result.type,
identifier
);
result.links = { ...computeLinks(item, requestOptions) };

return result;
}
Expand Down
Loading