aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json68
-rw-r--r--package.json6
-rw-r--r--src/client/Network.ts13
-rw-r--r--src/client/cognitive_services/CognitiveServices.ts1
-rw-r--r--src/client/documents/Documents.ts9
-rw-r--r--src/client/views/Main.tsx1
-rw-r--r--src/client/views/collections/CollectionMapView.scss4
-rw-r--r--src/client/views/collections/CollectionMapView.tsx72
-rw-r--r--src/client/views/collections/CollectionView.tsx10
-rw-r--r--src/new_fields/Types.ts1
-rw-r--r--webpack.config.js55
11 files changed, 195 insertions, 45 deletions
diff --git a/package-lock.json b/package-lock.json
index 1949a8a5c..f40dc7b0f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -584,6 +584,20 @@
"@types/node": "*"
}
},
+ "@types/google-maps-react": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@types/google-maps-react/-/google-maps-react-2.0.4.tgz",
+ "integrity": "sha512-8EGr84L6ozODnfjWN9xVUFIxFedBbZinuDe5lBEJ757yh/lZqoKkqxrYLqvrLksDRVVwQYwWdFvfEASujmk36A==",
+ "requires": {
+ "@types/googlemaps": "*",
+ "@types/react": "*"
+ }
+ },
+ "@types/googlemaps": {
+ "version": "3.39.3",
+ "resolved": "https://registry.npmjs.org/@types/googlemaps/-/googlemaps-3.39.3.tgz",
+ "integrity": "sha512-L8O9HAVFZj0TuiS8h5ORthiMsrrhjxTC8XUusp5k47oXCst4VTm+qWKvrAvmYMybZVokbp4Udco1mNwJrTNZPQ=="
+ },
"@types/isstream": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@types/isstream/-/isstream-0.1.0.tgz",
@@ -750,7 +764,7 @@
},
"@types/passport": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.0.tgz",
+ "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.2.tgz",
"integrity": "sha512-Pf39AYKf8q+YoONym3150cEwfUD66dtwHJWvbeOzKxnA0GZZ/vAXhNWv9vMhKyRQBQZiQyWQnhYBEBlKW6G8wg==",
"requires": {
"@types/express": "*"
@@ -5615,7 +5629,8 @@
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -5633,11 +5648,13 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5650,15 +5667,18 @@
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -5761,7 +5781,8 @@
},
"inherits": {
"version": "2.0.4",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -5771,6 +5792,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -5783,17 +5805,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -5810,6 +5835,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -5890,7 +5916,8 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -5900,6 +5927,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -5975,7 +6003,8 @@
},
"safe-buffer": {
"version": "5.1.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -6005,6 +6034,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -6022,6 +6052,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -6060,11 +6091,13 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"yallist": {
"version": "3.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
}
}
},
@@ -6344,6 +6377,11 @@
}
}
},
+ "google-maps-react": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/google-maps-react/-/google-maps-react-2.0.2.tgz",
+ "integrity": "sha512-6cYauGwt22haDUrWxKQ6yoNOqjiuxHo8YYcmb+aBvNICokdXmZOUB6Ah4vD5VexMVlrwP2PFqA/D8sHpEB52KA=="
+ },
"google-p12-pem": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.1.tgz",
@@ -14376,7 +14414,7 @@
},
"readable-stream": {
"version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
@@ -15990,7 +16028,7 @@
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
@@ -18303,7 +18341,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
"string-width": "^1.0.1",
diff --git a/package.json b/package.json
index 440646c48..c742857ad 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
},
"scripts": {
"start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts",
- "start": "cross-env HANDWRITING='61088486d76c4b12ba578775a5f55422' NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts",
+ "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts",
"debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --inspect -- src/server/index.ts",
"build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production",
"test": "mocha -r ts-node/register test/**/*.ts",
@@ -83,6 +83,7 @@
"@types/express-validator": "^3.0.0",
"@types/formidable": "^1.0.31",
"@types/gapi": "0.0.39",
+ "@types/google-maps-react": "^2.0.4",
"@types/jquery": "^3.3.31",
"@types/jquery-awesome-cursor": "^0.3.0",
"@types/jsonwebtoken": "^8.3.7",
@@ -162,6 +163,7 @@
"formidable": "^1.2.1",
"golden-layout": "^1.5.9",
"google-auth-library": "^4.2.4",
+ "google-maps-react": "^2.0.2",
"googleapis": "^40.0.0",
"googlephotos": "^0.2.5",
"howler": "^2.1.3",
@@ -258,4 +260,4 @@
"xoauth2": "^1.2.0",
"youtube": "^0.1.0"
}
-}
+} \ No newline at end of file
diff --git a/src/client/Network.ts b/src/client/Network.ts
index 6982ecf19..bd0e6e61a 100644
--- a/src/client/Network.ts
+++ b/src/client/Network.ts
@@ -4,10 +4,23 @@ import { Upload } from "../server/SharedMediaTypes";
export namespace Networking {
+ const EnvVarCache = new Map<string, string>();
+
export async function FetchFromServer(relativeRoute: string) {
return (await fetch(relativeRoute)).text();
}
+ export async function FetchEnvironmentVariable(varNameLiteral: string) {
+ let resolved = EnvVarCache.get(varNameLiteral);
+ if (!resolved) {
+ resolved = await FetchFromServer(`/environment/${varNameLiteral}`);
+ if (resolved !== undefined) {
+ EnvVarCache.set(varNameLiteral, resolved);
+ }
+ }
+ return resolved;
+ }
+
export async function PostToServer(relativeRoute: string, body?: any) {
const options = {
uri: Utils.prepend(relativeRoute),
diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index 5d83de233..3133bf4b1 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -8,7 +8,6 @@ import { UndoManager } from "../util/UndoManager";
import requestPromise = require("request-promise");
import { List } from "../../new_fields/List";
import { ClientRecommender } from "../ClientRecommender";
-import { ImageBox } from "../views/nodes/ImageBox";
type APIManager<D> = { converter: BodyConverter<D>, requester: RequestExecutor };
type RequestExecutor = (apiKey: string, body: string, service: Service) => Promise<string>;
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 703c049cd..43e379125 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -49,6 +49,8 @@ import { ContextMenuProps } from "../views/ContextMenuItem";
import { ContextMenu } from "../views/ContextMenu";
import { LinkBox } from "../views/nodes/LinkBox";
import { ScreenshotBox } from "../views/nodes/ScreenshotBox";
+import CollectionMapView from "../views/collections/CollectionMapView";
+import LocationField, { LocationData } from "../../new_fields/LocationField";
const requestImageSize = require('../util/request-image-size');
const path = require('path');
@@ -277,8 +279,7 @@ export namespace Docs {
}],
[DocumentType.SCREENSHOT, {
layout: { view: ScreenshotBox, dataField: data },
- options: {}
- }]
+ }],
]);
// All document prototypes are initialized with at least these values
@@ -624,6 +625,10 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Linear }, id);
}
+ export function MapDocument(documents: Array<Doc>, options: DocumentOptions = {}) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), options);
+ }
+
export function CarouselDocument(documents: Array<Doc>, options: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Carousel });
}
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6d705aa44..b21eb9c8f 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -5,7 +5,6 @@ import * as ReactDOM from 'react-dom';
import * as React from 'react';
import { DocServer } from "../DocServer";
import { AssignAllExtensions } from "../../extensions/General/Extensions";
-process.env.HANDWRITING = "61088486d76c4b12ba578775a5f55422";
AssignAllExtensions();
diff --git a/src/client/views/collections/CollectionMapView.scss b/src/client/views/collections/CollectionMapView.scss
new file mode 100644
index 000000000..c74433902
--- /dev/null
+++ b/src/client/views/collections/CollectionMapView.scss
@@ -0,0 +1,4 @@
+.collectionMapView-contents {
+ width: 100%;
+ height: 100%;
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
new file mode 100644
index 000000000..49411f61b
--- /dev/null
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -0,0 +1,72 @@
+import { observer } from "mobx-react";
+import { makeInterface } from "../../../new_fields/Schema";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import React = require("react");
+import { Map, Marker, MapProps, GoogleApiWrapper } from "google-maps-react";
+import { NumCast, StrCast } from "../../../new_fields/Types";
+import { CollectionSubView } from "./CollectionSubView";
+import { Utils } from "../../../Utils";
+
+type MapDocument = makeInterface<[typeof documentSchema]>;
+const MapDocument = makeInterface(documentSchema);
+
+export type LocationData = google.maps.LatLngLiteral & { address?: string };
+
+@observer
+class CollectionMapView extends CollectionSubView<MapDocument, Partial<MapProps> & { google: any }>(MapDocument) {
+
+ render() {
+ const { childLayoutPairs, props } = this;
+ const { Document } = props;
+ const center: LocationData = { lat: NumCast(Document.mapCenterLat), lng: NumCast(Document.mapCenterLng) };
+ if (!center.lat) {
+ center.lat = childLayoutPairs.length ? NumCast(childLayoutPairs[0].layout.locationLat, 0) : 0;
+ center.lng = childLayoutPairs.length ? NumCast(childLayoutPairs[0].layout.locationLng, 0) : 0;
+ }
+ return (
+ <div
+ className={"collectionMapView-contents"}
+ >
+ <Map
+ {...props}
+ zoom={NumCast(Document.zoom, 10)}
+ center={center}
+ initialCenter={center}
+ >
+ {childLayoutPairs.map(({ layout }) => {
+ const location: LocationData = {
+ lat: NumCast(childLayoutPairs[0].layout.locationLat, 0),
+ lng: NumCast(childLayoutPairs[0].layout.locationLng, 0)
+ };
+ const iconSize = new google.maps.Size(NumCast(layout.mapIconWidth, 45), NumCast(layout.mapIconHeight, 45));
+ return (
+ <Marker
+ key={Utils.GenerateGuid()}
+ label={StrCast(layout.title)}
+ position={location}
+ onClick={() => {
+ Document.mapCenterLat = location.lat;
+ Document.mapCenterLng = location.lng;
+ }}
+ icon={{
+ size: iconSize,
+ scaledSize: iconSize,
+ url: StrCast(Document.mapIconUrl, "https://www.pinclipart.com/picdir/middle/359-3598915_map-marker-icon-location-icon-png-clipart.png")
+ }}
+ />
+ );
+ })}
+ </Map>
+ </div>
+ );
+ }
+
+}
+
+declare var process: {
+ env: {
+ GOOGLE_MAPS_API_KEY: string;
+ }
+};
+
+export default GoogleApiWrapper({ apiKey: process.env.GOOGLE_MAPS_API_KEY })(CollectionMapView) as any; \ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 821840e0b..d1dc32829 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,7 +1,7 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import { faEye, faEdit } from '@fortawesome/free-regular-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
+import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree, faGlobeAmericas } from '@fortawesome/free-solid-svg-icons';
import { action, observable, computed } from 'mobx';
import { observer } from "mobx-react";
import * as React from 'react';
@@ -44,12 +44,15 @@ import { Docs } from '../../documents/Documents';
import { ScriptField, ComputedField } from '../../../new_fields/ScriptField';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ObjectField } from '../../../new_fields/ObjectField';
+import CollectionMapView from './CollectionMapView';
+import { ClientUtils } from '../../util/ClientUtils';
+import { GoogleApiWrapper } from 'google-maps-react';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
export const COLLECTION_BORDER_WIDTH = 2;
const path = require('path');
-library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy);
+library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faGlobeAmericas, faEllipsisV, faImage, faEye as any, faCopy);
export enum CollectionViewType {
Invalid = "invalid",
@@ -65,6 +68,7 @@ export enum CollectionViewType {
Carousel = "carousel",
Linear = "linear",
Staff = "staff",
+ Map = "map"
}
export interface CollectionRenderProps {
@@ -170,6 +174,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView key="collview" {...props} />); }
case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (<CollectionStackingView key="collview" {...props} />); }
case CollectionViewType.Time: { return (<CollectionTimeView key="collview" {...props} />); }
+ case CollectionViewType.Map: return (<CollectionMapView key="collview" {...props} />);
case CollectionViewType.Freeform:
default: { this.props.Document._freeformLayoutEngine = undefined; return (<CollectionFreeFormView key="collview" {...props} />); }
}
@@ -211,6 +216,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
subItems.push({ description: "Masonry", event: () => this.props.Document._viewType = CollectionViewType.Masonry, icon: "columns" });
subItems.push({ description: "Carousel", event: () => this.props.Document._viewType = CollectionViewType.Carousel, icon: "columns" });
subItems.push({ description: "Pivot/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" });
+ subItems.push({ description: "Map", event: () => this.props.Document._viewType = CollectionViewType.Map, icon: "globe-americas" });
switch (this.props.Document._viewType) {
case CollectionViewType.Freeform: {
subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) });
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index 0ca35fab2..aa44cefa0 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -87,6 +87,7 @@ export function BoolCast(field: FieldResult, defaultVal: boolean | null = false)
export function DateCast(field: FieldResult) {
return Cast(field, DateField, null);
}
+
export function ScriptCast(field: FieldResult) {
return Cast(field, ScriptField, null);
}
diff --git a/webpack.config.js b/webpack.config.js
index 6a14dfcda..655334ef2 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -2,6 +2,14 @@ var path = require('path');
var webpack = require('webpack');
const CopyWebpackPlugin = require("copy-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
+const env = require('dotenv').config().parsed;
+const envKeys = Object.keys(env).reduce((prev, next) => {
+ if (next.startsWith("DASH_")) {
+ const resolved = next.replace("DASH_", "");
+ prev[`process.env.${resolved}`] = JSON.stringify(env[next]);
+ }
+ return prev;
+}, {});
module.exports = {
mode: 'development',
@@ -33,17 +41,18 @@ module.exports = {
extensions: ['.js', '.ts', '.tsx']
},
module: {
- rules: [
- {
+ rules: [{
test: [/\.tsx?$/],
- use: [
- { loader: 'ts-loader', options: { transpileOnly: true } }
- ]
+ use: [{
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true
+ }
+ }]
},
{
test: /\.scss|css$/,
- use: [
- {
+ use: [{
loader: "style-loader"
},
{
@@ -56,28 +65,30 @@ module.exports = {
},
{
test: /\.(jpg|png|pdf)$/,
- use: [
- {
- loader: 'file-loader'
- }
- ]
+ use: [{
+ loader: 'file-loader'
+ }]
},
{
test: /\.(png|jpg|gif)$/i,
- use: [
- {
- loader: 'url-loader',
- options: {
- limit: 8192
- }
+ use: [{
+ loader: 'url-loader',
+ options: {
+ limit: 8192
}
- ]
- }]
+ }]
+ }
+ ]
},
plugins: [
- new CopyWebpackPlugin([{ from: "deploy", to: path.join(__dirname, "build") }]),
+ new CopyWebpackPlugin([{
+ from: "deploy",
+ to: path.join(__dirname, "build")
+ }]),
+ new webpack.DefinePlugin(envKeys),
new ForkTsCheckerWebpackPlugin({
- tslint: true, useTypescriptIncrementalApi: true
+ tslint: true,
+ useTypescriptIncrementalApi: true
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),