From 0a39ac7f93f2035115aa929c77ad0e8b797f9fb1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 18 Jul 2019 01:20:58 -0400 Subject: stackingViewwithSections --- .../views/collections/CollectionStackingView.tsx | 57 ++++++++++++++-------- 1 file changed, 37 insertions(+), 20 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 6d9e942c9..2f26846af 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, reaction, untracked, observable, r import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -import { BoolCast, NumCast, Cast } from "../../../new_fields/Types"; +import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, Utils } from "../../../Utils"; import { ContextMenu } from "../ContextMenu"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; @@ -15,6 +15,7 @@ import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; +import { string } from "prop-types"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -104,10 +105,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return this.offsetTransform(doc, translate[0], translate[1]); } - @computed - get children() { + children(docs: Doc[]) { this._docXfs.length = 0; - return this.filteredChildren.map((d, i) => { + return docs.map((d, i) => { let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; let height = () => this.getDocHeight(layoutDoc); @@ -219,28 +219,45 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } }); } - render() { + section(heading: string, docList: Doc[]) { let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; + return <> + {heading ?
{heading}
: (null)} +
+ {this.children(docList)} + {this.singleColumn ? (null) : this.columnDragger} +
; + } + render() { + let sectionFilter = StrCast(this.props.Document.sectionFilter); + let fields = new Map(); + sectionFilter && this.filteredChildren.map(d => { + if (!fields.has(d[sectionFilter] as object)) fields.set(d[sectionFilter] as object, [d]); + else fields.get(d[sectionFilter] as object)!.push(d); + }); return (
e.stopPropagation()} > -
- {this.children} - {this.singleColumn ? (null) : this.columnDragger} -
+ {/* {sectionFilter as boolean ? [ + ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], + ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], + ["height > width", this.filteredChildren.filter(f => f[WidthSym]() + 1 <= f[HeightSym]())]]. */} + {sectionFilter ? Array.from(fields.entries()). + map(section => this.section(section[0].toString(), section[1] as Doc[])) : + this.section("", this.filteredChildren)}
); } -- cgit v1.2.3-70-g09d2 From 123027bf525bfb6d635cf2304d01490bccb4abff Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 18 Jul 2019 02:22:27 -0400 Subject: fixes for single column layouts not contained in a free form view. --- .../views/collections/CollectionBaseView.tsx | 3 +-- .../views/collections/CollectionStackingView.tsx | 27 ++++++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index eba69b448..2603dc60b 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -78,7 +78,6 @@ export class CollectionBaseView extends React.Component { @action.bound addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { - let self = this; var curPage = NumCast(this.props.Document.curPage, -1); Doc.GetProto(doc).page = curPage; if (curPage >= 0) { @@ -146,7 +145,7 @@ export class CollectionBaseView extends React.Component { const viewtype = this.collectionViewType; return (
{viewtype !== undefined ? this.props.children(viewtype, props) : (null)} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 2f26846af..c42a423c1 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -34,9 +34,18 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { componentDidMount() { this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], - () => this.singleColumn && - (this.props.Document.height = this.filteredChildren.reduce((height, d, i) => - height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) + () => { + if (this.singleColumn) { + let sectionFilter = StrCast(this.props.Document.sectionFilter); + let fields = new Map(); + sectionFilter && this.filteredChildren.map(d => { + if (!fields.has(d[sectionFilter] as object)) fields.set(d[sectionFilter] as object, [d]); + else fields.get(d[sectionFilter] as object)!.push(d); + }); + (this.props.Document.height = fields.size * 50 + this.filteredChildren.reduce((height, d, i) => + height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)); + } + } , { fireImmediately: true }); } componentWillUnmount() { @@ -112,10 +121,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; let height = () => this.getDocHeight(layoutDoc); if (this.singleColumn) { + //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); - let rowHgtPcnt = height() / (this.props.Document[HeightSym]() - 2 * this.yMargin) * 100; + let rowHgtPcnt = height(); this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
+ return
{this.getDisplayDoc(layoutDoc, d, dxf)}
; } else { @@ -231,7 +241,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { padding: this.singleColumn ? `${this.yMargin}px ${this.xMargin}px ${this.yMargin}px ${this.xMargin}px` : `${this.yMargin}px ${this.xMargin}px`, margin: "auto", width: this.singleColumn ? undefined : `${cols * (this.columnWidth + this.gridGap) + 2 * this.xMargin - this.gridGap}px`, - height: this.singleColumn ? "100%" : 'max-content', + height: 'max-content', position: "relative", gridGap: this.gridGap, gridTemplateColumns: this.singleColumn ? undefined : templatecols, @@ -250,7 +260,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { else fields.get(d[sectionFilter] as object)!.push(d); }); return ( -
e.stopPropagation()} > +
e.stopPropagation()} > {/* {sectionFilter as boolean ? [ ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], -- cgit v1.2.3-70-g09d2 From 922c418f1207c43150c499e075a9c1be34719b58 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 18 Jul 2019 17:36:37 -0400 Subject: fixes for stacking view and added detailedLayout --- src/client/views/collections/CollectionStackingView.scss | 5 +++-- src/client/views/collections/CollectionStackingView.tsx | 8 ++++---- src/client/views/collections/CollectionView.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 13 ++++--------- src/new_fields/Doc.ts | 11 +++++++++-- 5 files changed, 22 insertions(+), 18 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index b6ad47813..7ebf5f77c 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -1,8 +1,9 @@ @import "../globalCssVariables"; .collectionStackingView { - overflow-y: auto; height: 100%; - + width: 100%; + position: absolute; + overflow-y: auto; .collectionStackingView-docView-container { width: 45%; margin: 5% 2.5%; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index c42a423c1..4424cffe1 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -15,6 +15,7 @@ import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; +import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss"; import { string } from "prop-types"; @observer @@ -107,6 +108,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); return this.offsetTransform(doc, translateX, translateY); } + getSingleDocTransform(doc: Doc, ind: number, width: number) { let localY = this.filteredChildren.reduce((height, d, i) => height + (i < ind ? this.getDocHeight(Doc.expandTemplateLayout(d, this.props.DataDoc)) + this.gridGap : 0), this.yMargin); @@ -234,7 +236,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; - return <> + return
{heading ?
{heading}
: (null)}
doc) { > {this.children(docList)} {this.singleColumn ? (null) : this.columnDragger} -
; +
; } render() { let sectionFilter = StrCast(this.props.Document.sectionFilter); @@ -261,8 +263,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); return (
e.stopPropagation()} > {/* {sectionFilter as boolean ? [ ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 377a46535..1b85a0cdb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -46,6 +46,7 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } + static _applyCount: number = 0; onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !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 let subItems: ContextMenuProps[] = []; @@ -62,7 +63,7 @@ export class CollectionView extends React.Component { let otherdoc = new Doc(); otherdoc.width = 100; otherdoc.height = 50; - Doc.GetProto(otherdoc).title = "applied(" + this.props.Document.title + ")"; + Doc.GetProto(otherdoc).title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); Doc.GetProto(otherdoc).miniLayout = StrCast(this.props.Document.miniLayout); Doc.GetProto(otherdoc).detailedLayout = Doc.GetProto(otherdoc).layout; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 899c47cb3..76b8658a5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -291,7 +291,9 @@ export class DocumentView extends DocComponent(Docu if (this._doubleTap && this.props.renderDepth) { let fullScreenAlias = Doc.MakeAlias(this.props.Document); fullScreenAlias.templates = new List(); - if (this.props.Document.layout === this.props.Document.miniLayout) fullScreenAlias.layout = this.props.Document.detailedLayout instanceof Doc ? this.props.Document.detailedLayout : StrCast(this.props.Document.detailedLayout); + if (this.props.Document.layout === this.props.Document.miniLayout) { + Doc.ToggleDetailLayout(fullScreenAlias); + } this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); this.props.Document.libraryBrush = undefined; @@ -557,14 +559,7 @@ export class DocumentView extends DocComponent(Docu }, icon: "search" }); if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) { - cm.addItem({ - description: "Toggle detail", event: async () => { - let d = this.props.Document; - let miniLayout = await PromiseValue(d.miniLayout); - let detailLayout = await PromiseValue(d.detailedLayout); - d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout); - }, icon: "image" - }); + cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); } cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 7180564ea..9a4b817d3 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -316,7 +316,7 @@ export namespace Doc { if (extensionDoc === undefined) { setTimeout(() => { let docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = "Extension of " + doc.title + "'s field:" + fieldKey; + docExtensionForField.title = doc.title + ":" + fieldKey + ".ext"; docExtensionForField.extendsDoc = doc; let proto: Doc | undefined = doc; while (proto && !Doc.IsPrototype(proto)) { @@ -351,7 +351,7 @@ export namespace Doc { if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { templateLayoutDoc["_expanded_" + dataDoc[Id]] = Doc.MakeDelegate(templateLayoutDoc); - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + " applied to " + dataDoc.title; + (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; // previously: "applied to" (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).isExpandedTemplate = templateLayoutDoc; }, 0); } @@ -420,4 +420,11 @@ export namespace Doc { fieldTemplate.showTitle = "title"; setTimeout(() => fieldTemplate.proto = proto); } + + export async function ToggleDetailLayout(d: Doc) { + let miniLayout = await PromiseValue(d.miniLayout); + let detailLayout = await PromiseValue(d.detailedLayout); + d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout); + if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined; + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From ae07ba8fb410752ea98702219247ce5f89d1758b Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 19 Jul 2019 14:42:39 -0400 Subject: fixes for templates and stacking views --- src/client/documents/Documents.ts | 3 ++- src/client/views/collections/CollectionStackingView.tsx | 5 +++-- src/new_fields/Doc.ts | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3c248760b..11df6c152 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -55,7 +55,8 @@ export enum DocumentType { ICON = "icon", IMPORT = "import", LINK = "link", - LINKDOC = "linkdoc" + LINKDOC = "linkdoc", + TEMPLATE = "template" } export interface DocumentOptions { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4424cffe1..039bd7b3a 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -258,8 +258,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let sectionFilter = StrCast(this.props.Document.sectionFilter); let fields = new Map(); sectionFilter && this.filteredChildren.map(d => { - if (!fields.has(d[sectionFilter] as object)) fields.set(d[sectionFilter] as object, [d]); - else fields.get(d[sectionFilter] as object)!.push(d); + let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; + if (!fields.has(sectionValue)) fields.set(sectionValue, [d]); + else fields.get(sectionValue)!.push(d); }); return (
fieldTemplate.proto = proto); } -- cgit v1.2.3-70-g09d2 From 5e9bcf2e35415fd0ab4dec4f0141511cd4d312d0 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 19 Jul 2019 16:03:09 -0400 Subject: split masonry collection view into its own view type. --- src/client/documents/Documents.ts | 4 ++ .../views/collections/CollectionBaseView.tsx | 3 +- .../views/collections/CollectionStackingView.tsx | 58 +++++++--------------- src/client/views/collections/CollectionView.tsx | 10 ++-- 4 files changed, 32 insertions(+), 43 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 11df6c152..47ed33adf 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -410,6 +410,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Stacking }); } + export function MasonryDocument(documents: Array, options: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Masonry }); + } + export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); } diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 2603dc60b..72faf52c4 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -18,7 +18,8 @@ export enum CollectionViewType { Schema, Docking, Tree, - Stacking + Stacking, + Masonry } export interface CollectionRenderProps { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 039bd7b3a..0e5f9a321 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -6,7 +6,6 @@ import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, Utils } from "../../../Utils"; -import { ContextMenu } from "../ContextMenu"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; @@ -15,16 +14,14 @@ import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; -import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss"; -import { string } from "prop-types"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _heightDisposer?: IReactionDisposer; - _gridSize = 1; _docXfs: any[] = []; + _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @@ -33,24 +30,25 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); } @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } + @computed get Sections() { + let sectionFilter = StrCast(this.props.Document.sectionFilter); + let fields = new Map(); + sectionFilter && this.filteredChildren.map(d => { + let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; + if (!fields.has(sectionValue)) fields.set(sectionValue, [d]); + else fields.get(sectionValue)!.push(d); + }); + return fields; + } componentDidMount() { this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], - () => { - if (this.singleColumn) { - let sectionFilter = StrCast(this.props.Document.sectionFilter); - let fields = new Map(); - sectionFilter && this.filteredChildren.map(d => { - if (!fields.has(d[sectionFilter] as object)) fields.set(d[sectionFilter] as object, [d]); - else fields.get(d[sectionFilter] as object)!.push(d); - }); - (this.props.Document.height = fields.size * 50 + this.filteredChildren.reduce((height, d, i) => - height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)); - } - } + () => this.singleColumn && + (this.props.Document.height = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => + height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) , { fireImmediately: true }); } componentWillUnmount() { - if (this._heightDisposer) this._heightDisposer(); + this._heightDisposer && this._heightDisposer(); } @action @@ -98,7 +96,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return (nw && nh) ? wid * aspect : d[HeightSym](); } - offsetTransform(doc: Doc, translateX: number, translateY: number) { let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); @@ -133,7 +130,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } else { let dref = React.createRef(); let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); + let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); this._docXfs.push({ dxf: dxf, width: width, height: height }); return
{this.getDisplayDoc(layoutDoc, d, dxf)} @@ -142,7 +139,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); } - _columnStart: number = 0; columnDividerDown = (e: React.PointerEvent) => { e.stopPropagation(); e.preventDefault(); @@ -156,7 +152,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let dragPos = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; let delta = dragPos - this._columnStart; this._columnStart = dragPos; - this.props.Document.columnWidth = this.columnWidth + delta; } @@ -172,14 +167,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
; } - onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // 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: "Toggle multi-column", - event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, true), icon: "file-pdf" - }); - } - } @undoBatch @action @@ -247,7 +234,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { position: "relative", gridGap: this.gridGap, gridTemplateColumns: this.singleColumn ? undefined : templatecols, - gridAutoRows: this.singleColumn ? undefined : `${this._gridSize}px` + gridAutoRows: this.singleColumn ? undefined : "0px" }} > {this.children(docList)} @@ -255,21 +242,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
; } render() { - let sectionFilter = StrCast(this.props.Document.sectionFilter); - let fields = new Map(); - sectionFilter && this.filteredChildren.map(d => { - let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; - if (!fields.has(sectionValue)) fields.set(sectionValue, [d]); - else fields.get(sectionValue)!.push(d); - }); return (
e.stopPropagation()} > + ref={this.createRef} onDrop={this.onDrop.bind(this)} onWheel={(e: React.WheelEvent) => e.stopPropagation()} > {/* {sectionFilter as boolean ? [ ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], ["height > width", this.filteredChildren.filter(f => f[WidthSym]() + 1 <= f[HeightSym]())]]. */} - {sectionFilter ? Array.from(fields.entries()). + {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()). map(section => this.section(section[0].toString(), section[1] as Doc[])) : this.section("", this.filteredChildren)}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 7e9d35d3d..045c8531e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faProjectDiagram, faSignature, faSquare, faTh, faImage, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram, faSignature, faColumns, faSquare, faTh, faImage, faThList, faTree, faEllipsisV } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc'; @@ -25,6 +25,8 @@ library.add(faSquare); library.add(faProjectDiagram); library.add(faSignature); library.add(faThList); +library.add(faColumns); +library.add(faEllipsisV); library.add(faImage); @observer @@ -37,7 +39,8 @@ export class CollectionView extends React.Component { case CollectionViewType.Schema: return (); case CollectionViewType.Docking: return (); case CollectionViewType.Tree: return (); - case CollectionViewType.Stacking: return (); + case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } + case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } case CollectionViewType.Freeform: default: return (); @@ -57,7 +60,8 @@ export class CollectionView extends React.Component { } subItems.push({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); subItems.push({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); - subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" }); + subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "ellipsis-v" }); + subItems.push({ description: "Masonry", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Masonry), icon: "columns" }); ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => { -- cgit v1.2.3-70-g09d2 From 6f8f9bd2eaba36dc64e7335dee53a372542bad46 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Mon, 22 Jul 2019 17:17:09 -0400 Subject: basic stuff working, column headers don tmatch add group button --- src/client/views/MetadataEntryMenu.tsx | 1 + .../views/collections/CollectionStackingView.scss | 55 ++++-- .../views/collections/CollectionStackingView.tsx | 113 +++++------- .../CollectionStackingViewFieldColumn.tsx | 202 +++++++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 3 - 5 files changed, 286 insertions(+), 88 deletions(-) create mode 100644 src/client/views/collections/CollectionStackingViewFieldColumn.tsx (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index bd5a307b3..7fce3dd0c 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -74,6 +74,7 @@ export class MetadataEntryMenu extends React.Component{ this.userModified = e.target.value.trim() !== ""; } + @action onValueKeyDown = async (e: React.KeyboardEvent) => { if (e.key === "Enter") { const script = KeyValueBox.CompileKVPScript(this._currentValue); diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 7ebf5f77c..3e389225a 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -1,9 +1,12 @@ @import "../globalCssVariables"; + .collectionStackingView { height: 100%; width: 100%; position: absolute; + display: flex; overflow-y: auto; + .collectionStackingView-docView-container { width: 45%; margin: 5% 2.5%; @@ -18,21 +21,23 @@ align-items: center; } - .collectionStackingView-masonrySingle, .collectionStackingView-masonryGrid { - width:100%; - height:100%; + .collectionStackingView-masonrySingle, + .collectionStackingView-masonryGrid { + width: 100%; + height: 100%; position: absolute; - display:grid; + display: grid; top: 0; left: 0; width: 100%; position: absolute; } + .collectionStackingView-masonrySingle { - width:100%; - height:100%; + width: 100%; + height: 100%; position: absolute; - display:flex; + display: flex; flex-direction: column; top: 0; left: 0; @@ -52,34 +57,50 @@ } .collectionStackingView-columnDragger { - width: 15; - height: 15; + width: 15; + height: 15; position: absolute; margin-left: -5; } - .collectionStackingView-columnDoc{ + .collectionStackingView-columnDoc { display: inline-block; } - .collectionStackingView-columnDoc, + .collectionStackingView-columnDoc, .collectionStackingView-masonryDoc { margin-left: auto; margin-right: auto; } - + .collectionStackingView-masonryDoc { transform-origin: top left; grid-column-end: span 1; height: 100%; } - .collectionStackingView-sectionHeader { - width: 90%; + + .collectionStackingView-sectionHeader { background: gray; text-align: center; - margin-left: 5%; - margin-right: 5%; - color: white; + margin-left: 10px; + margin-right: 10px; margin-top: 10px; + color: $light-color; + text-transform: uppercase; + letter-spacing: 2px; + padding: 10px; + + .editableView-input { + color: black; + } + } + + .collectionStackingView-addDocumentButton, + .collectionStackingView-addGroupButton { + display: inline-block; + margin: 0 10px; + overflow: hidden; + width: 90%; + color: lightgrey; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0e5f9a321..0ddd5528b 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -14,6 +14,7 @@ import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; +import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -35,8 +36,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let fields = new Map(); sectionFilter && this.filteredChildren.map(d => { let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; - if (!fields.has(sectionValue)) fields.set(sectionValue, [d]); - else fields.get(sectionValue)!.push(d); + let parsed = parseInt(sectionValue.toString()); + let castedSectionValue: any = sectionValue; + if (!isNaN(parsed)) { + castedSectionValue = parsed; + } + if (!fields.has(castedSectionValue)) fields.set(castedSectionValue, [d]); + else fields.get(castedSectionValue)!.push(d); }); return fields; } @@ -66,7 +72,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) { let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; - let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; + let headings = Array.from(this.Sections.keys()); + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let width = () => (d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth) / (uniqueHeadings.length + 1); let height = () => this.getDocHeight(layoutDoc); let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]()); return doc) { return (nw && nh) ? wid * aspect : d[HeightSym](); } - offsetTransform(doc: Doc, translateX: number, translateY: number) { - let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); - let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); - return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth); - } - getDocTransform(doc: Doc, dref: HTMLDivElement) { - let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); - return this.offsetTransform(doc, translateX, translateY); - } - - getSingleDocTransform(doc: Doc, ind: number, width: number) { - let localY = this.filteredChildren.reduce((height, d, i) => - height + (i < ind ? this.getDocHeight(Doc.expandTemplateLayout(d, this.props.DataDoc)) + this.gridGap : 0), this.yMargin); - let translate = this.props.ScreenToLocalTransform().inverse().transformPoint((this.props.PanelWidth() - width) / 2, localY); - return this.offsetTransform(doc, translate[0], translate[1]); - } - - children(docs: Doc[]) { - this._docXfs.length = 0; - return docs.map((d, i) => { - let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); - let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; - let height = () => this.getDocHeight(layoutDoc); - if (this.singleColumn) { - //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. - let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); - let rowHgtPcnt = height(); - this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
- {this.getDisplayDoc(layoutDoc, d, dxf)} -
; - } else { - let dref = React.createRef(); - let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); - this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
- {this.getDisplayDoc(layoutDoc, d, dxf)} -
; - } - }); - } - columnDividerDown = (e: React.PointerEvent) => { e.stopPropagation(); e.preventDefault(); @@ -218,30 +183,37 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } }); } - section(heading: string, docList: Doc[]) { - let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, + section = (heading: string, docList: Doc[]) => { + let key = StrCast(this.props.Document.sectionFilter); + let types = docList.map(d => typeof d[key]); + let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; + if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { + type = types[0]; + } + let parsed = parseInt(heading); + if (!isNaN(parsed)) { + heading = parsed.toString(); + } + let cols = () => this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); - let templatecols = ""; - for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; - return
- {heading ?
{heading}
: (null)} -
- {this.children(docList)} - {this.singleColumn ? (null) : this.columnDragger} -
; + return Array.from(this.Sections.keys())} + heading={heading} + docList={docList} + parent={this} + type={type} + createDropTarget={this.createDropTarget} />; + } + + @action + addGroup = () => { + } + render() { + let headings = Array.from(this.Sections.keys()); + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); return (
e.stopPropagation()} > @@ -249,9 +221,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], ["height > width", this.filteredChildren.filter(f => f[WidthSym]() + 1 <= f[HeightSym]())]]. */} - {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()). + {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()).sort((a, b) => a[0].toString() > b[0].toString() ? 1 : -1). map(section => this.section(section[0].toString(), section[1] as Doc[])) : this.section("", this.filteredChildren)} + {this.props.Document.sectionFilter ? +
+ +
: null}
); } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx new file mode 100644 index 000000000..9f64a4e93 --- /dev/null +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -0,0 +1,202 @@ +import React = require("react"); +import { observer } from "mobx-react"; +import { number } from "prop-types"; +import { Doc, WidthSym } from "../../../new_fields/Doc"; +import { CollectionStackingView } from "./CollectionStackingView"; +import { Id } from "../../../new_fields/FieldSymbols"; +import { Utils } from "../../../Utils"; +import { NumCast, StrCast } from "../../../new_fields/Types"; +import { EditableView } from "../EditableView"; +import { action, observable } from "mobx"; +import { undoBatch } from "../../util/UndoManager"; +import { DragManager } from "../../util/DragManager"; +import { DocumentManager } from "../../util/DocumentManager"; +import { SelectionManager } from "../../util/SelectionManager"; +import "./CollectionStackingView.scss"; +import { Docs } from "../../documents/Documents"; + + +interface CSVFieldColumnProps { + cols: () => number; + headings: () => object[]; + heading: string; + docList: Doc[]; + parent: CollectionStackingView; + type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined; + createDropTarget: (ele: HTMLDivElement) => void; +} + +@observer +export class CollectionStackingViewFieldColumn extends React.Component { + @observable private _background = "white"; + + private _dropRef: HTMLDivElement | null = null; + private dropDisposer?: DragManager.DragDropDisposer; + + createColumnDropRef = (ele: HTMLDivElement | null) => { + this._dropRef = ele; + this.dropDisposer && this.dropDisposer(); + if (ele) { + this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.columnDrop.bind(this) } }); + } + } + + @undoBatch + @action + columnDrop = (e: Event, de: DragManager.DropEvent) => { + if (de.data instanceof DragManager.DocumentDragData) { + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let castedValue = this.getValue(this.props.heading); + if (castedValue) { + de.data.droppedDocuments.forEach(d => d[key] = castedValue); + } + this.props.parent.drop(e, de); + e.stopPropagation(); + } + } + + children(docs: Doc[]) { + let style = this.props.parent; + this.props.parent._docXfs.length = 0; + return docs.map((d, i) => { + let layoutDoc = Doc.expandTemplateLayout(d, this.props.parent.props.DataDoc); + let headings = this.props.headings(); + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let width = () => (d.nativeWidth ? Math.min(layoutDoc[WidthSym](), style.columnWidth) : style.columnWidth) / (uniqueHeadings.length + 1); + let height = () => this.props.parent.getDocHeight(layoutDoc); + if (style.singleColumn) { + let dxf; + let dref = React.createRef(); + if (uniqueHeadings.length > 0) { + dxf = () => this.getDocTransform(layoutDoc, dref.current!); + this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); + } + else { + //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. + dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); + this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); + } + let rowHgtPcnt = height(); + return
+ {this.props.parent.getDisplayDoc(layoutDoc, d, dxf)} +
; + } else { + let dref = React.createRef(); + let dxf = () => this.getDocTransform(layoutDoc, dref.current!); + let rowSpan = Math.ceil((height() + style.gridGap) / style.gridGap); + this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); + return
+ {this.props.parent.getDisplayDoc(layoutDoc, d, dxf)} +
; + } + }); + } + + getSingleDocTransform(doc: Doc, ind: number, width: number) { + let localY = this.props.parent.filteredChildren.reduce((height, d, i) => + height + (i < ind ? this.props.parent.getDocHeight(Doc.expandTemplateLayout(d, this.props.parent.props.DataDoc)) + this.props.parent.gridGap : 0), this.props.parent.yMargin); + let translate = this.props.parent.props.ScreenToLocalTransform().inverse().transformPoint((this.props.parent.props.PanelWidth() - width) / 2, localY); + return this.offsetTransform(doc, translate[0], translate[1]); + } + + offsetTransform(doc: Doc, translateX: number, translateY: number) { + let outerXf = Utils.GetScreenTransform(this.props.parent._masonryGridRef!); + let offset = this.props.parent.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + return this.props.parent.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.props.parent.columnWidth); + } + + getDocTransform(doc: Doc, dref: HTMLDivElement) { + let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); + return this.offsetTransform(doc, translateX, translateY); + } + + getValue = (value: string): any => { + let parsed = parseInt(value); + if (!isNaN(parsed)) { + return parsed; + } + if (value.toLowerCase().indexOf("true") > -1) { + return true; + } + if (value.toLowerCase().indexOf("false") > -1) { + return false; + } + return value; + } + + headingChanged = (value: string, shiftDown?: boolean) => { + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let castedValue = this.getValue(value); + if (castedValue) { + this.props.docList.forEach(d => d[key] = castedValue); + return true; + } + return false; + } + + @action + pointerEntered = () => { + if (SelectionManager.GetIsDragging()) { + this._background = "#b4b4b4"; + } + } + + @action + pointerLeave = () => { + this._background = "white"; + } + + @action + addDocument = () => { + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let newDoc = Docs.Create.TextDocument({ height: 18, title: "new text document" }); + newDoc[key] = this.getValue(this.props.heading); + this.props.parent.props.addDocument(newDoc); + } + + render() { + let cols = this.props.cols(); + let templatecols = ""; + let headings = this.props.headings(); + let heading = this.props.heading; + let style = this.props.parent; + let singleColumn = style.singleColumn; + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let editableViewProps = { + GetValue: () => heading, + SetValue: this.headingChanged, + contents: heading, + } + let headingView = heading ? +
+ +
: (null); + for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `; + return ( +
+ {headingView} +
+ {this.children(this.props.docList)} + {singleColumn ? (null) : this.props.parent.columnDragger} +
+
+ +
+
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f4052c2c3..0d766cded 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -565,10 +565,7 @@ export class DocumentView extends DocComponent(Docu if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) { cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); } -<<<<<<< HEAD -======= cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); ->>>>>>> fc1dbb1327d10bd1832d33a87d18cff1e836ecfb cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); -- cgit v1.2.3-70-g09d2 From de9b03ca6c7116949952bc428e8d9257959ad974 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Tue, 23 Jul 2019 13:58:45 -0400 Subject: implemented most of the board functionality --- .../views/collections/CollectionStackingView.scss | 99 +++++++++++++++--- .../views/collections/CollectionStackingView.tsx | 115 ++++++++++++++------- .../CollectionStackingViewFieldColumn.tsx | 64 ++++++++++-- src/new_fields/SchemaHeaderField.ts | 46 +++++++++ 4 files changed, 266 insertions(+), 58 deletions(-) create mode 100644 src/new_fields/SchemaHeaderField.ts (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 3e389225a..e0ced8af4 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -6,6 +6,7 @@ position: absolute; display: flex; overflow-y: auto; + flex-wrap: wrap; .collectionStackingView-docView-container { width: 45%; @@ -67,12 +68,6 @@ display: inline-block; } - .collectionStackingView-columnDoc, - .collectionStackingView-masonryDoc { - margin-left: auto; - margin-right: auto; - } - .collectionStackingView-masonryDoc { transform-origin: top left; grid-column-end: span 1; @@ -80,27 +75,103 @@ } .collectionStackingView-sectionHeader { - background: gray; text-align: center; - margin-left: 10px; - margin-right: 10px; + margin-left: 5px; + margin-right: 5px; margin-top: 10px; - color: $light-color; - text-transform: uppercase; - letter-spacing: 2px; - padding: 10px; + overflow: hidden; .editableView-input { color: black; } + + .editableView-input:hover, + .editableView-container-editing:hover, + .editableView-container-editing-oneLine:hover { + cursor: text + } + + .collectionStackingView-sectionHeader-subCont { + outline: none; + border: 0px; + color: $light-color; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 75%; + transition: transform 0.2s; + position: relative; + + .editableView-container-editing-oneLine, + .editableView-container-editing { + color: grey; + padding: 10px; + } + + .editableView-input:hover, + .editableView-container-editing:hover, + .editableView-container-editing-oneLine:hover { + cursor: text + } + + .editableView-input { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + // font-size: 75%; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + } + } + + .collectionStackingView-sectionDelete { + position: absolute; + right: 0; + top: 0; + height: 100%; + } } .collectionStackingView-addDocumentButton, .collectionStackingView-addGroupButton { display: inline-block; - margin: 0 10px; + margin: 0 5px; overflow: hidden; width: 90%; color: lightgrey; + overflow: ellipses; + } + + .collectionStackingView-addGroupButton { + background: rgb(238, 238, 238); + font-size: 75%; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + height: fit-content; + + .editableView-container-editing-oneLine, + .editableView-container-editing { + color: grey; + padding: 10px; + } + + .editableView-input:hover, + .editableView-container-editing:hover, + .editableView-container-editing-oneLine:hover { + cursor: text + } + + .editableView-input { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + // font-size: 75%; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + } } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0ddd5528b..e4e6f92e3 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -2,9 +2,9 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, reaction, untracked, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; +import { Doc, HeightSym, WidthSym, DocListCast } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; +import { BoolCast, NumCast, Cast, StrCast, FieldValue } from "../../../new_fields/Types"; import { emptyFunction, Utils } from "../../../Utils"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; @@ -15,46 +15,80 @@ import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; +import { listSpec } from "../../../new_fields/Schema"; +import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { List } from "../../../new_fields/List"; +import { EditableView } from "../EditableView"; + +let valuesCreated = 1; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _heightDisposer?: IReactionDisposer; + _sectionFilterDisposer?: IReactionDisposer; _docXfs: any[] = []; _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; + get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); } @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); } @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } - - @computed get Sections() { + get Sections() { let sectionFilter = StrCast(this.props.Document.sectionFilter); - let fields = new Map(); - sectionFilter && this.filteredChildren.map(d => { - let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; - let parsed = parseInt(sectionValue.toString()); - let castedSectionValue: any = sectionValue; - if (!isNaN(parsed)) { - castedSectionValue = parsed; - } - if (!fields.has(castedSectionValue)) fields.set(castedSectionValue, [d]); - else fields.get(castedSectionValue)!.push(d); - }); + let sectionHeaders = this.sectionHeaders; + if (!sectionHeaders) { + this.props.Document.sectionHeaders = sectionHeaders = new List(); + } + let fields = new Map(sectionHeaders.map(sh => [sh, []])); + if (sectionFilter) { + this.filteredChildren.map(d => { + let sectionValue = (d[sectionFilter] ? d[sectionFilter] : `No ${sectionFilter} value`) as object; + // the next five lines ensures that floating point rounding errors don't create more than one section -syip + let parsed = parseInt(sectionValue.toString()); + let castedSectionValue: any = sectionValue; + if (!isNaN(parsed)) { + castedSectionValue = parsed; + } + + // look for if header exists already + let existingHeader = sectionHeaders!.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `No ${sectionFilter} value`)); + if (existingHeader) { + fields.get(existingHeader)!.push(d); + } + else { + let newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `No ${sectionFilter} value`); + fields.set(newSchemaHeader, [d]); + sectionHeaders!.push(newSchemaHeader); + } + }); + } return fields; } componentDidMount() { - this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], - () => this.singleColumn && - (this.props.Document.height = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => - height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) - , { fireImmediately: true }); + // is there any reason this needs to exist? -syip + // this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], + // () => this.singleColumn && + // (this.props.Document.height = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => + // height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) + // , { fireImmediately: true }); + + // reset section headers when a new filter is inputted + this._sectionFilterDisposer = reaction( + () => StrCast(this.props.Document.sectionFilter), + () => { + this.props.Document.sectionHeaders = new List(); + valuesCreated = 1; + } + ) } componentWillUnmount() { this._heightDisposer && this._heightDisposer(); + this._sectionFilterDisposer && this._sectionFilterDisposer(); } @action @@ -73,8 +107,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) { let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; let headings = Array.from(this.Sections.keys()); - let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); - let width = () => (d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth) / (uniqueHeadings.length + 1); + // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let width = () => (d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth) / (headings.length + 1); let height = () => this.getDocHeight(layoutDoc); let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]()); return doc) { } }); } - section = (heading: string, docList: Doc[]) => { + section = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { let key = StrCast(this.props.Document.sectionFilter); - let types = docList.map(d => typeof d[key]); let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; + let types = docList.length ? docList.map(d => typeof d[key]) : this.childDocs.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { type = types[0]; } - let parsed = parseInt(heading); - if (!isNaN(parsed)) { - heading = parsed.toString(); - } let cols = () => this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); return Array.from(this.Sections.keys())} - heading={heading} + heading={heading ? heading.heading : ""} + headingObject={heading} docList={docList} parent={this} type={type} @@ -207,13 +239,24 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } @action - addGroup = () => { - + addGroup = (value: string) => { + if (value) { + if (this.sectionHeaders) { + this.sectionHeaders.push(new SchemaHeaderField(value)); + return true; + } + } + return false; } render() { let headings = Array.from(this.Sections.keys()); - let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let editableViewProps = { + GetValue: () => "", + SetValue: this.addGroup, + contents: "+ Add a Group" + } + // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); return (
e.stopPropagation()} > @@ -222,12 +265,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], ["height > width", this.filteredChildren.filter(f => f[WidthSym]() + 1 <= f[HeightSym]())]]. */} {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()).sort((a, b) => a[0].toString() > b[0].toString() ? 1 : -1). - map(section => this.section(section[0].toString(), section[1] as Doc[])) : - this.section("", this.filteredChildren)} + map(section => this.section(section[0], section[1] as Doc[])) : + this.section(undefined, this.filteredChildren)} {this.props.Document.sectionFilter ?
- + style={{ width: (this.columnWidth / (headings.length + 1)) - 10, marginTop: 10 }}> +
: null}
); diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 9f64a4e93..fe24c63c7 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -7,19 +7,22 @@ import { Id } from "../../../new_fields/FieldSymbols"; import { Utils } from "../../../Utils"; import { NumCast, StrCast } from "../../../new_fields/Types"; import { EditableView } from "../EditableView"; -import { action, observable } from "mobx"; +import { action, observable, computed } from "mobx"; import { undoBatch } from "../../util/UndoManager"; import { DragManager } from "../../util/DragManager"; import { DocumentManager } from "../../util/DocumentManager"; import { SelectionManager } from "../../util/SelectionManager"; import "./CollectionStackingView.scss"; import { Docs } from "../../documents/Documents"; +import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; interface CSVFieldColumnProps { cols: () => number; headings: () => object[]; heading: string; + headingObject: SchemaHeaderField | undefined; docList: Doc[]; parent: CollectionStackingView; type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined; @@ -33,6 +36,8 @@ export class CollectionStackingViewFieldColumn extends React.Component { this._dropRef = ele; this.dropDisposer && this.dropDisposer(); @@ -46,10 +51,13 @@ export class CollectionStackingViewFieldColumn extends React.Component { if (de.data instanceof DragManager.DocumentDragData) { let key = StrCast(this.props.parent.props.Document.sectionFilter); - let castedValue = this.getValue(this.props.heading); + let castedValue = this.getValue(this._heading); if (castedValue) { de.data.droppedDocuments.forEach(d => d[key] = castedValue); } + else { + de.data.droppedDocuments.forEach(d => d[key] = undefined); + } this.props.parent.drop(e, de); e.stopPropagation(); } @@ -124,11 +132,21 @@ export class CollectionStackingViewFieldColumn extends React.Component { let key = StrCast(this.props.parent.props.Document.sectionFilter); let castedValue = this.getValue(value); if (castedValue) { + if (this.props.parent.sectionHeaders) { + if (this.props.parent.sectionHeaders.map(i => i.heading).indexOf(castedValue.toString()) > -1) { + return false; + } + } this.props.docList.forEach(d => d[key] = castedValue); + if (this.props.headingObject) { + this.props.headingObject.setHeading(castedValue.toString()); + this._heading = this.props.headingObject.heading; + } return true; } return false; @@ -154,23 +172,53 @@ export class CollectionStackingViewFieldColumn extends React.Component { + let key = StrCast(this.props.parent.props.Document.sectionFilter); + this.props.docList.forEach(d => d[key] = undefined); + if (this.props.parent.sectionHeaders && this.props.headingObject) { + let index = this.props.parent.sectionHeaders.indexOf(this.props.headingObject); + this.props.parent.sectionHeaders.splice(index, 1); + } + } + render() { let cols = this.props.cols(); + let key = StrCast(this.props.parent.props.Document.sectionFilter); let templatecols = ""; let headings = this.props.headings(); - let heading = this.props.heading; + let heading = this._heading; let style = this.props.parent; let singleColumn = style.singleColumn; let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `No ${key} value`; let editableViewProps = { - GetValue: () => heading, + GetValue: () => evContents, SetValue: this.headingChanged, - contents: heading, + contents: evContents, + oneLine: true } - let headingView = heading ? + let headingView = this.props.headingObject ?
- + {/* the default bucket (no key value) has a tooltip that describes what it is. + Further, it does not have a color and cannot be deleted. */} +
+ + {evContents === `No ${key} value` ? + (null) : + } +
: (null); for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `; return ( @@ -180,7 +228,7 @@ export class CollectionStackingViewFieldColumn extends React.Component([ + ["purple", "#f5b5fc"], + ["green", "#96F7D2"], + ["yellow", "#F0F696"], + ["red", "#FCB1B1"] +]) + +@scriptingGlobal +@Deserializable("schemaheader") +export class SchemaHeaderField extends ObjectField { + @serializable(primitive()) + heading: string; + color: string; + + constructor(heading: string = "", color: string = Array.from(PastelSchemaPalette.values())[Math.floor(Math.random() * 4)]) { + super(); + + this.heading = heading; + this.color = color; + } + + setHeading(heading: string) { + this.heading = heading; + this[OnUpdate](); + } + + setColor(color: string) { + this.color = color; + this[OnUpdate](); + } + + [Copy]() { + return new SchemaHeaderField(this.heading, this.color); + } + + [ToScriptString]() { + return `invalid`; + } +} + -- cgit v1.2.3-70-g09d2 From 828fdd80ab8af26f6e2ef521e05a71e7e500bf8c Mon Sep 17 00:00:00 2001 From: yipstanley Date: Wed, 24 Jul 2019 17:18:15 -0400 Subject: view specsss --- package.json | 1 + src/client/views/EditableView.tsx | 2 +- src/client/views/MainView.tsx | 4 +- .../views/collections/CollectionStackingView.tsx | 9 +- .../CollectionStackingViewFieldColumn.tsx | 44 +++- src/client/views/collections/CollectionSubView.tsx | 15 +- .../views/collections/CollectionViewChromes.scss | 113 ++++++++- .../views/collections/CollectionViewChromes.tsx | 261 ++++++++++++++++----- src/client/views/collections/KeyRestrictionRow.tsx | 45 ++++ 9 files changed, 428 insertions(+), 66 deletions(-) create mode 100644 src/client/views/collections/KeyRestrictionRow.tsx (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/package.json b/package.json index 4a15cbb2f..37052fde3 100644 --- a/package.json +++ b/package.json @@ -136,6 +136,7 @@ "image-size": "^0.7.4", "imagesloaded": "^4.1.4", "jquery-awesome-cursor": "^0.3.1", + "js-datepicker": "^4.6.6", "jsonwebtoken": "^8.5.0", "jsx-to-string": "^1.4.0", "lodash": "^4.17.11", diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index a5bb40243..bd00d47b9 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -116,7 +116,7 @@ export class EditableView extends React.Component { return (
+ onClick={this.onClick}> {this.props.contents}
); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 94a4835a1..69602deed 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowDown, faCloudUploadAlt, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDown, faCaretUp, faLongArrowAltRight, faCloudUploadAlt, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, runInAction, reaction, trace } from 'mobx'; import { observer } from 'mobx-react'; @@ -127,7 +127,9 @@ export class MainView extends React.Component { library.add(faCut); library.add(faCommentAlt); library.add(faThumbtack); + library.add(faLongArrowAltRight); library.add(faCheck); + library.add(faCaretUp); library.add(faArrowDown); library.add(faArrowUp); library.add(faCloudUploadAlt); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index e4e6f92e3..a78a47ffb 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -249,6 +249,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return false; } + sortFunc = (a: [SchemaHeaderField, Doc[]], b: [SchemaHeaderField, Doc[]]): 1 | -1 => { + let descending = BoolCast(this.props.Document.stackingHeadersSortDescending); + let firstEntry = descending ? b : a; + let secondEntry = descending ? a : b; + return firstEntry[0].heading > secondEntry[0].heading ? 1 : -1; + } + render() { let headings = Array.from(this.Sections.keys()); let editableViewProps = { @@ -264,7 +271,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], ["height > width", this.filteredChildren.filter(f => f[WidthSym]() + 1 <= f[HeightSym]())]]. */} - {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()).sort((a, b) => a[0].toString() > b[0].toString() ? 1 : -1). + {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc). map(section => this.section(section[0], section[1] as Doc[])) : this.section(undefined, this.filteredChildren)} {this.props.Document.sectionFilter ? diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index fe24c63c7..582adc418 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -16,6 +16,8 @@ import "./CollectionStackingView.scss"; import { Docs } from "../../documents/Documents"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { CompileScript } from "../../util/Scripting"; interface CSVFieldColumnProps { @@ -35,6 +37,7 @@ export class CollectionStackingViewFieldColumn extends React.Component = React.createRef(); @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading; @@ -182,6 +185,43 @@ export class CollectionStackingViewFieldColumn extends React.Component { + let alias = Doc.MakeAlias(this.props.parent.props.Document); + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let value = this.getValue(this._heading); + value = typeof value === "string" ? `"${value}"` : value; + let script = `return doc.${key} === ${value}`; + let compiled = CompileScript(script, { params: { doc: Doc.name } }); + if (compiled.compiled) { + let scriptField = new ScriptField(compiled); + alias.viewSpecScript = scriptField; + let dragData = new DragManager.DocumentDragData([alias], [alias.proto]); + DragManager.StartDocumentDrag([this._headerRef.current!], dragData, e.clientX, e.clientY); + } + + e.stopPropagation(); + document.removeEventListener("pointermove", this.startDrag); + document.removeEventListener("pointerup", this.pointerUp); + } + + pointerUp = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + + document.removeEventListener("pointermove", this.startDrag); + document.removeEventListener("pointerup", this.pointerUp); + } + + headerDown = (e: React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + + document.removeEventListener("pointermove", this.startDrag); + document.addEventListener("pointermove", this.startDrag); + document.removeEventListener("pointerup", this.pointerUp); + document.addEventListener("pointerup", this.pointerUp); + } + render() { let cols = this.props.cols(); let key = StrCast(this.props.parent.props.Document.sectionFilter); @@ -199,11 +239,11 @@ export class CollectionStackingViewFieldColumn extends React.Component {/* the default bucket (no key value) has a tooltip that describes what it is. Further, it does not have a color and cannot be deleted. */} -
boolean; @@ -54,7 +56,18 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { let self = this; //TODO tfs: This might not be what we want? //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) - return DocListCast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]); + let docs = DocListCast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]); + let viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); + if (viewSpecScript) { + let script = viewSpecScript.script; + docs = docs.filter(d => { + let res = script.run({ doc: d }); + if (res.success) { + return res.result; + } + }); + } + return docs; } get childDocList() { //TODO tfs: This might not be what we want? diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index e5cb1b546..3103cd309 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -1,12 +1,120 @@ @import "../globalCssVariables"; +@import '~js-datepicker/dist/datepicker.min.css'; + +.collectionViewBaseChrome { + display: flex; + + .collectionViewBaseChrome-viewPicker { + font-size: 75%; + text-transform: uppercase; + letter-spacing: 2px; + background: rgb(238, 238, 238); + color: grey; + outline-color: black; + border: none; + padding: 12px 10px 11px 10px; + } + + .collectionViewBaseChrome-viewPicker:active { + outline-color: black; + } + + .collectionViewBaseChrome-collapse { + margin-right: 10px; + transition: all .5s; + } + + .collectionViewBaseChrome-viewSpecs { + margin-left: 10px; + display: grid; + + .collectionViewBaseChrome-viewSpecsInput { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + font-size: 75%; + background: rgb(238, 238, 238); + height: 100%; + width: 150px; + } + + .collectionViewBaseChrome-viewSpecsMenu { + overflow: hidden; + transition: height .5s, display .5s; + position: absolute; + top: 60px; + z-index: 100; + display: flex; + flex-direction: column; + background: rgb(238, 238, 238); + box-shadow: grey 2px 2px 4px; + + .qs-datepicker { + left: unset; + right: 0; + } + + .collectionViewBaseChrome-viewSpecsMenu-row { + display: grid; + grid-template-columns: 150px 200px 150px; + margin-top: 10px; + margin-right: 10px; + + .collectionViewBaseChrome-viewSpecsMenu-rowLeft, + .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, + .collectionViewBaseChrome-viewSpecsMenu-rowRight { + font-size: 75%; + letter-spacing: 2px; + color: grey; + margin-left: 10px; + padding: 5px; + border: none; + outline-color: black; + } + } + + .collectionViewBaseChrome-viewSpecsMenu-lastRow { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 10px; + margin: 10px; + } + } + } +} .collectionStackingViewChrome { display: grid; - grid-template-columns: 1fr 1fr; + grid-template-columns: 1fr auto; padding-bottom: 10px; border-bottom: .5px solid lightgrey; margin: 10px; + .collectionStackingViewChrome-cont { + display: flex; + justify-content: space-between; + } + + .collectionStackingViewChrome-sort { + display: flex; + align-items: center; + justify-content: space-between; + + .collectionStackingViewChrome-sortIcon { + transition: transform .5s; + margin-left: 10px; + } + } + + button:hover { + transform: scale(1); + } + + .collectionStackingViewChrome-sectionFilter-cont { justify-self: right; display: flex; @@ -21,10 +129,9 @@ .collectionStackingViewChrome-sectionFilter { color: white; - width: fit-content; + width: 100px; text-align: center; background: rgb(238, 238, 238); - height: 37px; .editable-view-input, input, diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 52fee26bf..2edac384d 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -3,55 +3,189 @@ import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; import { CollectionViewType } from "./CollectionBaseView"; import { undoBatch } from "../../util/UndoManager"; -import { action, observable, runInAction, computed } from "mobx"; +import { action, observable, runInAction, computed, IObservable, IObservableValue } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { DocLike } from "../MetadataEntryMenu"; -const higflyout = require("@hig/flyout"); -export const Flyout = higflyout.default; import * as Autosuggest from 'react-autosuggest'; import { EditableView } from "../EditableView"; -import { StrCast } from "../../../new_fields/Types"; +import { StrCast, NumCast, BoolCast, Cast } from "../../../new_fields/Types"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Utils } from "../../../Utils"; +import KeyRestrictionRow from "./KeyRestrictionRow"; +import { CompileScript } from "../../util/Scripting"; +import { ScriptField } from "../../../new_fields/ScriptField"; +const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { CollectionView: CollectionView; } +let stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation(); + +@observer class CollectionViewBaseChrome extends React.Component { + @observable private _viewSpecsOpen: boolean = false; + @observable private _dateWithinValue: string = ""; + @observable private _dateValue: Date = new Date(); + @observable private _keyRestrictions: [JSX.Element, string][] = []; + @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); } + + private _picker: any; + private _datePickerElGuid = Utils.GenerateGuid(); + + componentDidMount = () => { + this._picker = datepicker("#" + this._datePickerElGuid, { + disabler: (date: Date) => date > new Date(), + onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date), + dateSelected: new Date() + }); + + runInAction(() => { + this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[0][1] = value)} />, ""]); + this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]); + }); + } + @undoBatch viewChanged = (e: React.ChangeEvent) => { //@ts-ignore - switch (e.target.selectedOptions[0].value) { - case "freeform": - this.props.CollectionView.props.Document.viewType = CollectionViewType.Freeform; - break; - case "schema": - this.props.CollectionView.props.Document.viewType = CollectionViewType.Schema; - break; - case "treeview": - this.props.CollectionView.props.Document.viewType = CollectionViewType.Tree; - break; - case "stacking": - this.props.CollectionView.props.Document.viewType = CollectionViewType.Stacking; - break; - case "masonry": - this.props.CollectionView.props.Document.viewType = CollectionViewType.Masonry; - break; - default: - break; + this.props.CollectionView.props.Document.viewType = parseInt(e.target.selectedOptions[0].value); + } + + @action + openViewSpecs = (e: React.SyntheticEvent) => { + this._viewSpecsOpen = true; + + //@ts-ignore + if (!e.target.classList[0].startsWith("qs")) { + this.closeDatePicker(); + } + + e.stopPropagation(); + document.removeEventListener("pointerdown", this.closeViewSpecs); + document.addEventListener("pointerdown", this.closeViewSpecs); + } + + @action closeViewSpecs = () => { this._viewSpecsOpen = false; document.removeEventListener("pointerdown", this.closeViewSpecs); }; + + @action + openDatePicker = (e: React.PointerEvent) => { + this.openViewSpecs(e); + if (this._picker) { + this._picker.alwaysShow = true; + this._picker.show(); + // TODO: calendar is offset when zoomed in/out + // this._picker.calendar.style.position = "absolute"; + // let transform = this.props.CollectionView.props.ScreenToLocalTransform(); + // let x = parseInt(this._picker.calendar.style.left) / transform.Scale; + // let y = parseInt(this._picker.calendar.style.top) / transform.Scale; + // this._picker.calendar.style.left = x; + // this._picker.calendar.style.top = y; + + e.stopPropagation(); } } + @action + addKeyRestriction = (e: React.MouseEvent) => { + let index = this._keyRestrictions.length; + this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[index][1] = value)} />, ""]); + + this.openViewSpecs(e); + } + + @action + applyFilter = (e: React.MouseEvent) => { + this.openViewSpecs(e); + + let keyRestrictionScript = `${this._keyRestrictions.map(i => i[1]) + .reduce((acc: string, value: string, i: number) => value ? `${acc} && ${value}` : acc)}`; + let yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0; + let monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0; + let weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0; + let dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7; + let lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset); + let upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1); + let dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; + let fullScript = `return ${dateRestrictionScript} && ${keyRestrictionScript}`; + let compiled = CompileScript(fullScript, { params: { doc: Doc.name } }); + if (compiled.compiled) { + this.props.CollectionView.props.Document.viewSpecScript = new ScriptField(compiled); + } + } + + @action + closeDatePicker = () => { + if (this._picker) { + this._picker.alwaysShow = false; + this._picker.hide(); + } + document.removeEventListener("pointerdown", this.closeDatePicker); + } + render() { return (
- + + + + + +
+ +
+ {this._keyRestrictions.map(i => i[0])} +
+
+ CREATED WITHIN: +
+ + +
+
+ + +
+
+
) } @@ -62,6 +196,7 @@ export class CollectionStackingViewChrome extends React.Component => { @@ -109,41 +244,53 @@ export class CollectionStackingViewChrome extends React.Component { this.props.CollectionView.props.Document.stackingHeadersSortDescending = !this.props.CollectionView.props.Document.stackingHeadersSortDescending; } @action resetValue = () => { this._currentKey = this.sectionFilter; }; render() { return (
-
-
- Group items by: -
-
- this.sectionFilter} - autosuggestProps={ - { - resetValue: this.resetValue, - value: this._currentKey, - onChange: this.onKeyChange, - autosuggestProps: { - inputProps: - { - value: this._currentKey, - onChange: this.onKeyChange - }, - getSuggestionValue: this.getSuggestionValue, - suggestions: this.suggestions, - alwaysRenderSuggestions: true, - renderSuggestion: this.renderSuggestion, - onSuggestionsFetchRequested: this.onSuggestionFetch, - onSuggestionsClearRequested: this.onSuggestionClear - } - }} - SetValue={this.setValue} - contents={this.sectionFilter ? this.sectionFilter : "N/A"} - /> +
+ +
+
+ Group items by: +
+
+ this.sectionFilter} + autosuggestProps={ + { + resetValue: this.resetValue, + value: this._currentKey, + onChange: this.onKeyChange, + autosuggestProps: { + inputProps: + { + value: this._currentKey, + onChange: this.onKeyChange + }, + getSuggestionValue: this.getSuggestionValue, + suggestions: this.suggestions, + alwaysRenderSuggestions: true, + renderSuggestion: this.renderSuggestion, + onSuggestionsFetchRequested: this.onSuggestionFetch, + onSuggestionsClearRequested: this.onSuggestionClear + } + }} + oneLine + SetValue={this.setValue} + contents={this.sectionFilter ? this.sectionFilter : "N/A"} + /> +
diff --git a/src/client/views/collections/KeyRestrictionRow.tsx b/src/client/views/collections/KeyRestrictionRow.tsx new file mode 100644 index 000000000..8051a8359 --- /dev/null +++ b/src/client/views/collections/KeyRestrictionRow.tsx @@ -0,0 +1,45 @@ +import * as React from "react"; +import { observable, runInAction } from "mobx"; +import { observer } from "mobx-react"; +import { PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField"; + +interface IKeyRestrictionProps { + contains: boolean; + script: (value: string) => void; +} + +@observer +export default class KeyRestrictionRow extends React.Component { + @observable private _key = ""; + @observable private _value = ""; + @observable private _contains = this.props.contains; + + render() { + if (this._key && this._value) { + let parsedValue: string | number = `"${this._value}"`; + let parsed = parseInt(this._value); + if (!isNaN(parsed)) { + parsedValue = parsed; + } + let scriptText = `(doc.${this._key} ${this._contains ? "===" : "!=="} ${parsedValue})`; + this.props.script(scriptText); + } + return ( +
+ runInAction(() => this._key = e.target.value)} + placeholder="KEY" /> + + runInAction(() => this._value = e.target.value)} + placeholder="VALUE" /> +
+ ) + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From ede0719d96cc2551490398caf3e1f41fe7992931 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Wed, 24 Jul 2019 22:27:37 -0400 Subject: view specs almost entirely done, refactored some chrome impl --- .../views/collections/CollectionStackingView.scss | 1 + .../views/collections/CollectionStackingView.tsx | 6 +- src/client/views/collections/CollectionSubView.tsx | 1 + src/client/views/collections/CollectionView.tsx | 42 ++-- .../views/collections/CollectionViewChromes.scss | 156 +++++++-------- .../views/collections/CollectionViewChromes.tsx | 214 ++++++++++++--------- 6 files changed, 227 insertions(+), 193 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index e0ced8af4..f43340967 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -7,6 +7,7 @@ display: flex; overflow-y: auto; flex-wrap: wrap; + transition: top .5s; .collectionStackingView-docView-container { width: 45%; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a78a47ffb..31ec80d76 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -8,7 +8,7 @@ import { BoolCast, NumCast, Cast, StrCast, FieldValue } from "../../../new_field import { emptyFunction, Utils } from "../../../Utils"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; -import { CollectionSubView } from "./CollectionSubView"; +import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import { undoBatch } from "../../util/UndoManager"; import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; @@ -19,6 +19,7 @@ import { listSpec } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { List } from "../../../new_fields/List"; import { EditableView } from "../EditableView"; +import { CollectionViewProps } from "./CollectionBaseView"; let valuesCreated = 1; @@ -32,6 +33,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } + get chromeCollapsed() { return this.props.chromeCollapsed; } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @@ -265,7 +267,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); return ( -
e.stopPropagation()} > {/* {sectionFilter as boolean ? [ ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 24c8adb35..98447e824 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -30,6 +30,7 @@ export interface CollectionViewProps extends FieldViewProps { moveDocument: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; PanelWidth: () => number; PanelHeight: () => number; + chromeCollapsed: boolean; } export interface SubCollectionViewProps extends CollectionViewProps { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ba9780c24..e2f652908 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -17,7 +17,8 @@ import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; import { StrCast, PromiseValue } from '../../../new_fields/Types'; import { DocumentType } from '../../documents/Documents'; -import { CollectionStackingViewChrome } from './CollectionViewChromes'; +import { CollectionStackingViewChrome, CollectionViewBaseChrome } from './CollectionViewChromes'; +import { observable } from 'mobx'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -32,40 +33,39 @@ library.add(faImage); @observer export class CollectionView extends React.Component { + @observable private _collapsed = false; + public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); } private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (this.isAnnotationOverlay ? CollectionViewType.Freeform : type) { - case CollectionViewType.Schema: return (); - case CollectionViewType.Docking: return (); - case CollectionViewType.Tree: return (); - case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } - case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } + case CollectionViewType.Schema: return (); + case CollectionViewType.Docking: return (); + case CollectionViewType.Tree: return (); + case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } + case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } case CollectionViewType.Freeform: default: - return (); + return (); } return (null); } - private Chrome = (type: CollectionViewType) => { - if (this.isAnnotationOverlay || this.props.Document === CurrentUserUtils.UserDocument.sidebar) { - return (null); - } - - switch (type) { - case CollectionViewType.Stacking: return (); - default: - return null; - } + private collapse = (value: boolean) => { + this._collapsed = value; } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - return [ - this.Chrome(type), - this.SubViewHelper(type, renderProps) - ] + if (this.isAnnotationOverlay || this.props.Document === CurrentUserUtils.UserDocument.sidebar) { + return [(null), this.SubViewHelper(type, renderProps)]; + } + else { + return [ + (), + this.SubViewHelper(type, renderProps) + ]; + } } get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 3103cd309..d37228bde 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -1,98 +1,104 @@ @import "../globalCssVariables"; @import '~js-datepicker/dist/datepicker.min.css'; -.collectionViewBaseChrome { - display: flex; - - .collectionViewBaseChrome-viewPicker { - font-size: 75%; - text-transform: uppercase; - letter-spacing: 2px; - background: rgb(238, 238, 238); - color: grey; - outline-color: black; - border: none; - padding: 12px 10px 11px 10px; - } - - .collectionViewBaseChrome-viewPicker:active { - outline-color: black; - } - - .collectionViewBaseChrome-collapse { - margin-right: 10px; - transition: all .5s; - } +.collectionViewChrome { + display: grid; + grid-template-columns: 1fr auto; + padding-bottom: 10px; + border-bottom: .5px solid lightgrey; + margin: 10px; + position: relative; + z-index: 9001; + transition: top .5s; - .collectionViewBaseChrome-viewSpecs { - margin-left: 10px; - display: grid; + .collectionViewBaseChrome { + display: flex; - .collectionViewBaseChrome-viewSpecsInput { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; - text-align: center; + .collectionViewBaseChrome-viewPicker { + font-size: 75%; text-transform: uppercase; letter-spacing: 2px; - outline-color: black; - font-size: 75%; background: rgb(238, 238, 238); - height: 100%; - width: 150px; + color: grey; + outline-color: black; + border: none; + padding: 12px 10px 11px 10px; + margin-left: 50px; } - .collectionViewBaseChrome-viewSpecsMenu { - overflow: hidden; - transition: height .5s, display .5s; + .collectionViewBaseChrome-viewPicker:active { + outline-color: black; + } + + .collectionViewBaseChrome-collapse { + transition: all .5s; position: absolute; - top: 60px; - z-index: 100; - display: flex; - flex-direction: column; - background: rgb(238, 238, 238); - box-shadow: grey 2px 2px 4px; + width: 40px; + } + + .collectionViewBaseChrome-viewSpecs { + margin-left: 10px; + display: grid; - .qs-datepicker { - left: unset; - right: 0; + .collectionViewBaseChrome-viewSpecsInput { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + font-size: 75%; + background: rgb(238, 238, 238); + height: 100%; + width: 150px; } - .collectionViewBaseChrome-viewSpecsMenu-row { - display: grid; - grid-template-columns: 150px 200px 150px; - margin-top: 10px; - margin-right: 10px; - - .collectionViewBaseChrome-viewSpecsMenu-rowLeft, - .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, - .collectionViewBaseChrome-viewSpecsMenu-rowRight { - font-size: 75%; - letter-spacing: 2px; - color: grey; - margin-left: 10px; - padding: 5px; - border: none; - outline-color: black; + .collectionViewBaseChrome-viewSpecsMenu { + overflow: hidden; + transition: height .5s, display .5s; + position: absolute; + top: 60px; + z-index: 100; + display: flex; + flex-direction: column; + background: rgb(238, 238, 238); + box-shadow: grey 2px 2px 4px; + + .qs-datepicker { + left: unset; + right: 0; + } + + .collectionViewBaseChrome-viewSpecsMenu-row { + display: grid; + grid-template-columns: 150px 200px 150px; + margin-top: 10px; + margin-right: 10px; + + .collectionViewBaseChrome-viewSpecsMenu-rowLeft, + .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, + .collectionViewBaseChrome-viewSpecsMenu-rowRight { + font-size: 75%; + letter-spacing: 2px; + color: grey; + margin-left: 10px; + padding: 5px; + border: none; + outline-color: black; + } } - } - .collectionViewBaseChrome-viewSpecsMenu-lastRow { - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 10px; - margin: 10px; + .collectionViewBaseChrome-viewSpecsMenu-lastRow { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 10px; + margin: 10px; + } } } } -} -.collectionStackingViewChrome { - display: grid; - grid-template-columns: 1fr auto; - padding-bottom: 10px; - border-bottom: .5px solid lightgrey; - margin: 10px; .collectionStackingViewChrome-cont { display: flex; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 2edac384d..24d13d5cb 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -19,16 +19,19 @@ const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { CollectionView: CollectionView; + type: CollectionViewType; + collapse?: (value: boolean) => any; } let stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation(); @observer -class CollectionViewBaseChrome extends React.Component { +export class CollectionViewBaseChrome extends React.Component { @observable private _viewSpecsOpen: boolean = false; @observable private _dateWithinValue: string = ""; @observable private _dateValue: Date = new Date(); @observable private _keyRestrictions: [JSX.Element, string][] = []; + @observable private _collapsed: boolean = false; @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); } private _picker: any; @@ -124,68 +127,92 @@ class CollectionViewBaseChrome extends React.Component { + this._collapsed = !this._collapsed; + this.props.collapse(this._collapsed); + } + + subChrome = () => { + + switch (this.props.type) { + case CollectionViewType.Stacking: return ( + ); + default: + return null; + } + } + render() { return ( -
- - -
- -
- {this._keyRestrictions.map(i => i[0])} -
-
- CREATED WITHIN: +
+
+ + +
+ +
+ {this._keyRestrictions.map(i => i[0])} +
+
+ CREATED WITHIN:
- - -
-
-
+
+ - +
+ {this.subChrome()}
) } @@ -249,48 +276,45 @@ export class CollectionStackingViewChrome extends React.Component - -
- -
-
- Group items by: -
-
- this.sectionFilter} - autosuggestProps={ - { - resetValue: this.resetValue, - value: this._currentKey, - onChange: this.onKeyChange, - autosuggestProps: { - inputProps: - { - value: this._currentKey, - onChange: this.onKeyChange - }, - getSuggestionValue: this.getSuggestionValue, - suggestions: this.suggestions, - alwaysRenderSuggestions: true, - renderSuggestion: this.renderSuggestion, - onSuggestionsFetchRequested: this.onSuggestionFetch, - onSuggestionsClearRequested: this.onSuggestionClear - } - }} - oneLine - SetValue={this.setValue} - contents={this.sectionFilter ? this.sectionFilter : "N/A"} - /> +
+ +
+ +
+
+ Group items by:
+
+ this.sectionFilter} + autosuggestProps={ + { + resetValue: this.resetValue, + value: this._currentKey, + onChange: this.onKeyChange, + autosuggestProps: { + inputProps: + { + value: this._currentKey, + onChange: this.onKeyChange + }, + getSuggestionValue: this.getSuggestionValue, + suggestions: this.suggestions, + alwaysRenderSuggestions: true, + renderSuggestion: this.renderSuggestion, + onSuggestionsFetchRequested: this.onSuggestionFetch, + onSuggestionsClearRequested: this.onSuggestionClear + } + }} + oneLine + SetValue={this.setValue} + contents={this.sectionFilter ? this.sectionFilter : "N/A"} + />
-- cgit v1.2.3-70-g09d2 From db560a8c43f77b9342e55a48dd96f695813b32ef Mon Sep 17 00:00:00 2001 From: yipstanley Date: Thu, 25 Jul 2019 12:53:09 -0400 Subject: oof a lot of stuff here --- .../views/collections/CollectionSchemaView.scss | 1 + .../views/collections/CollectionSchemaView.tsx | 2 + .../views/collections/CollectionStackingView.tsx | 5 +- .../views/collections/CollectionTreeView.scss | 27 ++- .../views/collections/CollectionTreeView.tsx | 2 + src/client/views/collections/CollectionView.tsx | 18 +- .../views/collections/CollectionViewChromes.scss | 258 +++++++++++---------- .../views/collections/CollectionViewChromes.tsx | 137 ++++++----- .../authentication/models/current_user_utils.ts | 4 + 9 files changed, 251 insertions(+), 203 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 186e006f3..1e6d1fe99 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -12,6 +12,7 @@ width: 100%; height: 100%; overflow: hidden; + transition: top 0.5s; .collectionSchemaView-cellContents { height: $MAX_ROW_HEIGHT; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 2cf50e551..bdcedea10 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -69,6 +69,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @observable _newKeyName: string = ""; @observable previewScript: string = ""; + @computed get chromeCollapsed() { return this.props.chromeCollapsed; } @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); } @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; } @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH - this.previewWidth(); } @@ -390,6 +391,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { render() { return (
this.onDrop(e, {})} onContextMenu={this.onContextMenu} ref={this.createTarget}> {this.reactTable} {this.dividerDragger} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 31ec80d76..b5c0fb3d6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -21,8 +21,6 @@ import { List } from "../../../new_fields/List"; import { EditableView } from "../EditableView"; import { CollectionViewProps } from "./CollectionBaseView"; -let valuesCreated = 1; - @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; @@ -33,7 +31,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } - get chromeCollapsed() { return this.props.chromeCollapsed; } + @computed get chromeCollapsed() { return this.props.chromeCollapsed; } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @@ -84,7 +82,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { () => StrCast(this.props.Document.sectionFilter), () => { this.props.Document.sectionHeaders = new List(); - valuesCreated = 1; } ) } diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 5205f4313..db3652ff6 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -31,6 +31,7 @@ margin-top: 4px; transform: scale(1.3, 1.3); } + .editableView-container { font-weight: bold; } @@ -43,18 +44,20 @@ display: inline; } - .editableView-input, .editableView-container-editing { + .editableView-input, + .editableView-container-editing { display: block; text-overflow: ellipsis; font-size: 24px; white-space: nowrap; } } + .collectionTreeView-keyHeader { font-style: italic; font-size: 8pt; margin-left: 3px; - display:none; + display: none; background: lightgray; } @@ -72,28 +75,31 @@ // width:100%;//width: max-content; } + .treeViewItem-openRight { display: none; } .treeViewItem-border { - display:inherit; + display: inherit; border-left: dashed 1px #00000042; } .treeViewItem-header:hover { .collectionTreeView-keyHeader { - display:inherit; + display: inherit; } + .treeViewItem-openRight { display: inline-block; - height:13px; - margin-top:2px; + height: 13px; + margin-top: 2px; margin-left: 5px; + // display: inline; svg { - display:block; - padding:0px; + display: block; + padding: 0px; margin: 0px; } } @@ -101,14 +107,17 @@ .treeViewItem-header { border: transparent 1px solid; - display:flex; + display: flex; } + .treeViewItem-header-above { border-top: black 1px solid; } + .treeViewItem-header-below { border-bottom: black 1px solid; } + .treeViewItem-header-inside { border: black 1px solid; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d05cc375e..cbf32c667 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -456,6 +456,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { private treedropDisposer?: DragManager.DragDropDisposer; private _mainEle?: HTMLDivElement; + @computed get chromeCollapsed() { return this.props.chromeCollapsed; } + protected createTreeDropTarget = (ele: HTMLDivElement) => { this.treedropDisposer && this.treedropDisposer(); if (this._mainEle = ele) { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index e2f652908..1c6dd661d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -18,7 +18,7 @@ import { CollectionTreeView } from "./CollectionTreeView"; import { StrCast, PromiseValue } from '../../../new_fields/Types'; import { DocumentType } from '../../documents/Documents'; import { CollectionStackingViewChrome, CollectionViewBaseChrome } from './CollectionViewChromes'; -import { observable } from 'mobx'; +import { observable, action, runInAction } from 'mobx'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -37,11 +37,20 @@ export class CollectionView extends React.Component { public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); } + componentDidMount = () => { + // chrome status is one of disabled, collapsed, or visible. this determines initial state from document + let chromeStatus = this.props.Document.chromeStatus; + if (chromeStatus && (chromeStatus === "disabled" || chromeStatus === "collapsed")) { + runInAction(() => this._collapsed = true); + } + } + private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (this.isAnnotationOverlay ? CollectionViewType.Freeform : type) { case CollectionViewType.Schema: return (); - case CollectionViewType.Docking: return (); + // currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip + case CollectionViewType.Docking: return (); case CollectionViewType.Tree: return (); case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } @@ -52,12 +61,15 @@ export class CollectionView extends React.Component { return (null); } + @action private collapse = (value: boolean) => { this._collapsed = value; + this.props.Document.chromeStatus = value ? "collapsed" : "visible"; } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - if (this.isAnnotationOverlay || this.props.Document === CurrentUserUtils.UserDocument.sidebar) { + // currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip + if (this.isAnnotationOverlay || this.props.Document.chromeStatus === "disabled" || type === CollectionViewType.Docking) { return [(null), this.SubViewHelper(type, renderProps)]; } else { diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index d37228bde..0faca0607 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -1,167 +1,171 @@ @import "../globalCssVariables"; @import '~js-datepicker/dist/datepicker.min.css'; -.collectionViewChrome { - display: grid; - grid-template-columns: 1fr auto; - padding-bottom: 10px; - border-bottom: .5px solid lightgrey; - margin: 10px; +.collectionViewChrome-cont { position: relative; z-index: 9001; transition: top .5s; + background: rgb(238, 238, 238); + padding: 10px; - .collectionViewBaseChrome { - display: flex; + .collectionViewChrome { + display: grid; + grid-template-columns: 1fr auto; + padding-bottom: 10px; + border-bottom: .5px solid lightgrey; - .collectionViewBaseChrome-viewPicker { - font-size: 75%; - text-transform: uppercase; - letter-spacing: 2px; - background: rgb(238, 238, 238); - color: grey; - outline-color: black; - border: none; - padding: 12px 10px 11px 10px; - margin-left: 50px; - } - - .collectionViewBaseChrome-viewPicker:active { - outline-color: black; - } - - .collectionViewBaseChrome-collapse { - transition: all .5s; - position: absolute; - width: 40px; - } - - .collectionViewBaseChrome-viewSpecs { - margin-left: 10px; - display: grid; + .collectionViewBaseChrome { + display: flex; - .collectionViewBaseChrome-viewSpecsInput { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; - text-align: center; + .collectionViewBaseChrome-viewPicker { + font-size: 75%; text-transform: uppercase; letter-spacing: 2px; - outline-color: black; - font-size: 75%; background: rgb(238, 238, 238); - height: 100%; - width: 150px; + color: grey; + outline-color: black; + border: none; + padding: 12px 10px 11px 10px; + margin-left: 50px; + } + + .collectionViewBaseChrome-viewPicker:active { + outline-color: black; } - .collectionViewBaseChrome-viewSpecsMenu { - overflow: hidden; - transition: height .5s, display .5s; + .collectionViewBaseChrome-collapse { + transition: all .5s; position: absolute; - top: 60px; - z-index: 100; - display: flex; - flex-direction: column; - background: rgb(238, 238, 238); - box-shadow: grey 2px 2px 4px; + width: 40px; + } - .qs-datepicker { - left: unset; - right: 0; + .collectionViewBaseChrome-viewSpecs { + margin-left: 10px; + display: grid; + + .collectionViewBaseChrome-viewSpecsInput { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + font-size: 75%; + background: rgb(238, 238, 238); + height: 100%; + width: 150px; } - .collectionViewBaseChrome-viewSpecsMenu-row { - display: grid; - grid-template-columns: 150px 200px 150px; - margin-top: 10px; - margin-right: 10px; - - .collectionViewBaseChrome-viewSpecsMenu-rowLeft, - .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, - .collectionViewBaseChrome-viewSpecsMenu-rowRight { - font-size: 75%; - letter-spacing: 2px; - color: grey; - margin-left: 10px; - padding: 5px; - border: none; - outline-color: black; + .collectionViewBaseChrome-viewSpecsMenu { + overflow: hidden; + transition: height .5s, display .5s; + position: absolute; + top: 60px; + z-index: 100; + display: flex; + flex-direction: column; + background: rgb(238, 238, 238); + box-shadow: grey 2px 2px 4px; + + .qs-datepicker { + left: unset; + right: 0; } - } - .collectionViewBaseChrome-viewSpecsMenu-lastRow { - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 10px; - margin: 10px; + .collectionViewBaseChrome-viewSpecsMenu-row { + display: grid; + grid-template-columns: 150px 200px 150px; + margin-top: 10px; + margin-right: 10px; + + .collectionViewBaseChrome-viewSpecsMenu-rowLeft, + .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, + .collectionViewBaseChrome-viewSpecsMenu-rowRight { + font-size: 75%; + letter-spacing: 2px; + color: grey; + margin-left: 10px; + padding: 5px; + border: none; + outline-color: black; + } + } + + .collectionViewBaseChrome-viewSpecsMenu-lastRow { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 10px; + margin: 10px; + } } } } - } - .collectionStackingViewChrome-cont { - display: flex; - justify-content: space-between; - } + .collectionStackingViewChrome-cont { + display: flex; + justify-content: space-between; + } - .collectionStackingViewChrome-sort { - display: flex; - align-items: center; - justify-content: space-between; + .collectionStackingViewChrome-sort { + display: flex; + align-items: center; + justify-content: space-between; - .collectionStackingViewChrome-sortIcon { - transition: transform .5s; - margin-left: 10px; + .collectionStackingViewChrome-sortIcon { + transition: transform .5s; + margin-left: 10px; + } } - } - - button:hover { - transform: scale(1); - } + button:hover { + transform: scale(1); + } - .collectionStackingViewChrome-sectionFilter-cont { - justify-self: right; - display: flex; - font-size: 75%; - text-transform: uppercase; - letter-spacing: 2px; - .collectionStackingViewChrome-sectionFilter-label { - vertical-align: center; - padding: 10px; - } + .collectionStackingViewChrome-sectionFilter-cont { + justify-self: right; + display: flex; + font-size: 75%; + text-transform: uppercase; + letter-spacing: 2px; - .collectionStackingViewChrome-sectionFilter { - color: white; - width: 100px; - text-align: center; - background: rgb(238, 238, 238); + .collectionStackingViewChrome-sectionFilter-label { + vertical-align: center; + padding: 10px; + } - .editable-view-input, - input, - .editableView-container-editing-oneLine, - .editableView-container-editing { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; + .collectionStackingViewChrome-sectionFilter { + color: white; + width: 100px; text-align: center; - text-transform: uppercase; - letter-spacing: 2px; - outline-color: black; - height: 100%; - } + background: rgb(238, 238, 238); - .react-autosuggest__container { - margin: 0; - color: grey; - padding: 0px; + .editable-view-input, + input, + .editableView-container-editing-oneLine, + .editableView-container-editing { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + height: 100%; + } + + .react-autosuggest__container { + margin: 0; + color: grey; + padding: 0px; + } } } - } - .collectionStackingViewChrome-sectionFilter:hover { - cursor: text; + .collectionStackingViewChrome-sectionFilter:hover { + cursor: text; + } } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 24d13d5cb..4129781f7 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -47,6 +47,20 @@ export class CollectionViewBaseChrome extends React.Component { this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[0][1] = value)} />, ""]); this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]); + + // chrome status is one of disabled, collapsed, or visible. this determines initial state from document + let chromeStatus = this.props.CollectionView.props.Document.chromeStatus; + if (chromeStatus) { + if (chromeStatus === "disabled") { + throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!"); + } + else if (chromeStatus === "collapsed") { + this._collapsed = true; + if (this.props.collapse) { + this.props.collapse(true); + } + } + } }); } @@ -130,11 +144,12 @@ export class CollectionViewBaseChrome extends React.Component { this._collapsed = !this._collapsed; - this.props.collapse(this._collapsed); + if (this.props.collapse) { + this.props.collapse(this._collapsed); + } } subChrome = () => { - switch (this.props.type) { case CollectionViewType.Stacking: return ( -
- - -
- -
- {this._keyRestrictions.map(i => i[0])} -
-
- CREATED WITHIN: -
- - +
+
+
+ + +
+ +
+ {this._keyRestrictions.map(i => i[0])} +
+
+ CREATED WITHIN:
-
-
+
+ - +
+ {this.subChrome()}
- {this.subChrome()}
) } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 1c52a3f11..41eb1aa0c 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -50,6 +50,7 @@ export class CurrentUserUtils { if (doc.workspaces === undefined) { const workspaces = Docs.Create.TreeDocument([], { title: "Workspaces", height: 100 }); workspaces.excludeFromLibrary = true; + workspaces.chromeStatus = "disabled"; workspaces.workspaceLibrary = true; workspaces.boxShadow = "0 0"; doc.workspaces = workspaces; @@ -57,6 +58,7 @@ export class CurrentUserUtils { if (doc.recentlyClosed === undefined) { const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed", height: 75 }); recentlyClosed.excludeFromLibrary = true; + recentlyClosed.chromeStatus = "disabled"; recentlyClosed.boxShadow = "0 0"; doc.recentlyClosed = recentlyClosed; } @@ -65,11 +67,13 @@ export class CurrentUserUtils { sidebar.excludeFromLibrary = true; sidebar.gridGap = 5; sidebar.xMargin = 5; + sidebar.chromeStatus = "disabled"; sidebar.yMargin = 5; Doc.GetProto(sidebar).backgroundColor = "#aca3a6"; sidebar.boxShadow = "1 1 3"; doc.sidebar = sidebar; } + doc.chromeStatus = "disabled"; StrCast(doc.title).indexOf("@") !== -1 && (doc.title = StrCast(doc.title).split("@")[0] + "'s Library"); } -- cgit v1.2.3-70-g09d2 From 0baefb4e0b133df60f42d894733113c961740af3 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Thu, 25 Jul 2019 19:30:44 -0400 Subject: almost done --- .../views/collections/CollectionStackingView.scss | 42 ++++++++++++---------- .../views/collections/CollectionStackingView.tsx | 8 ++--- .../CollectionStackingViewFieldColumn.tsx | 26 ++++++++------ .../views/collections/CollectionViewChromes.scss | 5 +-- .../views/collections/CollectionViewChromes.tsx | 6 ++-- 5 files changed, 48 insertions(+), 39 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index f43340967..9dbe4ccb8 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -96,7 +96,6 @@ outline: none; border: 0px; color: $light-color; - text-transform: uppercase; letter-spacing: 2px; font-size: 75%; transition: transform 0.2s; @@ -118,9 +117,7 @@ padding: 12px 10px 11px 10px; border: 0px; color: grey; - // font-size: 75%; text-align: center; - text-transform: uppercase; letter-spacing: 2px; outline-color: black; } @@ -142,15 +139,6 @@ width: 90%; color: lightgrey; overflow: ellipses; - } - - .collectionStackingView-addGroupButton { - background: rgb(238, 238, 238); - font-size: 75%; - text-align: center; - text-transform: uppercase; - letter-spacing: 2px; - height: fit-content; .editableView-container-editing-oneLine, .editableView-container-editing { @@ -165,14 +153,32 @@ } .editableView-input { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; - // font-size: 75%; - text-align: center; - text-transform: uppercase; + outline-color: black; letter-spacing: 2px; + color: grey; + border: 0px; + padding: 12px 10px 11px 10px; + } + } + + .collectionStackingView-addDocumentButton { + font-size: 75%; + letter-spacing: 2px; + + .editableView-input { outline-color: black; + letter-spacing: 2px; + color: grey; + border: 0px; + padding: 12px 10px 11px 10px; } } + + .collectionStackingView-addGroupButton { + background: rgb(238, 238, 238); + font-size: 75%; + text-align: center; + letter-spacing: 2px; + height: fit-content; + } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b5c0fb3d6..7c93201fe 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -47,7 +47,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let fields = new Map(sectionHeaders.map(sh => [sh, []])); if (sectionFilter) { this.filteredChildren.map(d => { - let sectionValue = (d[sectionFilter] ? d[sectionFilter] : `No ${sectionFilter} value`) as object; + let sectionValue = (d[sectionFilter] ? d[sectionFilter] : `NO ${sectionFilter.toUpperCase()} VALUE`) as object; // the next five lines ensures that floating point rounding errors don't create more than one section -syip let parsed = parseInt(sectionValue.toString()); let castedSectionValue: any = sectionValue; @@ -56,12 +56,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } // look for if header exists already - let existingHeader = sectionHeaders!.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `No ${sectionFilter} value`)); + let existingHeader = sectionHeaders!.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${sectionFilter.toUpperCase()} VALUE`)); if (existingHeader) { fields.get(existingHeader)!.push(d); } else { - let newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `No ${sectionFilter} value`); + let newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${sectionFilter.toUpperCase()} VALUE`); fields.set(newSchemaHeader, [d]); sectionHeaders!.push(newSchemaHeader); } @@ -260,7 +260,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let editableViewProps = { GetValue: () => "", SetValue: this.addGroup, - contents: "+ Add a Group" + contents: "+ ADD A GROUP" } // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); return ( diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 582adc418..ea2a302ff 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -18,6 +18,7 @@ import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { ScriptField } from "../../../new_fields/ScriptField"; import { CompileScript } from "../../util/Scripting"; +import { RichTextField } from "../../../new_fields/RichTextField"; interface CSVFieldColumnProps { @@ -168,11 +169,11 @@ export class CollectionStackingViewFieldColumn extends React.Component { + addDocument = (value: string, shiftDown?: boolean) => { let key = StrCast(this.props.parent.props.Document.sectionFilter); - let newDoc = Docs.Create.TextDocument({ height: 18, title: "new text document" }); + let newDoc = Docs.Create.TextDocument({ height: 18, width: 200, title: value }); newDoc[key] = this.getValue(this.props.heading); - this.props.parent.props.addDocument(newDoc); + return this.props.parent.props.addDocument(newDoc); } @action @@ -231,29 +232,34 @@ export class CollectionStackingViewFieldColumn extends React.Component headings.indexOf(i) === idx); - let evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `No ${key} value`; - let editableViewProps = { + let evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`; + let headerEditableViewProps = { GetValue: () => evContents, SetValue: this.headingChanged, contents: evContents, oneLine: true } + let newEditableViewProps = { + GetValue: () => "", + SetValue: this.addDocument, + contents: "+ NEW" + } let headingView = this.props.headingObject ?
{/* the default bucket (no key value) has a tooltip that describes what it is. Further, it does not have a color and cannot be deleted. */}
- - {evContents === `No ${key} value` ? + + {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : +
); diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 0faca0607..6525f3b07 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -5,7 +5,7 @@ position: relative; z-index: 9001; transition: top .5s; - background: rgb(238, 238, 238); + background: lightslategray; padding: 10px; .collectionViewChrome { @@ -48,7 +48,6 @@ border: 0px; color: grey; text-align: center; - text-transform: uppercase; letter-spacing: 2px; outline-color: black; font-size: 75%; @@ -128,7 +127,6 @@ justify-self: right; display: flex; font-size: 75%; - text-transform: uppercase; letter-spacing: 2px; .collectionStackingViewChrome-sectionFilter-label { @@ -150,7 +148,6 @@ border: 0px; color: grey; text-align: center; - text-transform: uppercase; letter-spacing: 2px; outline-color: black; height: 100%; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 4129781f7..78ceaad86 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -180,11 +180,11 @@ export class CollectionViewBaseChrome extends React.ComponentSchema View - +
- Group items by: + GROUP ITEMS BY:
Date: Sat, 27 Jul 2019 17:03:20 -0400 Subject: schema headers changed to schemaheaderfields, a bug with udpating the headers (in CollectionSchemaView>ChangeColumn) --- src/client/documents/Documents.ts | 13 +-- src/client/util/DragManager.ts | 5 +- src/client/views/MainView.tsx | 3 +- .../views/collections/CollectionSchemaCells.tsx | 30 +++++- .../views/collections/CollectionSchemaHeaders.tsx | 9 +- .../CollectionSchemaMovableTableHOC.tsx | 7 +- .../views/collections/CollectionSchemaView.scss | 15 +++ .../views/collections/CollectionSchemaView.tsx | 103 +++++++++++++-------- .../views/collections/CollectionStackingView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 3 +- src/client/views/nodes/LinkEditor.tsx | 3 +- src/client/views/nodes/LinkMenuGroup.tsx | 3 +- src/new_fields/SchemaHeaderField.ts | 55 +++++++++-- 13 files changed, 186 insertions(+), 65 deletions(-) (limited to 'src/client/views/collections/CollectionStackingView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 76ac34d85..e6fe1b8b3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -39,6 +39,7 @@ import { DocumentManager } from "../util/DocumentManager"; import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox"; import { Scripting } from "../util/Scripting"; import { ButtonBox } from "../views/nodes/ButtonBox"; +import { SchemaHeaderField, RandomPastel } from "../../new_fields/SchemaHeaderField"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -84,7 +85,7 @@ export interface DocumentOptions { curPage?: number; documentText?: string; borderRounding?: string; - schemaColumns?: List; + schemaColumns?: List; dockingConfig?: string; dbDoc?: Doc; // [key: string]: Opt; @@ -403,23 +404,23 @@ export namespace Docs { } export function FreeformDocument(documents: Array, options: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Freeform }); + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List([new SchemaHeaderField("title")]), ...options, viewType: CollectionViewType.Freeform }); } - export function SchemaDocument(schemaColumns: string[], documents: Array, options: DocumentOptions) { + export function SchemaDocument(schemaColumns: SchemaHeaderField[], documents: Array, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(schemaColumns), ...options, viewType: CollectionViewType.Schema }); } export function TreeDocument(documents: Array, options: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Tree }); + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List([new SchemaHeaderField("title")]), ...options, viewType: CollectionViewType.Tree }); } export function StackingDocument(documents: Array, options: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Stacking }); + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List([new SchemaHeaderField("title")]), ...options, viewType: CollectionViewType.Stacking }); } export function MasonryDocument(documents: Array, options: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Masonry }); + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List([new SchemaHeaderField("title")]), ...options, viewType: CollectionViewType.Masonry }); } export function ButtonDocument(options?: DocumentOptions) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0299b1d90..47d3c313d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -8,6 +8,7 @@ import * as globalCssVariables from "../views/globalCssVariables.scss"; import { DocumentManager } from "./DocumentManager"; import { LinkManager } from "./LinkManager"; import { SelectionManager } from "./SelectionManager"; +import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( @@ -290,10 +291,10 @@ export namespace DragManager { // for column dragging in schema view export class ColumnDragData { - constructor(colKey: string) { + constructor(colKey: SchemaHeaderField) { this.colKey = colKey; } - colKey: string; + colKey: SchemaHeaderField; [id: string]: any; } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0e04b5e7e..282db244e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -39,6 +39,7 @@ import { PreviewCursor } from './PreviewCursor'; import { FilterBox } from './search/FilterBox'; import { CollectionTreeView } from './collections/CollectionTreeView'; import { ClientUtils } from '../util/ClientUtils'; +import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField'; @observer export class MainView extends React.Component { @@ -375,7 +376,7 @@ export class MainView extends React.Component { let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; // let addDockingNode = action(() => Docs.Create.StandardCollectionDockingDocument([{ doc: addColNode(), initialWidth: 200 }], { width: 200, height: 200, title: "a nested docking freeform collection" })); - let addSchemaNode = action(() => Docs.Create.SchemaDocument(["title"], [], { width: 200, height: 200, title: "a schema collection" })); + let addSchemaNode = action(() => Docs.Create.SchemaDocument([new SchemaHeaderField("title")], [], { width: 200, height: 200, title: "a schema collection" })); //let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, dropAction: "alias" })); // let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", dropAction: "copy" })); let addColNode = action(() => Docs.Create.FreeformDocument([], { width: this.pwidth * .7, height: this.pheight, title: "a freeform collection" })); diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 4a618a436..c91f1017b 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -21,7 +21,12 @@ import { NumCast, StrCast, BoolCast, FieldValue, Cast } from "../../../new_field import { Docs } from "../../documents/Documents"; import { DocumentContentsView } from "../nodes/DocumentContentsView"; import { SelectionManager } from "../../util/SelectionManager"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faExpand } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { SchemaHeaderField, RandomPastel } from "../../../new_fields/SchemaHeaderField"; +library.add(faExpand); export interface CellProps { row: number; @@ -38,6 +43,7 @@ export interface CellProps { changeFocusedCellByIndex: (row: number, col: number) => void; setIsEditing: (isEditing: boolean) => void; isEditable: boolean; + setPreviewDoc: (doc: Doc) => void; } @observer @@ -92,7 +98,7 @@ export class CollectionSchemaCell extends React.Component { this._document[fieldKey] = de.data.draggedDocuments[0]; } else { - let coll = Docs.Create.SchemaDocument(["title"], de.data.draggedDocuments, {}); + let coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title")], de.data.draggedDocuments, {}); this._document[fieldKey] = coll; } e.stopPropagation(); @@ -106,6 +112,18 @@ export class CollectionSchemaCell extends React.Component { } } + expandDoc = (e: React.PointerEvent) => { + let field = this.props.rowProps.original[this.props.rowProps.column.id as string]; + let doc = FieldValue(Cast(field, Doc)); + + console.log("Expanding doc", StrCast(doc!.title)); + this.props.setPreviewDoc(doc!); + + // this.props.changeFocusedCellByIndex(this.props.row, this.props.col); + + e.stopPropagation(); + } + renderCellWithType(type: string | undefined) { let dragRef: React.RefObject = React.createRef(); @@ -157,6 +175,15 @@ export class CollectionSchemaCell extends React.Component { if (this.props.isFocused && this.props.isEditable) className += " focused"; if (this.props.isFocused && !this.props.isEditable) className += " inactive"; + let doc = FieldValue(Cast(field, Doc)); + if (type === "document") console.log("doc", typeof field); + let fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc); + let docExpander = ( +
+ +
+ ); + return (
@@ -193,6 +220,7 @@ export class CollectionSchemaCell extends React.Component { val && val.forEach(doc => this.applyToDoc(doc, run)); }} />
+ {fieldIsDoc ? docExpander : null}
); diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index d1d0674c4..9fc28eafa 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -10,11 +10,12 @@ import { ColumnType } from "./CollectionSchemaView"; import { emptyFunction } from "../../../Utils"; import { contains } from "typescript-collections/dist/lib/arrays"; import { faFile } from "@fortawesome/free-regular-svg-icons"; +import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile); export interface HeaderProps { - keyValue: string; + keyValue: SchemaHeaderField; possibleKeys: string[]; existingKeys: string[]; keyType: ColumnType; @@ -33,14 +34,14 @@ export class CollectionSchemaHeader extends React.Component { this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "file" : "align-justify"; return ( -
+
{this.props.keyValue}
} + menuButtonContent={
{this.props.keyValue.heading}
} addNew={false} onSelect={this.props.onSelect} setIsEditing={this.props.setIsEditing} diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx index 0ddd56180..2349e42ca 100644 --- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx +++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx @@ -12,14 +12,15 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faGripVertical, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { DocumentManager } from "../../util/DocumentManager"; +import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; library.add(faGripVertical, faTrash); export interface MovableColumnProps { columnRenderer: TableCellRenderer; - columnValue: string; - allColumns: string[]; - reorderColumns: (toMove: string, relativeTo: string, before: boolean, columns: string[]) => void; + columnValue: SchemaHeaderField; + allColumns: SchemaHeaderField[]; + reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void; ScreenToLocalTransform: () => Transform; } export class MovableColumn extends React.Component { diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 91c6e8b3c..e0de76247 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -379,6 +379,7 @@ button.add-column { .collectionSchemaView-cellWrapper { height: 100%; padding: 4px; + position: relative; &:focus { outline: none; @@ -405,6 +406,20 @@ button.add-column { height: 100%; // word-wrap: break-word; } + + &:hover .collectionSchemaView-cellContents-docExpander { + display: block; + } +} + +.collectionSchemaView-cellContents-docExpander { + height: 30px; + width: 30px; + display: none; + position: absolute; + top: 0; + right: 0; + background-color: lightgray; } .doc-drag-over { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index c6550560a..176872503 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -38,6 +38,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import { DocumentManager } from "../../util/DocumentManager"; import { ImageBox } from "../nodes/ImageBox"; import { ComputedField } from "../../../new_fields/ScriptField"; +import { SchemaHeaderField, RandomPastel } from "../../../new_fields/SchemaHeaderField"; library.add(faCog, faPlus, faSortUp, faSortDown); @@ -284,11 +285,13 @@ export class SchemaTable extends React.Component { @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); } @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; } @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH - this.previewWidth(); } - @computed get columns() { return Cast(this.props.Document.schemaColumns, listSpec("string"), []); } - set columns(columns: string[]) { this.props.Document.schemaColumns = new List(columns); } + @computed get columns() { + return Cast(this.props.Document.schemaColumns, listSpec(SchemaHeaderField), []); + } + set columns(columns: SchemaHeaderField[]) { this.props.Document.schemaColumns = new List(columns); } @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } @computed get tableColumns(): Column[] { - let possibleKeys = this.documentKeys.filter(key => this.columns.findIndex(existingKey => existingKey.toUpperCase() === key.toUpperCase()) === -1); + let possibleKeys = this.documentKeys.filter(key => this.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1); let columns: Column[] = []; let tableIsFocused = this.props.isFocused(this.props.Document); let focusedRow = this._focusedCell.row; @@ -321,9 +324,9 @@ export class SchemaTable extends React.Component { let header = c.heading)} keyType={this.getColumnType(col)} - typeConst={columnTypes.get(col) !== undefined} + typeConst={col.type !== undefined || columnTypes.get(col.heading) !== undefined} onSelect={this.changeColumns} setIsEditing={this.setHeaderIsEditing} deleteColumn={this.deleteColumn} @@ -334,16 +337,16 @@ export class SchemaTable extends React.Component { return { Header: , - accessor: (doc: Doc) => doc ? doc[col] : 0, - id: col, + accessor: (doc: Doc) => doc ? doc[col.heading] : 0, + id: col.heading, Cell: (rowProps: CellInfo) => { - let row = rowProps.index; - let column = this.columns.indexOf(rowProps.column.id!); - let isFocused = focusedRow === row && focusedCol === column && tableIsFocused; + let rowIndex = rowProps.index; + let columnIndex = this.columns.map(c => c.heading).indexOf(rowProps.column.id!); + let isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused; let props: CellProps = { - row: row, - col: column, + row: rowIndex, + col: columnIndex, rowProps: rowProps, isFocused: isFocused, changeFocusedCellByIndex: this.changeFocusedCellByIndex, @@ -356,6 +359,7 @@ export class SchemaTable extends React.Component { moveDocument: this.props.moveDocument, setIsEditing: this.setCellIsEditing, isEditable: isEditable, + setPreviewDoc: this.props.setPreviewDoc }; let colType = this.getColumnType(col); @@ -394,6 +398,15 @@ export class SchemaTable extends React.Component { // } // return this.props.Document; // } + constructor(props: SchemaTableProps) { + super(props); + // convert old schema columns (list of strings) into new schema columns (list of schema header fields) + let oldSchemaColumns = Cast(this.props.Document.schemaColumns, listSpec("string"), []); + if (oldSchemaColumns && oldSchemaColumns.length) { + let newSchemaColumns = oldSchemaColumns.map(i => typeof i === "string" ? new SchemaHeaderField(i) : i); + this.props.Document.schemaColumns = new List(newSchemaColumns); + } + } componentDidMount() { document.addEventListener("keydown", this.onKeyDown); @@ -440,7 +453,7 @@ export class SchemaTable extends React.Component { let row = rowInfo.index; //@ts-ignore - let col = this.columns.indexOf(column!.id); + let col = this.columns.map(c => c.heading).indexOf(column!.id); // let col = column ? this.columns.indexOf(column!) : -1; let isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document); // let column = this.columns.indexOf(column.id!); @@ -502,6 +515,11 @@ export class SchemaTable extends React.Component { if (!this._cellIsEditing && !this._headerIsEditing && this.props.isFocused(this.props.Document)) {// && this.props.isSelected()) { let direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : ""; this.changeFocusedCellByDirection(direction); + + let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document; + let children = Cast(doc[this.props.fieldKey], listSpec(Doc), []); + const pdoc = FieldValue(children[this._focusedCell.row]); + pdoc && this.props.setPreviewDoc(pdoc); } } @@ -532,8 +550,8 @@ export class SchemaTable extends React.Component { this._focusedCell = { row: this._focusedCell.row + 1 === children.length ? this._focusedCell.row : this._focusedCell.row + 1, col: this._focusedCell.col }; break; } - const pdoc = FieldValue(children[this._focusedCell.row]); - pdoc && this.props.setPreviewDoc(pdoc); + // const pdoc = FieldValue(children[this._focusedCell.row]); + // pdoc && this.props.setPreviewDoc(pdoc); } @action @@ -544,8 +562,8 @@ export class SchemaTable extends React.Component { this._focusedCell = { row: row, col: col }; this.props.setFocused(this.props.Document); - const fdoc = FieldValue(children[this._focusedCell.row]); - fdoc && this.props.setPreviewDoc(fdoc); + // const fdoc = FieldValue(children[this._focusedCell.row]); + // fdoc && this.props.setPreviewDoc(fdoc); } createRow = () => { @@ -561,25 +579,25 @@ export class SchemaTable extends React.Component { @action createColumn = () => { let index = 0; - let found = this.columns.findIndex(col => col.toUpperCase() === "New field".toUpperCase()) > -1; + let found = this.columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1; if (!found) { - this.columns.push("New field"); + this.columns.push(new SchemaHeaderField("New field")); return; } while (found) { index++; - found = this.columns.findIndex(col => col.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1; + found = this.columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1; } - this.columns.push("New field (" + index + ")"); + this.columns.push(new SchemaHeaderField("New field (" + index + ")")); } @action deleteColumn = (key: string) => { - let list = Cast(this.props.Document.schemaColumns, listSpec("string")); + let list = Cast(this.props.Document.schemaColumns, listSpec(SchemaHeaderField)); if (list === undefined) { - this.props.Document.schemaColumns = list = new List([]); + this.props.Document.schemaColumns = list = new List([]); } else { - const index = list.indexOf(key); + const index = list.map(c => c.heading).indexOf(key); if (index > -1) { list.splice(index, 1); } @@ -588,26 +606,37 @@ export class SchemaTable extends React.Component { @action changeColumns = (oldKey: string, newKey: string, addNew: boolean) => { - let list = Cast(this.props.Document.schemaColumns, listSpec("string")); + let list = Cast(this.props.Document.schemaColumns, listSpec(SchemaHeaderField)); if (list === undefined) { - this.props.Document.schemaColumns = list = new List([newKey]); + this.props.Document.schemaColumns = list = new List([new SchemaHeaderField(newKey)]); } else { if (addNew) { - this.columns.push(newKey); + this.columns.push(new SchemaHeaderField(newKey)); } else { - const index = list.indexOf(oldKey); + const index = list.map(c => c.heading).indexOf(oldKey); if (index > -1) { - list[index] = newKey; + list[index] = new SchemaHeaderField(newKey); } } } } - getColumnType = (key: string): ColumnType => { - if (columnTypes.get(key)) return columnTypes.get(key)!; + getColumnType = (column: SchemaHeaderField): ColumnType => { + // added functionality to convert old column type stuff to new column type stuff -syip + if (column.type && column.type !== 0) { + return column.type; + } + if (columnTypes.get(column.heading)) { + column.type = columnTypes.get(column.heading)!; + return columnTypes.get(column.heading)!; + } const typesDoc = FieldValue(Cast(this.props.Document.schemaColumnTypes, Doc)); - if (!typesDoc) return ColumnType.Any; - return NumCast(typesDoc[key]); + if (!typesDoc) { + column.type = ColumnType.Any; + return ColumnType.Any; + } + column.type = NumCast(typesDoc[column.heading]); + return NumCast(typesDoc[column.heading]); } setColumnType = (key: string, type: ColumnType): void => { @@ -624,11 +653,11 @@ export class SchemaTable extends React.Component { } @action - setColumns = (columns: string[]) => { + setColumns = (columns: SchemaHeaderField[]) => { this.columns = columns; } - reorderColumns = (toMove: string, relativeTo: string, before: boolean, columnsValues: string[]) => { + reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => { let columns = [...columnsValues]; let oldIndex = columns.indexOf(toMove); let relIndex = columns.indexOf(relativeTo); @@ -661,7 +690,7 @@ export class SchemaTable extends React.Component { //TODO Types untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)))); - this.columns.forEach(key => keys[key] = true); + this.columns.forEach(key => keys[key.heading] = true); return Array.from(Object.keys(keys)); } @@ -727,7 +756,7 @@ export class SchemaTable extends React.Component { csv = csv.substr(0, csv.length - 1) + "\n"; let self = this; DocListCast(this.props.Document.data).map(doc => { - csv += self.columns.reduce((val, col) => val + (doc[col] ? doc[col]!.toString() : "0") + ",", ""); + csv += self.columns.reduce((val, col) => val + (doc[col.heading] ? doc[col.heading]!.toString() : "0") + ",", ""); csv = csv.substr(0, csv.length - 1) + "\n"; }); csv.substring(0, csv.length - 1); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 7677f53c1..e897c5676 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -16,7 +16,7 @@ import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; import { listSpec } from "../../../new_fields/Schema"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { SchemaHeaderField, RandomPastel } from "../../../new_fields/SchemaHeaderField"; import { List } from "../../../new_fields/List"; import { EditableView } from "../EditableView"; import { CollectionViewProps } from "./CollectionBaseView"; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b765517a2..2e54a9736 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -19,6 +19,7 @@ import { CollectionViewType } from "../CollectionBaseView"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); +import { SchemaHeaderField, RandomPastel } from "../../../../new_fields/SchemaHeaderField"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -134,7 +135,7 @@ export class MarqueeView extends React.Component doc.width = 200; docList.push(doc); } - let newCol = Docs.Create.SchemaDocument([...(groupAttr ? ["_group"] : []), ...columns.filter(c => c)], docList, { x: x, y: y, title: "droppedTable", width: 300, height: 100 }); + let newCol = Docs.Create.SchemaDocument([...(groupAttr ? [new SchemaHeaderField("_group")] : []), ...columns.filter(c => c).map(c => new SchemaHeaderField(c))], docList, { x: x, y: y, title: "droppedTable", width: 300, height: 100 }); this.props.addDocument(newCol, false); } diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx index afde85b69..0ea948c81 100644 --- a/src/client/views/nodes/LinkEditor.tsx +++ b/src/client/views/nodes/LinkEditor.tsx @@ -11,6 +11,7 @@ import { faArrowLeft, faEllipsisV, faTable, faTrash, faCog, faExchangeAlt, faTim import { library } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { SetupDrag } from "../../util/DragManager"; +import { SchemaHeaderField, RandomPastel } from "../../../new_fields/SchemaHeaderField"; library.add(faArrowLeft, faEllipsisV, faTable, faTrash, faCog, faExchangeAlt, faTimes, faPlus); @@ -289,7 +290,7 @@ export class LinkGroupEditor extends React.Component { let keys = LinkManager.Instance.getMetadataKeysInGroup(groupType); let index = keys.indexOf(""); if (index > -1) keys.splice(index, 1); - let cols = ["anchor1", "anchor2", ...[...keys]]; + let cols = ["anchor1", "anchor2", ...[...keys]].map(c => new SchemaHeaderField(c)); let docs: Doc[] = LinkManager.Instance.getAllMetadataDocsInGroup(groupType); let createTable = action(() => Docs.Create.SchemaDocument(cols, docs, { width: 500, height: 300, title: groupType + " table" })); let ref = React.createRef(); diff --git a/src/client/views/nodes/LinkMenuGroup.tsx b/src/client/views/nodes/LinkMenuGroup.tsx index ae97bed2f..3637807ad 100644 --- a/src/client/views/nodes/LinkMenuGroup.tsx +++ b/src/client/views/nodes/LinkMenuGroup.tsx @@ -14,6 +14,7 @@ import { Docs } from "../../documents/Documents"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { UndoManager } from "../../util/UndoManager"; import { StrCast } from "../../../new_fields/Types"; +import { SchemaHeaderField, RandomPastel } from "../../../new_fields/SchemaHeaderField"; interface LinkMenuGroupProps { sourceDoc: Doc; @@ -70,7 +71,7 @@ export class LinkMenuGroup extends React.Component { let keys = LinkManager.Instance.getMetadataKeysInGroup(groupType); let index = keys.indexOf(""); if (index > -1) keys.splice(index, 1); - let cols = ["anchor1", "anchor2", ...[...keys]]; + let cols = ["anchor1", "anchor2", ...[...keys]].map(c => new SchemaHeaderField(c)); let docs: Doc[] = LinkManager.Instance.getAllMetadataDocsInGroup(groupType); let createTable = action(() => Docs.Create.SchemaDocument(cols, docs, { width: 500, height: 300, title: groupType + " table" })); let ref = React.createRef(); diff --git a/src/new_fields/SchemaHeaderField.ts b/src/new_fields/SchemaHeaderField.ts index 284de3023..a6df31e81 100644 --- a/src/new_fields/SchemaHeaderField.ts +++ b/src/new_fields/SchemaHeaderField.ts @@ -3,13 +3,42 @@ import { serializable, createSimpleSchema, primitive } from "serializr"; import { ObjectField } from "./ObjectField"; import { Copy, ToScriptString, OnUpdate } from "./FieldSymbols"; import { scriptingGlobal, Scripting } from "../client/util/Scripting"; +import { ColumnType } from "../client/views/collections/CollectionSchemaView"; export const PastelSchemaPalette = new Map([ - ["purple", "#f5b5fc"], - ["green", "#96F7D2"], - ["yellow", "#F0F696"], - ["red", "#FCB1B1"] -]) + ["pink1", "#FFB4E8"], + ["pink2", "#ff9cee"], + ["pink3", "#ffccf9"], + ["pink4", "#fcc2ff"], + ["pink5", "#f6a6ff"], + ["purple1", "#b28dff"], + ["purple2", "#c5a3ff"], + ["purple3", "#d5aaff"], + ["purple4", "#ecd4ff"], + ["purple5", "#fb34ff"], + ["purple6", "#dcd3ff"], + ["purple7", "#a79aff"], + ["purple8", "#b5b9ff"], + ["purple9", "#97a2ff"], + ["bluegreen1", "#afcbff"], + ["bluegreen2", "#aff8db"], + ["bluegreen3", "#c4faf8"], + ["bluegreen4", "#85e3ff"], + ["bluegreen5", "#ace7ff"], + ["bluegreen6", "#6eb5ff"], + ["bluegreen7", "#bffcc6"], + ["bluegreen8", "#dbffd6"], + ["yellow1", "#f3ffe3"], + ["yellow2", "#e7ffac"], + ["yellow3", "#ffffd1"], + ["yellow4", "#fff5ba"], + ["red1", "#ffc9de"], + ["red2", "#ffabab"], + ["red3", "#ffbebc"], + ["red4", "#ffcbc1"], +]); + +export const RandomPastel = () => Array.from(PastelSchemaPalette.values())[Math.floor(Math.random() * PastelSchemaPalette.size)]; @scriptingGlobal @Deserializable("schemaheader") @@ -17,12 +46,19 @@ export class SchemaHeaderField extends ObjectField { @serializable(primitive()) heading: string; color: string; + type: number; - constructor(heading: string = "", color: string = Array.from(PastelSchemaPalette.values())[Math.floor(Math.random() * 4)]) { + constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType) { super(); this.heading = heading; this.color = color; + if (type) { + this.type = type; + } + else { + this.type = 0; + } } setHeading(heading: string) { @@ -35,8 +71,13 @@ export class SchemaHeaderField extends ObjectField { this[OnUpdate](); } + setType(type: ColumnType) { + this.type = type; + this[OnUpdate](); + } + [Copy]() { - return new SchemaHeaderField(this.heading, this.color); + return new SchemaHeaderField(this.heading, this.color, this.type); } [ToScriptString]() { -- cgit v1.2.3-70-g09d2