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

Add Cesium ion support to the Add Data panel #7193

Merged
merged 45 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4f999ca
Start adding support for Cesium ion via OAuth2.
kring Apr 7, 2024
65c3f60
Persist login across sessions.
kring Apr 7, 2024
8b8b327
Show tokens and assets.
kring Apr 21, 2024
6a2a13b
Basic ability to add 3D Tiles assets from ion.
kring Apr 21, 2024
5384521
Improve ion UI.
kring Jun 1, 2024
ab31a00
Add ion details to info sections.
kring Jun 1, 2024
a3925f5
Fix TS errors.
kring Jun 2, 2024
1dedf1c
Better asset selector.
kring Jun 8, 2024
3117aac
Warn about dangerous tokens.
kring Jun 8, 2024
49b3cc2
Link to Cesium ion.
kring Jun 8, 2024
fc8c89e
CesiumIonMixin.
kring Jun 8, 2024
7a7b47f
Add support for more asset types.
kring Jun 8, 2024
45da3f2
Remember selected ion token.
kring Jun 9, 2024
6b06973
Select first token by default.
kring Jun 9, 2024
ac844dd
Close catalog when ion asset is added.
kring Jun 9, 2024
4909fd3
Loading indicators, cleanup.
kring Jun 9, 2024
aedd676
Make oauth2 appid configurable, build redirect URI dynamically.
kring Jun 9, 2024
412d822
Add Cesium ion appid to ci.terria.io config.
kring Jun 9, 2024
bb26aee
Detect and inform about missing crypto.subtle.
kring Jun 9, 2024
393bc42
Disable ion on ci.terria.io.
kring Jun 9, 2024
60b0d3d
Formatting.
kring Jun 9, 2024
b1a1838
Fix eslint errors.
kring Jun 9, 2024
e82e727
Remove old TODO.
kring Jun 9, 2024
19ab08d
Remove unnecessary code.
kring Jun 9, 2024
101ea15
Merge remote-tracking branch 'origin/main' into cesium-ion
kring Jun 9, 2024
565f5ed
Fix eslint errors, fix switch case fallthrough.
kring Jun 10, 2024
9ba824d
Fix import of Dropdown, after I fixed the export.
kring Jun 10, 2024
a0b748b
Remove use of nonexistent prop on Dropdown.
kring Jun 10, 2024
ae4b86a
Filter assets to only ones accessible by token.
kring Aug 17, 2024
ae52cbd
Warn if site URL is not a token allowedUrl.
kring Aug 17, 2024
34fe0f5
Fix eslint error.
kring Aug 17, 2024
6b0b88f
Option to store ion login token in page, sessionStorage, or localStor…
kring Aug 24, 2024
3699c38
Don't allow ion catalog items to be shared.
kring Aug 24, 2024
b0346fc
CSS tweak recommended in review.
kring Aug 24, 2024
62f2ce8
Close ion auth window even if auth denied / fails.
kring Aug 24, 2024
6642cbb
Tweaks from review.
kring Sep 8, 2024
011a333
Add cesiumIonAllowSharingAddedAssets option.
kring Sep 8, 2024
bd09797
Fix translation for custom remote file types.
kring Sep 8, 2024
fa89275
More changes from review.
kring Sep 8, 2024
243f433
Prettier.
kring Sep 8, 2024
7f8083c
Improve doc.
kring Sep 8, 2024
797c982
Fix test failures.
kring Sep 8, 2024
0aec23d
Merge remote-tracking branch 'origin/main' into cesium-ion
kring Sep 8, 2024
32be1ae
Merge branch 'main' into cesium-ion
na9da Sep 30, 2024
a1796f6
Lint fixes after merging in main.
na9da Sep 30, 2024
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
29 changes: 16 additions & 13 deletions lib/Core/getDataType.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import i18next from "i18next";
import { action, observable } from "mobx";
import { type ComponentType } from "react";

interface DataType {
value: string;
name: string;
description?: string;
customComponent?: ComponentType;
}

export interface RemoteDataType extends DataType {}
Expand Down Expand Up @@ -193,39 +195,39 @@ const builtinLocalDataTypes: LocalDataType[] = [
];

/**
* Custom remote data types. Add to it by calling addRemoteDataType().
* Custom remote data types. Add to it by calling addOrReplaceRemoteFileUploadType().
*/
export const customRemoteDataTypes: Map<string, RemoteDataType> = observable(
new Map()
);

/**
* Custom local data types. Add by calling addLocalDataType().
* Custom local data types. Add by calling addOrReplaceLocalFileUploadType().
*/
export const customLocalDataTypes: Map<string, LocalDataType> = observable(
new Map()
);

export default function getDataTypes(): GetDataTypes {
const uniqueRemoteDataTypes: Map<string, RemoteDataType> = new Map([
...(builtinRemoteDataTypes.map((dtype) => [
dtype.value,
translateDataType(dtype)
]) as [string, RemoteDataType][]),
...(builtinRemoteDataTypes.map((dtype) => [dtype.value, dtype]) as [
string,
RemoteDataType
][]),
...customRemoteDataTypes.entries()
]);

const uniqueLocalDataTypes: Map<string, LocalDataType> = new Map([
...(builtinLocalDataTypes.map((dtype) => [
dtype.value,
translateDataType(dtype)
]) as [string, LocalDataType][]),
...(builtinLocalDataTypes.map((dtype) => [dtype.value, dtype]) as [
string,
LocalDataType
][]),
...customLocalDataTypes.entries()
]);

return {
remoteDataType: [...uniqueRemoteDataTypes.values()],
localDataType: [...uniqueLocalDataTypes.values()]
remoteDataType: [...uniqueRemoteDataTypes.values()].map(translateDataType),
localDataType: [...uniqueLocalDataTypes.values()].map(translateDataType)
};
}

Expand Down Expand Up @@ -264,6 +266,7 @@ function translateDataType<T extends DataType>(dataType: T): T {
name: i18next.t(dataType.name),
description: dataType.description
? i18next.t(dataType.description)
: undefined
: undefined,
customComponent: dataType.customComponent
};
}
47 changes: 47 additions & 0 deletions lib/ModelMixins/CesiumIonMixin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { observable, runInAction } from "mobx";
import IonResource from "terriajs-cesium/Source/Core/IonResource";
import AbstractConstructor from "../Core/AbstractConstructor";
import Model from "../Models/Definition/Model";
import CatalogMemberTraits from "../Traits/TraitsClasses/CatalogMemberTraits";
import CesiumIonTraits from "../Traits/TraitsClasses/CesiumIonTraits";

type BaseType = Model<CesiumIonTraits & CatalogMemberTraits>;

/**
* A mixin for a model that can be loaded from Cesium ion via an `ionAssetId`. If an asset ID is supplied,
* the `ionResource` will be populated asynchronously after `loadIonResource` is called (usually from
* `forceLoadMetadata`). If defined, the resource in this property should be used as the "URL" given to
* CesiumJS instead of a regular URL.
*/
export default function CesiumIonMixin<T extends AbstractConstructor<BaseType>>(
na9da marked this conversation as resolved.
Show resolved Hide resolved
Base: T
) {
abstract class CesiumIonMixin extends Base {
/**
* The {@link IonResource} that can be given to CesiumJS most places that a resource URL can be used.
*/
@observable
ionResource: IonResource | undefined = undefined;

/**
* Populates the the `ionResource` from the `ionAssetId`, `ionAccessToken`, and `ionServer`
* traits. This should be called from `forceLoadMetadata`.
*/
async loadIonResource(): Promise<void> {
if (this.ionAssetId) {
const resource = await IonResource.fromAssetId(this.ionAssetId, {
accessToken: this.ionAccessToken,
server: this.ionServer
});

runInAction(() => {
this.ionResource = resource;
});
} else {
this.ionResource = undefined;
}
}
}

return CesiumIonMixin;
}
10 changes: 8 additions & 2 deletions lib/ModelMixins/GltfMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import GltfTraits from "../Traits/TraitsClasses/GltfTraits";
import CatalogMemberMixin from "./CatalogMemberMixin";
import MappableMixin from "./MappableMixin";
import ShadowMixin from "./ShadowMixin";
import Resource from "terriajs-cesium/Source/Core/Resource";

// We want TS to look at the type declared in lib/ThirdParty/terriajs-cesium-extra/index.d.ts
// and import doesn't allows us to do that, so instead we use require + type casting to ensure
Expand Down Expand Up @@ -143,15 +144,20 @@ function GltfMixin<T extends AbstractConstructor<BaseType>>(Base: T) {
};
}

protected abstract get gltfModelUrl(): string | undefined;
protected abstract get gltfModelUrl(): string | Resource | undefined;

@computed
private get modelGraphics() {
if (this.gltfModelUrl === undefined) {
return undefined;
}

const url = this.gltfModelUrl;

const options = {
uri: new ConstantProperty(proxyCatalogItemUrl(this, this.gltfModelUrl)),
uri: new ConstantProperty(
typeof url === "string" ? proxyCatalogItemUrl(this, url) : url
),
upAxis: new ConstantProperty(this.cesiumUpAxis),
forwardAxis: new ConstantProperty(this.cesiumForwardAxis),
scale: new ConstantProperty(this.scale !== undefined ? this.scale : 1),
Expand Down
9 changes: 7 additions & 2 deletions lib/Models/Catalog/CatalogItems/CzmlCatalogItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import StratumOrder from "../../Definition/StratumOrder";
import HasLocalData from "../../HasLocalData";
import { ModelConstructorParameters } from "../../Definition/Model";
import proxyCatalogItemUrl from "../proxyCatalogItemUrl";
import CesiumIonMixin from "../../../ModelMixins/CesiumIonMixin";

/**
* A loadable stratum for CzmlCatalogItemTraits that derives TimeVaryingTraits
Expand Down Expand Up @@ -70,7 +71,9 @@ StratumOrder.addLoadStratum(CzmlTimeVaryingStratum.stratumName);
export default class CzmlCatalogItem
extends AutoRefreshingMixin(
MappableMixin(
UrlMixin(CatalogMemberMixin(CreateModel(CzmlCatalogItemTraits)))
UrlMixin(
CesiumIonMixin(CatalogMemberMixin(CreateModel(CzmlCatalogItemTraits)))
)
)
)
implements TimeVarying, HasLocalData
Expand Down Expand Up @@ -107,6 +110,8 @@ export default class CzmlCatalogItem
loadableData = JSON.parse(this.czmlString);
} else if (isDefined(this._czmlFile)) {
loadableData = readJson(this._czmlFile);
} else if (isDefined(this.ionResource)) {
loadableData = this.ionResource;
} else if (isDefined(this.url)) {
loadableData = proxyCatalogItemUrl(this, this.url, this.cacheDuration);
}
Expand Down Expand Up @@ -145,7 +150,7 @@ export default class CzmlCatalogItem
}

protected forceLoadMetadata(): Promise<void> {
return Promise.resolve();
return this.loadIonResource();
}

@computed
Expand Down
11 changes: 10 additions & 1 deletion lib/Models/Catalog/CatalogItems/GeoJsonCatalogItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ import proxyCatalogItemUrl from "../proxyCatalogItemUrl";
import ApiRequestTraits from "../../../Traits/TraitsClasses/ApiRequestTraits";
import filterOutUndefined from "../../../Core/filterOutUndefined";
import { featureCollection, FeatureCollection } from "@turf/helpers";
import CesiumIonMixin from "../../../ModelMixins/CesiumIonMixin";

class GeoJsonCatalogItem
extends GeoJsonMixin(CreateModel(GeoJsonCatalogItemTraits))
extends CesiumIonMixin(GeoJsonMixin(CreateModel(GeoJsonCatalogItemTraits)))
implements HasLocalData
{
static readonly type = "geojson";
Expand Down Expand Up @@ -90,6 +91,12 @@ class GeoJsonCatalogItem
return undefined;
}

protected override async forceLoadMetadata() {
const ionResourcePromise = this.loadIonResource();
await super.forceLoadMetadata();
await ionResourcePromise;
}

protected async forceLoadGeojsonData() {
let jsonData: JsonValue | undefined = undefined;

Expand All @@ -110,6 +117,8 @@ class GeoJsonCatalogItem
} else {
jsonData = await readJson(this._file);
}
} else if (isDefined(this.ionResource)) {
jsonData = await loadJson(this.ionResource);
}
// We have multiple sources.
else if (this.urls.length > 0) {
Expand Down
9 changes: 7 additions & 2 deletions lib/Models/Catalog/CatalogItems/KmlCatalogItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ import CreateModel from "../../Definition/CreateModel";
import HasLocalData from "../../HasLocalData";
import { ModelConstructorParameters } from "../../Definition/Model";
import proxyCatalogItemUrl from "../proxyCatalogItemUrl";
import CesiumIonMixin from "../../../ModelMixins/CesiumIonMixin";

const kmzRegex = /\.kmz$/i;

class KmlCatalogItem
extends MappableMixin(
UrlMixin(CatalogMemberMixin(CreateModel(KmlCatalogItemTraits)))
UrlMixin(
CesiumIonMixin(CatalogMemberMixin(CreateModel(KmlCatalogItemTraits)))
)
)
implements HasLocalData
{
Expand Down Expand Up @@ -74,6 +77,8 @@ class KmlCatalogItem
} else {
resolve(readXml(this._kmlFile));
}
} else if (isDefined(this.ionResource)) {
resolve(this.ionResource);
} else if (isDefined(this.url)) {
resolve(proxyCatalogItemUrl(this, this.url));
} else {
Expand Down Expand Up @@ -115,7 +120,7 @@ class KmlCatalogItem
}

protected forceLoadMetadata(): Promise<void> {
return Promise.resolve();
return this.loadIonResource();
}

private doneLoading(kmlDataSource: KmlDataSource) {
Expand Down
5 changes: 3 additions & 2 deletions lib/Models/Catalog/Gltf/AssImpCatalogItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import HasLocalData from "../../HasLocalData";
import proxyCatalogItemUrl from "../proxyCatalogItemUrl";
import { ModelConstructorParameters } from "../../Definition/Model";
import { GlTf } from "./GLTF";
import Resource from "terriajs-cesium/Source/Core/Resource";

// List of supported image formats from https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
// + Cesium adds support for ktx2
Expand All @@ -36,7 +37,7 @@ export default class AssImpCatalogItem
implements HasLocalData
{
@observable
protected gltfModelUrl: string | undefined;
protected gltfModelUrl: string | Resource | undefined;

static readonly type = "assimp";

Expand Down Expand Up @@ -178,7 +179,7 @@ export default class AssImpCatalogItem
}

/** This is used so we only set `this.gltfModelUrl` after process has finished */
let gltfModelUrl: string | undefined;
let gltfModelUrl: string | Resource | undefined;
/** List of unsupported texture URLs to show in warning message */
const unsupportedTextures: string[] = [];

Expand Down
15 changes: 13 additions & 2 deletions lib/Models/Catalog/Gltf/GltfCatalogItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import CommonStrata from "../../Definition/CommonStrata";
import CreateModel from "../../Definition/CreateModel";
import { ModelConstructorParameters } from "../../Definition/Model";
import HasLocalData from "../../HasLocalData";
import CesiumIonMixin from "../../../ModelMixins/CesiumIonMixin";

export default class GltfCatalogItem
extends UrlMixin(GltfMixin(CreateModel(GltfCatalogItemTraits)))
extends UrlMixin(
CesiumIonMixin(GltfMixin(CreateModel(GltfCatalogItemTraits)))
)
implements HasLocalData
{
static readonly type = "gltf";
Expand All @@ -24,7 +27,15 @@ export default class GltfCatalogItem

@computed
get gltfModelUrl() {
return this.url;
if (this.ionResource) {
return this.ionResource;
} else {
return this.url;
}
}

protected override forceLoadMetadata(): Promise<void> {
return this.loadIonResource();
}

@observable hasLocalData = false;
Expand Down
23 changes: 23 additions & 0 deletions lib/Models/Terria.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,26 @@ export interface ConfigParameters {
* True to use Bing Maps from Cesium ion (Cesium World Imagery). By default, Ion will be used, unless the `bingMapsKey` property is specified, in which case that will be used instead. To disable the Bing Maps layers entirely, set this property to false and set `bingMapsKey` to null.
*/
useCesiumIonBingImagery?: boolean;
/**
* The OAuth2 application ID to use to allow login to Cesium ion on the "Add Data" panel. The referenced application must be configured on
* Cesium ion with a Redirect URI of `[TerriaMap Base URL]/build/TerriaJS/cesium-ion-oauth2.html`. For example, if users access your TerriaJS
* application at `https://example.com/AwesomeMap` then the Redirect URI must be exactly
* `https://example.com/AwesomeMap/build/TerriaJS/cesium-ion-oauth2.html`.
*/
cesiumIonOAuth2ApplicationID?: number;
/**
* Specifies where to store the Cesium ion login token. Valid values are:
* - `page` (default) - The login token is associated with the current page load. Even simply reloading the current page will clear the token. This is the safest option.
* - `sessionStorage` - The login token is associated with a browser session, which means it is shared/accessible from any page hosted on the same domain and running in the same browser tab.
* - `localStorage` - The login token is shared/accessible from any page hosted on the same domain, even when running in different tabs or after exiting and restarted the web browser.
*/
cesiumIonLoginTokenPersistence?: string;
/**
* Whether or not Cesium ion assets added via the "Add Data" panel will be shared with others via share links. If true, users will be asked to select a Cesium ion token when adding assets,
* and this choice must be made carefully to avoid exposing more Cesium ion assets than intended. If false (the default), the user's login token will be used, which is safe because this
* token will not be shared with others.
*/
cesiumIonAllowSharingAddedAssets?: boolean;
/**
* A [Bing Maps API key](https://msdn.microsoft.com/en-us/library/ff428642.aspx) used for requesting Bing Maps base maps and using the Bing Maps geocoder for searching. It is your responsibility to request a key and comply with all terms and conditions.
*/
Expand Down Expand Up @@ -516,6 +536,9 @@ export default class Terria {
cesiumTerrainAssetId: undefined,
cesiumIonAccessToken: undefined,
useCesiumIonBingImagery: undefined,
cesiumIonOAuth2ApplicationID: undefined,
cesiumIonLoginTokenPersistence: "page",
cesiumIonAllowSharingAddedAssets: false,
bingMapsKey: undefined,
hideTerriaLogo: false,
brandBarElements: undefined,
Expand Down
11 changes: 11 additions & 0 deletions lib/ReactViewModels/ViewState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ export default class ViewState {

@observable printWindow: Window | null = null;

/**
* The currently-selected web service type on the My Data -> Add web data panel.
*/
@observable remoteDataType: any | undefined = undefined;

/**
* The ID of the Cesium ion token that is currently selected on the
* My Data -> Add web data -> Cesium ion panel.
*/
@observable currentCesiumIonToken: string | undefined = undefined;

/**
* Toggles ActionBar visibility. Do not set manually, it is
* automatically set when rendering <ActionBar>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import { Button, StyledButton } from "../../../Styled/Button";
import Icon, { StyledIcon } from "../../../Styled/Icon";
import UrlTraits from "../../../Traits/TraitsClasses/UrlTraits";
import Styles from "./chart-expand-and-download-buttons.scss";

const Dropdown = require("../../Generic/Dropdown");
import Dropdown from "../../Generic/Dropdown";

interface PropsType extends WithTranslation {
terria: Terria;
Expand Down
Loading
Loading