From 9712a046868ee51a565a425d3216a2bb297c4eee Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 17 Apr 2019 19:45:59 -0400 Subject: Got saving to database working --- src/server/Message.ts | 12 ++++++++++++ src/server/database.ts | 16 +++++++++------- src/server/index.ts | 19 ++++++++++++++++++- 3 files changed, 39 insertions(+), 8 deletions(-) (limited to 'src/server') diff --git a/src/server/Message.ts b/src/server/Message.ts index bbe4ffcad..843a923d1 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -24,6 +24,14 @@ export interface Transferable { readonly data?: any; } +export interface Reference { + readonly id: string; +} + +export interface Diff extends Reference { + readonly diff: any; +} + export namespace MessageStore { export const Foo = new Message("Foo"); export const Bar = new Message("Bar"); @@ -32,4 +40,8 @@ export namespace MessageStore { export const GetFields = new Message("Get Fields"); // send string[] of 'id' get Transferable[] back export const GetDocument = new Message("Get Document"); export const DeleteAll = new Message("Delete All"); + + export const GetRefField = new Message("Get Ref Field"); + export const UpdateField = new Message("Update Ref Field"); + export const CreateField = new Message("Create Ref Field"); } diff --git a/src/server/database.ts b/src/server/database.ts index 5457e4dd5..a61b4d823 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -13,14 +13,14 @@ export class Database { this.MongoClient.connect(this.url, (err, client) => this.db = client.db()); } - public update(id: string, value: any, callback: () => void) { + public update(id: string, value: any, callback: () => void, upsert = true, collectionName = Database.DocumentsCollection) { if (this.db) { - let collection = this.db.collection('documents'); + let collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; let newProm: Promise; const run = (): Promise => { return new Promise(resolve => { - collection.updateOne({ _id: id }, { $set: value }, { upsert: true } + collection.updateOne({ _id: id }, { $set: value }, { upsert } , (err, res) => { if (err) { console.log(err.message); @@ -51,10 +51,12 @@ export class Database { this.db && this.db.collection(collectionName).deleteMany({}, res)); } - public insert(kvpairs: any, collectionName = Database.DocumentsCollection) { - this.db && this.db.collection(collectionName).insertOne(kvpairs, (err, res) => - err // && console.log(err) - ); + public insert(value: any, collectionName = Database.DocumentsCollection) { + if ("id" in value) { + value._id = value.id; + delete value.id; + } + this.db && this.db.collection(collectionName).insertOne(value); } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { diff --git a/src/server/index.ts b/src/server/index.ts index 70a7d266c..d6d5f0e55 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -22,7 +22,7 @@ import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLo import { DashUserModel } from './authentication/models/user_model'; import { Client } from './Client'; import { Database } from './database'; -import { MessageStore, Transferable } from "./Message"; +import { MessageStore, Transferable, Diff } from "./Message"; import { RouteStore } from './RouteStore'; const app = express(); const config = require('../../webpack.config'); @@ -232,6 +232,10 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); + + Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); + Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); + Utils.AddServerHandler(socket, MessageStore.GetRefField, GetRefField); }); function deleteFields() { @@ -262,5 +266,18 @@ function setField(socket: Socket, newValue: Transferable) { socket.broadcast.emit(MessageStore.SetField.Message, newValue)); } +function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { + Database.Instance.getDocument(id, callback, "newDocuments"); +} + +function UpdateField(socket: Socket, diff: Diff) { + Database.Instance.update(diff.id, diff.diff, + () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); +} + +function CreateField(newValue: any) { + Database.Instance.insert(newValue, "newDocuments"); +} + server.listen(serverPort); console.log(`listening on port ${serverPort}`); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 50a950238def89ae30d386676bbfe884c8b8c7be Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 24 Apr 2019 02:23:36 -0400 Subject: Added get fields and did some more fixing --- src/client/DocServer.ts | 25 +++ src/client/documents/Documents.ts | 43 ++-- src/fields/Document.ts | 430 -------------------------------------- src/fields/IconFIeld.ts | 25 --- src/fields/InkField.ts | 53 ----- src/new_fields/IconField.ts | 14 ++ src/new_fields/InkField.ts | 31 +++ src/server/Message.ts | 1 + src/server/index.ts | 6 +- 9 files changed, 101 insertions(+), 527 deletions(-) delete mode 100644 src/fields/Document.ts delete mode 100644 src/fields/IconFIeld.ts delete mode 100644 src/fields/InkField.ts create mode 100644 src/new_fields/IconField.ts create mode 100644 src/new_fields/InkField.ts (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 615e48af0..cba0c4770 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -30,6 +30,31 @@ export namespace DocServer { } } + export async function GetRefFields(ids: string[]): Promise<{ [id: string]: Opt }> { + const requestedIds: string[] = []; + const waitingIds: string[] = []; + const promises: Promise>[] = []; + const map: { [id: string]: Opt } = {}; + for (const id of ids) { + const cached = _cache[id]; + if (cached === undefined) { + requestedIds.push(id); + } else if (cached instanceof Promise) { + promises.push(cached); + waitingIds.push(id); + } else { + map[id] = cached; + } + } + const prom = Utils.EmitCallback(_socket, MessageStore.GetFields, requestedIds); + requestedIds.map((id, index) => _cache[id] = prom.then((fields: RefField[]) => fields[index])); + const fields = await prom; + requestedIds.map((id, index) => map[id] = fields[index]); + const otherFields = await Promise.all(promises); + waitingIds.map((id, index) => map[id] = otherFields[index]); + return map; + } + export function UpdateField(id: string, diff: any) { Utils.Emit(_socket, MessageStore.UpdateField, { id, diff }); } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a145a76c9..a5ce7c076 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -26,6 +26,9 @@ import { ImageField, VideoField, AudioField, PdfField, WebField } from "../../ne import { HtmlField } from "../../new_fields/HtmlField"; import { List } from "../../new_fields/List"; import { Cast } from "../../new_fields/Types"; +import { IconField } from "../../new_fields/IconField"; +import { listSpec } from "../../new_fields/Schema"; +import { DocServer } from "../DocServer"; export interface DocumentOptions { x?: number; @@ -73,17 +76,17 @@ export namespace Docs { const iconProtoId = "iconProto"; export function initProtos(): Promise { - return Server.GetFields([textProtoId, histoProtoId, collProtoId, pdfProtoId, imageProtoId, videoProtoId, audioProtoId, webProtoId, kvpProtoId]).then(fields => { - textProto = fields[textProtoId] as Document || CreateTextPrototype(); - histoProto = fields[histoProtoId] as Document || CreateHistogramPrototype(); - collProto = fields[collProtoId] as Document || CreateCollectionPrototype(); - imageProto = fields[imageProtoId] as Document || CreateImagePrototype(); - webProto = fields[webProtoId] as Document || CreateWebPrototype(); - kvpProto = fields[kvpProtoId] as Document || CreateKVPPrototype(); - videoProto = fields[videoProtoId] as Document || CreateVideoPrototype(); - audioProto = fields[audioProtoId] as Document || CreateAudioPrototype(); - pdfProto = fields[pdfProtoId] as Document || CreatePdfPrototype(); - iconProto = fields[iconProtoId] as Document || CreateIconPrototype(); + return DocServer.GetRefFields([textProtoId, histoProtoId, collProtoId, pdfProtoId, imageProtoId, videoProtoId, audioProtoId, webProtoId, kvpProtoId]).then(fields => { + textProto = fields[textProtoId] as Doc || CreateTextPrototype(); + histoProto = fields[histoProtoId] as Doc || CreateHistogramPrototype(); + collProto = fields[collProtoId] as Doc || CreateCollectionPrototype(); + imageProto = fields[imageProtoId] as Doc || CreateImagePrototype(); + webProto = fields[webProtoId] as Doc || CreateWebPrototype(); + kvpProto = fields[kvpProtoId] as Doc || CreateKVPPrototype(); + videoProto = fields[videoProtoId] as Doc || CreateVideoPrototype(); + audioProto = fields[audioProtoId] as Doc || CreateAudioPrototype(); + pdfProto = fields[pdfProtoId] as Doc || CreatePdfPrototype(); + iconProto = fields[iconProtoId] as Doc || CreateIconPrototype(); }); } @@ -191,25 +194,29 @@ export namespace Docs { let ctlog = await Gateway.Instance.GetSchema(url, schemaName); if (ctlog && ctlog.schemas) { let schema = ctlog.schemas[0]; - let schemaDoc = Documents.TreeDocument([], { ...options, nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: schema.displayName! }); - let schemaDocuments = schemaDoc.GetList(KeyStore.Data, [] as Document[]); + let schemaDoc = Docs.TreeDocument([], { ...options, nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: schema.displayName! }); + let schemaDocuments = Cast(schemaDoc.data, listSpec(Doc)); + if (!schemaDocuments) { + return; + } + const docs = schemaDocuments; CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { - Server.GetField(attr.displayName! + ".alias", action((field: Opt) => { - if (field instanceof Document) { - schemaDocuments.push(field); + DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { + if (field instanceof Doc) { + docs.push(field); } else { var atmod = new ColumnAttributeModel(attr); let histoOp = new HistogramOperation(schema.displayName!, new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); - schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); + docs.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); } })); }); return schemaDoc; } - return Documents.TreeDocument([], { width: 50, height: 100, title: schemaName }); + return Docs.TreeDocument([], { width: 50, height: 100, title: schemaName }); } export function WebDocument(url: string, options: DocumentOptions = {}) { return CreateInstance(webProto, new WebField(new URL(url)), options); diff --git a/src/fields/Document.ts b/src/fields/Document.ts deleted file mode 100644 index 7cf784f0e..000000000 --- a/src/fields/Document.ts +++ /dev/null @@ -1,430 +0,0 @@ -import { Key } from "./Key"; -import { KeyStore } from "./KeyStore"; -import { Field, Cast, FieldWaiting, FieldValue, FieldId, Opt } from "./Field"; -import { NumberField } from "./NumberField"; -import { ObservableMap, computed, action, runInAction } from "mobx"; -import { TextField } from "./TextField"; -import { ListField } from "./ListField"; -import { Server } from "../client/Server"; -import { Types } from "../server/Message"; -import { UndoManager } from "../client/util/UndoManager"; -import { HtmlField } from "./HtmlField"; -import { BooleanField } from "./BooleanField"; -import { allLimit } from "async"; -import { prototype } from "nodemailer/lib/smtp-pool"; -import { HistogramField } from "../client/northstar/dash-fields/HistogramField"; - -export class Document extends Field { - //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field - public fields: ObservableMap = new ObservableMap(); - public _proxies: ObservableMap = new ObservableMap(); - - constructor(id?: string, save: boolean = true) { - super(id); - - if (save) { - Server.UpdateField(this); - } - } - static FromJson(data: any, id: string, save: boolean): Document { - let doc = new Document(id, save); - let fields = data as [string, string][]; - fields.forEach(pair => doc._proxies.set(pair[0], pair[1])); - return doc; - } - - UpdateFromServer(data: [string, string][]) { - for (const key in data) { - const element = data[key]; - this._proxies.set(element[0], element[1]); - } - } - - public Width = () => this.GetNumber(KeyStore.Width, 0); - public Height = () => this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? (this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0)) * this.GetNumber(KeyStore.Width, 0) : 0); - public Scale = () => this.GetNumber(KeyStore.Scale, 1); - - @computed - public get Title(): string { - let title = this.Get(KeyStore.Title, true); - if (title || title === FieldWaiting) { - if (title !== FieldWaiting && title instanceof TextField) { - return title.Data; - } - else return "-waiting-"; - } - let parTitle = this.GetT(KeyStore.Title, TextField); - if (parTitle || parTitle === FieldWaiting) { - if (parTitle !== FieldWaiting) return parTitle.Data + ".alias"; - else return "-waiting-.alias"; - } - return "-untitled-"; - } - - @computed - public get Fields() { - return this.fields; - } - - /** - * Get the field in the document associated with the given key. If the - * associated field has not yet been filled in from the server, a request - * to the server will automatically be sent, the value will be filled in - * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned. - * @param key - The key of the value to get - * @param ignoreProto - If true, ignore any prototype this document - * might have and only search for the value on this immediate document. - * If false (default), search up the prototype chain, starting at this document, - * for a document that has a field associated with the given key, and return the first - * one found. - * - * @returns If the document does not have a field associated with the given key, returns `undefined`. - * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}. - * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field. - */ - Get(key: Key, ignoreProto: boolean = false): FieldValue { - let field: FieldValue; - if (ignoreProto) { - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key); - /* - The field might have been instantly filled from the cache - Maybe we want to just switch back to returning the value - from Server.GetDocumentField if it's in the cache - */ - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else { - field = FieldWaiting; - } - } - } else { - let doc: FieldValue = this; - while (doc && field !== FieldWaiting) { - let curField = doc.fields.get(key.Id); - let curProxy = doc._proxies.get(key.Id); - if (!curField || (curProxy && curField.field.Id !== curProxy)) { - if (curProxy) { - Server.GetDocumentField(doc, key); - /* - The field might have been instantly filled from the cache - Maybe we want to just switch back to returning the value - from Server.GetDocumentField if it's in the cache - */ - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else { - field = FieldWaiting; - } - break; - } - if ( - doc.fields.has(KeyStore.Prototype.Id) || - doc._proxies.has(KeyStore.Prototype.Id) - ) { - doc = doc.GetPrototype(); - } else { - break; - } - } else { - field = curField.field; - break; - } - } - if (doc === FieldWaiting) field = FieldWaiting; - } - - return field; - } - - /** - * Tries to get the field associated with the given key, and if there is an - * associated field, calls the given callback with that field. - * @param key - The key of the value to get - * @param callback - A function that will be called with the associated field, if it exists, - * once it is fetched from the server (this may be immediately if the field has already been fetched). - * Note: The callback will not be called if there is no associated field. - * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise - */ - GetAsync(key: Key, callback: (field: Opt) => void): void { - //TODO: This currently doesn't deal with prototypes - let field = this.fields.get(key.Id); - if (field && field.field) { - callback(field.field); - } else if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key, callback); - } else if (this._proxies.has(KeyStore.Prototype.Id)) { - this.GetTAsync(KeyStore.Prototype, Document, proto => { - if (proto) { - proto.GetAsync(key, callback); - } else { - callback(undefined); - } - }); - } else { - callback(undefined); - } - } - - GetTAsync(key: Key, ctor: { new(): T }): Promise>; - GetTAsync( - key: Key, - ctor: { new(): T }, - callback: (field: Opt) => void - ): void; - GetTAsync( - key: Key, - ctor: { new(): T }, - callback?: (field: Opt) => void - ): Promise> | void { - let fn = (cb: (field: Opt) => void) => { - return this.GetAsync(key, field => { - cb(Cast(field, ctor)); - }); - }; - if (callback) { - fn(callback); - } else { - return new Promise(fn); - } - } - - /** - * Same as {@link Document#GetAsync}, except a field of the given type - * will be created if there is no field associated with the given key, - * or the field associated with the given key is not of the given type. - * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc. - */ - GetOrCreateAsync( - key: Key, - ctor: { new(): T }, - callback: (field: T) => void - ): void { - //This currently doesn't deal with prototypes - if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key, field => { - if (field && field instanceof ctor) { - callback(field); - } else { - let newField = new ctor(); - this.Set(key, newField); - callback(newField); - } - }); - } else { - let newField = new ctor(); - this.Set(key, newField); - callback(newField); - } - } - - /** - * Same as {@link Document#Get}, except that it will additionally - * check if the field is of the given type. - * @param ctor - Constructor of the field type to get. E.g., `TextField`, `ImageField`, etc. - * @returns Same as {@link Document#Get}, except will return `undefined` - * if there is an associated field but it is of the wrong type. - */ - GetT( - key: Key, - ctor: { new(...args: any[]): T }, - ignoreProto: boolean = false - ): FieldValue { - var getfield = this.Get(key, ignoreProto); - if (getfield !== FieldWaiting) { - return Cast(getfield, ctor); - } - return FieldWaiting; - } - - GetOrCreate( - key: Key, - ctor: { new(): T }, - ignoreProto: boolean = false - ): T { - const field = this.GetT(key, ctor, ignoreProto); - if (field && field !== FieldWaiting) { - return field; - } - const newField = new ctor(); - this.Set(key, newField); - return newField; - } - - GetData( - key: Key, - ctor: { new(): U }, - defaultVal: T - ): T { - let val = this.Get(key); - let vval = val && val instanceof ctor ? val.Data : defaultVal; - return vval; - } - - GetHtml(key: Key, defaultVal: string): string { - return this.GetData(key, HtmlField, defaultVal); - } - - GetBoolean(key: Key, defaultVal: boolean): boolean { - return this.GetData(key, BooleanField, defaultVal); - } - - GetNumber(key: Key, defaultVal: number): number { - return this.GetData(key, NumberField, defaultVal); - } - - GetText(key: Key, defaultVal: string): string { - return this.GetData(key, TextField, defaultVal); - } - - GetList(key: Key, defaultVal: T[]): T[] { - return this.GetData>(key, ListField, defaultVal); - } - - @action - Set(key: Key, field: Field | undefined, setOnPrototype = false): void { - let old = this.fields.get(key.Id); - let oldField = old ? old.field : undefined; - if (setOnPrototype) { - this.SetOnPrototype(key, field); - } else { - if (field) { - this.fields.set(key.Id, { key, field }); - this._proxies.set(key.Id, field.Id); - // Server.AddDocumentField(this, key, field); - } else { - this.fields.delete(key.Id); - this._proxies.delete(key.Id); - // Server.DeleteDocumentField(this, key); - } - Server.UpdateField(this); - } - if (oldField || field) { - UndoManager.AddEvent({ - undo: () => this.Set(key, oldField, setOnPrototype), - redo: () => this.Set(key, field, setOnPrototype) - }); - } - } - - @action - SetOnPrototype(key: Key, field: Field | undefined): void { - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && f.Set(key, field); - }); - } - - @action - SetDataOnPrototype(key: Key, value: T, ctor: { new(): U }, replaceWrongType = true) { - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && f.SetData(key, value, ctor, replaceWrongType); - }); - } - - @action - SetData(key: Key, value: T, ctor: { new(data: T): U }, replaceWrongType = true) { - let field = this.Get(key, true); - if (field instanceof ctor) { - field.Data = value; - } else if (!field || replaceWrongType) { - let newField = new ctor(value); - // newField.Data = value; - this.Set(key, newField); - } - } - - @action - SetText(key: Key, value: string, replaceWrongType = true) { - this.SetData(key, value, TextField, replaceWrongType); - } - @action - SetBoolean(key: Key, value: boolean, replaceWrongType = true) { - this.SetData(key, value, BooleanField, replaceWrongType); - } - @action - SetNumber(key: Key, value: number, replaceWrongType = true) { - this.SetData(key, value, NumberField, replaceWrongType); - } - - GetPrototype(): FieldValue { - return this.GetT(KeyStore.Prototype, Document, true); - } - - GetAllPrototypes(): Document[] { - let protos: Document[] = []; - let doc: FieldValue = this; - while (doc && doc !== FieldWaiting) { - protos.push(doc); - doc = doc.GetPrototype(); - } - return protos; - } - - CreateAlias(id?: string): Document { - let alias = new Document(id); - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && alias.Set(KeyStore.Prototype, f); - }); - - return alias; - } - - MakeDelegate(id?: string): Document { - let delegate = new Document(id); - - delegate.Set(KeyStore.Prototype, this); - - return delegate; - } - - ToScriptString(): string { - return ""; - } - - TrySetValue(value: any): boolean { - throw new Error("Method not implemented."); - } - GetValue() { - return this.Title; - var title = (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + "(" + this.Id + ")"; - return title; - //throw new Error("Method not implemented."); - } - Copy(copyProto?: boolean, id?: string): Field { - let copy = new Document(); - this._proxies.forEach((fieldid, keyid) => { // copy each prototype field - let key = KeyStore.KeyLookup(keyid); - if (key) { - this.GetAsync(key, (field: Opt) => { - if (key === KeyStore.Prototype && copyProto) { // handle prototype field specially - if (field instanceof Document) { - copy.Set(key, field.Copy(false)); // only copying one level of prototypes for now... - } - } - else - if (field instanceof Document) { // ... TODO bcz: should we copy documents or reference them - copy.Set(key!, field); - } - else if (field) { - copy.Set(key!, field.Copy()); - } - }); - } - }); - return copy; - } - - ToJson() { - let fields: [string, string][] = []; - this._proxies.forEach((field, key) => - field && fields.push([key, field])); - - return { - type: Types.Document, - data: fields, - id: this.Id - }; - } -} diff --git a/src/fields/IconFIeld.ts b/src/fields/IconFIeld.ts deleted file mode 100644 index a6694cc49..000000000 --- a/src/fields/IconFIeld.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BasicField } from "./BasicField"; -import { FieldId } from "./Field"; -import { Types } from "../server/Message"; - -export class IconField extends BasicField { - constructor(data: string = "", id?: FieldId, save: boolean = true) { - super(data, save, id); - } - - ToScriptString(): string { - return `new IconField("${this.Data}")`; - } - - Copy() { - return new IconField(this.Data); - } - - ToJson() { - return { - type: Types.Icon, - data: this.Data, - id: this.Id - }; - } -} \ No newline at end of file diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts deleted file mode 100644 index 2eacd7d0c..000000000 --- a/src/fields/InkField.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { BasicField } from "./BasicField"; -import { Types } from "../server/Message"; -import { FieldId } from "./Field"; -import { observable, ObservableMap } from "mobx"; - -export enum InkTool { - None, - Pen, - Highlighter, - Eraser -} -export interface StrokeData { - pathData: Array<{ x: number, y: number }>; - color: string; - width: string; - tool: InkTool; - page: number; -} -export type StrokeMap = Map; - -export class InkField extends BasicField { - constructor(data: StrokeMap = new Map, id?: FieldId, save: boolean = true) { - super(data, save, id); - } - - ToScriptString(): string { - return `new InkField("${this.Data}")`; - } - - Copy() { - return new InkField(this.Data); - } - - ToJson() { - return { - type: Types.Ink, - data: this.Data, - id: this.Id, - }; - } - - UpdateFromServer(data: any) { - this.data = new ObservableMap(data); - } - - static FromJson(id: string, data: any): InkField { - let map: StrokeMap = new Map(); - Object.keys(data).forEach(key => { - map.set(key, data[key]); - }); - return new InkField(map, id, false); - } -} \ No newline at end of file diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts new file mode 100644 index 000000000..32f3aa4d5 --- /dev/null +++ b/src/new_fields/IconField.ts @@ -0,0 +1,14 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, primitive } from "serializr"; +import { ObjectField } from "./Doc"; + +@Deserializable("icon") +export class IconField extends ObjectField { + @serializable(primitive()) + readonly layout: string; + + constructor(layout: string) { + super(); + this.layout = layout; + } +} diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts new file mode 100644 index 000000000..cdb34cedf --- /dev/null +++ b/src/new_fields/InkField.ts @@ -0,0 +1,31 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; +import { ObjectField } from "./Doc"; + +export enum InkTool { + None, + Pen, + Highlighter, + Eraser +} +export interface StrokeData { + pathData: Array<{ x: number, y: number }>; + color: string; + width: string; + tool: InkTool; + page: number; +} + +const pointSchema = createSimpleSchema({ + x: true, y: true +}); + +const strokeDataSchema = createSimpleSchema({ + pathData: list(object(pointSchema)), + "*": true +}); + +export class InkField extends ObjectField { + @serializable(map(object(strokeDataSchema))) + readonly inkData: Map = new Map; +} diff --git a/src/server/Message.ts b/src/server/Message.ts index b01934724..81da44f72 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -42,6 +42,7 @@ export namespace MessageStore { export const DeleteAll = new Message("Delete All"); export const GetRefField = new Message("Get Ref Field"); + export const GetRefFields = new Message("Get Ref Fields"); export const UpdateField = new Message("Update Ref Field"); export const CreateField = new Message("Create Ref Field"); } diff --git a/src/server/index.ts b/src/server/index.ts index d6d5f0e55..10158eb96 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -16,7 +16,6 @@ import { Socket } from 'socket.io'; import * as webpack from 'webpack'; import * as wdm from 'webpack-dev-middleware'; import * as whm from 'webpack-hot-middleware'; -import { Field, FieldId } from '../fields/Field'; import { Utils } from '../Utils'; import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/controllers/user_controller'; import { DashUserModel } from './authentication/models/user_model'; @@ -236,6 +235,7 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); Utils.AddServerHandler(socket, MessageStore.GetRefField, GetRefField); + Utils.AddServerHandler(socket, MessageStore.GetRefFields, GetRefFields); }); function deleteFields() { @@ -270,6 +270,10 @@ function GetRefField([id, callback]: [string, (result?: Transferable) => void]) Database.Instance.getDocument(id, callback, "newDocuments"); } +function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) { + Database.Instance.getDocuments(ids, callback, "newDocuments"); +} + function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); -- cgit v1.2.3-70-g09d2 From 2e2377aaee0801ab20134b54e5105815c59f38e8 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 24 Apr 2019 20:50:53 -0400 Subject: Freeform view done --- .../collectionFreeForm/CollectionFreeFormView.tsx | 105 ++++++------- src/new_fields/Types.ts | 2 +- src/server/ServerUtil.ts | 62 -------- test/test.ts | 166 ++------------------- 4 files changed, 69 insertions(+), 266 deletions(-) delete mode 100644 src/server/ServerUtil.ts (limited to 'src/server') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ee7d65d23..3a9c9780b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -19,7 +19,7 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); -import { createSchema, makeInterface } from "../../../../new_fields/Schema"; +import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; import { Doc, Id } from "../../../../new_fields/Doc"; import { FieldValue, Cast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; @@ -83,19 +83,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { let dragDoc = de.data.droppedDocuments[0]; - let dropX = dragDoc.GetNumber(KeyStore.X, 0); - let dropY = dragDoc.GetNumber(KeyStore.Y, 0); + let dropX = Cast(dragDoc.x, "number", 0); + let dropY = Cast(dragDoc.y, "number", 0); de.data.droppedDocuments.map(d => { - d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0)) - dropX); - d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0)) - dropY); - if (!d.GetBoolean(KeyStore.IsMinimized, false)) { - if (!d.GetNumber(KeyStore.Width, 0)) { - d.SetNumber(KeyStore.Width, 300); + d.x = x + Cast(d.x, "number", 0) - dropX; + d.y = y + Cast(d.y, "number", 0) - dropY; + if (!Cast(d.isMinimized, "boolean", false)) { + if (!Cast(d.width, "number", 0)) { + d.width = 300; } - if (!d.GetNumber(KeyStore.Height, 0)) { - let nw = d.GetNumber(KeyStore.NativeWidth, 0); - let nh = d.GetNumber(KeyStore.NativeHeight, 0); - d.SetNumber(KeyStore.Height, nw && nh ? nh / nw * d.Width() : 300); + if (!Cast(d.height, "number", 0)) { + let nw = Cast(d.nativeWidth, "number", 0); + let nh = Cast(d.nativeHeight, "number", 0); + d.height = nw && nh ? nh / nw * Cast(d.width, "number", 0) : 300; } } this.bringToFront(d); @@ -115,7 +115,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerDown = (e: React.PointerEvent): void => { - let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => { + let childSelected = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), [] as Doc[]).filter(doc => doc).reduce((childSelected, doc) => { var dv = DocumentManager.Instance.getDocumentView(doc); return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false); }, false); @@ -139,20 +139,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble) { - let x = this.props.Document.GetNumber(KeyStore.PanX, 0); - let y = this.props.Document.GetNumber(KeyStore.PanY, 0); - let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); + let x = Cast(this.props.Document.panX, "number", 0); + let y = Cast(this.props.Document.panY, "number", 0); + let docs = this.children || []; let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); if (!this.isAnnotationOverlay) { - let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0; - let maxx = docs.length ? docs[0].Width() + minx : minx; - let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0; - let maxy = docs.length ? docs[0].Height() + miny : miny; + let minx = docs.length ? Cast(docs[0].x, "number", 0) : 0; + let maxx = docs.length ? Cast(docs[0].width, "number", 0) + minx : minx; + let miny = docs.length ? Cast(docs[0].y, "number", 0) : 0; + let maxy = docs.length ? Cast(docs[0].height, "number", 0) + miny : miny; let ranges = docs.filter(doc => doc).reduce((range, doc) => { - let x = doc.GetNumber(KeyStore.X, 0); - let xe = x + doc.GetNumber(KeyStore.Width, 0); - let y = doc.GetNumber(KeyStore.Y, 0); - let ye = y + doc.GetNumber(KeyStore.Height, 0); + let x = Cast(doc.x, "number", 0); + let xe = x + Cast(doc.width, "number", 0); + let y = Cast(doc.y, "number", 0); + let ye = y + Cast(doc.height, "number", 0); return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); @@ -176,10 +176,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // if (!this.props.active()) { // return; // } - let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => { + let childSelected = (this.children || []).filter(doc => doc).some(doc => { var dv = DocumentManager.Instance.getDocumentView(doc); - return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false); - }, false); + return dv && SelectionManager.IsSelected(dv) ? true : false; + }); if (!this.props.isSelected() && !childSelected && !this.props.isTopMost) { return; } @@ -188,8 +188,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (e.ctrlKey) { let deltaScale = (1 - (e.deltaY / coefficient)); - this.props.Document.SetNumber(KeyStore.NativeWidth, this.nativeWidth * deltaScale); - this.props.Document.SetNumber(KeyStore.NativeHeight, this.nativeHeight * deltaScale); + this.props.Document.nativeWidth = this.nativeWidth * deltaScale; + this.props.Document.nativeHeight = this.nativeHeight * deltaScale; e.stopPropagation(); e.preventDefault(); } else { @@ -204,7 +204,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y); let safeScale = Math.abs(localTransform.Scale); - this.props.Document.SetNumber(KeyStore.Scale, Math.abs(safeScale)); + this.props.Document.scale = Math.abs(safeScale); this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale); e.stopPropagation(); } @@ -216,8 +216,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { var scale = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY)); - this.props.Document.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX); - this.props.Document.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY); + this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; + this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; } @action @@ -230,23 +230,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } @action - bringToFront(doc: Document) { - this.props.Document.GetList(this.props.fieldKey, [] as Document[]).slice().sort((doc1, doc2) => { + bringToFront(doc: Doc) { + (this.children || []).slice().sort((doc1, doc2) => { if (doc1 === doc) return 1; if (doc2 === doc) return -1; - return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0); - }).map((doc, index) => doc.SetNumber(KeyStore.ZIndex, index + 1)); + return Cast(doc1.zIndex, "number", 0) - Cast(doc2.zIndex, "number", 0); + }).forEach((doc, index) => doc.zIndex = index + 1); return doc; } - focusDocument = (doc: Document) => { + focusDocument = (doc: Doc) => { this.setPan( - doc.GetNumber(KeyStore.X, 0) + doc.Width() / 2, - doc.GetNumber(KeyStore.Y, 0) + doc.Height() / 2); + Cast(doc.x, "number", 0) + Cast(doc.width, "number", 0) / 2, + Cast(doc.y, "number", 0) + Cast(doc.height, "number", 0) / 2); this.props.focus(this.props.Document); } - getDocumentViewProps(document: Document): DocumentViewProps { + getDocumentViewProps(document: Doc): DocumentViewProps { return { Document: document, addDocument: this.props.addDocument, @@ -255,8 +255,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ScreenToLocalTransform: this.getTransform, isTopMost: false, selectOnLoad: document.Id === this._selectOnLoaded, - PanelWidth: document.Width, - PanelHeight: document.Height, + PanelWidth: () => Cast(document.width, "number", 0),//TODO Types These are inline functions + PanelHeight: () => Cast(document.height, "number", 0), ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, @@ -267,13 +267,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed get views() { - var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); - let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { - var page = doc.GetNumber(KeyStore.Page, -1); + let curPage = FieldValue(this.Document.curPage, -1); + let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { + var page = Cast(doc.page, "number", -1); if (page === curPage || page === -1) { - let minim = doc.GetT(KeyStore.IsMinimized, BooleanField); - if (minim === undefined || (minim && !minim.Data)) - prev.push(); + let minim = Cast(doc.isMinimized, "boolean"); + if (minim === undefined || !minim) { + prev.push(); + } } return prev; }, [] as JSX.Element[]); @@ -316,9 +317,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @observer class CollectionFreeFormOverlayView extends React.Component { @computed get overlayView() { - let overlayLayout = this.props.Document.GetText(KeyStore.OverlayLayout, ""); + let overlayLayout = Cast(this.props.Document.overlayLayout, "string", ""); return !overlayLayout ? (null) : - (); } render() { @@ -329,9 +330,9 @@ class CollectionFreeFormOverlayView extends React.Component { @observer class CollectionFreeFormBackgroundView extends React.Component { @computed get backgroundView() { - let backgroundLayout = this.props.Document.GetText(KeyStore.BackgroundLayout, ""); + let backgroundLayout = Cast(this.props.Document.backgroundLayout, "string", ""); return !backgroundLayout ? (null) : - (); } render() { diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 55083765a..4ad8dcade 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -38,7 +38,7 @@ export interface Interface { } export function Cast | ListSpec>(field: FieldResult, ctor: T): FieldResult>; -export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal: ToType): ToType; +export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal: WithoutList>): WithoutList>; export function Cast | ListSpec>(field: FieldResult, ctor: T, defaultVal?: ToType): FieldResult> | undefined { if (field instanceof Promise) { return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal; diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts deleted file mode 100644 index 79ca5e55d..000000000 --- a/src/server/ServerUtil.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { HistogramField } from "../client/northstar/dash-fields/HistogramField"; -import { AudioField } from "../fields/AudioField"; -import { BooleanField } from "../fields/BooleanField"; -import { HtmlField } from "../fields/HtmlField"; -import { InkField } from "../fields/InkField"; -import { PDFField } from "../fields/PDFField"; -import { ScriptField } from "../fields/ScriptField"; -import { TupleField } from "../fields/TupleField"; -import { VideoField } from "../fields/VideoField"; -import { WebField } from "../fields/WebField"; -import { Utils } from "../Utils"; -import { Document } from "./../fields/Document"; -import { Field } from "./../fields/Field"; -import { ImageField } from "./../fields/ImageField"; -import { Key } from "./../fields/Key"; -import { ListField } from "./../fields/ListField"; -import { NumberField } from "./../fields/NumberField"; -import { RichTextField } from "./../fields/RichTextField"; -import { TextField } from "./../fields/TextField"; -import { Transferable, Types } from "./Message"; -import { IconField } from "../fields/IconFIeld"; - -export class ServerUtils { - public static prepend(extension: string): string { - return window.location.origin + extension; - } - - public static FromJson(json: Transferable): Field { - - if (!(json.data !== undefined && json.id && json.type !== undefined)) { - console.log( - "how did you manage to get an object that doesn't have a data or an id?" - ); - return new TextField("Something to fill the space", Utils.GenerateGuid()); - } - - switch (json.type) { - case Types.Boolean: return new BooleanField(json.data, json.id, false); - case Types.Number: return new NumberField(json.data, json.id, false); - case Types.Text: return new TextField(json.data, json.id, false); - case Types.Icon: return new IconField(json.data, json.id, false); - case Types.Html: return new HtmlField(json.data, json.id, false); - case Types.Web: return new WebField(new URL(json.data), json.id, false); - case Types.RichText: return new RichTextField(json.data, json.id, false); - case Types.Key: return new Key(json.data, json.id, false); - case Types.Image: return new ImageField(new URL(json.data), json.id, false); - case Types.HistogramOp: return HistogramField.FromJson(json.id, json.data); - case Types.PDF: return new PDFField(new URL(json.data), json.id, false); - case Types.List: return ListField.FromJson(json.id, json.data); - case Types.Script: return ScriptField.FromJson(json.id, json.data); - case Types.Audio: return new AudioField(new URL(json.data), json.id, false); - case Types.Video: return new VideoField(new URL(json.data), json.id, false); - case Types.Tuple: return new TupleField(json.data, json.id, false); - case Types.Ink: return InkField.FromJson(json.id, json.data); - case Types.Document: return Document.FromJson(json.data, json.id, false); - default: - throw Error( - "Error, unrecognized field type received from server. If you just created a new field type, be sure to add it here" - ); - } - } -} diff --git a/test/test.ts b/test/test.ts index 16cace026..91dc43379 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,171 +1,35 @@ -import { NumberField } from "../src/fields/NumberField"; import { expect } from 'chai'; import 'mocha'; -import { Key } from "../src/fields/Key"; -import { Document } from "../src/fields/Document"; import { autorun, reaction } from "mobx"; -import { DocumentReference } from "../src/fields/DocumentReference"; -import { TextField } from "../src/fields/TextField"; -import { Field, FieldWaiting } from "../src/fields/Field"; - -describe('Number Controller', () => { - it('Should be constructable', () => { - const numController = new NumberField(15); - expect(numController.Data).to.equal(15); - }); - - it('Should update', () => { - const numController = new NumberField(15); - let ran = false; - reaction(() => numController.Data, (data) => { ran = true; }); - expect(ran).to.equal(false); - numController.Data = 5; - expect(ran).to.equal(true); - }); -}); +import { Doc } from '../src/new_fields/Doc'; +import { Cast } from '../src/new_fields/Types'; describe("Document", () => { it('should hold fields', () => { - let key = new Key("Test"); - let key2 = new Key("Test2"); - let field = new NumberField(15); - let doc = new Document(); - doc.Set(key, field); - let getField = doc.GetT(key, NumberField); - let getField2 = doc.GetT(key2, NumberField); + let key = "Test"; + let key2 = "Test2"; + let field = 15; + let doc = new Doc(); + doc[key] = field; + let getField = Cast(doc[key], "number"); + let getField2 = Cast(doc[key2], "number"); expect(getField).to.equal(field); expect(getField2).to.equal(undefined); }); it('should update', () => { - let doc = new Document(); - let key = new Key("Test"); - let key2 = new Key("Test2"); + let doc = new Doc(); + let key = "Test"; + let key2 = "Test2"; let ran = false; - reaction(() => doc.Get(key), (field) => { ran = true; }); + reaction(() => doc[key], (field) => { ran = true; }); expect(ran).to.equal(false); - doc.Set(key2, new NumberField(4)); + doc[key2] = 4; expect(ran).to.equal(false); - doc.Set(key, new NumberField(5)); + doc[key] = 5; expect(ran).to.equal(true); }); }); - -describe("Reference", () => { - it('should dereference', () => { - let doc = new Document(); - let doc2 = new Document(); - const key = new Key("test"); - const key2 = new Key("test2"); - - const numCont = new NumberField(55); - doc.Set(key, numCont); - let ref = new DocumentReference(doc, key); - let ref2 = new DocumentReference(doc, key2); - doc2.Set(key2, ref); - - let ref3 = new DocumentReference(doc2, key2); - let ref4 = new DocumentReference(doc2, key); - - expect(ref.Dereference()).to.equal(numCont); - expect(ref.DereferenceToRoot()).to.equal(numCont); - expect(ref2.Dereference()).to.equal(undefined); - expect(ref2.DereferenceToRoot()).to.equal(undefined); - expect(ref3.Dereference()).to.equal(ref); - expect(ref3.DereferenceToRoot()).to.equal(numCont); - expect(ref4.Dereference()).to.equal(undefined); - expect(ref4.DereferenceToRoot()).to.equal(undefined); - }); - - it('should work with prototypes', () => { - let doc = new Document; - let doc2 = doc.MakeDelegate(); - let key = new Key("test"); - expect(doc.Get(key)).to.equal(undefined); - expect(doc2.Get(key)).to.equal(undefined); - let num = new NumberField(55); - let num2 = new NumberField(56); - - doc.Set(key, num); - expect(doc.Get(key)).to.equal(num); - expect(doc2.Get(key)).to.equal(num); - - doc2.Set(key, num2); - expect(doc.Get(key)).to.equal(num); - expect(doc2.Get(key)).to.equal(num2); - }); - - it('should update through layers', () => { - let doc = new Document(); - let doc2 = new Document(); - let doc3 = new Document(); - const key = new Key("test"); - const key2 = new Key("test2"); - const key3 = new Key("test3"); - - const numCont = new NumberField(55); - doc.Set(key, numCont); - const ref = new DocumentReference(doc, key); - doc2.Set(key2, ref); - const ref3 = new DocumentReference(doc2, key2); - doc3.Set(key3, ref3); - - let ran = false; - reaction(() => { - let field = ((doc3.Get(key3)).DereferenceToRoot()).GetValue(); - return field; - }, (field) => { - ran = true; - }); - expect(ran).to.equal(false); - - numCont.Data = 44; - expect(ran).to.equal(true); - ran = false; - - doc.Set(key, new NumberField(33)); - expect(ran).to.equal(true); - ran = false; - - doc.Set(key2, new NumberField(4)); - expect(ran).to.equal(false); - - doc2.Set(key2, new TextField("hello")); - expect(ran).to.equal(true); - ran = false; - - doc3.Set(key3, new TextField("world")); - expect(ran).to.equal(true); - ran = false; - }); - - it('should update with prototypes', () => { - let doc = new Document(); - let doc2 = doc.MakeDelegate(); - const key = new Key("test"); - - const numCont = new NumberField(55); - - let ran = false; - reaction(() => { - let field = doc2.GetT(key, NumberField); - if (field && field !== FieldWaiting) { - return field.Data; - } - return undefined; - }, (field) => { - ran = true; - }); - expect(ran).to.equal(false); - - doc.Set(key, numCont); - expect(ran).to.equal(true); - - ran = false; - numCont.Data = 1; - expect(ran).to.equal(true); - }); -}); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e1a65c5fa52dd094cc48c0c85b3c92ae8789666d Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 25 Apr 2019 01:26:28 -0400 Subject: Bunch of files --- src/client/DocServer.ts | 4 + src/client/Server.ts | 173 --------------------- src/client/SocketStub.ts | 69 -------- src/client/util/Scripting.ts | 33 +--- .../views/collections/CollectionBaseView.tsx | 76 +++++---- src/client/views/nodes/LinkMenu.tsx | 26 ++-- .../authentication/models/current_user_utils.ts | 28 ++-- 7 files changed, 73 insertions(+), 336 deletions(-) delete mode 100644 src/client/Server.ts delete mode 100644 src/client/SocketStub.ts (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index cba0c4770..02fd28a86 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -9,6 +9,10 @@ export namespace DocServer { const _socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`); const GUID: string = Utils.GenerateGuid(); + export function prepend(extension: string): string { + return window.location.origin + extension; + } + export async function GetRefField(id: string): Promise> { let cached = _cache[id]; if (cached === undefined) { diff --git a/src/client/Server.ts b/src/client/Server.ts deleted file mode 100644 index 66e9878d9..000000000 --- a/src/client/Server.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { Key } from "../fields/Key"; -import { ObservableMap, action, reaction, runInAction } from "mobx"; -import { Field, FieldWaiting, FIELD_WAITING, Opt, FieldId } from "../fields/Field"; -import { Document } from "../fields/Document"; -import { SocketStub, FieldMap } from "./SocketStub"; -import * as OpenSocket from 'socket.io-client'; -import { Utils, emptyFunction } from "./../Utils"; -import { MessageStore, Types } from "./../server/Message"; - -export class Server { - public static ClientFieldsCached: ObservableMap = new ObservableMap(); - static Socket: SocketIOClient.Socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`); - static GUID: string = Utils.GenerateGuid(); - - // Retrieves the cached value of the field and sends a request to the server for the real value (if it's not cached). - // Call this is from within a reaction and test whether the return value is FieldWaiting. - public static GetField(fieldid: FieldId): Promise>; - public static GetField(fieldid: FieldId, callback: (field: Opt) => void): void; - public static GetField(fieldid: FieldId, callback?: (field: Opt) => void): Promise> | void { - let fn = (cb: (field: Opt) => void) => { - - let cached = this.ClientFieldsCached.get(fieldid); - if (cached === undefined) { - this.ClientFieldsCached.set(fieldid, FieldWaiting); - SocketStub.SEND_FIELD_REQUEST(fieldid, action((field: Field | undefined) => { - let cached = this.ClientFieldsCached.get(fieldid); - if (cached !== FieldWaiting) { - cb(cached); - } - else { - if (field) { - this.ClientFieldsCached.set(fieldid, field); - } else { - this.ClientFieldsCached.delete(fieldid); - } - cb(field); - } - })); - } else if (cached !== FieldWaiting) { - setTimeout(() => cb(cached as Field), 0); - } else { - reaction(() => this.ClientFieldsCached.get(fieldid), - (field, reaction) => { - if (field !== FieldWaiting) { - reaction.dispose(); - cb(field); - } - }); - } - }; - if (callback) { - fn(callback); - } else { - return new Promise(fn); - } - } - - public static GetFields(fieldIds: FieldId[]): Promise<{ [id: string]: Field }>; - public static GetFields(fieldIds: FieldId[], callback: (fields: FieldMap) => any): void; - public static GetFields(fieldIds: FieldId[], callback?: (fields: FieldMap) => any): Promise | void { - let fn = action((cb: (fields: FieldMap) => void) => { - - let neededFieldIds: FieldId[] = []; - let waitingFieldIds: FieldId[] = []; - let existingFields: FieldMap = {}; - for (let id of fieldIds) { - let field = this.ClientFieldsCached.get(id); - if (field === undefined) { - neededFieldIds.push(id); - this.ClientFieldsCached.set(id, FieldWaiting); - } else if (field === FieldWaiting) { - waitingFieldIds.push(id); - } else { - existingFields[id] = field; - } - } - SocketStub.SEND_FIELDS_REQUEST(neededFieldIds, action((fields: FieldMap) => { - for (let id of neededFieldIds) { - let field = fields[id]; - if (field) { - if (this.ClientFieldsCached.get(field.Id) === FieldWaiting) { - this.ClientFieldsCached.set(field.Id, field); - } else { - throw new Error("we shouldn't be trying to replace things that are already in the cache"); - } - } else { - if (this.ClientFieldsCached.get(id) === FieldWaiting) { - this.ClientFieldsCached.delete(id); - } else { - throw new Error("we shouldn't be trying to replace things that are already in the cache"); - } - } - } - reaction(() => waitingFieldIds.map(id => this.ClientFieldsCached.get(id)), - (cachedFields, reaction) => { - if (!cachedFields.some(field => field === FieldWaiting)) { - const realFields = cachedFields as Opt[]; - reaction.dispose(); - waitingFieldIds.forEach((id, index) => { - existingFields[id] = realFields[index]; - }); - cb({ ...fields, ...existingFields }); - } - }, { fireImmediately: true }); - })); - }); - if (callback) { - fn(callback); - } else { - return new Promise(fn); - } - } - - public static GetDocumentField(doc: Document, key: Key, callback?: (field: Field) => void) { - let field = doc._proxies.get(key.Id); - if (field) { - this.GetField(field, - action((fieldfromserver: Opt) => { - if (fieldfromserver) { - doc.fields.set(key.Id, { key, field: fieldfromserver }); - if (callback) { - callback(fieldfromserver); - } - } - })); - } - } - - public static DeleteDocumentField(doc: Document, key: Key) { - SocketStub.SEND_DELETE_DOCUMENT_FIELD(doc, key); - } - - public static UpdateField(field: Field) { - if (!this.ClientFieldsCached.has(field.Id)) { - this.ClientFieldsCached.set(field.Id, field); - } - SocketStub.SEND_SET_FIELD(field); - } - - static connected(message: string) { - Server.Socket.emit(MessageStore.Bar.Message, Server.GUID); - } - - @action - private static cacheField(clientField: Field) { - var cached = this.ClientFieldsCached.get(clientField.Id); - if (!cached) { - this.ClientFieldsCached.set(clientField.Id, clientField); - } else { - // probably should overwrite the values within any field that was already here... - } - return this.ClientFieldsCached.get(clientField.Id); - } - - @action - static updateField(field: { id: string, data: any, type: Types }) { - if (Server.ClientFieldsCached.has(field.id)) { - var f = Server.ClientFieldsCached.get(field.id); - if (f) { - // console.log("Applying : " + field.id); - f.UpdateFromServer(field.data); - f.init(emptyFunction); - } else { - // console.log("Not applying wa : " + field.id); - } - } else { - // console.log("Not applying mi : " + field.id); - } - } -} - -Utils.AddServerHandler(Server.Socket, MessageStore.Foo, Server.connected); -Utils.AddServerHandler(Server.Socket, MessageStore.SetField, Server.updateField); diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts deleted file mode 100644 index 382a81f66..000000000 --- a/src/client/SocketStub.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Key } from "../fields/Key"; -import { Field, FieldId, Opt } from "../fields/Field"; -import { ObservableMap } from "mobx"; -import { Document } from "../fields/Document"; -import { MessageStore, Transferable } from "../server/Message"; -import { Utils } from "../Utils"; -import { Server } from "./Server"; -import { ServerUtils } from "../server/ServerUtil"; - - -export interface FieldMap { - [id: string]: Opt; -} - -//TODO tfs: I think it might be cleaner to not have SocketStub deal with turning what the server gives it into Fields (in other words not call ServerUtils.FromJson), and leave that for the Server class. -export class SocketStub { - - static FieldStore: ObservableMap = new ObservableMap(); - - public static SEND_FIELD_REQUEST(fieldid: FieldId): Promise>; - public static SEND_FIELD_REQUEST(fieldid: FieldId, callback: (field: Opt) => void): void; - public static SEND_FIELD_REQUEST(fieldid: FieldId, callback?: (field: Opt) => void): Promise> | void { - let fn = function (cb: (field: Opt) => void) { - Utils.EmitCallback(Server.Socket, MessageStore.GetField, fieldid, (field: Transferable) => { - if (field) { - ServerUtils.FromJson(field).init(cb); - } else { - cb(undefined); - } - }); - }; - if (callback) { - fn(callback); - } else { - return new Promise(fn); - } - } - - public static SEND_FIELDS_REQUEST(fieldIds: FieldId[], callback: (fields: FieldMap) => any) { - Utils.EmitCallback(Server.Socket, MessageStore.GetFields, fieldIds, (fields: Transferable[]) => { - let fieldMap: FieldMap = {}; - fields.map(field => fieldMap[field.id] = ServerUtils.FromJson(field)); - let proms = Object.values(fieldMap).map(val => - new Promise(resolve => val!.init(resolve))); - Promise.all(proms).then(() => callback(fieldMap)); - }); - } - - public static SEND_DELETE_DOCUMENT_FIELD(doc: Document, key: Key) { - // Send a request to delete the field stored under the specified key from the document - - // ...SOCKET(DELETE_DOCUMENT_FIELD, document id, key id) - - // Server removes the field id from the document's list of field proxies - var document = this.FieldStore.get(doc.Id) as Document; - if (document) { - document._proxies.delete(key.Id); - } - } - - public static SEND_SET_FIELD(field: Field) { - // Send a request to set the value of a field - - // ...SOCKET(SET_FIELD, field id, serialized field value) - - // Server updates the value of the field in its fieldstore - Utils.Emit(Server.Socket, MessageStore.SetField, field.ToJson()); - } -} diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index c67cc067a..dbec82340 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -1,13 +1,5 @@ // import * as ts from "typescript" let ts = (window as any).ts; -import { Opt, Field } from "../../fields/Field"; -import { Document } from "../../fields/Document"; -import { NumberField } from "../../fields/NumberField"; -import { ImageField } from "../../fields/ImageField"; -import { TextField } from "../../fields/TextField"; -import { RichTextField } from "../../fields/RichTextField"; -import { KeyStore } from "../../fields/KeyStore"; -import { ListField } from "../../fields/ListField"; // // @ts-ignore // import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts' // // @ts-ignore @@ -15,8 +7,10 @@ import { ListField } from "../../fields/ListField"; // @ts-ignore import * as typescriptlib from '!!raw-loader!./type_decls.d'; -import { Documents } from "../documents/Documents"; -import { Key } from "../../fields/Key"; +import { Docs } from "../documents/Documents"; +import { Doc, Field } from '../../new_fields/Doc'; +import { ImageField, PdfField, VideoField, AudioField } from '../../new_fields/URLField'; +import { List } from '../../new_fields/List'; export interface ScriptSucccess { success: true; @@ -50,9 +44,9 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an return { compiled: false, errors: diagnostics }; } - let fieldTypes = [Document, NumberField, TextField, ImageField, RichTextField, ListField, Key]; - let paramNames = ["KeyStore", "Documents", ...fieldTypes.map(fn => fn.name)]; - let params: any[] = [KeyStore, Documents, ...fieldTypes]; + let fieldTypes = [Doc, ImageField, PdfField, VideoField, AudioField, List, RichTextField]; + let paramNames = ["Docs", ...fieldTypes.map(fn => fn.name)]; + let params: any[] = [Docs, ...fieldTypes]; let compiledFunction = new Function(...paramNames, `return ${script}`); let { capturedVariables = {} } = options; let run = (args: { [name: string]: any } = {}): ScriptResult => { @@ -171,17 +165,4 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp let diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics); return Run(outputText, paramNames, diagnostics, script, options); -} - -export function OrLiteralType(returnType: string): string { - return `${returnType} | string | number`; -} - -export function ToField(data: any): Opt { - if (typeof data === "string") { - return new TextField(data); - } else if (typeof data === "number") { - return new NumberField(data); - } - return undefined; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 4755b2d57..058893198 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -1,13 +1,12 @@ import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Document } from '../../../fields/Document'; -import { Field, FieldValue, FieldWaiting } from '../../../fields/Field'; -import { KeyStore } from '../../../fields/KeyStore'; -import { ListField } from '../../../fields/ListField'; -import { NumberField } from '../../../fields/NumberField'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; +import { Cast, FieldValue, PromiseValue } from '../../../new_fields/Types'; +import { Doc, FieldResult, Opt, Id } from '../../../new_fields/Doc'; +import { listSpec } from '../../../new_fields/Schema'; +import { List } from '../../../new_fields/List'; export enum CollectionViewType { Invalid, @@ -18,9 +17,9 @@ export enum CollectionViewType { } export interface CollectionRenderProps { - addDocument: (document: Document, allowDuplicates?: boolean) => boolean; - removeDocument: (document: Document) => boolean; - moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; + addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; + removeDocument: (document: Doc) => boolean; + moveDocument: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; active: () => boolean; whenActiveChanged: (isActive: boolean) => void; } @@ -37,11 +36,9 @@ export interface CollectionViewProps extends FieldViewProps { export class CollectionBaseView extends React.Component { get collectionViewType(): CollectionViewType | undefined { let Document = this.props.Document; - let viewField = Document.GetT(KeyStore.ViewType, NumberField); - if (viewField === FieldWaiting) { - return undefined; - } else if (viewField) { - return viewField.Data; + let viewField = Cast(Document.viewType, "number"); + if (viewField !== undefined) { + return viewField; } else { return CollectionViewType.Invalid; } @@ -60,47 +57,48 @@ export class CollectionBaseView extends React.Component { this.props.whenActiveChanged(isActive); } - createsCycle(documentToAdd: Document, containerDocument: Document): boolean { - if (!(documentToAdd instanceof Document)) { + createsCycle(documentToAdd: Doc, containerDocument: Doc): boolean { + if (!(documentToAdd instanceof Doc)) { return false; } - let data = documentToAdd.GetList(KeyStore.Data, [] as Document[]); + let data = Cast(documentToAdd.data, listSpec(Doc), []); for (const doc of data.filter(d => d instanceof Document)) { if (this.createsCycle(doc, containerDocument)) { return true; } } - let annots = documentToAdd.GetList(KeyStore.Annotations, [] as Document[]); + let annots = Cast(documentToAdd.annotations, listSpec(Doc), []); for (const annot of annots) { if (this.createsCycle(annot, containerDocument)) { return true; } } - for (let containerProto: FieldValue = containerDocument; containerProto && containerProto !== FieldWaiting; containerProto = containerProto.GetPrototype()) { - if (containerProto.Id === documentToAdd.Id) { + for (let containerProto: Opt = containerDocument; containerProto !== undefined; containerProto = FieldValue(containerProto.proto)) { + if (containerProto[Id] === documentToAdd[Id]) { return true; } } return false; } - @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? + @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } @action.bound - addDocument(doc: Document, allowDuplicates: boolean = false): boolean { + addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { let props = this.props; - var curPage = props.Document.GetNumber(KeyStore.CurPage, -1); - doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage)); + var curPage = Cast(props.Document.curPage, "number", -1); + Doc.SetOnPrototype(doc, "page", curPage); if (true || this.isAnnotationOverlay) { - doc.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1)); + doc.zoom = Cast(this.props.Document.scale, "number", 1); } if (curPage >= 0) { - doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document); + Doc.SetOnPrototype(doc, "annotationOn", props.Document); } - if (props.Document.Get(props.fieldKey) instanceof Field) { + const data = props.Document[props.fieldKey]; + if (data !== undefined) { //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()); - if (!this.createsCycle(doc, props.Document)) { - if (!value.some(v => v.Id === doc.Id) || allowDuplicates) { + const value = Cast(data, listSpec(Doc)); + if (!this.createsCycle(doc, props.Document) && value !== undefined) { + if (allowDuplicates || !value.some(v => v.Id === doc.Id)) { value.push(doc); } } @@ -108,9 +106,9 @@ export class CollectionBaseView extends React.Component { return false; } } else { - let proto = props.Document.GetPrototype(); - if (!proto || proto === FieldWaiting || !this.createsCycle(proto, doc)) { - const field = new ListField([doc]); + let proto = FieldValue(props.Document.proto); + if (!proto || !this.createsCycle(proto, doc)) { + const field = new List([doc]); // const script = CompileScript(` // if(added) { // console.log("added " + field.Title + " " + doc.Title); @@ -130,7 +128,7 @@ export class CollectionBaseView extends React.Component { // if (script.compiled) { // field.addScript(new ScriptField(script)); // } - props.Document.SetOnPrototype(props.fieldKey, field); + Doc.SetOnPrototype(props.Document, props.fieldKey, field); } else { return false; @@ -140,20 +138,20 @@ export class CollectionBaseView extends React.Component { } @action.bound - removeDocument(doc: Document): boolean { + removeDocument(doc: Doc): boolean { const props = this.props; //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()); + const value = Cast(props.Document[props.fieldKey], listSpec(Doc), []); let index = -1; for (let i = 0; i < value.length; i++) { - if (value[i].Id === doc.Id) { + if (value[i][Id] === doc[Id]) { index = i; break; } } - doc.GetTAsync(KeyStore.AnnotationOn, Document).then((annotationOn) => { + PromiseValue(Cast(doc.annotationOn, Doc)).then((annotationOn) => { if (annotationOn === props.Document) { - doc.Set(KeyStore.AnnotationOn, undefined, true); + doc.annotationOn = undefined; } }); @@ -168,7 +166,7 @@ export class CollectionBaseView extends React.Component { } @action.bound - moveDocument(doc: Document, targetCollection: Document, addDocument: (doc: Document) => boolean): boolean { + moveDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean { if (this.props.Document === targetCollection) { return true; } diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index ac09da305..3ecc8555d 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -1,15 +1,13 @@ import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../fields/Document"; -import { FieldWaiting } from "../../../fields/Field"; -import { Key } from "../../../fields/Key"; -import { KeyStore } from '../../../fields/KeyStore'; -import { ListField } from "../../../fields/ListField"; import { DocumentView } from "./DocumentView"; import { LinkBox } from "./LinkBox"; import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); +import { Doc, Id } from "../../../new_fields/Doc"; +import { Cast, FieldValue } from "../../../new_fields/Types"; +import { listSpec } from "../../../new_fields/Schema"; interface Props { docView: DocumentView; @@ -19,28 +17,28 @@ interface Props { @observer export class LinkMenu extends React.Component { - @observable private _editingLink?: Document; + @observable private _editingLink?: Doc; - renderLinkItems(links: Document[], key: Key, type: string) { + renderLinkItems(links: Doc[], key: string, type: string) { return links.map(link => { - let doc = link.GetT(key, Document); - if (doc && doc !== FieldWaiting) { - return this._editingLink = link)} type={type} />; + let doc = FieldValue(Cast(link[key], Doc)); + if (doc) { + return this._editingLink = link)} type={type} />; } }); } render() { //get list of links from document - let linkFrom: Document[] = this.props.docView.props.Document.GetData(KeyStore.LinkedFromDocs, ListField, []); - let linkTo: Document[] = this.props.docView.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []); + let linkFrom: Doc[] = Cast(this.props.docView.props.Document.linkedFromDocs, listSpec(Doc), []); + let linkTo: Doc[] = Cast(this.props.docView.props.Document.linkedToDocs, listSpec(Doc), []); if (this._editingLink === undefined) { return (
- {this.renderLinkItems(linkTo, KeyStore.LinkedToDocs, "Destination: ")} - {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Source: ")} + {this.renderLinkItems(linkTo, "linkedTo", "Destination: ")} + {this.renderLinkItems(linkFrom, "linkedFrom", "Source: ")}
); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 5d4479c88..30a8980ae 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -1,19 +1,17 @@ import { computed, observable, action, runInAction } from "mobx"; import * as rp from 'request-promise'; -import { Documents } from "../../../client/documents/Documents"; +import { Docs } from "../../../client/documents/Documents"; import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea"; import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; -import { Server } from "../../../client/Server"; -import { Document } from "../../../fields/Document"; -import { KeyStore } from "../../../fields/KeyStore"; -import { ListField } from "../../../fields/ListField"; import { RouteStore } from "../../RouteStore"; -import { ServerUtils } from "../../ServerUtil"; +import { DocServer } from "../../../client/DocServer"; +import { Doc } from "../../../new_fields/Doc"; +import { List } from "../../../new_fields/List"; export class CurrentUserUtils { private static curr_email: string; private static curr_id: string; - @observable private static user_document: Document; + @observable private static user_document: Doc; //TODO tfs: these should be temporary... private static mainDocId: string | undefined; @@ -23,15 +21,15 @@ export class CurrentUserUtils { public static get MainDocId() { return this.mainDocId; } public static set MainDocId(id: string | undefined) { this.mainDocId = id; } - private static createUserDocument(id: string): Document { - let doc = new Document(id); - doc.Set(KeyStore.Workspaces, new ListField()); - doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })); + private static createUserDocument(id: string): Doc { + let doc = new Doc(id, true); + doc.workspaces = new List(); + doc.optionalRightCollection = Docs.SchemaDocument([], { title: "Pending documents" }); return doc; } public static loadCurrentUser(): Promise { - let userPromise = rp.get(ServerUtils.prepend(RouteStore.getCurrUser)).then(response => { + let userPromise = rp.get(DocServer.prepend(RouteStore.getCurrUser)).then(response => { if (response) { let obj = JSON.parse(response); CurrentUserUtils.curr_id = obj.id as string; @@ -40,10 +38,10 @@ export class CurrentUserUtils { throw new Error("There should be a user! Why does Dash think there isn't one?"); } }); - let userDocPromise = rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)).then(id => { + let userDocPromise = rp.get(DocServer.prepend(RouteStore.getUserDocumentId)).then(id => { if (id) { - return Server.GetField(id).then(field => - runInAction(() => this.user_document = field instanceof Document ? field : this.createUserDocument(id))); + return DocServer.GetRefField(id).then(field => + runInAction(() => this.user_document = field instanceof Doc ? field : this.createUserDocument(id))); } else { throw new Error("There should be a user id! Why does Dash think there isn't one?"); } -- cgit v1.2.3-70-g09d2 From 7cda7f95e724bb621c57b5c53b083e6d6245afa5 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 26 Apr 2019 21:14:50 -0400 Subject: More --- src/client/views/InkingCanvas.tsx | 29 +- src/client/views/InkingControl.tsx | 7 +- .../views/collections/CollectionTreeView.tsx | 51 ++- src/client/views/nodes/LinkEditor.tsx | 16 +- src/debug/Viewer.tsx | 368 ++++++++++----------- src/fields/ScriptField.ts | 174 +++++----- src/mobile/ImageUpload.tsx | 34 +- src/new_fields/Doc.ts | 4 +- .../authentication/controllers/WorkspacesMenu.tsx | 16 +- 9 files changed, 344 insertions(+), 355 deletions(-) (limited to 'src/server') diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 47ee8eb85..1e26893c5 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -1,9 +1,5 @@ import { action, computed, trace, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../fields/Document"; -import { FieldWaiting } from "../../fields/Field"; -import { InkField, InkTool, StrokeData, StrokeMap } from "../../fields/InkField"; -import { KeyStore } from "../../fields/KeyStore"; import { Utils } from "../../Utils"; import { Transform } from "../util/Transform"; import "./InkingCanvas.scss"; @@ -11,10 +7,13 @@ import { InkingControl } from "./InkingControl"; import { InkingStroke } from "./InkingStroke"; import React = require("react"); import { undoBatch, UndoManager } from "../util/UndoManager"; +import { StrokeData, InkField, InkTool } from "../../new_fields/InkField"; +import { Doc } from "../../new_fields/Doc"; +import { Cast, PromiseValue, NumCast } from "../../new_fields/Types"; interface InkCanvasProps { getScreenTransform: () => Transform; - Document: Document; + Document: Doc; children: () => JSX.Element[]; } @@ -23,7 +22,7 @@ export class InkingCanvas extends React.Component { maxCanvasDim = 8192 / 2; // 1/2 of the maximum canvas dimension for Chrome @observable inkMidX: number = 0; @observable inkMidY: number = 0; - private previousState?: StrokeMap; + private previousState?: Map; private _currentStrokeId: string = ""; public static IntersectStrokeRect(stroke: StrokeData, selRect: { left: number, top: number, width: number, height: number }): boolean { return stroke.pathData.reduce((inside: boolean, val) => inside || @@ -33,9 +32,9 @@ export class InkingCanvas extends React.Component { } componentDidMount() { - this.props.Document.GetTAsync(KeyStore.Ink, InkField, ink => runInAction(() => { + PromiseValue(Cast(this.props.Document.ink, InkField)).then(ink => runInAction(() => { if (ink) { - let bounds = Array.from(ink.Data).reduce(([mix, max, miy, may], [id, strokeData]) => + let bounds = Array.from(ink.inkData).reduce(([mix, max, miy, may], [id, strokeData]) => strokeData.pathData.reduce(([mix, max, miy, may], p) => [Math.min(mix, p.x), Math.max(max, p.x), Math.min(miy, p.y), Math.max(may, p.y)], [mix, max, miy, may]), @@ -47,13 +46,13 @@ export class InkingCanvas extends React.Component { } @computed - get inkData(): StrokeMap { - let map = this.props.Document.GetT(KeyStore.Ink, InkField); - return !map || map === FieldWaiting ? new Map : new Map(map.Data); + get inkData(): Map { + let map = Cast(this.props.Document.ink, InkField); + return !map ? new Map : new Map(map.inkData); } - set inkData(value: StrokeMap) { - this.props.Document.SetDataOnPrototype(KeyStore.Ink, value, InkField); + set inkData(value: Map) { + Doc.SetOnPrototype(this.props.Document, "ink", new InkField(value)); } @action @@ -78,7 +77,7 @@ export class InkingCanvas extends React.Component { color: InkingControl.Instance.selectedColor, width: InkingControl.Instance.selectedWidth, tool: InkingControl.Instance.selectedTool, - page: this.props.Document.GetNumber(KeyStore.CurPage, -1) + page: NumCast(this.props.Document.curPage, -1) }); this.inkData = data; } @@ -137,7 +136,7 @@ export class InkingCanvas extends React.Component { @computed get drawnPaths() { - let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); + let curPage = NumCast(this.props.Document.curPage, -1); let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { if (strokeData.page === -1 || strokeData.page === curPage) { paths.push( void; + document: Doc; + deleteDoc: (doc: Doc) => void; moveDocument: DragManager.MoveFunction; copyOnDrag: boolean; } @@ -43,9 +42,9 @@ class TreeView extends React.Component { @action remove = (document: Document) => { - var children = this.props.document.GetT>(KeyStore.Data, ListField); - if (children && children !== FieldWaiting) { - children.Data.splice(children.Data.indexOf(document), 1); + var children = Cast(this.props.document.data, listSpec(Doc)); + if (children) { + children.splice(children.indexOf(document), 1); } } @@ -80,15 +79,15 @@ class TreeView extends React.Component { display={"inline"} contents={titleString} height={36} - GetValue={() => this.props.document.Title} + GetValue={() => StrCast(this.props.document.title)} SetValue={(value: string) => { - this.props.document.SetText(KeyStore.Title, value); + this.props.document.title = value; return true; }} />); return (
- {editableView(this.props.document.Title)} + {editableView(StrCast(this.props.document.title))}
); } @@ -96,12 +95,12 @@ class TreeView extends React.Component { render() { let bulletType = BulletType.List; let childElements: JSX.Element | undefined = undefined; - var children = this.props.document.GetT>(KeyStore.Data, ListField); - if (children && children !== FieldWaiting) { // add children for a collection + var children = Cast(this.props.document.data, listSpec(Doc)); + if (children) { // add children for a collection if (!this._collapsed) { bulletType = BulletType.Collapsible; childElements =
    - {children.Data.map(value => )} + {children.map(value => )}
; } else bulletType = BulletType.Collapsed; @@ -117,22 +116,22 @@ class TreeView extends React.Component { } @observer -export class CollectionTreeView extends CollectionSubView { +export class CollectionTreeView extends CollectionSubView(Document) { @action remove = (document: Document) => { - var children = this.props.Document.GetT>(KeyStore.Data, ListField); - if (children && children !== FieldWaiting) { - children.Data.splice(children.Data.indexOf(document), 1); + const children = this.children; + if (children) { + children.splice(children.indexOf(document), 1); } } render() { - let children = this.props.Document.GetT>(KeyStore.Data, ListField); - let copyOnDrag = this.props.Document.GetBoolean(KeyStore.CopyDraggedItems, false); - let childrenElement = !children || children === FieldWaiting ? (null) : - (children.Data.map(value => - ) + const children = this.children; + let copyOnDrag = BoolCast(this.props.Document.copyDraggedItems, false); + let childrenElement = !children ? (null) : + (children.map(value => + ) ); return ( @@ -145,9 +144,9 @@ export class CollectionTreeView extends CollectionSubView { contents={this.props.Document.Title} display={"inline"} height={72} - GetValue={() => this.props.Document.Title} + GetValue={() => StrCast(this.props.Document.title)} SetValue={(value: string) => { - this.props.Document.SetText(KeyStore.Title, value); + this.props.Document.title = value; return true; }} /> diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx index bde50fed8..f82c6e9cb 100644 --- a/src/client/views/nodes/LinkEditor.tsx +++ b/src/client/views/nodes/LinkEditor.tsx @@ -3,31 +3,29 @@ import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; import './LinkEditor.scss'; -import { KeyStore } from '../../../fields/KeyStore'; import { props } from "bluebird"; import { DocumentView } from "./DocumentView"; -import { Document } from "../../../fields/Document"; -import { TextField } from "../../../fields/TextField"; import { link } from "fs"; +import { StrCast } from "../../../new_fields/Types"; +import { Doc } from "../../../new_fields/Doc"; interface Props { - linkDoc: Document; + linkDoc: Doc; showLinks: () => void; } @observer export class LinkEditor extends React.Component { - @observable private _nameInput: string = this.props.linkDoc.GetText(KeyStore.Title, ""); - @observable private _descriptionInput: string = this.props.linkDoc.GetText(KeyStore.LinkDescription, ""); + @observable private _nameInput: string = StrCast(this.props.linkDoc.title); + @observable private _descriptionInput: string = StrCast(this.props.linkDoc.linkDescription); onSaveButtonPressed = (e: React.PointerEvent): void => { - console.log("view down"); e.stopPropagation(); - this.props.linkDoc.SetData(KeyStore.Title, this._nameInput, TextField); - this.props.linkDoc.SetData(KeyStore.LinkDescription, this._descriptionInput, TextField); + this.props.linkDoc.title = this._nameInput; + this.props.linkDoc.linkDescription = this._descriptionInput; this.props.showLinks(); } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 857da1ebb..4cac09dee 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -3,190 +3,184 @@ import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; -import { Document } from '../fields/Document'; -import { BasicField } from '../fields/BasicField'; -import { ListField } from '../fields/ListField'; -import { Key } from '../fields/Key'; -import { Opt, Field } from '../fields/Field'; -import { Server } from '../client/Server'; - -configure({ - enforceActions: "observed" -}); - -@observer -class FieldViewer extends React.Component<{ field: BasicField }> { - render() { - return {JSON.stringify(this.props.field.Data)} ({this.props.field.Id}); - } -} - -@observer -class KeyViewer extends React.Component<{ field: Key }> { - render() { - return this.props.field.Name; - } -} - -@observer -class ListViewer extends React.Component<{ field: ListField }>{ - @observable - expanded = false; - - render() { - let content; - if (this.expanded) { - content = ( -
- {this.props.field.Data.map(field => )} -
- ); - } else { - content = <>[...] ({this.props.field.Id}); - } - return ( -
- - {content} -
- ); - } -} - -@observer -class DocumentViewer extends React.Component<{ field: Document }> { - private keyMap: ObservableMap = new ObservableMap; - - private disposer?: Lambda; - - componentDidMount() { - let f = () => { - Array.from(this.props.field._proxies.keys()).forEach(id => { - if (!this.keyMap.has(id)) { - Server.GetField(id, (field) => { - if (field && field instanceof Key) { - this.keyMap.set(id, field); - } - }); - } - }); - }; - this.disposer = this.props.field._proxies.observe(f); - f(); - } - - componentWillUnmount() { - if (this.disposer) { - this.disposer(); - } - } - - render() { - let fields = Array.from(this.props.field._proxies.entries()).map(kv => { - let key = this.keyMap.get(kv[0]); - return ( -
- ({key ? key.Name : kv[0]}): - -
- ); - }); - return ( -
- Document ({this.props.field.Id}) -
- {fields} -
-
- ); - } -} - -@observer -class DebugViewer extends React.Component<{ fieldId: string }> { - @observable - private field?: Field; - - @observable - private error?: string; - - constructor(props: { fieldId: string }) { - super(props); - this.update(); - } - - update() { - Server.GetField(this.props.fieldId, action((field: Opt) => { - this.field = field; - if (!field) { - this.error = `Field with id ${this.props.fieldId} not found`; - } - })); - - } - - render() { - let content; - if (this.field) { - // content = this.field.ToJson(); - if (this.field instanceof ListField) { - content = (); - } else if (this.field instanceof Document) { - content = (); - } else if (this.field instanceof BasicField) { - content = (); - } else if (this.field instanceof Key) { - content = (); - } else { - content = (Unrecognized field type); - } - } else if (this.error) { - content = Field {this.props.fieldId} not found ; - } else { - content = Field loading: {this.props.fieldId}; - } - return content; - } -} - -@observer -class Viewer extends React.Component { - @observable - private idToAdd: string = ''; - - @observable - private ids: string[] = []; - - @action - inputOnChange = (e: React.ChangeEvent) => { - this.idToAdd = e.target.value; - } - - @action - onKeyPress = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { - this.ids.push(this.idToAdd); - this.idToAdd = ""; - } - } - - render() { - return ( - <> - -
- {this.ids.map(id => )} -
- - ); - } -} - -ReactDOM.render(( -
- -
), - document.getElementById('root') -); \ No newline at end of file + +// configure({ +// enforceActions: "observed" +// }); + +// @observer +// class FieldViewer extends React.Component<{ field: BasicField }> { +// render() { +// return {JSON.stringify(this.props.field.Data)} ({this.props.field.Id}); +// } +// } + +// @observer +// class KeyViewer extends React.Component<{ field: Key }> { +// render() { +// return this.props.field.Name; +// } +// } + +// @observer +// class ListViewer extends React.Component<{ field: ListField }>{ +// @observable +// expanded = false; + +// render() { +// let content; +// if (this.expanded) { +// content = ( +//
+// {this.props.field.Data.map(field => )} +//
+// ); +// } else { +// content = <>[...] ({this.props.field.Id}); +// } +// return ( +//
+// +// {content} +//
+// ); +// } +// } + +// @observer +// class DocumentViewer extends React.Component<{ field: Document }> { +// private keyMap: ObservableMap = new ObservableMap; + +// private disposer?: Lambda; + +// componentDidMount() { +// let f = () => { +// Array.from(this.props.field._proxies.keys()).forEach(id => { +// if (!this.keyMap.has(id)) { +// Server.GetField(id, (field) => { +// if (field && field instanceof Key) { +// this.keyMap.set(id, field); +// } +// }); +// } +// }); +// }; +// this.disposer = this.props.field._proxies.observe(f); +// f(); +// } + +// componentWillUnmount() { +// if (this.disposer) { +// this.disposer(); +// } +// } + +// render() { +// let fields = Array.from(this.props.field._proxies.entries()).map(kv => { +// let key = this.keyMap.get(kv[0]); +// return ( +//
+// ({key ? key.Name : kv[0]}): +// +//
+// ); +// }); +// return ( +//
+// Document ({this.props.field.Id}) +//
+// {fields} +//
+//
+// ); +// } +// } + +// @observer +// class DebugViewer extends React.Component<{ fieldId: string }> { +// @observable +// private field?: Field; + +// @observable +// private error?: string; + +// constructor(props: { fieldId: string }) { +// super(props); +// this.update(); +// } + +// update() { +// Server.GetField(this.props.fieldId, action((field: Opt) => { +// this.field = field; +// if (!field) { +// this.error = `Field with id ${this.props.fieldId} not found`; +// } +// })); + +// } + +// render() { +// let content; +// if (this.field) { +// // content = this.field.ToJson(); +// if (this.field instanceof ListField) { +// content = (); +// } else if (this.field instanceof Document) { +// content = (); +// } else if (this.field instanceof BasicField) { +// content = (); +// } else if (this.field instanceof Key) { +// content = (); +// } else { +// content = (Unrecognized field type); +// } +// } else if (this.error) { +// content = Field {this.props.fieldId} not found ; +// } else { +// content = Field loading: {this.props.fieldId}; +// } +// return content; +// } +// } + +// @observer +// class Viewer extends React.Component { +// @observable +// private idToAdd: string = ''; + +// @observable +// private ids: string[] = []; + +// @action +// inputOnChange = (e: React.ChangeEvent) => { +// this.idToAdd = e.target.value; +// } + +// @action +// onKeyPress = (e: React.KeyboardEvent) => { +// if (e.key === "Enter") { +// this.ids.push(this.idToAdd); +// this.idToAdd = ""; +// } +// } + +// render() { +// return ( +// <> +// +//
+// {this.ids.map(id => )} +//
+// +// ); +// } +// } + +// ReactDOM.render(( +//
+// +//
), +// document.getElementById('root') +// ); \ No newline at end of file diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 7f87be45d..ae532c9e2 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -1,101 +1,101 @@ -import { Field, FieldId } from "./Field"; -import { Types } from "../server/Message"; -import { CompileScript, ScriptOptions, CompiledScript } from "../client/util/Scripting"; -import { Server } from "../client/Server"; -import { Without } from "../Utils"; +// import { Field, FieldId } from "./Field"; +// import { Types } from "../server/Message"; +// import { CompileScript, ScriptOptions, CompiledScript } from "../client/util/Scripting"; +// import { Server } from "../client/Server"; +// import { Without } from "../Utils"; -export interface SerializableOptions extends Without { - capturedIds: { [id: string]: string }; -} +// export interface SerializableOptions extends Without { +// capturedIds: { [id: string]: string }; +// } -export interface ScriptData { - script: string; - options: SerializableOptions; -} +// export interface ScriptData { +// script: string; +// options: SerializableOptions; +// } -export class ScriptField extends Field { - private _script?: CompiledScript; - get script(): CompiledScript { - return this._script!; - } - private options?: ScriptData; +// export class ScriptField extends Field { +// private _script?: CompiledScript; +// get script(): CompiledScript { +// return this._script!; +// } +// private options?: ScriptData; - constructor(script?: CompiledScript, id?: FieldId, save: boolean = true) { - super(id); +// constructor(script?: CompiledScript, id?: FieldId, save: boolean = true) { +// super(id); - this._script = script; +// this._script = script; - if (save) { - Server.UpdateField(this); - } - } +// if (save) { +// Server.UpdateField(this); +// } +// } - ToScriptString() { - return "new ScriptField(...)"; - } +// ToScriptString() { +// return "new ScriptField(...)"; +// } - GetValue() { - return this.script; - } +// GetValue() { +// return this.script; +// } - TrySetValue(): boolean { - throw new Error("Script fields currently can't be modified"); - } +// TrySetValue(): boolean { +// throw new Error("Script fields currently can't be modified"); +// } - UpdateFromServer() { - throw new Error("Script fields currently can't be updated"); - } +// UpdateFromServer() { +// throw new Error("Script fields currently can't be updated"); +// } - static FromJson(id: string, data: ScriptData): ScriptField { - let field = new ScriptField(undefined, id, false); - field.options = data; - return field; - } +// static FromJson(id: string, data: ScriptData): ScriptField { +// let field = new ScriptField(undefined, id, false); +// field.options = data; +// return field; +// } - init(callback: (res: Field) => any) { - const options = this.options!; - const keys = Object.keys(options.options.capturedIds); - Server.GetFields(keys).then(fields => { - let captured: { [name: string]: Field } = {}; - keys.forEach(key => captured[options.options.capturedIds[key]] = fields[key]); - const opts: ScriptOptions = { - addReturn: options.options.addReturn, - params: options.options.params, - requiredType: options.options.requiredType, - capturedVariables: captured - }; - const script = CompileScript(options.script, opts); - if (!script.compiled) { - throw new Error("Can't compile script"); - } - this._script = script; - callback(this); - }); - } +// init(callback: (res: Field) => any) { +// const options = this.options!; +// const keys = Object.keys(options.options.capturedIds); +// Server.GetFields(keys).then(fields => { +// let captured: { [name: string]: Field } = {}; +// keys.forEach(key => captured[options.options.capturedIds[key]] = fields[key]); +// const opts: ScriptOptions = { +// addReturn: options.options.addReturn, +// params: options.options.params, +// requiredType: options.options.requiredType, +// capturedVariables: captured +// }; +// const script = CompileScript(options.script, opts); +// if (!script.compiled) { +// throw new Error("Can't compile script"); +// } +// this._script = script; +// callback(this); +// }); +// } - ToJson() { - const { options, originalScript } = this.script; - let capturedIds: { [id: string]: string } = {}; - for (const capt in options.capturedVariables) { - capturedIds[options.capturedVariables[capt].Id] = capt; - } - const opts: SerializableOptions = { - ...options, - capturedIds - }; - delete (opts as any).capturedVariables; - return { - id: this.Id, - type: Types.Script, - data: { - script: originalScript, - options: opts, - }, - }; - } +// ToJson() { +// const { options, originalScript } = this.script; +// let capturedIds: { [id: string]: string } = {}; +// for (const capt in options.capturedVariables) { +// capturedIds[options.capturedVariables[capt].Id] = capt; +// } +// const opts: SerializableOptions = { +// ...options, +// capturedIds +// }; +// delete (opts as any).capturedVariables; +// return { +// id: this.Id, +// type: Types.Script, +// data: { +// script: originalScript, +// options: opts, +// }, +// }; +// } - Copy(): Field { - //Script fields are currently immutable, so we can fake copy them - return this; - } -} \ No newline at end of file +// Copy(): Field { +// //Script fields are currently immutable, so we can fake copy them +// return this; +// } +// } \ No newline at end of file diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index ec89a1194..1f9e160ce 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -1,15 +1,14 @@ import * as ReactDOM from 'react-dom'; import * as rp from 'request-promise'; -import { Documents } from '../client/documents/Documents'; -import { Server } from '../client/Server'; -import { Document } from '../fields/Document'; -import { KeyStore } from '../fields/KeyStore'; -import { ListField } from '../fields/ListField'; +import { Docs } from '../client/documents/Documents'; import { RouteStore } from '../server/RouteStore'; -import { ServerUtils } from '../server/ServerUtil'; import "./ImageUpload.scss"; import React = require('react'); -import { Opt } from '../fields/Field'; +import { DocServer } from '../client/DocServer'; +import { Opt, Doc } from '../new_fields/Doc'; +import { Cast } from '../new_fields/Types'; +import { listSpec } from '../new_fields/Schema'; +import { List } from '../new_fields/List'; @@ -38,21 +37,24 @@ const onFileLoad = async (file: any) => { const json = await res.json(); json.map(async (file: any) => { let path = window.location.origin + file; - var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }); + var doc = Docs.ImageDocument(path, { nativeWidth: 200, width: 200 }); - const res = await rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)); + const res = await rp.get(DocServer.prepend(RouteStore.getUserDocumentId)); if (!res) { throw new Error("No user id returned"); } - const field = await Server.GetField(res); - let pending: Opt; - if (field instanceof Document) { - pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document); + const field = await DocServer.GetRefField(res); + let pending: Opt; + if (field instanceof Doc) { + pending = await Cast(field.optionalRightCollection, Doc); } if (pending) { - pending.GetOrCreateAsync(KeyStore.Data, ListField, list => { - list.Data.push(doc); - }); + const data = await Cast(pending.data, listSpec(Doc)); + if (data) { + data.push(doc); + } else { + pending.data = new List([doc]); + } } }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a5f495477..6dfa37c1b 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -166,6 +166,4 @@ export namespace Doc { return delegate; } export const Prototype = Symbol("Prototype"); -} - -export const GetAsync = Doc.GetAsync; \ No newline at end of file +} \ No newline at end of file diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index b08c1aebe..29327e5ad 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -2,15 +2,15 @@ import * as React from 'react'; import { observable, action, configure, reaction, computed, ObservableMap, runInAction } from 'mobx'; import { observer } from "mobx-react"; import './WorkspacesMenu.css'; -import { Document } from '../../../fields/Document'; import { EditableView } from '../../../client/views/EditableView'; -import { KeyStore } from '../../../fields/KeyStore'; +import { Doc, Id } from '../../../new_fields/Doc'; +import { StrCast } from '../../../new_fields/Types'; export interface WorkspaceMenuProps { - active: Document | undefined; - open: (workspace: Document) => void; + active: Doc | undefined; + open: (workspace: Doc) => void; new: () => void; - allWorkspaces: Document[]; + allWorkspaces: Doc[]; isShown: () => boolean; toggle: () => void; } @@ -60,7 +60,7 @@ export class WorkspacesMenu extends React.Component { /> {this.props.allWorkspaces.map((s, i) =>
{ e.preventDefault(); this.props.open(s); @@ -73,9 +73,9 @@ export class WorkspacesMenu extends React.Component { {i + 1} - s.Title} + GetValue={() => StrCast(s.title)} SetValue={(title: string): boolean => { - s.SetText(KeyStore.Title, title); + s.title = title; return true; }} contents={s.Title} -- cgit v1.2.3-70-g09d2 From d4a77dd055685dd81a762ef40e0c3b7606586e9c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 21:40:17 -0400 Subject: Split more files up --- src/client/DocServer.ts | 3 +- src/client/northstar/dash-fields/HistogramField.ts | 2 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 3 +- src/client/util/Scripting.ts | 1 + src/client/views/Main.tsx | 3 +- .../views/collections/CollectionBaseView.tsx | 3 +- .../views/collections/CollectionDockingView.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 3 +- src/client/views/collections/CollectionSubView.tsx | 3 +- .../views/collections/CollectionTreeView.tsx | 3 +- .../CollectionFreeFormLinksView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 3 +- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/LinkMenu.tsx | 3 +- src/new_fields/Doc.ts | 37 +++------------------- src/new_fields/HtmlField.ts | 2 +- src/new_fields/IconField.ts | 2 +- src/new_fields/InkField.ts | 2 +- src/new_fields/List.ts | 3 +- src/new_fields/ObjectField.ts | 17 ++++++++++ src/new_fields/Proxy.ts | 4 ++- src/new_fields/RefField.ts | 18 +++++++++++ src/new_fields/RichTextField.ts | 2 +- src/new_fields/Schema.ts | 8 ++--- src/new_fields/Types.ts | 2 +- src/new_fields/URLField.ts | 2 +- src/new_fields/util.ts | 4 ++- .../authentication/controllers/WorkspacesMenu.tsx | 3 +- src/server/database.ts | 2 ++ 30 files changed, 88 insertions(+), 60 deletions(-) create mode 100644 src/new_fields/ObjectField.ts create mode 100644 src/new_fields/RefField.ts (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 3f17baec6..c7cbfce37 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,8 +1,9 @@ import * as OpenSocket from 'socket.io-client'; import { MessageStore, Types, Message } from "./../server/Message"; -import { Opt, FieldWaiting, RefField, HandleUpdate } from '../new_fields/Doc'; +import { Opt, FieldWaiting } from '../new_fields/Doc'; import { Utils } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; +import { RefField, HandleUpdate } from '../new_fields/RefField'; export namespace DocServer { const _cache: { [id: string]: RefField | Promise> } = {}; diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 118f4cf7f..730289536 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -3,7 +3,7 @@ import { custom, serializable } from "serializr"; import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { ObjectField } from "../../../new_fields/Doc"; +import { ObjectField } from "../../../new_fields/ObjectField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 4a65b14cf..a9c68ccba 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -20,7 +20,8 @@ import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; import { NumCast, Cast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; -import { Doc, Id } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; +import { Id } from "../../../new_fields/RefField"; @observer diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index dbec82340..e45f61c11 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -11,6 +11,7 @@ import { Docs } from "../documents/Documents"; import { Doc, Field } from '../../new_fields/Doc'; import { ImageField, PdfField, VideoField, AudioField } from '../../new_fields/URLField'; import { List } from '../../new_fields/List'; +import { RichTextField } from '../../new_fields/RichTextField'; export interface ScriptSucccess { success: true; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 1e3d4e259..4a68d1c68 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -33,10 +33,11 @@ import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; import { SelectionManager } from '../util/SelectionManager'; -import { FieldResult, Field, Doc, Id, Opt } from '../../new_fields/Doc'; +import { FieldResult, Field, Doc, Opt } from '../../new_fields/Doc'; import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; import { DocServer } from '../DocServer'; import { listSpec } from '../../new_fields/Schema'; +import { Id } from '../../new_fields/RefField'; @observer diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 4807dc40a..b2fba1415 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -4,9 +4,10 @@ import * as React from 'react'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Types'; -import { Doc, FieldResult, Opt, Id } from '../../../new_fields/Doc'; +import { Doc, FieldResult, Opt } from '../../../new_fields/Doc'; import { listSpec } from '../../../new_fields/Schema'; import { List } from '../../../new_fields/List'; +import { Id } from '../../../new_fields/RefField'; export enum CollectionViewType { Invalid, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2ff409b9b..1574562c6 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -13,11 +13,12 @@ import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { Transform } from '../../util/Transform'; -import { Doc, Id, Opt, Field, FieldId } from "../../../new_fields/Doc"; +import { Doc, Opt, Field } from "../../../new_fields/Doc"; import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; import { listSpec } from "../../../new_fields/Schema"; +import { Id, FieldId } from "../../../new_fields/RefField"; @observer export class CollectionDockingView extends React.Component { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 874170f3d..58d20819b 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -19,10 +19,11 @@ import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { Opt, Field, Doc, Id } from "../../../new_fields/Doc"; +import { Opt, Field, Doc } from "../../../new_fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; +import { Id } from "../../../new_fields/RefField"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 558a8728f..4d090b680 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,12 +10,13 @@ import * as rp from 'request-promise'; import { CollectionView } from "./CollectionView"; import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; -import { Doc, ObjectField, Opt } from "../../../new_fields/Doc"; +import { Doc, Opt } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, PromiseValue } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; +import { ObjectField } from "../../../new_fields/ObjectField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index c9d8d83c8..7ec9a8549 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -10,7 +10,8 @@ import "./CollectionTreeView.scss"; import React = require("react"); import { Document, listSpec } from '../../../new_fields/Schema'; import { Cast, StrCast, BoolCast } from '../../../new_fields/Types'; -import { Doc, Id } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; +import { Id } from '../../../new_fields/RefField'; export interface TreeViewProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index ce9995630..f693d55e8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -7,10 +7,11 @@ import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); -import { Doc, Id } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../new_fields/Doc"; import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; import { listSpec } from "../../../../new_fields/Schema"; import { List } from "../../../../new_fields/List"; +import { Id } from "../../../../new_fields/RefField"; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 047fbad18..18107e98a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -19,10 +19,11 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; -import { Doc, Id } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../new_fields/Doc"; import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; import { List } from "../../../../new_fields/List"; +import { Id } from "../../../../new_fields/RefField"; export const panZoomSchema = createSchema({ panX: "number", diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index aabc1633e..c304b6a35 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -15,7 +15,7 @@ import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); -import { Field, Opt, Doc, Id } from "../../../new_fields/Doc"; +import { Opt, Doc } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; import { FieldValue, Cast, PromiseValue } from "../../../new_fields/Types"; @@ -24,6 +24,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { MarqueeView } from "../collections/collectionFreeForm/MarqueeView"; import { DocServer } from "../../DocServer"; +import { Id } from "../../../new_fields/RefField"; const linkSchema = createSchema({ title: "string", diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index c00c47fc4..dc36c5914 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -16,6 +16,7 @@ import { Opt, Doc, FieldResult } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { ImageField, VideoField, AudioField } from "../../../new_fields/URLField"; import { IconField } from "../../../new_fields/IconField"; +import { RichTextField } from "../../../new_fields/RichTextField"; // diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 3ecc8555d..e21adebbc 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -5,9 +5,10 @@ import { LinkBox } from "./LinkBox"; import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); -import { Doc, Id } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; import { Cast, FieldValue } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; +import { Id } from "../../../new_fields/RefField"; interface Props { docView: DocumentView; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index fb7b6e360..4ef2a465f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -8,38 +8,8 @@ import { Cast, ToConstructor, PromiseValue, FieldValue } from "./Types"; import { UndoManager, undoBatch } from "../client/util/UndoManager"; import { listSpec } from "./Schema"; import { List } from "./List"; - -export type FieldId = string; -export const HandleUpdate = Symbol("HandleUpdate"); -export const Id = Symbol("Id"); -export abstract class RefField { - @serializable(alias("id", primitive())) - private __id: FieldId; - readonly [Id]: FieldId; - - constructor(id?: FieldId) { - this.__id = id || Utils.GenerateGuid(); - this[Id] = this.__id; - } - - protected [HandleUpdate]?(diff: any): void; -} - -export const Update = Symbol("Update"); -export const OnUpdate = Symbol("OnUpdate"); -export const Parent = Symbol("Parent"); -export class ObjectField { - protected [OnUpdate]?: (diff?: any) => void; - private [Parent]?: Doc; - readonly [Id] = ""; -} - -export namespace ObjectField { - export function MakeCopy(field: ObjectField) { - //TODO Types - return field; - } -} +import { ObjectField } from "./ObjectField"; +import { RefField, FieldId, Id } from "./RefField"; export function IsField(field: any): field is Field { return (typeof field === "string") @@ -53,6 +23,7 @@ export type Opt = T | undefined; export type FieldWaiting = T extends undefined ? never : Promise; export type FieldResult = Opt | FieldWaiting>; +export const Update = Symbol("Update"); export const Self = Symbol("Self"); @Deserializable("doc").withFields(["id"]) @@ -161,7 +132,7 @@ export namespace Doc { copy[key] = field; } } - }) + }); return copy; } diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts index 76fdb1f62..808a3499b 100644 --- a/src/new_fields/HtmlField.ts +++ b/src/new_fields/HtmlField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; @Deserializable("html") export class HtmlField extends ObjectField { diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts index 32f3aa4d5..46f111f8e 100644 --- a/src/new_fields/IconField.ts +++ b/src/new_fields/IconField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; @Deserializable("icon") export class IconField extends ObjectField { diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 49e6bf61e..42223c494 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; export enum InkTool { None, diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index f01ac210a..428f661c9 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,8 +1,9 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Field, ObjectField, Update, OnUpdate, Self } from "./Doc"; +import { Field, Update, Self } from "./Doc"; import { setter, getter } from "./util"; import { serializable, alias, list } from "serializr"; import { observable } from "mobx"; +import { ObjectField, OnUpdate } from "./ObjectField"; @Deserializable("list") class ListImpl extends ObjectField { diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts new file mode 100644 index 000000000..9cac2c528 --- /dev/null +++ b/src/new_fields/ObjectField.ts @@ -0,0 +1,17 @@ +import { Doc } from "./Doc"; + +export const OnUpdate = Symbol("OnUpdate"); +export const Parent = Symbol("Parent"); +const Id = Symbol("Object Id"); +export class ObjectField { + protected [OnUpdate]?: (diff?: any) => void; + private [Parent]?: Doc; + readonly [Id] = ""; +} + +export namespace ObjectField { + export function MakeCopy(field: ObjectField) { + //TODO Types + return field; + } +} diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index 2aa78731e..56e41cc0f 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -1,8 +1,10 @@ import { Deserializable } from "../client/util/SerializationHelper"; -import { RefField, Id, ObjectField, FieldWaiting } from "./Doc"; +import { FieldWaiting } from "./Doc"; import { primitive, serializable } from "serializr"; import { observable, action } from "mobx"; import { DocServer } from "../client/DocServer"; +import { RefField, Id } from "./RefField"; +import { ObjectField } from "./ObjectField"; @Deserializable("proxy") export class ProxyField extends ObjectField { diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts new file mode 100644 index 000000000..202c65f21 --- /dev/null +++ b/src/new_fields/RefField.ts @@ -0,0 +1,18 @@ +import { serializable, primitive, alias } from "serializr"; +import { Utils } from "../Utils"; + +export type FieldId = string; +export const HandleUpdate = Symbol("HandleUpdate"); +export const Id = Symbol("Id"); +export abstract class RefField { + @serializable(alias("id", primitive())) + private __id: FieldId; + readonly [Id]: FieldId; + + constructor(id?: FieldId) { + this.__id = id || Utils.GenerateGuid(); + this[Id] = this.__id; + } + + protected [HandleUpdate]?(diff: any): void; +} diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index 156e4efd9..0fa3cf73c 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -1,4 +1,4 @@ -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; import { serializable } from "serializr"; export class RichTextField extends ObjectField { diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index 5081521c7..7444878fe 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -21,15 +21,15 @@ export function makeInterface(...schemas: T): (doc?: Doc) } } const proto = new Proxy({}, { - get(target: any, prop) { - const field = target.doc[prop]; + get(target: any, prop, receiver) { + const field = receiver.doc[prop]; if (prop in schema) { return Cast(field, (schema as any)[prop]); } return field; }, - set(target: any, prop, value) { - target.doc[prop] = value; + set(target: any, prop, value, receiver) { + receiver.doc[prop] = value; return true; } }); diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 7fa18673f..3f8eabd45 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -1,4 +1,4 @@ -import { Field, Opt, FieldWaiting, FieldResult, RefField } from "./Doc"; +import { Field, Opt, FieldResult } from "./Doc"; import { List } from "./List"; export type ToType | ListSpec> = diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index 1da245e73..95c679df7 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; function url() { return custom( diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 2d9721b2e..011e8c8d9 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -1,8 +1,10 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Update, OnUpdate, Parent, ObjectField, RefField, Doc, Id, Field } from "./Doc"; +import { Update, Doc, Field } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; +import { RefField, Id } from "./RefField"; +import { ObjectField, Parent, OnUpdate } from "./ObjectField"; export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index 29327e5ad..91756315d 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -3,8 +3,9 @@ import { observable, action, configure, reaction, computed, ObservableMap, runIn import { observer } from "mobx-react"; import './WorkspacesMenu.css'; import { EditableView } from '../../../client/views/EditableView'; -import { Doc, Id } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; import { StrCast } from '../../../new_fields/Types'; +import { Id } from '../../../new_fields/RefField'; export interface WorkspaceMenuProps { active: Doc | undefined; diff --git a/src/server/database.ts b/src/server/database.ts index a61b4d823..6b3b6797f 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -60,11 +60,13 @@ export class Database { } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { + console.log("getDocument"); this.db && this.db.collection(collectionName).findOne({ id: id }, (err, result) => fn(result ? ({ id: result._id, type: result.type, data: result.data }) : undefined)); } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { + console.log("getDocuments"); this.db && this.db.collection(collectionName).find({ id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); -- cgit v1.2.3-70-g09d2 From 506af03831bf3cc002f93ad8708eafb909c0a194 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 22:27:26 -0400 Subject: Various fixes --- src/client/DocServer.ts | 24 ++++++++++++++++++---- src/client/documents/Documents.ts | 2 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/views/collections/CollectionPDFView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 1 + .../views/collections/CollectionVideoView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 4 ++-- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/new_fields/util.ts | 5 +++-- src/server/database.ts | 21 +++++++++++++------ src/server/index.ts | 10 +++++---- 14 files changed, 55 insertions(+), 26 deletions(-) (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index c7cbfce37..07997f072 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -55,12 +55,28 @@ export namespace DocServer { map[id] = cached; } } - const prom = Utils.EmitCallback(_socket, MessageStore.GetFields, requestedIds); - requestedIds.map((id, index) => _cache[id] = prom.then((fields: RefField[]) => fields[index])); + const prom = Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds).then(fields => { + for (const key in fields) { + const field = fields[key]; + if (field) { + fields[key] = SerializationHelper.Deserialize(field); + } + } + return fields; + }); + requestedIds.forEach((id, index) => _cache[id] = prom.then((fields: RefField[]) => fields[index])); const fields = await prom; - requestedIds.map((id, index) => map[id] = fields[index]); + requestedIds.forEach((id, index) => { + const field = fields[index]; + if (field) { + _cache[id] = field; + } else { + delete _cache[id]; + } + map[id] = field; + }); const otherFields = await Promise.all(promises); - waitingIds.map((id, index) => map[id] = otherFields[index]); + waitingIds.forEach((id, index) => map[id] = otherFields[index]); return map; } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c30fb21d5..2a9687bda 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -138,7 +138,7 @@ export namespace Docs { return webProto; } function CreateCollectionPrototype(): Doc { - let collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("DataKey"), + let collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("data"), { panX: 0, panY: 0, scale: 1, width: 500, height: 500 }); return collProto; } diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a9c68ccba..19d108676 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -26,7 +26,7 @@ import { Id } from "../../../new_fields/RefField"; @observer export class HistogramBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(HistogramBox, fieldStr); } private _dropXRef = React.createRef(); private _dropYRef = React.createRef(); private _dropXDisposer?: DragManager.DragDropDisposer; diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index e73b7b4a6..99438b4e8 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -13,7 +13,7 @@ import { NumCast } from "../../../new_fields/Types"; @observer export class CollectionPDFView extends React.Component { - public static LayoutString(fieldKey: string = "DataKey") { + public static LayoutString(fieldKey: string = "data") { return FieldView.LayoutString(CollectionPDFView, fieldKey); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 4d090b680..2c2d74302 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -53,6 +53,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @action protected async setCursorPosition(position: [number, number]) { + return; let ind; let doc = this.props.Document; let id = CurrentUserUtils.id; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index d314e3fc0..d45be228a 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -18,7 +18,7 @@ export class CollectionVideoView extends React.Component { @observable _currentTimecode: number = 0; @observable _isPlaying: boolean = false; - public static LayoutString(fieldKey: string = "DataKey") { + public static LayoutString(fieldKey: string = "data") { return FieldView.LayoutString(CollectionVideoView, fieldKey); } private get uIButtons() { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index e7bf1e121..b72065bca 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,7 +13,7 @@ import { trace } from 'mobx'; @observer export class CollectionView extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(CollectionView, fieldStr); } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 18107e98a..dfacca204 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -314,7 +314,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.childViews} - + {/* */} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index dc36c5914..df76f7cea 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -45,8 +45,8 @@ export interface FieldViewProps { @observer export class FieldView extends React.Component { - public static LayoutString(fieldType: { name: string }, fieldStr: string = "DataKey") { - return `<${fieldType.name} {...props} fieldKey={${fieldStr}} />`; + public static LayoutString(fieldType: { name: string }, fieldStr: string = "data") { + return `<${fieldType.name} {...props} fieldKey={"${fieldStr}"} />`; } @computed diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7a85c9dd3..96512718f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -55,7 +55,7 @@ const RichTextDocument = makeInterface(richTextSchema); @observer export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxOverlay), RichTextDocument>(RichTextDocument) { - public static LayoutString(fieldStr: string = "DataKey") { + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(FormattedTextBox, fieldStr); } private _ref: React.RefObject; diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index ae39ebe2d..876a3c173 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -14,7 +14,7 @@ import { Doc, IsField } from "../../../new_fields/Doc"; export class KeyValueBox extends React.Component { private _mainCont = React.createRef(); - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(KeyValueBox, fieldStr); } @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 011e8c8d9..b2299f34a 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -5,8 +5,9 @@ import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; import { RefField, Id } from "./RefField"; import { ObjectField, Parent, OnUpdate } from "./ObjectField"; +import { action } from "mobx"; -export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { +export const setter = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { target[prop] = value; return true; @@ -46,7 +47,7 @@ export function setter(target: any, prop: string | symbol | number, value: any, undo: () => receiver[prop] = curValue }); return true; -} +}); export function getter(target: any, prop: string | symbol | number, receiver: any): any { if (typeof prop === "symbol") { diff --git a/src/server/database.ts b/src/server/database.ts index 6b3b6797f..4775c0eeb 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -60,19 +60,28 @@ export class Database { } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { - console.log("getDocument"); - this.db && this.db.collection(collectionName).findOne({ id: id }, (err, result) => - fn(result ? ({ id: result._id, type: result.type, data: result.data }) : undefined)); + this.db && this.db.collection(collectionName).findOne({ _id: id }, (err, result) => { + if (result) { + result.id = result._id; + delete result._id; + fn(result); + } else { + fn(undefined); + } + }); } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { - console.log("getDocuments"); - this.db && this.db.collection(collectionName).find({ id: { "$in": ids } }).toArray((err, docs) => { + this.db && this.db.collection(collectionName).find({ _id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } - fn(docs.map(doc => ({ id: doc._id, type: doc.type, data: doc.data }))); + fn(docs.map(doc => { + doc.id = doc._id; + delete doc._id; + return doc; + })); }); } diff --git a/src/server/index.ts b/src/server/index.ts index 10158eb96..6801b3132 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -234,16 +234,18 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); - Utils.AddServerHandler(socket, MessageStore.GetRefField, GetRefField); - Utils.AddServerHandler(socket, MessageStore.GetRefFields, GetRefFields); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); }); -function deleteFields() { - return Database.Instance.deleteAll(); +async function deleteFields() { + await Database.Instance.deleteAll(); + await Database.Instance.deleteAll('newDocuments'); } async function deleteAll() { await Database.Instance.deleteAll(); + await Database.Instance.deleteAll('newDocuments'); await Database.Instance.deleteAll('sessions'); await Database.Instance.deleteAll('users'); } -- cgit v1.2.3-70-g09d2 From 307564d9b02ed9d4de8ffa4229b0494bf8d671bd Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 29 Apr 2019 01:36:00 -0400 Subject: Fixes --- src/client/util/SerializationHelper.ts | 5 +++++ src/new_fields/Doc.ts | 20 +++++++++++++++++--- src/new_fields/List.ts | 26 +++++++++++++++++++------- src/new_fields/util.ts | 14 +++++++++----- src/server/database.ts | 2 +- 5 files changed, 51 insertions(+), 16 deletions(-) (limited to 'src/server') diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts index ac70aba9d..1a8cc3a44 100644 --- a/src/client/util/SerializationHelper.ts +++ b/src/client/util/SerializationHelper.ts @@ -63,6 +63,11 @@ export function Deserializable(name: string): DeserializableOpts; export function Deserializable(constructor: Function): void; export function Deserializable(constructor: Function | string): DeserializableOpts | void { function addToMap(name: string, ctor: Function) { + const schema = getDefaultModelSchema(ctor as any) as any; + if (schema.targetClass !== ctor) { + const newSchema = { ...schema, factory: () => new (ctor as any)() }; + setDefaultModelSchema(ctor as any, newSchema); + } if (!(name in serializationTypes)) { serializationTypes[name] = ctor; reverseMap[ctor.name] = name; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 4ef2a465f..d15b6309d 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -3,12 +3,12 @@ import { serializable, primitive, map, alias, list } from "serializr"; import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper"; import { Utils } from "../Utils"; import { DocServer } from "../client/DocServer"; -import { setter, getter, getField } from "./util"; +import { setter, getter, getField, updateFunction } from "./util"; import { Cast, ToConstructor, PromiseValue, FieldValue } from "./Types"; import { UndoManager, undoBatch } from "../client/util/UndoManager"; import { listSpec } from "./Schema"; import { List } from "./List"; -import { ObjectField } from "./ObjectField"; +import { ObjectField, Parent, OnUpdate } from "./ObjectField"; import { RefField, FieldId, Id } from "./RefField"; export function IsField(field: any): field is Field { @@ -47,9 +47,23 @@ export class Doc extends RefField { [key: string]: FieldResult; @serializable(alias("fields", map(autoObject()))) + private get __fields() { + return this.___fields; + } + + private set __fields(value) { + this.___fields = value; + for (const key in value) { + const field = value[key]; + if (!(field instanceof ObjectField)) continue; + field[Parent] = this[Self]; + field[OnUpdate] = updateFunction(this[Self], key, field); + } + } + @observable //{ [key: string]: Field | FieldWaiting | undefined } - private __fields: any = {}; + private ___fields: any = {}; private [Update] = (diff: any) => { DocServer.UpdateField(this[Id], diff); diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index ecde4edc7..e4a80f7a1 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -2,13 +2,13 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; import { Field, Update, Self } from "./Doc"; import { setter, getter } from "./util"; import { serializable, alias, list } from "serializr"; -import { observable, observe, IArrayChange, IArraySplice, IObservableArray, Lambda } from "mobx"; +import { observable, observe, IArrayChange, IArraySplice, IObservableArray, Lambda, reaction } from "mobx"; import { ObjectField, OnUpdate } from "./ObjectField"; const listHandlers: any = { push(...items: any[]) { - console.log("push"); - console.log(...items); + // console.log("push"); + // console.log(...items); return this[Self].__fields.push(...items); }, pop(): any { @@ -62,7 +62,7 @@ function listObserver(this: ListImpl, change: IArrayChange extends ObjectField { constructor(fields: T[] = []) { super(); - this.__fields = fields; + this.___fields = fields; this[ObserveDisposer] = observe(this.__fields as IObservableArray, listObserver.bind(this)); const list = new Proxy(this, { set: setter, @@ -76,13 +76,25 @@ class ListImpl extends ObjectField { [key: number]: T | null | undefined; @serializable(alias("fields", list(autoObject()))) + private get __fields() { + return this.___fields; + } + + private set __fields(value) { + this.___fields = value; + this[ObserveDisposer](); + this[ObserveDisposer] = observe(this.__fields as IObservableArray, listObserver.bind(this)); + } + + // @serializable(alias("fields", list(autoObject()))) @observable - private __fields: (T | null | undefined)[]; + private ___fields: (T | null | undefined)[]; private [Update] = (diff: any) => { - console.log(diff); + // console.log(diff); const update = this[OnUpdate]; - update && update(diff); + // update && update(diff); + update && update(); } private [ObserveDisposer]: Lambda; diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index b2299f34a..511820115 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -31,17 +31,14 @@ export const setter = action(function (target: any, prop: string | symbol | numb throw new Error("Can't put the same object in multiple documents at the same time"); } value[Parent] = target; - value[OnUpdate] = (diff?: any) => { - if (!diff) diff = SerializationHelper.Serialize(value); - target[Update]({ [prop]: diff }); - }; + value[OnUpdate] = updateFunction(target, prop, value); } if (curValue instanceof ObjectField) { delete curValue[Parent]; delete curValue[OnUpdate]; } target.__fields[prop] = value; - target[Update]({ ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) }); + target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); UndoManager.AddEvent({ redo: () => receiver[prop] = value, undo: () => receiver[prop] = curValue @@ -80,3 +77,10 @@ export function getField(target: any, prop: string | number, ignoreProto: boolea callback && callback(field); return field; } + +export function updateFunction(target: any, prop: any, value: any) { + return (diff?: any) => { + if (!diff) diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; + target[Update](diff); + }; +} \ No newline at end of file diff --git a/src/server/database.ts b/src/server/database.ts index 4775c0eeb..37cfcf3a3 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -20,7 +20,7 @@ export class Database { let newProm: Promise; const run = (): Promise => { return new Promise(resolve => { - collection.updateOne({ _id: id }, { $set: value }, { upsert } + collection.updateOne({ _id: id }, value, { upsert } , (err, res) => { if (err) { console.log(err.message); -- cgit v1.2.3-70-g09d2 From 797b54c849d7c4691c470ac73da2bf468c68c4b0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 1 May 2019 21:58:38 -0400 Subject: tweaked current user utils for workspace naming --- src/client/views/Main.tsx | 8 ++++---- src/server/authentication/models/current_user_utils.ts | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/server') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 2636b08bd..4e918221c 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -146,9 +146,9 @@ export class Main extends React.Component { @action createNewWorkspace = async (id?: string) => { - const list = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); if (list) { - let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); + let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; let mainDoc = Docs.DockDocument([freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); list.push(mainDoc); @@ -219,7 +219,7 @@ export class Main extends React.Component { let addTextNode = action(() => Docs.TextDocument({ borderRounding: -1, width: 200, height: 200, title: "a text note" })); let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); let addSchemaNode = action(() => Docs.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); - let addTreeNode = action(() => Docs.TreeDocument([this.mainContainer!], { width: 250, height: 400, title: "Library:" + StrCast(this.mainContainer!.title), copyDraggedItems: true })); + let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, copyDraggedItems: true })); // let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); @@ -281,7 +281,7 @@ export class Main extends React.Component { get workspaceMenu() { let areWorkspacesShown = () => this._workspacesShown; let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let workspaces = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + let workspaces = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); return (!workspaces || !this.mainContainer) ? (null) : (); + doc.title = this.email; + doc.data = new List(); doc.optionalRightCollection = Docs.SchemaDocument([], { title: "Pending documents" }); return doc; } -- cgit v1.2.3-70-g09d2 From 5f8f133040918713ace577cfe82f38254ea07964 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 2 May 2019 12:19:31 -0400 Subject: library and workspace stuff. --- src/client/views/Main.tsx | 28 ++----- src/client/views/TemplateMenu.tsx | 7 +- .../views/collections/CollectionDockingView.tsx | 27 ++----- .../views/collections/CollectionTreeView.scss | 1 - .../views/collections/CollectionTreeView.tsx | 57 ++++++++++---- src/client/views/collections/CollectionView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 10 +-- .../authentication/controllers/WorkspacesMenu.css | 3 - .../authentication/controllers/WorkspacesMenu.tsx | 90 ---------------------- 9 files changed, 60 insertions(+), 164 deletions(-) delete mode 100644 src/server/authentication/controllers/WorkspacesMenu.css delete mode 100644 src/server/authentication/controllers/WorkspacesMenu.tsx (limited to 'src/server') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 4e918221c..b2ca4a196 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -100,8 +100,7 @@ export class Main extends React.Component { onHistory = () => { if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); - CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; - DocServer.GetRefField(CurrentUserUtils.MainDocId).then(action((field: Opt) => { + DocServer.GetRefField(pathname[pathname.length - 1]).then(action((field: Opt) => { if (field instanceof Doc) { this.openWorkspace(field, true); } @@ -132,7 +131,6 @@ export class Main extends React.Component { if (!CurrentUserUtils.MainDocId) { const doc = await Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc); if (doc) { - CurrentUserUtils.MainDocId = doc[Id]; this.openWorkspace(doc); } else { this.createNewWorkspace(); @@ -148,11 +146,12 @@ export class Main extends React.Component { createNewWorkspace = async (id?: string) => { const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); if (list) { + let libraryDoc = Docs.TreeDocument([CurrentUserUtils.UserDocument], { x: 0, y: 400, title: `Library: ${CurrentUserUtils.email} ${list.length + 1}` }); + libraryDoc.excludeFromLibrary = true; let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); - var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; - let mainDoc = Docs.DockDocument([freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(libraryDoc, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; + let mainDoc = Docs.DockDocument([libraryDoc, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); list.push(mainDoc); - CurrentUserUtils.MainDocId = mainDoc[Id]; // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => { this.openWorkspace(mainDoc); @@ -164,6 +163,7 @@ export class Main extends React.Component { @action openWorkspace = async (doc: Doc, fromHistory = false) => { + CurrentUserUtils.MainDocId = doc[Id]; this.mainContainer = doc; fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc[Id]); const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc); @@ -259,9 +259,7 @@ export class Main extends React.Component { /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ @computed get miscButtons() { - let workspacesRef = React.createRef(); let logoutRef = React.createRef(); - let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); return [ , @@ -270,24 +268,11 @@ export class Main extends React.Component {
, -
-
,
]; } - @computed - get workspaceMenu() { - let areWorkspacesShown = () => this._workspacesShown; - let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let workspaces = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); - return (!workspaces || !this.mainContainer) ? (null) : - ; - } - render() { return (
@@ -297,7 +282,6 @@ export class Main extends React.Component { {this.nodesMenu()} {this.miscButtons} - {this.workspaceMenu}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 7be846e05..f29d9c8a1 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -59,12 +59,9 @@ export class TemplateMenu extends React.Component { } render() { - trace(); let templateMenu: Array = []; - this.props.templates.forEach((checked, template) => { - console.log("checked + " + checked + " " + this.props.templates.get(template)); - templateMenu.push(); - }); + this.props.templates.forEach((checked, template) => + templateMenu.push()); return (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 014773ab6..cfb1aef7d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -19,15 +19,17 @@ import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; import { listSpec } from "../../../new_fields/Schema"; import { Id, FieldId } from "../../../new_fields/RefField"; +import { faSignInAlt } from "@fortawesome/free-solid-svg-icons"; @observer export class CollectionDockingView extends React.Component { public static Instance: CollectionDockingView; - public static makeDocumentConfig(document: Doc) { + public static makeDocumentConfig(document: Doc, width?: number) { return { type: 'react-component', component: 'DocumentFrameRenderer', title: document.title, + width: width, props: { documentId: document[Id], //collectionDockingView: CollectionDockingView.Instance @@ -37,7 +39,6 @@ export class CollectionDockingView extends React.Component(); - private _fullScreen: any = null; private _flush: boolean = false; private _ignoreStateChange = ""; @@ -67,20 +68,9 @@ export class CollectionDockingView extends React.Component { - _mainCont = React.createRef(); @observable private _panelWidth = 0; @observable private _panelHeight = 0; @@ -347,10 +336,7 @@ export class DockedFrameRenderer extends React.Component { const nativeH = this.nativeHeight(); const nativeW = this.nativeWidth(); let wscale = this._panelWidth / nativeW; - if (wscale * nativeH > this._panelHeight) { - return this._panelHeight / nativeH; - } - return wscale; + return wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale; } ScreenToLocalTransform = () => { @@ -364,6 +350,8 @@ export class DockedFrameRenderer extends React.Component { get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } get content() { + if (!this._document) + return (null); return (
@@ -385,9 +373,10 @@ export class DockedFrameRenderer extends React.Component { } render() { + let theContent = this.content; return !this._document ? (null) : { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height; })}> - {({ measureRef }) =>
{this.content}
} + {({ measureRef }) =>
{theContent}
}
; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 95df5edb9..ecb5f78bb 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -41,7 +41,6 @@ .coll-title { font-size: 24px; - margin-bottom: 20px; } .docContainer { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f148c2b2f..0520e0f88 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -9,10 +9,15 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); import { Document, listSpec } from '../../../new_fields/Schema'; -import { Cast, StrCast, BoolCast } from '../../../new_fields/Types'; +import { Cast, StrCast, BoolCast, FieldValue } from '../../../new_fields/Types'; import { Doc } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/RefField'; import { Utils } from '../../../Utils'; +import { JSXElement } from 'babel-types'; +import { ContextMenu } from '../ContextMenu'; +import { undoBatch } from '../../util/UndoManager'; +import { Main } from '../Main'; +import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; export interface TreeViewProps { @@ -42,11 +47,14 @@ class TreeView extends React.Component { delete = () => this.props.deleteDoc(this.props.document); + get children() { + return Cast(this.props.document.data, listSpec(Doc), []).filter(doc => FieldValue(doc)); + } + @action remove = (document: Document) => { - var children = Cast(this.props.document.data, listSpec(Doc)); - if (children) { - children.splice(children.indexOf(document), 1); + if (this.children) { + this.children.splice(this.children.indexOf(document), 1); } } @@ -94,27 +102,38 @@ class TreeView extends React.Component {
); } + onWorkspaceContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!ContextMenu.Instance.getItems().some(item => item.description === "Open as Workspace")) { + ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => Main.Instance.openWorkspace(this.props.document)) }); + } + } + } render() { let bulletType = BulletType.List; - let childElements: JSX.Element | undefined = undefined; + let contentElement: JSX.Element | null = (null); var children = Cast(this.props.document.data, listSpec(Doc)); if (children) { // add children for a collection if (!this._collapsed) { bulletType = BulletType.Collapsible; - childElements =
    - {children.map(value => )} + contentElement =
      + {TreeView.GetChildElements(children, this.remove, this.move, this.props.copyOnDrag)}
    ; } else bulletType = BulletType.Collapsed; } - return
    + return
  • {this.renderBullet(bulletType)} {this.renderTitle()} - {childElements ? childElements : (null)} + {contentElement}
  • ; } + public static GetChildElements(docs: Doc[], remove: ((doc: Doc) => void), move: DragManager.MoveFunction, copyOnDrag: boolean) { + return docs.filter(child => !child.excludeFromLibrary).map(child => + ); + } } @observer @@ -128,21 +147,30 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => Main.Instance.createNewWorkspace()) }); + } + } render() { const children = this.children; let copyOnDrag = BoolCast(this.props.Document.copyDraggedItems, false); - let childrenElement = !children ? (null) : - (children.map(value => - )); + if (!children) { + return (null); + } + let testForLibrary = children && children.length === 1 && children[0] === CurrentUserUtils.UserDocument; + var subchildren = testForLibrary ? Cast(children[0].data, listSpec(Doc), children) : children; + let childElements = TreeView.GetChildElements(subchildren, this.remove, this.props.moveDocument, copyOnDrag); return (
    e.stopPropagation()} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget}>
    StrCast(this.props.Document.title)} @@ -151,9 +179,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { return true; }} />
    -
      - {childrenElement} + {childElements}
    ); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c2049a09a..8c1442d38 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -11,6 +11,7 @@ import { observer } from 'mobx-react'; import { undoBatch } from '../../util/UndoManager'; import { trace } from 'mobx'; import { Id } from '../../../new_fields/RefField'; +import { Main } from '../Main'; @observer export class CollectionView extends React.Component { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5588fa1ac..86d34725d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -205,16 +205,8 @@ export class DocumentView extends DocComponent(Docu CollectionDockingView.Instance.OpenFullScreen(doc); } ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked }); - ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - } - closeFullScreenClicked = (e: React.MouseEvent): void => { - CollectionDockingView.Instance.CloseFullScreen(); - ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }); - ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); + SelectionManager.DeselectAll(); } - @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { diff --git a/src/server/authentication/controllers/WorkspacesMenu.css b/src/server/authentication/controllers/WorkspacesMenu.css deleted file mode 100644 index b89039965..000000000 --- a/src/server/authentication/controllers/WorkspacesMenu.css +++ /dev/null @@ -1,3 +0,0 @@ -.ids:hover { - color: darkblue; -} \ No newline at end of file diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx deleted file mode 100644 index 91756315d..000000000 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import * as React from 'react'; -import { observable, action, configure, reaction, computed, ObservableMap, runInAction } from 'mobx'; -import { observer } from "mobx-react"; -import './WorkspacesMenu.css'; -import { EditableView } from '../../../client/views/EditableView'; -import { Doc } from '../../../new_fields/Doc'; -import { StrCast } from '../../../new_fields/Types'; -import { Id } from '../../../new_fields/RefField'; - -export interface WorkspaceMenuProps { - active: Doc | undefined; - open: (workspace: Doc) => void; - new: () => void; - allWorkspaces: Doc[]; - isShown: () => boolean; - toggle: () => void; -} - -@observer -export class WorkspacesMenu extends React.Component { - constructor(props: WorkspaceMenuProps) { - super(props); - this.addNewWorkspace = this.addNewWorkspace.bind(this); - } - - @action - addNewWorkspace() { - this.props.new(); - this.props.toggle(); - } - - render() { - return ( -
    - - {this.props.allWorkspaces.map((s, i) => -
    { - e.preventDefault(); - this.props.open(s); - }} - style={{ - marginTop: 10, - color: s === this.props.active ? "red" : "black" - }} - > - {i + 1} - - StrCast(s.title)} - SetValue={(title: string): boolean => { - s.title = title; - return true; - }} - contents={s.Title} - height={20} - /> -
    - )} -
    - ); - } -} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From a78282cdf7fbb99386484640e1fb89d4b9b0cbee Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 2 May 2019 16:19:07 -0400 Subject: fixed some things with trees and summaries. --- src/client/views/Main.tsx | 3 +-- src/client/views/Templates.tsx | 12 +++++++++++- src/client/views/collections/CollectionTreeView.tsx | 10 +++++++--- .../views/collections/collectionFreeForm/MarqueeView.tsx | 4 +++- src/client/views/nodes/DocumentContentsView.tsx | 3 ++- src/client/views/nodes/FieldView.tsx | 11 ++++------- src/client/views/nodes/ImageBox.scss | 2 ++ src/new_fields/List.ts | 6 +++--- src/server/authentication/models/current_user_utils.ts | 2 ++ 9 files changed, 35 insertions(+), 18 deletions(-) (limited to 'src/server') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index a07a2d5b1..97eb73d7f 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -144,8 +144,7 @@ export class Main extends React.Component { createNewWorkspace = async (id?: string) => { const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); if (list) { - let libraryDoc = Docs.TreeDocument([CurrentUserUtils.UserDocument], { x: 0, y: 400, title: `Library: ${CurrentUserUtils.email} ${list.length + 1}` }); - libraryDoc.excludeFromLibrary = true; + let libraryDoc = await (CurrentUserUtils.UserDocument.library as Doc); let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(libraryDoc, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; let mainDoc = Docs.DockDocument([libraryDoc, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index e17dd2354..668ae5312 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -54,7 +54,17 @@ export namespace Templates { `
    {layout}
    {props.Document.title}
    ` ); export const Summary = new Template("Title", TemplatePosition.InnerTop, - `
    {layout}
    {props.Document.doc1.title}
    ` + `
    +
    + {layout} +
    +
    + +
    +
    + +
    +
    ` ); export const TemplateList: Template[] = [Title, OuterCaption, InnerCaption, SideCaption]; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 48b226615..2cef1462b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,7 +1,7 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable } from "mobx"; +import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; import { EditableView } from "../EditableView"; @@ -145,8 +145,11 @@ class TreeView extends React.Component {
    ; } public static GetChildElements(docs: Doc[], remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { - return docs.filter(child => !child.excludeFromLibrary).map(child => - ); + return docs.filter(child => !child.excludeFromLibrary).filter(doc => FieldValue(doc)).map(child => { + console.log("child = " + child[Id]); + return + } + ); } } @@ -168,6 +171,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } render() { + trace(); const children = this.children; let dropAction = StrCast(this.props.Document.dropAction, "alias") as dropActionType; if (!children) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index c58e7780c..82027a6f2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -180,7 +180,9 @@ export class MarqueeView extends React.Component // SelectionManager.DeselectAll(); if (e.key === "r") { let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - summary.doc1 = newCollection.proto!; + summary.doc1 = selected[0]; + if (selected.length > 1) + summary.doc2 = selected[1]; summary.templates = new List([Templates.Summary.Layout]); this.props.addLiveTextDocument(summary); e.preventDefault(); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 24e8a36ae..ddfe79a5c 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -15,6 +15,7 @@ import { IconBox } from "./IconBox"; import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; import { VideoBox } from "./VideoBox"; +import { FieldView } from "./FieldView"; import { WebBox } from "./WebBox"; import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox"; import React = require("react"); @@ -63,7 +64,7 @@ export class DocumentContentsView extends React.Component { } render() { const field = this.field; - if (!field) { + if (field === undefined) { return

    {''}

    ; } - if (typeof field === "string") { - return

    {field}

    ; - } + // if (typeof field === "string") { + // return

    {field}

    ; + // } else if (field instanceof RichTextField) { return ; } @@ -108,9 +108,6 @@ export class FieldView extends React.Component { // else if (field instanceof HtmlField) { // return // } - else if (typeof field === "number") { - return

    {field}

    ; - } else if (!(field instanceof Promise)) { return

    {JSON.stringify(field)}

    ; } diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 9fe211df0..2316a050e 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -10,6 +10,8 @@ } .imageBox-cont-interactive { pointer-events: all; + width:100%; + height:auto; } .imageBox-dot { diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 1c4b96c81..db7932cec 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -2,7 +2,7 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; import { Field, Update, Self, FieldResult } from "./Doc"; import { setter, getter, deleteProperty } from "./util"; import { serializable, alias, list } from "serializr"; -import { observable } from "mobx"; +import { observable, action } from "mobx"; import { ObjectField, OnUpdate, Copy } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; @@ -25,12 +25,12 @@ const listHandlers: any = { this[Update](); return field; }, - push(...items: any[]) { + push: action(function (this: any, ...items: any[]) { items = items.map(toObjectField); const res = this[Self].__fields.push(...items); this[Update](); return res; - }, + }), reverse() { const res = this[Self].__fields.reverse(); this[Update](); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 9db470ca0..93c2afb1d 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -26,6 +26,8 @@ export class CurrentUserUtils { doc.title = this.email; doc.data = new List(); doc.optionalRightCollection = Docs.SchemaDocument([], { title: "Pending documents" }); + doc.library = Docs.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` }); + (doc.library as Doc).excludeFromLibrary = true; return doc; } -- cgit v1.2.3-70-g09d2 From ac9b42dba420139c0a7fad5685425b3cf9c1570e Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 2 May 2019 16:58:14 -0400 Subject: clean up --- src/client/views/Main.tsx | 5 ++--- src/client/views/collections/CollectionTreeView.scss | 2 ++ src/client/views/collections/CollectionTreeView.tsx | 11 +++-------- src/new_fields/Doc.ts | 5 +++-- src/server/authentication/models/current_user_utils.ts | 10 ++++++++-- 5 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src/server') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 97eb73d7f..90339aea2 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -144,10 +144,9 @@ export class Main extends React.Component { createNewWorkspace = async (id?: string) => { const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); if (list) { - let libraryDoc = await (CurrentUserUtils.UserDocument.library as Doc); let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); - var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(libraryDoc, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; - let mainDoc = Docs.DockDocument([libraryDoc, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(CurrentUserUtils.UserDocument, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; + let mainDoc = Docs.DockDocument([CurrentUserUtils.UserDocument, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }); list.push(mainDoc); // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => { diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index ce7da5767..19d4abc05 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -37,6 +37,8 @@ width: 1.5em; display: inline-block; color: $intermediate-color; + margin-top: 3px; + transform: scale(1.3,1.3); } .coll-title { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2cef1462b..b67d6f965 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -145,11 +145,8 @@ class TreeView extends React.Component {
; } public static GetChildElements(docs: Doc[], remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { - return docs.filter(child => !child.excludeFromLibrary).filter(doc => FieldValue(doc)).map(child => { - console.log("child = " + child[Id]); - return - } - ); + return docs.filter(child => !child.excludeFromLibrary).filter(doc => FieldValue(doc)).map(child => + ); } } @@ -177,9 +174,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { if (!children) { return (null); } - let testForLibrary = children && children.length === 1 && children[0] === CurrentUserUtils.UserDocument; - var subchildren = testForLibrary ? Cast(children[0].data, listSpec(Doc), children) : children; - let childElements = TreeView.GetChildElements(subchildren, this.remove, this.props.moveDocument, dropAction); + let childElements = TreeView.GetChildElements(children, this.remove, this.props.moveDocument, dropAction); return (
{ - // let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); - let linkDoc = new Doc; + let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); + //let linkDoc = new Doc; linkDoc.title = "-link name-"; linkDoc.linkDescription = ""; linkDoc.linkTags = "Default"; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 93c2afb1d..5f45d7bcc 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -7,6 +7,9 @@ import { RouteStore } from "../../RouteStore"; import { DocServer } from "../../../client/DocServer"; import { Doc } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; +import { CollectionViewType } from "../../../client/views/collections/CollectionBaseView"; +import { CollectionTreeView } from "../../../client/views/collections/CollectionTreeView"; +import { CollectionView } from "../../../client/views/collections/CollectionView"; export class CurrentUserUtils { private static curr_email: string; @@ -23,11 +26,14 @@ export class CurrentUserUtils { private static createUserDocument(id: string): Doc { let doc = new Doc(id, true); + doc.viewType = CollectionViewType.Tree; + doc.layout = CollectionView.LayoutString(); doc.title = this.email; doc.data = new List(); + doc.excludeFromLibrary = true; doc.optionalRightCollection = Docs.SchemaDocument([], { title: "Pending documents" }); - doc.library = Docs.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` }); - (doc.library as Doc).excludeFromLibrary = true; + // doc.library = Docs.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` }); + // (doc.library as Doc).excludeFromLibrary = true; return doc; } -- cgit v1.2.3-70-g09d2