aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionSchemaHeaders.tsx
diff options
context:
space:
mode:
authorStanley Yip <33562077+yipstanley@users.noreply.github.com>2019-07-30 19:26:30 -0400
committerGitHub <noreply@github.com>2019-07-30 19:26:30 -0400
commit3549b22f40183bb9fbb715a187229ea0e8575718 (patch)
tree14cbe7263c6a792cce18cf3cd93da3071eab7835 /src/client/views/collections/CollectionSchemaHeaders.tsx
parent5ec18c73ec04d0f50cedb220518be9c58e62997c (diff)
parentb1848431fe96e2653590864cbf2127e1904df47b (diff)
Merge pull request #238 from browngraphicslab/schema_view_improvements_2
Schema view improvements 2
Diffstat (limited to 'src/client/views/collections/CollectionSchemaHeaders.tsx')
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx162
1 files changed, 94 insertions, 68 deletions
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index 387107c55..4f0681f6c 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -2,7 +2,7 @@ import React = require("react");
import { action, computed, observable, trace, untracked } from "mobx";
import { observer } from "mobx-react";
import "./CollectionSchemaView.scss";
-import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn } from '@fortawesome/free-solid-svg-icons';
+import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes } from '@fortawesome/free-solid-svg-icons';
import { library, IconProp } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Flyout, anchorPoints } from "../DocumentDecorations";
@@ -10,9 +10,9 @@ 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";
+import { SchemaHeaderField, RandomPastel, PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField";
-library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile);
+library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile, faSortAmountDown, faSortAmountUp, faTimes);
export interface HeaderProps {
keyValue: SchemaHeaderField;
@@ -23,23 +23,24 @@ export interface HeaderProps {
onSelect: (oldKey: string, newKey: string, addnew: boolean) => void;
setIsEditing: (isEditing: boolean) => void;
deleteColumn: (column: string) => void;
- setColumnType: (key: string, type: ColumnType) => void;
- setColumnSort: (key: string, desc: boolean) => void;
- removeColumnSort: (key: string) => void;
+ setColumnType: (column: SchemaHeaderField, type: ColumnType) => void;
+ setColumnSort: (column: SchemaHeaderField, desc: boolean | undefined) => void;
+ setColumnColor: (column: SchemaHeaderField, color: string) => void;
+
}
export class CollectionSchemaHeader extends React.Component<HeaderProps> {
render() {
let icon: IconProp = this.props.keyType === ColumnType.Number ? "hashtag" : this.props.keyType === ColumnType.String ? "font" :
this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "file" : "align-justify";
-
return (
<div className="collectionSchemaView-header" style={{ background: this.props.keyValue.color }}>
<CollectionSchemaColumnMenu
- keyValue={this.props.keyValue.heading}
+ columnField={this.props.keyValue}
+ // keyValue={this.props.keyValue.heading}
possibleKeys={this.props.possibleKeys}
existingKeys={this.props.existingKeys}
- keyType={this.props.keyType}
+ // keyType={this.props.keyType}
typeConst={this.props.typeConst}
menuButtonContent={<div><FontAwesomeIcon icon={icon} size="sm" />{this.props.keyValue.heading}</div>}
addNew={false}
@@ -49,7 +50,7 @@ export class CollectionSchemaHeader extends React.Component<HeaderProps> {
onlyShowOptions={false}
setColumnType={this.props.setColumnType}
setColumnSort={this.props.setColumnSort}
- removeColumnSort={this.props.removeColumnSort}
+ setColumnColor={this.props.setColumnColor}
/>
</div>
);
@@ -70,13 +71,12 @@ export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHe
}
}
-
-
export interface ColumnMenuProps {
- keyValue: string;
+ columnField: SchemaHeaderField;
+ // keyValue: string;
possibleKeys: string[];
existingKeys: string[];
- keyType: ColumnType;
+ // keyType: ColumnType;
typeConst: boolean;
menuButtonContent: JSX.Element;
addNew: boolean;
@@ -84,10 +84,10 @@ export interface ColumnMenuProps {
setIsEditing: (isEditing: boolean) => void;
deleteColumn: (column: string) => void;
onlyShowOptions: boolean;
- setColumnType: (key: string, type: ColumnType) => void;
- setColumnSort: (key: string, desc: boolean) => void;
- removeColumnSort: (key: string) => void;
+ setColumnType: (column: SchemaHeaderField, type: ColumnType) => void;
+ setColumnSort: (column: SchemaHeaderField, desc: boolean | undefined) => void;
anchorPoint?: any;
+ setColumnColor: (column: SchemaHeaderField, color: string) => void;
}
@observer
export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps> {
@@ -116,10 +116,16 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
this.props.setIsEditing(this._isOpen);
}
- setColumnType = (oldKey: string, newKey: string, addnew: boolean) => {
- let typeStr = newKey as keyof typeof ColumnType;
- let type = ColumnType[typeStr];
- this.props.setColumnType(this.props.keyValue, type);
+ changeColumnType = (type: ColumnType): void => {
+ this.props.setColumnType(this.props.columnField, type);
+ }
+
+ changeColumnSort = (desc: boolean | undefined): void => {
+ this.props.setColumnSort(this.props.columnField, desc);
+ }
+
+ changeColumnColor = (color: string): void => {
+ this.props.setColumnColor(this.props.columnField, color);
}
@action
@@ -129,78 +135,82 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
}
}
- changeColumnColor = (color: string): void => {
-
- }
-
renderTypes = () => {
if (this.props.typeConst) return <></>;
+
+ let type = this.props.columnField.type;
return (
<div className="collectionSchema-headerMenu-group">
<label>Column type:</label>
<div className="columnMenu-types">
- <button title="Any" className={this.props.keyType === ColumnType.Any ? "active" : ""} onClick={() => this.props.setColumnType(this.props.keyValue, ColumnType.Any)}>
+ <div className={"columnMenu-option" + (type === ColumnType.Any ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Any)}>
<FontAwesomeIcon icon={"align-justify"} size="sm" />
- </button>
- <button title="Number" className={this.props.keyType === ColumnType.Number ? "active" : ""} onClick={() => this.props.setColumnType(this.props.keyValue, ColumnType.Number)}>
+ Any
+ </div>
+ <div className={"columnMenu-option" + (type === ColumnType.Number ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Number)}>
<FontAwesomeIcon icon={"hashtag"} size="sm" />
- </button>
- <button title="String" className={this.props.keyType === ColumnType.String ? "active" : ""} onClick={() => this.props.setColumnType(this.props.keyValue, ColumnType.String)}>
+ Number
+ </div>
+ <div className={"columnMenu-option" + (type === ColumnType.String ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.String)}>
<FontAwesomeIcon icon={"font"} size="sm" />
- </button>
- <button title="Checkbox" className={this.props.keyType === ColumnType.Boolean ? "active" : ""} onClick={() => this.props.setColumnType(this.props.keyValue, ColumnType.Boolean)}>
+ Text
+ </div>
+ <div className={"columnMenu-option" + (type === ColumnType.Boolean ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Boolean)}>
<FontAwesomeIcon icon={"check-square"} size="sm" />
- </button>
- <button title="Document" className={this.props.keyType === ColumnType.Doc ? "active" : ""} onClick={() => this.props.setColumnType(this.props.keyValue, ColumnType.Doc)}>
+ Checkbox
+ </div>
+ <div className={"columnMenu-option" + (type === ColumnType.Doc ? " active" : "")} onClick={() => this.changeColumnType(ColumnType.Doc)}>
<FontAwesomeIcon icon={"file"} size="sm" />
- </button>
+ Document
+ </div>
</div>
- </div>
+ </div >
);
}
renderSorting = () => {
+ let sort = this.props.columnField.desc;
return (
<div className="collectionSchema-headerMenu-group">
<label>Sort by:</label>
<div className="columnMenu-sort">
- <div className="columnMenu-option" onClick={() => this.props.setColumnSort(this.props.keyValue, false)}>Sort ascending</div>
- <div className="columnMenu-option" onClick={() => this.props.setColumnSort(this.props.keyValue, true)}>Sort descending</div>
- <div className="columnMenu-option" onClick={() => this.props.removeColumnSort(this.props.keyValue)}>Clear sorting</div>
+ <div className={"columnMenu-option" + (sort === true ? " active" : "")} onClick={() => this.changeColumnSort(true)}>
+ <FontAwesomeIcon icon="sort-amount-down" size="sm" />
+ Sort descending
+ </div>
+ <div className={"columnMenu-option" + (sort === false ? " active" : "")} onClick={() => this.changeColumnSort(false)}>
+ <FontAwesomeIcon icon="sort-amount-up" size="sm" />
+ Sort ascending
+ </div>
+ <div className="columnMenu-option" onClick={() => this.changeColumnSort(undefined)}>
+ <FontAwesomeIcon icon="times" size="sm" />
+ Clear sorting
+ </div>
</div>
</div>
);
}
renderColors = () => {
+ let selected = this.props.columnField.color;
+
+ let pink = PastelSchemaPalette.get("pink2");
+ let purple = PastelSchemaPalette.get("purple2");
+ let blue = PastelSchemaPalette.get("bluegreen1");
+ let yellow = PastelSchemaPalette.get("yellow4");
+ let red = PastelSchemaPalette.get("red2");
+ let gray = "#f1efeb";
+
return (
<div className="collectionSchema-headerMenu-group">
<label>Color:</label>
<div className="columnMenu-colors">
- <input type="radio" name="column-color" id="pink" value="#FFB4E8" onClick={() => this.changeColumnColor("#FFB4E8")} />
- <label htmlFor="pink">
- <div className="columnMenu-colorPicker" style={{ backgroundColor: "#FFB4E8" }}></div>
- </label>
- <input type="radio" name="column-color" id="purple" value="#b28dff" onClick={() => this.changeColumnColor("#b28dff")} />
- <label htmlFor="purple">
- <div className="columnMenu-colorPicker" style={{ backgroundColor: "#FFB4E8" }}></div>
- </label>
- <input type="radio" name="column-color" id="blue" value="#afcbff" onClick={() => this.changeColumnColor("#afcbff")} />
- <label htmlFor="blue">
- <div className="columnMenu-colorPicker" style={{ backgroundColor: "#FFB4E8" }}></div>
- </label>
- <input type="radio" name="column-color" id="yellow" value="#f3ffe3" onClick={() => this.changeColumnColor("#f3ffe3")} />
- <label htmlFor="yellow">
- <div className="columnMenu-colorPicker" style={{ backgroundColor: "#FFB4E8" }}></div>
- </label>
- <input type="radio" name="column-color" id="red" value="#ffc9de" onClick={() => this.changeColumnColor("#ffc9de")} />
- <label htmlFor="red">
- <div className="columnMenu-colorPicker" style={{ backgroundColor: "#FFB4E8" }}></div>
- </label>
- <input type="radio" name="column=color" id="none" value="#f1efeb" onClick={() => this.changeColumnColor("#f1efeb")} />
- <label htmlFor="none">
- <div className="columnMenu-colorPicker" style={{ backgroundColor: "#FFB4E8" }}></div>
- </label>
+ <div className={"columnMenu-colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.changeColumnColor(pink!)}></div>
+ <div className={"columnMenu-colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.changeColumnColor(purple!)}></div>
+ <div className={"columnMenu-colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.changeColumnColor(blue!)}></div>
+ <div className={"columnMenu-colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.changeColumnColor(yellow!)}></div>
+ <div className={"columnMenu-colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.changeColumnColor(red!)}></div>
+ <div className={"columnMenu-colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.changeColumnColor(gray)}></div>
</div>
</div>
);
@@ -209,10 +219,10 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
renderContent = () => {
return (
<div className="collectionSchema-header-menuOptions">
- <label>Key:</label>
<div className="collectionSchema-headerMenu-group">
+ <label>Key:</label>
<KeysDropdown
- keyValue={this.props.keyValue}
+ keyValue={this.props.columnField.heading}
possibleKeys={this.props.possibleKeys}
existingKeys={this.props.existingKeys}
canAddNew={true}
@@ -227,7 +237,7 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
{this.renderSorting()}
{this.renderColors()}
<div className="collectionSchema-headerMenu-group">
- <button onClick={() => this.props.deleteColumn(this.props.keyValue)}>Delete Column</button>
+ <button onClick={() => this.props.deleteColumn(this.props.columnField.heading)}>Delete Column</button>
</div>
</>
}
@@ -259,9 +269,10 @@ interface KeysDropdownProps {
@observer
class KeysDropdown extends React.Component<KeysDropdownProps> {
@observable private _key: string = this.props.keyValue;
- @observable private _searchTerm: string = "";
+ @observable private _searchTerm: string = this.props.keyValue;
@observable private _isOpen: boolean = false;
@observable private _canClose: boolean = true;
+ @observable private _inputRef: React.RefObject<HTMLInputElement> = React.createRef();
@action setSearchTerm = (value: string): void => { this._searchTerm = value; };
@action setKey = (key: string): void => { this._key = key; };
@@ -275,6 +286,21 @@ class KeysDropdown extends React.Component<KeysDropdownProps> {
this.props.setIsEditing(false);
}
+ @action
+ onKeyDown = (e: React.KeyboardEvent): void => {
+ if (e.key === "Enter") {
+ let keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ let exactFound = keyOptions.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1 ||
+ this.props.existingKeys.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
+
+ if (!exactFound && this._searchTerm !== "" && this.props.canAddNew) {
+ this.onSelect(this._searchTerm);
+ } else {
+ this._searchTerm = this._key;
+ }
+ }
+ }
+
onChange = (val: string): void => {
this.setSearchTerm(val);
}
@@ -327,7 +353,7 @@ class KeysDropdown extends React.Component<KeysDropdownProps> {
render() {
return (
<div className="keys-dropdown">
- <input className="keys-search" type="text" value={this._searchTerm} placeholder="Search for or create a new key"
+ <input className="keys-search" ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
onChange={e => this.onChange(e.target.value)} onFocus={this.onFocus} onBlur={this.onBlur}></input>
<div className="keys-options-wrapper" onPointerEnter={this.onPointerEnter} onPointerOut={this.onPointerOut}>
{this.renderOptions()}