From b1362ef23d2a31f52c21647e4a4931f091849d9b Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 13 Jun 2016 22:08:52 +0200 Subject: [PATCH 01/52] INT-1160: Adding UI for edit/delete top level element --- package.json | 7 +- src/app/index.less | 2 + .../crud/lib/component/document-list-item.jsx | 81 ++++++++++++++ .../crud/lib/component/document-list.jsx | 45 +------- .../crud/lib/component/editable-element.jsx | 104 ++++++++++++++++++ .../crud/lib/component/editable-key.jsx | 85 ++++++++++++++ .../crud/lib/component/editable-value.jsx | 84 ++++++++++++++ src/internal-packages/crud/styles/crud.less | 104 ++++++++++++++++++ 8 files changed, 465 insertions(+), 47 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/document-list-item.jsx create mode 100644 src/internal-packages/crud/lib/component/editable-element.jsx create mode 100644 src/internal-packages/crud/lib/component/editable-key.jsx create mode 100644 src/internal-packages/crud/lib/component/editable-value.jsx create mode 100644 src/internal-packages/crud/styles/crud.less diff --git a/package.json b/package.json index d044586b466..8c5b8fa6fb3 100644 --- a/package.json +++ b/package.json @@ -100,10 +100,11 @@ "electron-squirrel-startup": "^0.1.4", "font-awesome": "https://github.com/FortAwesome/Font-Awesome/archive/v4.4.0.tar.gz", "get-object-path": "azer/get-object-path#74eb42de0cfd02c14ffdd18552f295aba723d394", - "hadron-action": "^0.0.2", + "hadron-action": "^0.0.4", "hadron-auto-update-manager": "^0.0.12", + "hadron-document": "^0.2.0", "hadron-compile-cache": "^0.1.0", - "hadron-component-registry": "^0.2.0", + "hadron-component-registry": "^0.2.1", "hadron-ipc": "^0.0.7", "hadron-module-cache": "^0.0.3", "hadron-package-manager": "0.1.0", @@ -120,7 +121,7 @@ "marky-mark": "^1.2.1", "moment": "^2.10.6", "mongodb-collection-model": "^0.2.3", - "mongodb-connection-model": "^4.2.0", + "mongodb-connection-model": "^4.3.0", "mongodb-data-service": "^0.2.1", "mongodb-database-model": "^0.1.2", "mongodb-explain-plan-model": "^0.2.0", diff --git a/src/app/index.less b/src/app/index.less index eff4a442be6..467bb27d09d 100644 --- a/src/app/index.less +++ b/src/app/index.less @@ -22,3 +22,5 @@ @import "../auto-update/index.less"; @import "../help/index.less"; @import "metrics/index.less"; + +@import "../internal-packages/crud/styles/crud.less"; diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx new file mode 100644 index 00000000000..eda75a51794 --- /dev/null +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -0,0 +1,81 @@ +'use strict'; + +const _ = require('lodash'); +const React = require('react'); +const ElementFactory = require('hadron-component-registry').ElementFactory; +const HadronDocument = require('hadron-document'); +const EditableElement = require('./editable-element'); + +/** + * The class for the document itself. + */ +const DOCUMENT_CLASS = 'document-property-body'; + +/** + * The class for the list item wrapper. + */ +const LIST_ITEM_CLASS = 'document-list-item'; + +/** + * Component for a single document in a list of documents. + */ +class DocumentListItem extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.state = { doc: props.doc, editing: false }; + } + + /** + * Render a single document list item. + */ + render() { + return ( +
  • +
      +
      + {this.elements()} +
      +
      + + +
      +
    +
  • + ); + } + + elements() { + if (this.state.editing) { + return this.editableElements(this.state.doc); + } + return ElementFactory.elements(this.state.doc); + } + + editableElements() { + return _.map(this.state.doc.elements, (element, index) => { + return React.createElement( + EditableElement, + { key: `${this.state.doc._id}_${element.key}`, element: element, lineNumber: index + 1 } + ); + }); + } + + editDocument() { + var doc = new HadronDocument(this.props.doc); + this.setState({ doc: doc, editing: true }); + } + + deleteDocument() { + + } +} + +DocumentListItem.displayName = 'DocumentListItem'; + +module.exports = DocumentListItem; diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index 573aa47061b..5dca238d8ff 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -4,8 +4,8 @@ const _ = require('lodash'); const React = require('react'); const ReactDOM = require('react-dom'); const app = require('ampersand-app'); -const ElementFactory = require('hadron-component-registry').ElementFactory; const Action = require('hadron-action'); +const DocumentListItem = require('./document-list-item'); const DocumentListStore = require('../store/document-list-store'); /** @@ -118,12 +118,6 @@ class DocumentList extends React.Component { // from the end of the list, we will fire the event to load more documents. this._nextBatch(); } - // Bonus: if we have passed a certain number of docs that are out of view: - // this._unloadPreviousBatch(); - // Bonus: if we are scrolling back up and are running out of previous docs: - // this._previousBatch(); - // Bonus: if we are scrolling up and docs below are out of view: - // this._unloadNextBatch(); } /** @@ -150,44 +144,7 @@ class DocumentList extends React.Component { } } -/** - * The class for the document itself. - */ -const DOCUMENT_CLASS = 'document-property-body'; - -/** - * The class for the list item wrapper. - */ -const LIST_ITEM_CLASS = 'document-list-item'; - -/** - * Component for a single document in a list of documents. - */ -class DocumentListItem extends React.Component { - - /** - * Render a single document list item. - */ - render() { - return ( -
  • -
      - {ElementFactory.elements(this.props.doc)} -
    -
  • - ); - } -} - -/** - * Set the display names for all components. - */ DocumentList.displayName = 'DocumentList'; -DocumentListItem.displayName = 'DocumentListItem'; - -/** - * Set the child components. - */ DocumentList.DocumentListItem = DocumentListItem; module.exports = DocumentList; diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx new file mode 100644 index 00000000000..4da9ec272ac --- /dev/null +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -0,0 +1,104 @@ +'use strict'; + +const React = require('react'); +const TypeChecker = require('hadron-component-registry').TypeChecker; +const Element = require('hadron-document').Element; +const EditableKey = require('./editable-key'); +const EditableValue = require('./editable-value'); + +/** + * The added constant. + */ +const ADDED = 'added'; + +/** + * The edited constant. + */ +const EDITED = 'edited'; + +/** + * The removed constant. + */ +const REMOVED = 'removed'; + +/** + * The editing class constant. + */ +const EDITING = 'editing'; + +/** + * The property class. + */ +const PROPERTY_CLASS = 'document-property'; + +/** + * General editable element component. + */ +class EditableElement extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + this.state = { type: TypeChecker.type(this.element.currentValue) }; + + this.element.on(Element.Events.Edited, this.handleEdit.bind(this)); + } + + /** + * Render a single editable element. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
  • +
    +
    x
    + + : + +
    {this.state.type}
    +
  • + ); + } + + handleEdit() { + this.setState({}); + } + + /** + * Handle removal of an element. + */ + handleRemove() { + this.element.remove(); + this.setState({}); + } + + /** + * Get the style for the element component. + * + * @returns {String} The element style. + */ + style() { + var style = `${PROPERTY_CLASS} ${this.state.type.toLowerCase()}`; + if (this.element.isAdded()) { + style = style.concat(` ${ADDED}`); + } + if (this.element.isEdited()) { + style = style.concat(` ${EDITED}`); + } + if (this.element.isRemoved()) { + style = style.concat(` ${REMOVED}`); + } + return style; + } +} + +EditableElement.displayName = 'EditableElement'; + +module.exports = EditableElement; diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx new file mode 100644 index 00000000000..9cc6449fcdb --- /dev/null +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -0,0 +1,85 @@ +'use strict'; + +const React = require('react'); + +/** + * The editing class constant. + */ +const EDITING = 'editing'; + +/** + * The document key class. + */ +const KEY_CLASS = 'editable-key'; + +/** + * General editable key component. + */ +class EditableKey extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + this.state = { key: this.element.currentKey, editing: false }; + } + + /** + * Render a single editable key. + * + * @returns {React.Component} The element component. + */ + render() { + return ( + + ); + } + + /** + * Handles changes to the element key. + * + * @param {Event} evt - The event. + */ + handleChange(evt) { + this.element.edit(evt.target.value, this.element.currentValue); + this.setState({ key: this.element.currentKey }); + } + + /** + * Handle focus on the key. + */ + handleFocus() { + this.setState({ editing: true }); + } + + /** + * Handle blur from the key. + */ + handleBlur() { + this.setState({ editing: false }); + } + + /** + * Get the style for the key of the element. + * + * @returns {String} The key style. + */ + style() { + return this.state.editing ? `${KEY_CLASS} ${EDITING}` : KEY_CLASS; + } +} + +EditableKey.displayName = 'EditableKey'; + +module.exports = EditableKey; diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx new file mode 100644 index 00000000000..9c446904c06 --- /dev/null +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -0,0 +1,84 @@ +'use strict'; + +const React = require('react'); + +/** + * The editing class constant. + */ +const EDITING = 'editing'; + +/** + * The document value class. + */ +const VALUE_CLASS = 'editable-value'; + +/** + * General editable value component. + */ +class EditableValue extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + this.state = { value: this.element.currentValue, editing: false }; + } + + /** + * Render a single editable value. + * + * @returns {React.Component} The element component. + */ + render() { + return ( + + ); + } + + /** + * Handles changes to the element value. + * + * @param {Event} evt - The event. + */ + handleChange(evt) { + this.element.edit(this.element.currentKey, evt.target.value); + this.setState({ value: this.element.currentValue }); + } + + /** + * Handle focus on the value. + */ + handleFocus() { + this.setState({ editing: true }); + } + + /** + * Handle blur from the value. + */ + handleBlur() { + this.setState({ editing: false }); + } + + /** + * Get the style for the value of the element. + * + * @returns {String} The value style. + */ + style() { + return this.state.editing ? `${VALUE_CLASS} ${EDITING}` : VALUE_CLASS; + } +} + +EditableValue.displayName = 'EditableValue'; + +module.exports = EditableValue; diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less new file mode 100644 index 00000000000..8b9ba304700 --- /dev/null +++ b/src/internal-packages/crud/styles/crud.less @@ -0,0 +1,104 @@ +.document-elements { + float: left; + width: 75%; + counter-reset: line; + + .line-number { + display: inline-block; + color: #999999; + width: 18px; + text-align: center; + + &::before { + counter-increment: line; + content: counter(line); + } + } + + .actions { + display: inline-block; + width: 18px; + text-align: center; + cursor: pointer; + } + + .types { + display: inline-block; + float: right; + width: 100px; + color: #999999; + } + + li.document-property { + + &.edited { + background-color: #FFEFD5; + + input { + background-color: #FFEFD5; + } + + .line-number { + background-color: #FFA500; + color: #FFFFFF; + } + } + + &.removed { + background-color: #FFB6C1; + + input { + background-color: #FFB6C1; + } + + .line-number { + background-color: #FF0000; + color: #FFFFFF; + } + } + } +} + +.document-actions { + float: right; + padding-right: 10px; +} + +input.editable-key { + font-weight: bold; + border: none; + padding-left: 1px; + + &.editing { + border: 1px solid #999999; + box-shadow: 0px 2px 4px 0px #999999; + margin-bottom: 4px; + } +} + +input.editable-value { + border: none; + padding-left: 1px; + + &.editing { + border: 1px solid #999999; + box-shadow: 0px 2px 4px 0px #999999; + margin-bottom: 4px; + } +} + +.document-property.string > .editable-value { + color: steelblue; +} + +.document-property.number > .editable-value { + color: green; +} + +.document-property.boolean > .editable-value { + color: purple; +} + +.document-property.date > .editable-value { + color: firebrick; +} From f5d5185519ef4a46c4a35af0310e9279ba9a41f0 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 13 Jun 2016 22:40:44 +0200 Subject: [PATCH 02/52] INT-1160: Handling embedded elements --- .../crud/lib/component/document-list-item.jsx | 4 ++-- .../crud/lib/component/editable-element.jsx | 22 ++++++++++++++++++- src/internal-packages/crud/styles/crud.less | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index eda75a51794..fc8a017cdaa 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -58,10 +58,10 @@ class DocumentListItem extends React.Component { } editableElements() { - return _.map(this.state.doc.elements, (element, index) => { + return _.map(this.state.doc.elements, (element) => { return React.createElement( EditableElement, - { key: `${this.state.doc._id}_${element.key}`, element: element, lineNumber: index + 1 } + { key: `${this.state.doc._id}_${element.key}`, element: element } ); }); } diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index 4da9ec272ac..91d9e654153 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -61,12 +61,32 @@ class EditableElement extends React.Component {
    x
    : - + {this.editableValue()}
    {this.state.type}
    ); } + editableValue() { + if (this.element.elements) { + return React.createElement('ol', {}, this.childElements()); + } + return React.createElement(EditableValue, { element: this.element }); + } + + childElements() { + return _.map(this.element.elements, (element) => { + console.log(element); + return React.createElement( + EditableElement, + { key: `${this.element.key}_${element.key}`, element: element } + ); + }); + } + + /** + * Handle an edit to the element. + */ handleEdit() { this.setState({}); } diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 8b9ba304700..ca3c594c2e1 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -20,6 +20,7 @@ width: 18px; text-align: center; cursor: pointer; + color: #999999; } .types { From dfa741cc8a42e344be8258600d42d8e14128f151 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 14 Jun 2016 00:45:09 +0200 Subject: [PATCH 03/52] INT-1160: Bringing in expandable editables --- package.json | 2 +- .../crud/lib/component/document-list-item.jsx | 37 ++++- .../crud/lib/component/editable-element.jsx | 28 +--- .../component/editable-expandable-element.jsx | 148 ++++++++++++++++++ 4 files changed, 184 insertions(+), 31 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/editable-expandable-element.jsx diff --git a/package.json b/package.json index 8c5b8fa6fb3..33eaa3e8d74 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "get-object-path": "azer/get-object-path#74eb42de0cfd02c14ffdd18552f295aba723d394", "hadron-action": "^0.0.4", "hadron-auto-update-manager": "^0.0.12", - "hadron-document": "^0.2.0", + "hadron-document": "^0.3.0", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.2.1", "hadron-ipc": "^0.0.7", diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index fc8a017cdaa..04a815e3f1c 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -5,6 +5,7 @@ const React = require('react'); const ElementFactory = require('hadron-component-registry').ElementFactory; const HadronDocument = require('hadron-document'); const EditableElement = require('./editable-element'); +const EditableExpandableElement = require('./editable-expandable-element'); /** * The class for the document itself. @@ -42,7 +43,7 @@ class DocumentListItem extends React.Component { {this.elements()}
    - +
    @@ -50,6 +51,12 @@ class DocumentListItem extends React.Component { ); } + /** + * Get the elements for the document. If we are editing, we get editable elements, + * otherwise the readonly elements are returned. + * + * @returns {Array} The elements. + */ elements() { if (this.state.editing) { return this.editableElements(this.state.doc); @@ -57,16 +64,21 @@ class DocumentListItem extends React.Component { return ElementFactory.elements(this.state.doc); } + /** + * Get the editable elements. + * + * @returns {Array} The editable elements. + */ editableElements() { return _.map(this.state.doc.elements, (element) => { - return React.createElement( - EditableElement, - { key: `${this.state.doc._id}_${element.key}`, element: element } - ); + return this.elementComponent(element); }); } - editDocument() { + /** + * Handle the editing of the document. + */ + handleEdit() { var doc = new HadronDocument(this.props.doc); this.setState({ doc: doc, editing: true }); } @@ -74,6 +86,19 @@ class DocumentListItem extends React.Component { deleteDocument() { } + + /** + * Get the component for the element value. + * + * @returns {EditableValue,EditableExpandableElement} The element. + */ + elementComponent(element) { + var key = `${this.props.doc._id}_${element.key}`; + if (element.elements) { + return React.createElement(EditableExpandableElement, { key: key, element: element }); + } + return React.createElement(EditableElement, { key: key, element: element }); + } } DocumentListItem.displayName = 'DocumentListItem'; diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index 91d9e654153..0ed7b51d35d 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -1,7 +1,6 @@ 'use strict'; const React = require('react'); -const TypeChecker = require('hadron-component-registry').TypeChecker; const Element = require('hadron-document').Element; const EditableKey = require('./editable-key'); const EditableValue = require('./editable-value'); @@ -44,8 +43,6 @@ class EditableElement extends React.Component { constructor(props) { super(props); this.element = props.element; - this.state = { type: TypeChecker.type(this.element.currentValue) }; - this.element.on(Element.Events.Edited, this.handleEdit.bind(this)); } @@ -61,31 +58,14 @@ class EditableElement extends React.Component {
    x
    : - {this.editableValue()} -
    {this.state.type}
    + +
    {this.element.currentType}
    ); } - editableValue() { - if (this.element.elements) { - return React.createElement('ol', {}, this.childElements()); - } - return React.createElement(EditableValue, { element: this.element }); - } - - childElements() { - return _.map(this.element.elements, (element) => { - console.log(element); - return React.createElement( - EditableElement, - { key: `${this.element.key}_${element.key}`, element: element } - ); - }); - } - /** - * Handle an edit to the element. + * Here to re-render the component when a key or value is edited. */ handleEdit() { this.setState({}); @@ -105,7 +85,7 @@ class EditableElement extends React.Component { * @returns {String} The element style. */ style() { - var style = `${PROPERTY_CLASS} ${this.state.type.toLowerCase()}`; + var style = `${PROPERTY_CLASS} ${this.element.currentType.toLowerCase()}`; if (this.element.isAdded()) { style = style.concat(` ${ADDED}`); } diff --git a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx new file mode 100644 index 00000000000..98f6836af8e --- /dev/null +++ b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx @@ -0,0 +1,148 @@ +'use strict'; + +const React = require('react'); +const Element = require('hadron-document').Element; +const EditableKey = require('./editable-key'); +const EditableElement = require('./editable-element'); + +/** + * The added constant. + */ +const ADDED = 'added'; + +/** + * The edited constant. + */ +const EDITED = 'edited'; + +/** + * The removed constant. + */ +const REMOVED = 'removed'; + +/** + * The class for the document itself. + */ +const DOCUMENT_CLASS = 'document-property-body'; + +/** + * The header class for expandable elements. + */ +const HEADER_CLASS = 'document-property-header'; + +/** + * The caret for expanding elements. + */ +const CARET = 'caret'; + +/** + * The expanded class name. + */ +const EXPANDED = 'expanded'; + +/** + * The property class. + */ +const PROPERTY_CLASS = 'document-property'; + +/** + * The expandable label class. + */ +const LABEL_CLASS = 'document-property-type-label'; + +/** + * General editable expandable element component. + */ +class EditableExpandableElement extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + this.state = { expanded: false }; + this.element.on(Element.Events.Edited, this.handleEdit.bind(this)); + } + + /** + * Render a single editable element. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
  • +
    +
    +
    x
    +
    + + : +
    + {this.element.currentType} +
    +
    +
  • + ); + } + + elementComponents() { + return _.map(this.element.elements, (element) => { + return React.createElement( + EditableElement, + { key: `${this.element.key}_${element.key}`, element: element } + ); + }); + } + + /** + * Toggles the expandable aspect of the element. + */ + toggleExpandable() { + this.setState({ expanded: !this.state.expanded }); + } + + /** + * Here to re-render the component when a key or value is edited. + */ + handleEdit() { + this.setState({}); + } + + /** + * Handle removal of an element. + */ + handleRemove() { + this.element.remove(); + this.setState({}); + } + + /** + * Get the style for the element component. + * + * @returns {String} The element style. + */ + style() { + var style = `${PROPERTY_CLASS} ${this.element.currentType.toLowerCase()}`; + if (this.element.isAdded()) { + style = style.concat(` ${ADDED}`); + } + if (this.element.isEdited()) { + style = style.concat(` ${EDITED}`); + } + if (this.element.isRemoved()) { + style = style.concat(` ${REMOVED}`); + } + if (this.state.expanded) { + style = style.concat(` ${EXPANDED}`); + } + return style; + } +} + +EditableExpandableElement.displayName = 'EditableExpandableElement'; + +module.exports = EditableExpandableElement; From dc7b0078acc4c45ba989a8e0375de7b05a8931b2 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 14 Jun 2016 01:09:59 +0200 Subject: [PATCH 04/52] INT-1160: Split rename and edit actions --- package.json | 2 +- src/internal-packages/crud/lib/component/editable-key.jsx | 2 +- src/internal-packages/crud/lib/component/editable-value.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 33eaa3e8d74..d94bc39c707 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "get-object-path": "azer/get-object-path#74eb42de0cfd02c14ffdd18552f295aba723d394", "hadron-action": "^0.0.4", "hadron-auto-update-manager": "^0.0.12", - "hadron-document": "^0.3.0", + "hadron-document": "^0.4.0", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.2.1", "hadron-ipc": "^0.0.7", diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 9cc6449fcdb..4158e1cf6bb 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -52,7 +52,7 @@ class EditableKey extends React.Component { * @param {Event} evt - The event. */ handleChange(evt) { - this.element.edit(evt.target.value, this.element.currentValue); + this.element.rename(evt.target.value); this.setState({ key: this.element.currentKey }); } diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index 9c446904c06..a0d2260dec9 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -51,7 +51,7 @@ class EditableValue extends React.Component { * @param {Event} evt - The event. */ handleChange(evt) { - this.element.edit(this.element.currentKey, evt.target.value); + this.element.edit(evt.target.value); this.setState({ value: this.element.currentValue }); } From 3ea2a122181aac8e714a2018234188c319d2476a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 14 Jun 2016 01:52:34 +0200 Subject: [PATCH 05/52] INT-1160: Adding static footer --- .../component/document-list-item-footer.jsx | 38 +++++++++++++++++++ .../crud/lib/component/document-list-item.jsx | 5 +++ .../component/editable-expandable-element.jsx | 8 ++++ src/internal-packages/crud/styles/crud.less | 13 +++++++ 4 files changed, 64 insertions(+) create mode 100644 src/internal-packages/crud/lib/component/document-list-item-footer.jsx diff --git a/src/internal-packages/crud/lib/component/document-list-item-footer.jsx b/src/internal-packages/crud/lib/component/document-list-item-footer.jsx new file mode 100644 index 00000000000..5993411d6e2 --- /dev/null +++ b/src/internal-packages/crud/lib/component/document-list-item-footer.jsx @@ -0,0 +1,38 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the document footer. + */ +class DocumentListItemFooter extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render a single document list item. + */ + render() { + return ( +
    +
    +
    + + +
    +
    + ); + } + +} + +DocumentListItemFooter.displayName = 'DocumentListItemFooter'; + +module.exports = DocumentListItemFooter; diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index 04a815e3f1c..375969a91e8 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -47,6 +47,7 @@ class DocumentListItem extends React.Component { + {this.footer()} ); } @@ -75,6 +76,10 @@ class DocumentListItem extends React.Component { }); } + footer() { + + } + /** * Handle the editing of the document. */ diff --git a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx index 98f6836af8e..7072c150afa 100644 --- a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx @@ -84,11 +84,19 @@ class EditableExpandableElement extends React.Component {
    {this.element.currentType}
    +
      + {this.elementComponents()} +
    ); } + /** + * Get the components for the elements. + * + * @returns {Array} The components. + */ elementComponents() { return _.map(this.element.elements, (element) => { return React.createElement( diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index ca3c594c2e1..938172e5247 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -1,3 +1,16 @@ +.document-footer { + height: 20px; + + .edit-message { + float: left; + } + + .document-actions { + float: right; + padding-right: 10px; + } +} + .document-elements { float: left; width: 75%; From d2ea4b40db10915f7c825f98baa9f9ff63ef25b7 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 14 Jun 2016 14:14:08 +0200 Subject: [PATCH 06/52] INT-1160: Element can be removed or reverted --- .../crud/lib/component/editable-element.jsx | 26 ++++++++++- .../crud/lib/component/remove-action.jsx | 46 +++++++++++++++++++ .../crud/lib/component/revert-action.jsx | 46 +++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/remove-action.jsx create mode 100644 src/internal-packages/crud/lib/component/revert-action.jsx diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index 0ed7b51d35d..081529c4e39 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -4,6 +4,8 @@ const React = require('react'); const Element = require('hadron-document').Element; const EditableKey = require('./editable-key'); const EditableValue = require('./editable-value'); +const RevertAction = require('./revert-action'); +const RemoveAction = require('./remove-action'); /** * The added constant. @@ -44,6 +46,8 @@ class EditableElement extends React.Component { super(props); this.element = props.element; this.element.on(Element.Events.Edited, this.handleEdit.bind(this)); + this.element.on(Element.Events.Removed, this.handleRemove.bind(this)); + this.element.on(Element.Events.Reverted, this.handleRevert.bind(this)); } /** @@ -55,7 +59,7 @@ class EditableElement extends React.Component { return (
  • -
    x
    + {this.action()} : @@ -64,6 +68,18 @@ class EditableElement extends React.Component { ); } + /** + * Get the revert or remove action. + * + * @returns {Component} The component. + */ + action() { + if (this.element.isEdited() || this.element.isRemoved()) { + return React.createElement(RevertAction, { element: this.element }); + } + return React.createElement(RemoveAction, { element: this.element }); + } + /** * Here to re-render the component when a key or value is edited. */ @@ -75,7 +91,13 @@ class EditableElement extends React.Component { * Handle removal of an element. */ handleRemove() { - this.element.remove(); + this.setState({}); + } + + /** + * Here to re-render the component when an edit is reverted. + */ + handleRevert() { this.setState({}); } diff --git a/src/internal-packages/crud/lib/component/remove-action.jsx b/src/internal-packages/crud/lib/component/remove-action.jsx new file mode 100644 index 00000000000..82bc49c9833 --- /dev/null +++ b/src/internal-packages/crud/lib/component/remove-action.jsx @@ -0,0 +1,46 @@ +'use strict'; + +const React = require('react'); + +/** + * The actions class. + */ +const ACTIONS = 'actions'; + +/** + * General element action component. + */ +class RemoveAction extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + } + + /** + * Render a single editable key. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
    X
    + ); + } + + /** + * Remove the change. + */ + handleClick() { + this.element.remove(); + } +} + +RemoveAction.displayName = 'RemoveAction'; + +module.exports = RemoveAction; diff --git a/src/internal-packages/crud/lib/component/revert-action.jsx b/src/internal-packages/crud/lib/component/revert-action.jsx new file mode 100644 index 00000000000..2d8db999eed --- /dev/null +++ b/src/internal-packages/crud/lib/component/revert-action.jsx @@ -0,0 +1,46 @@ +'use strict'; + +const React = require('react'); + +/** + * The actions class. + */ +const ACTIONS = 'actions'; + +/** + * General element action component. + */ +class RevertAction extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + } + + /** + * Render a single editable key. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
    R
    + ); + } + + /** + * Revert the change. + */ + handleClick() { + this.element.revert(); + } +} + +RevertAction.displayName = 'RevertAction'; + +module.exports = RevertAction; From 795fa92e3566b36106ff9af0237e1926c4ed0d45 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 14 Jun 2016 15:26:31 +0200 Subject: [PATCH 07/52] INT-1160: Expand editable elements --- .../crud/lib/component/editable-element.jsx | 3 ++ .../component/editable-expandable-element.jsx | 6 +-- .../crud/lib/component/no-action.jsx | 39 +++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/no-action.jsx diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index 081529c4e39..e4381601468 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -6,6 +6,7 @@ const EditableKey = require('./editable-key'); const EditableValue = require('./editable-value'); const RevertAction = require('./revert-action'); const RemoveAction = require('./remove-action'); +const NoAction = require('./no-action'); /** * The added constant. @@ -76,6 +77,8 @@ class EditableElement extends React.Component { action() { if (this.element.isEdited() || this.element.isRemoved()) { return React.createElement(RevertAction, { element: this.element }); + } else if (this.element.key === '_id') { + return React.createElement(NoAction, { element: this.element }); } return React.createElement(RemoveAction, { element: this.element }); } diff --git a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx index 7072c150afa..e83a579b492 100644 --- a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx @@ -84,10 +84,10 @@ class EditableExpandableElement extends React.Component {
    {this.element.currentType}
    -
      - {this.elementComponents()} -
    +
      + {this.elementComponents()} +
  • ); } diff --git a/src/internal-packages/crud/lib/component/no-action.jsx b/src/internal-packages/crud/lib/component/no-action.jsx new file mode 100644 index 00000000000..b18dccf0bc7 --- /dev/null +++ b/src/internal-packages/crud/lib/component/no-action.jsx @@ -0,0 +1,39 @@ +'use strict'; + +const React = require('react'); + +/** + * The actions class. + */ +const ACTIONS = 'actions'; + +/** + * General element action component. + */ +class NoAction extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + } + + /** + * Render a single editable key. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
    + ); + } +} + +NoAction.displayName = 'NoAction'; + +module.exports = NoAction; From a3440767ecc560cfef9b08bce90ffeea7ddee48f Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 14 Jun 2016 15:56:20 +0200 Subject: [PATCH 08/52] INT-1160: Switch to icons for revert/remove --- .../component/editable-expandable-element.jsx | 16 +++++++++++++++- .../crud/lib/component/remove-action.jsx | 4 +++- .../crud/lib/component/revert-action.jsx | 4 +++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx index e83a579b492..0d8e35f25b3 100644 --- a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx @@ -4,6 +4,8 @@ const React = require('react'); const Element = require('hadron-document').Element; const EditableKey = require('./editable-key'); const EditableElement = require('./editable-element'); +const RevertAction = require('./revert-action'); +const RemoveAction = require('./remove-action'); /** * The added constant. @@ -77,7 +79,7 @@ class EditableExpandableElement extends React.Component {
  • -
    x
    + {this.action()}
    : @@ -92,6 +94,18 @@ class EditableExpandableElement extends React.Component { ); } + /** + * Get the revert or remove action. + * + * @returns {Component} The component. + */ + action() { + if (this.element.isEdited() || this.element.isRemoved()) { + return React.createElement(RevertAction, { element: this.element }); + } + return React.createElement(RemoveAction, { element: this.element }); + } + /** * Get the components for the elements. * diff --git a/src/internal-packages/crud/lib/component/remove-action.jsx b/src/internal-packages/crud/lib/component/remove-action.jsx index 82bc49c9833..f3d62b09f6a 100644 --- a/src/internal-packages/crud/lib/component/remove-action.jsx +++ b/src/internal-packages/crud/lib/component/remove-action.jsx @@ -29,7 +29,9 @@ class RemoveAction extends React.Component { */ render() { return ( -
    X
    +
    + +
    ); } diff --git a/src/internal-packages/crud/lib/component/revert-action.jsx b/src/internal-packages/crud/lib/component/revert-action.jsx index 2d8db999eed..9313e9dc109 100644 --- a/src/internal-packages/crud/lib/component/revert-action.jsx +++ b/src/internal-packages/crud/lib/component/revert-action.jsx @@ -29,7 +29,9 @@ class RevertAction extends React.Component { */ render() { return ( -
    R
    +
    + +
    ); } From 9614e8ca92cde7c4e7031a887021f147550944ea Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 16 Jun 2016 12:37:42 +0200 Subject: [PATCH 09/52] INT-1160: Cleaning up styles with hover --- package.json | 2 +- .../crud/lib/component/document-list-item.jsx | 13 +- .../crud/lib/component/editable-element.jsx | 82 ++++++++- .../component/editable-expandable-element.jsx | 170 ------------------ .../crud/lib/component/editable-value.jsx | 24 +++ src/internal-packages/crud/styles/crud.less | 49 ++++- 6 files changed, 151 insertions(+), 189 deletions(-) delete mode 100644 src/internal-packages/crud/lib/component/editable-expandable-element.jsx diff --git a/package.json b/package.json index d94bc39c707..7259d6dc977 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "get-object-path": "azer/get-object-path#74eb42de0cfd02c14ffdd18552f295aba723d394", "hadron-action": "^0.0.4", "hadron-auto-update-manager": "^0.0.12", - "hadron-document": "^0.4.0", + "hadron-document": "^0.6.0", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.2.1", "hadron-ipc": "^0.0.7", diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index 375969a91e8..2487805d2db 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -4,8 +4,8 @@ const _ = require('lodash'); const React = require('react'); const ElementFactory = require('hadron-component-registry').ElementFactory; const HadronDocument = require('hadron-document'); +const Element = require('hadron-document').Element; const EditableElement = require('./editable-element'); -const EditableExpandableElement = require('./editable-expandable-element'); /** * The class for the document itself. @@ -52,6 +52,10 @@ class DocumentListItem extends React.Component { ); } + handleAdd() { + this.setState({}); + } + /** * Get the elements for the document. If we are editing, we get editable elements, * otherwise the readonly elements are returned. @@ -85,6 +89,7 @@ class DocumentListItem extends React.Component { */ handleEdit() { var doc = new HadronDocument(this.props.doc); + doc.on(Element.Events.Added, this.handleAdd.bind(this)); this.setState({ doc: doc, editing: true }); } @@ -98,11 +103,7 @@ class DocumentListItem extends React.Component { * @returns {EditableValue,EditableExpandableElement} The element. */ elementComponent(element) { - var key = `${this.props.doc._id}_${element.key}`; - if (element.elements) { - return React.createElement(EditableExpandableElement, { key: key, element: element }); - } - return React.createElement(EditableElement, { key: key, element: element }); + return React.createElement(EditableElement, { key: element.uuid, element: element }); } } diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index e4381601468..b85ced33cf4 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -28,11 +28,36 @@ const REMOVED = 'removed'; */ const EDITING = 'editing'; +/** + * The caret for expanding elements. + */ +const CARET = 'caret'; + +/** + * The class for the document itself. + */ +const DOCUMENT_CLASS = 'document-property-body'; + +/** + * The header class for expandable elements. + */ +const HEADER_CLASS = 'document-property-header'; + /** * The property class. */ const PROPERTY_CLASS = 'document-property'; +/** + * The expandable label class. + */ +const LABEL_CLASS = 'document-property-type-label'; + +/** + * The expanded class name. + */ +const EXPANDED = 'expanded'; + /** * General editable element component. */ @@ -46,6 +71,8 @@ class EditableElement extends React.Component { constructor(props) { super(props); this.element = props.element; + this.state = { expanded: false }; + this.element.on(Element.Events.Added, this.handleAdd.bind(this)); this.element.on(Element.Events.Edited, this.handleEdit.bind(this)); this.element.on(Element.Events.Removed, this.handleRemove.bind(this)); this.element.on(Element.Events.Reverted, this.handleRevert.bind(this)); @@ -57,6 +84,10 @@ class EditableElement extends React.Component { * @returns {React.Component} The element component. */ render() { + return this.element.elements ? this.renderExpandable() : this.renderNonExpandable(); + } + + renderNonExpandable() { return (
  • @@ -69,6 +100,37 @@ class EditableElement extends React.Component { ); } + renderExpandable() { + return ( +
  • +
    +
    + {this.action()} +
    + + : +
    + {this.element.currentType} +
    +
    +
      + {this.elementComponents()} +
    +
  • + ); + } + + /** + * Get the components for the elements. + * + * @returns {Array} The components. + */ + elementComponents() { + return _.map(this.element.elements, (element) => { + return React.createElement(EditableElement, { key: element.uuid, element: element }); + }); + } + /** * Get the revert or remove action. * @@ -83,6 +145,10 @@ class EditableElement extends React.Component { return React.createElement(RemoveAction, { element: this.element }); } + handleAdd() { + this.setState({ expanded: true }); + } + /** * Here to re-render the component when a key or value is edited. */ @@ -104,6 +170,13 @@ class EditableElement extends React.Component { this.setState({}); } + /** + * Toggles the expandable aspect of the element. + */ + toggleExpandable() { + this.setState({ expanded: !this.state.expanded }); + } + /** * Get the style for the element component. * @@ -113,13 +186,14 @@ class EditableElement extends React.Component { var style = `${PROPERTY_CLASS} ${this.element.currentType.toLowerCase()}`; if (this.element.isAdded()) { style = style.concat(` ${ADDED}`); - } - if (this.element.isEdited()) { + } else if (this.element.isEdited()) { style = style.concat(` ${EDITED}`); - } - if (this.element.isRemoved()) { + } else if (this.element.isRemoved()) { style = style.concat(` ${REMOVED}`); } + if (this.state.expanded) { + style = style.concat(` ${EXPANDED}`); + } return style; } } diff --git a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx b/src/internal-packages/crud/lib/component/editable-expandable-element.jsx deleted file mode 100644 index 0d8e35f25b3..00000000000 --- a/src/internal-packages/crud/lib/component/editable-expandable-element.jsx +++ /dev/null @@ -1,170 +0,0 @@ -'use strict'; - -const React = require('react'); -const Element = require('hadron-document').Element; -const EditableKey = require('./editable-key'); -const EditableElement = require('./editable-element'); -const RevertAction = require('./revert-action'); -const RemoveAction = require('./remove-action'); - -/** - * The added constant. - */ -const ADDED = 'added'; - -/** - * The edited constant. - */ -const EDITED = 'edited'; - -/** - * The removed constant. - */ -const REMOVED = 'removed'; - -/** - * The class for the document itself. - */ -const DOCUMENT_CLASS = 'document-property-body'; - -/** - * The header class for expandable elements. - */ -const HEADER_CLASS = 'document-property-header'; - -/** - * The caret for expanding elements. - */ -const CARET = 'caret'; - -/** - * The expanded class name. - */ -const EXPANDED = 'expanded'; - -/** - * The property class. - */ -const PROPERTY_CLASS = 'document-property'; - -/** - * The expandable label class. - */ -const LABEL_CLASS = 'document-property-type-label'; - -/** - * General editable expandable element component. - */ -class EditableExpandableElement extends React.Component { - - /** - * The component constructor. - * - * @param {Object} props - The properties. - */ - constructor(props) { - super(props); - this.element = props.element; - this.state = { expanded: false }; - this.element.on(Element.Events.Edited, this.handleEdit.bind(this)); - } - - /** - * Render a single editable element. - * - * @returns {React.Component} The element component. - */ - render() { - return ( -
  • -
    -
    - {this.action()} -
    - - : -
    - {this.element.currentType} -
    -
    -
      - {this.elementComponents()} -
    -
  • - ); - } - - /** - * Get the revert or remove action. - * - * @returns {Component} The component. - */ - action() { - if (this.element.isEdited() || this.element.isRemoved()) { - return React.createElement(RevertAction, { element: this.element }); - } - return React.createElement(RemoveAction, { element: this.element }); - } - - /** - * Get the components for the elements. - * - * @returns {Array} The components. - */ - elementComponents() { - return _.map(this.element.elements, (element) => { - return React.createElement( - EditableElement, - { key: `${this.element.key}_${element.key}`, element: element } - ); - }); - } - - /** - * Toggles the expandable aspect of the element. - */ - toggleExpandable() { - this.setState({ expanded: !this.state.expanded }); - } - - /** - * Here to re-render the component when a key or value is edited. - */ - handleEdit() { - this.setState({}); - } - - /** - * Handle removal of an element. - */ - handleRemove() { - this.element.remove(); - this.setState({}); - } - - /** - * Get the style for the element component. - * - * @returns {String} The element style. - */ - style() { - var style = `${PROPERTY_CLASS} ${this.element.currentType.toLowerCase()}`; - if (this.element.isAdded()) { - style = style.concat(` ${ADDED}`); - } - if (this.element.isEdited()) { - style = style.concat(` ${EDITED}`); - } - if (this.element.isRemoved()) { - style = style.concat(` ${REMOVED}`); - } - if (this.state.expanded) { - style = style.concat(` ${EXPANDED}`); - } - return style; - } -} - -EditableExpandableElement.displayName = 'EditableExpandableElement'; - -module.exports = EditableExpandableElement; diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index a0d2260dec9..2e4408531f9 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -41,10 +41,34 @@ class EditableValue extends React.Component { onBlur={this.handleBlur.bind(this)} onFocus={this.handleFocus.bind(this)} onChange={this.handleChange.bind(this)} + onKeyUp={this.handleKeyUp.bind(this)} value={this.element.currentValue} /> ); } + handleKeyUp(evt) { + if (evt.keyCode === 13) { + var value = evt.target.value; + if (value === '{') { + this.changeElementToObject(); + } else if (value === '[') { + this.changeElementToArray(); + } else { + this.element.parentElement.add('', ''); + } + } + } + + changeElementToObject() { + this.element.edit({}); + this.element.add('', ''); + } + + changeElementToArray() { + this.element.edit([]); + this.element.add('0', ''); + } + /** * Handles changes to the element value. * diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 938172e5247..eebae06f48e 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -15,12 +15,25 @@ float: left; width: 75%; counter-reset: line; + position: relative; + + .document-property.array { + margin-left: 0px !important; + } + + .document-property.object { + margin-left: 0px !important; + } .line-number { display: inline-block; color: #999999; width: 18px; + height: 17px; text-align: center; + position: absolute; + left: -20px; + margin-right: 18px; &::before { counter-increment: line; @@ -28,14 +41,6 @@ } } - .actions { - display: inline-block; - width: 18px; - text-align: center; - cursor: pointer; - color: #999999; - } - .types { display: inline-block; float: right; @@ -43,8 +48,36 @@ color: #999999; } + li.document-property:hover { + .actions { + visibility: visible; + } + } + li.document-property { + .actions { + display: inline-block; + visibility: hidden; + width: 18px; + text-align: center; + cursor: pointer; + color: #999999; + } + + &.added { + background-color: #98FB98 !important; + + input { + background-color: #98FB98 !important; + } + + .line-number { + background-color: #008000 !important; + color: #FFFFFF; + } + } + &.edited { background-color: #FFEFD5; From 142db80cfb5e1a87fbf9d372cd0380d7198896fd Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 16 Jun 2016 13:06:26 +0200 Subject: [PATCH 10/52] INT-1160: Don't allow _id edits --- .../crud/lib/component/document-list-item.jsx | 5 +++++ .../crud/lib/component/editable-key.jsx | 18 ++++++++++++++---- .../crud/lib/component/editable-value.jsx | 18 ++++++++++++++---- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index 2487805d2db..6f5563b0bb0 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -56,6 +56,10 @@ class DocumentListItem extends React.Component { this.setState({}); } + handleRemove() { + this.setState({}); + } + /** * Get the elements for the document. If we are editing, we get editable elements, * otherwise the readonly elements are returned. @@ -90,6 +94,7 @@ class DocumentListItem extends React.Component { handleEdit() { var doc = new HadronDocument(this.props.doc); doc.on(Element.Events.Added, this.handleAdd.bind(this)); + doc.on(Element.Events.Removed, this.handleRemove.bind(this)); this.setState({ doc: doc, editing: true }); } diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 4158e1cf6bb..2fca9429ccc 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -52,22 +52,32 @@ class EditableKey extends React.Component { * @param {Event} evt - The event. */ handleChange(evt) { - this.element.rename(evt.target.value); - this.setState({ key: this.element.currentKey }); + if (this.isEditable()) { + this.element.rename(evt.target.value); + this.setState({ key: this.element.currentKey }); + } } /** * Handle focus on the key. */ handleFocus() { - this.setState({ editing: true }); + if (this.isEditable()) { + this.setState({ editing: true }); + } } /** * Handle blur from the key. */ handleBlur() { - this.setState({ editing: false }); + if (this.isEditable()) { + this.setState({ editing: false }); + } + } + + isEditable() { + return this.element.key !== '_id' } /** diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index 2e4408531f9..acfb17b2b3a 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -75,22 +75,32 @@ class EditableValue extends React.Component { * @param {Event} evt - The event. */ handleChange(evt) { - this.element.edit(evt.target.value); - this.setState({ value: this.element.currentValue }); + if (this.isEditable()) { + this.element.edit(evt.target.value); + this.setState({ value: this.element.currentValue }); + } } /** * Handle focus on the value. */ handleFocus() { - this.setState({ editing: true }); + if (this.isEditable()) { + this.setState({ editing: true }); + } } /** * Handle blur from the value. */ handleBlur() { - this.setState({ editing: false }); + if (this.isEditable()) { + this.setState({ editing: false }); + } + } + + isEditable() { + return this.element.key !== '_id' } /** From 986986ccae4f9059ba2e577c0f06a34ea91ab9ce Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 16 Jun 2016 13:16:14 +0200 Subject: [PATCH 11/52] INT-1160: Auto set array indexes on add --- .../crud/lib/component/editable-key.jsx | 2 +- .../crud/lib/component/editable-value.jsx | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 2fca9429ccc..40b9e8f5a55 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -77,7 +77,7 @@ class EditableKey extends React.Component { } isEditable() { - return this.element.key !== '_id' + return this.element.key !== '_id' && this.element.parentElement.type !== 'Array'; } /** diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index acfb17b2b3a..4231bfb8d77 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -54,11 +54,21 @@ class EditableValue extends React.Component { } else if (value === '[') { this.changeElementToArray(); } else { - this.element.parentElement.add('', ''); + this.addElementToParent(); } } } + addElementToParent() { + var parentElement = this.element.parentElement; + if (parentElement.type === 'Array') { + var length = parentElement.elements.length; + parentElement.add(String(length), ''); + } else { + parentElement.add('', ''); + } + } + changeElementToObject() { this.element.edit({}); this.element.add('', ''); @@ -100,7 +110,7 @@ class EditableValue extends React.Component { } isEditable() { - return this.element.key !== '_id' + return this.element.key !== '_id'; } /** From 39fc66815b995bdf0c68df8767441d8d651b6661 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 16 Jun 2016 14:03:48 +0200 Subject: [PATCH 12/52] INT-1160: Focus on newly added elements --- .../crud/lib/component/editable-key.jsx | 9 +++++++++ .../crud/lib/component/editable-value.jsx | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 40b9e8f5a55..868990f820e 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -28,6 +28,14 @@ class EditableKey extends React.Component { this.state = { key: this.element.currentKey, editing: false }; } + componentDidMount() { + if (this.element.isAdded()) { + if (this.isEditable() && this._node) { + this._node.focus(); + } + } + } + /** * Render a single editable key. * @@ -38,6 +46,7 @@ class EditableKey extends React.Component { this._node = c} size={this.element.currentKey.length} onBlur={this.handleBlur.bind(this)} onFocus={this.handleFocus.bind(this)} diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index 4231bfb8d77..c84a7b921bc 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -28,6 +28,14 @@ class EditableValue extends React.Component { this.state = { value: this.element.currentValue, editing: false }; } + componentDidMount() { + if (this.element.isAdded()) { + if (this.element.parentElement.type === 'Array' && this._node) { + this._node.focus(); + } + } + } + /** * Render a single editable value. * @@ -37,6 +45,7 @@ class EditableValue extends React.Component { return ( this._node = c} className={this.style()} onBlur={this.handleBlur.bind(this)} onFocus={this.handleFocus.bind(this)} @@ -71,12 +80,13 @@ class EditableValue extends React.Component { changeElementToObject() { this.element.edit({}); - this.element.add('', ''); + var newElement = this.element.add('', ''); } changeElementToArray() { this.element.edit([]); - this.element.add('0', ''); + var newElement = this.element.add('0', ''); + React.findDOMNode(this.refs.nameInput).focus(); } /** From 6c1ea6fcac4d249c071650597e16fb03743a0d89 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 16 Jun 2016 20:10:46 +0200 Subject: [PATCH 13/52] INT-1160: Remove added elements --- package.json | 2 +- .../component/document-list-item-footer.jsx | 38 --------- .../crud/lib/component/document-list-item.jsx | 23 ++++-- .../crud/lib/component/edit-footer.jsx | 77 +++++++++++++++++++ .../crud/lib/component/editable-value.jsx | 5 +- src/internal-packages/crud/styles/crud.less | 59 +++++++++++++- 6 files changed, 154 insertions(+), 50 deletions(-) delete mode 100644 src/internal-packages/crud/lib/component/document-list-item-footer.jsx create mode 100644 src/internal-packages/crud/lib/component/edit-footer.jsx diff --git a/package.json b/package.json index 7259d6dc977..69e9841ae0c 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "get-object-path": "azer/get-object-path#74eb42de0cfd02c14ffdd18552f295aba723d394", "hadron-action": "^0.0.4", "hadron-auto-update-manager": "^0.0.12", - "hadron-document": "^0.6.0", + "hadron-document": "^0.8.1", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.2.1", "hadron-ipc": "^0.0.7", diff --git a/src/internal-packages/crud/lib/component/document-list-item-footer.jsx b/src/internal-packages/crud/lib/component/document-list-item-footer.jsx deleted file mode 100644 index 5993411d6e2..00000000000 --- a/src/internal-packages/crud/lib/component/document-list-item-footer.jsx +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -const React = require('react'); - -/** - * Component for the document footer. - */ -class DocumentListItemFooter extends React.Component { - - /** - * The component constructor. - * - * @param {Object} props - The properties. - */ - constructor(props) { - super(props); - } - - /** - * Render a single document list item. - */ - render() { - return ( -
    -
    -
    - - -
    -
    - ); - } - -} - -DocumentListItemFooter.displayName = 'DocumentListItemFooter'; - -module.exports = DocumentListItemFooter; diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index 6f5563b0bb0..4c777b6e078 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -6,6 +6,7 @@ const ElementFactory = require('hadron-component-registry').ElementFactory; const HadronDocument = require('hadron-document'); const Element = require('hadron-document').Element; const EditableElement = require('./editable-element'); +const EditFooter = require('./edit-footer'); /** * The class for the document itself. @@ -44,7 +45,7 @@ class DocumentListItem extends React.Component {
    - +
    {this.footer()} @@ -52,6 +53,12 @@ class DocumentListItem extends React.Component { ); } + footer() { + if (this.state.editing) { + return (); + } + } + handleAdd() { this.setState({}); } @@ -60,6 +67,14 @@ class DocumentListItem extends React.Component { this.setState({}); } + handleRevert() { + this.setState({}); + } + + handleEdit() { + this.setState({}); + } + /** * Get the elements for the document. If we are editing, we get editable elements, * otherwise the readonly elements are returned. @@ -84,10 +99,6 @@ class DocumentListItem extends React.Component { }); } - footer() { - - } - /** * Handle the editing of the document. */ @@ -98,7 +109,7 @@ class DocumentListItem extends React.Component { this.setState({ doc: doc, editing: true }); } - deleteDocument() { + handleDelete() { } diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/edit-footer.jsx new file mode 100644 index 00000000000..b9a38b6abf1 --- /dev/null +++ b/src/internal-packages/crud/lib/component/edit-footer.jsx @@ -0,0 +1,77 @@ +'use strict'; + +const React = require('react'); +const Element = require('hadron-document').Element; + +/** + * Component for a the edit document footer. + */ +class EditFooter extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.state = { modified: false }; + } + + /** + * Render the footer. + * + * @returns {Component} The footer component. + */ + render() { + return ( +
    +
    + {this.message()} +
    + {this.actions()} +
    + ); + } + + actions() { + if (this.state.modified) { + return ( +
    + + +
    + ); + } + return ( +
    + ); + } + + message() { + return this.state.modified ? 'Document Modified' : ''; + } + + style() { + return `document-footer${this.state.modified ? ' modified' : ''}`; + } + + handleCancel() { + this.setState({ modified: false }); + } + + handleUpdate() { + console.log(this.props.doc.generateObject()); + } + + /** + * Handle modification to the document. + */ + handleModification() { + this.setState({ modified: this.props.doc.isModified() }); + } +} + +EditFooter.displayName = 'EditFooter'; + +module.exports = EditFooter; diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index c84a7b921bc..646079a0b4f 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -80,13 +80,12 @@ class EditableValue extends React.Component { changeElementToObject() { this.element.edit({}); - var newElement = this.element.add('', ''); + this.element.add('', ''); } changeElementToArray() { this.element.edit([]); - var newElement = this.element.add('0', ''); - React.findDOMNode(this.refs.nameInput).focus(); + this.element.add('0', ''); } /** diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index eebae06f48e..59af2ae20ba 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -1,13 +1,64 @@ .document-footer { - height: 20px; + height: 25px; + vertical-align: middle; + top: 10px; + position: relative; .edit-message { float: left; + font-style: italic; + padding-left: 10px; } - .document-actions { + .document-footer-actions { float: right; padding-right: 10px; + padding-top: 1px; + + .cancel { + font-weight: bold; + text-transform: uppercase; + background-color: #FFFFFF; + border: 0px; + } + + .update { + font-weight: bold; + text-transform: uppercase; + border: 1px solid #B8860B; + border-radius: 4px; + } + } + + &.modified { + + background-color: #FFA500; + + .edit-message { + color: #FFFFFF; + font-style: italic; + } + + .document-footer-actions { + + .cancel { + background-color: #FFA500; + color: #B8860B; + } + + .update { + background-color: #FFEFD5; + color: #B8860B; + } + } + } +} + +ol.document-property-body:hover { + .document-actions { + button { + visibility: visible; + } } } @@ -109,6 +160,10 @@ .document-actions { float: right; padding-right: 10px; + + button { + visibility: hidden; + } } input.editable-key { From c01e9008e4a28050f8fcb92b2451707b5ad50165 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 17 Jun 2016 17:42:08 +0200 Subject: [PATCH 14/52] INT-1160: footer has events --- .../crud/lib/component/document-list-item.jsx | 8 -------- src/internal-packages/crud/lib/component/edit-footer.jsx | 7 ++++++- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index 4c777b6e078..a02c08b4cf7 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -67,14 +67,6 @@ class DocumentListItem extends React.Component { this.setState({}); } - handleRevert() { - this.setState({}); - } - - handleEdit() { - this.setState({}); - } - /** * Get the elements for the document. If we are editing, we get editable elements, * otherwise the readonly elements are returned. diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/edit-footer.jsx index b9a38b6abf1..ae83a8b2d3b 100644 --- a/src/internal-packages/crud/lib/component/edit-footer.jsx +++ b/src/internal-packages/crud/lib/component/edit-footer.jsx @@ -15,6 +15,11 @@ class EditFooter extends React.Component { */ constructor(props) { super(props); + this.doc = props.doc; + this.doc.on(Element.Events.Added, this.handleModification.bind(this)); + this.doc.on(Element.Events.Edited, this.handleModification.bind(this)); + this.doc.on(Element.Events.Removed, this.handleModification.bind(this)); + this.doc.on(Element.Events.Reverted, this.handleModification.bind(this)); this.state = { modified: false }; } @@ -68,7 +73,7 @@ class EditFooter extends React.Component { * Handle modification to the document. */ handleModification() { - this.setState({ modified: this.props.doc.isModified() }); + this.setState({ modified: this.doc.isModified() }); } } From 364616fd656231148fd373ece05c0d8454fff438 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Sun, 19 Jun 2016 11:47:17 +0200 Subject: [PATCH 15/52] INT-1160: Adding type dropdowns --- package.json | 3 ++- .../crud/lib/component/document-list-item.jsx | 5 ++++ .../crud/lib/component/edit-footer.jsx | 1 + .../crud/lib/component/editable-element.jsx | 26 ++++++++++++++++++- src/internal-packages/crud/styles/crud.less | 17 ++++++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 69e9841ae0c..bb8916551d1 100644 --- a/package.json +++ b/package.json @@ -102,13 +102,14 @@ "get-object-path": "azer/get-object-path#74eb42de0cfd02c14ffdd18552f295aba723d394", "hadron-action": "^0.0.4", "hadron-auto-update-manager": "^0.0.12", - "hadron-document": "^0.8.1", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.2.1", + "hadron-document": "^0.8.3", "hadron-ipc": "^0.0.7", "hadron-module-cache": "^0.0.3", "hadron-package-manager": "0.1.0", "hadron-reflux-store": "^0.0.2", + "hadron-type-checker": "^0.1.0", "highlight.js": "^8.9.1", "jquery": "^2.1.4", "kerberos": "mongodb-js/kerberos#bc619b1b9213eb4cdae786cf3fb916fc7be66758", diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index a02c08b4cf7..a365095ab5e 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -98,9 +98,14 @@ class DocumentListItem extends React.Component { var doc = new HadronDocument(this.props.doc); doc.on(Element.Events.Added, this.handleAdd.bind(this)); doc.on(Element.Events.Removed, this.handleRemove.bind(this)); + doc.on("Document::Cancel", this.handleCancel.bind(this)); this.setState({ doc: doc, editing: true }); } + handleCancel() { + this.setState({ doc: this.props.doc, editing: false }); + } + handleDelete() { } diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/edit-footer.jsx index ae83a8b2d3b..2071390d3b0 100644 --- a/src/internal-packages/crud/lib/component/edit-footer.jsx +++ b/src/internal-packages/crud/lib/component/edit-footer.jsx @@ -62,6 +62,7 @@ class EditFooter extends React.Component { } handleCancel() { + this.doc.cancel(); this.setState({ modified: false }); } diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index b85ced33cf4..2371d2c7467 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -7,6 +7,7 @@ const EditableValue = require('./editable-value'); const RevertAction = require('./revert-action'); const RemoveAction = require('./remove-action'); const NoAction = require('./no-action'); +const TypeChecker = require('hadron-type-checker'); /** * The added constant. @@ -87,6 +88,21 @@ class EditableElement extends React.Component { return this.element.elements ? this.renderExpandable() : this.renderNonExpandable(); } + castableTypesComponent() { + // Handle array and objects. + return _.map(TypeChecker.castableTypes(this.currentValue), (type) => { + return ( +
  • + {type} +
  • + ); + }); + } + + handleTypeChange(evt) { + console.log(evt); + } + renderNonExpandable() { return (
  • @@ -95,7 +111,15 @@ class EditableElement extends React.Component { : -
    {this.element.currentType}
    +
    + +
      + {this.castableTypesComponent()} +
    +
  • ); } diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 59af2ae20ba..f9d0ed3c61c 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -97,6 +97,23 @@ ol.document-property-body:hover { float: right; width: 100px; color: #999999; + height: 17px; + + .btn { + text-transform: none; + font-size: 11px; + border-radius: 4px; + padding-top: 1px; + padding-bottom: 1px; + padding-right: 4px; + padding-left: 4px; + width: 100px; + text-align: right; + } + + .dropdown-menu { + + } } li.document-property:hover { From 2166b93779b5668509e071794d49957c852e9944 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 20 Jun 2016 11:18:55 -0400 Subject: [PATCH 16/52] INT-1160: Move types into own component --- .../crud/lib/component/editable-element.jsx | 32 ++------ .../crud/lib/component/types.jsx | 78 +++++++++++++++++++ src/internal-packages/crud/styles/crud.less | 67 +++++++++++++++- 3 files changed, 151 insertions(+), 26 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/types.jsx diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index 2371d2c7467..3ff6187bf59 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -7,7 +7,7 @@ const EditableValue = require('./editable-value'); const RevertAction = require('./revert-action'); const RemoveAction = require('./remove-action'); const NoAction = require('./no-action'); -const TypeChecker = require('hadron-type-checker'); +const Types = require('./types'); /** * The added constant. @@ -59,6 +59,8 @@ const LABEL_CLASS = 'document-property-type-label'; */ const EXPANDED = 'expanded'; +const NON_EXPANDABLE = 'non-expandable'; + /** * General editable element component. */ @@ -88,21 +90,6 @@ class EditableElement extends React.Component { return this.element.elements ? this.renderExpandable() : this.renderNonExpandable(); } - castableTypesComponent() { - // Handle array and objects. - return _.map(TypeChecker.castableTypes(this.currentValue), (type) => { - return ( -
  • - {type} -
  • - ); - }); - } - - handleTypeChange(evt) { - console.log(evt); - } - renderNonExpandable() { return (
  • @@ -111,15 +98,7 @@ class EditableElement extends React.Component { : -
    - -
      - {this.castableTypesComponent()} -
    -
    +
  • ); } @@ -215,6 +194,9 @@ class EditableElement extends React.Component { } else if (this.element.isRemoved()) { style = style.concat(` ${REMOVED}`); } + if (!this.element.elements) { + style = style.concat(` ${NON_EXPANDABLE}`); + } if (this.state.expanded) { style = style.concat(` ${EXPANDED}`); } diff --git a/src/internal-packages/crud/lib/component/types.jsx b/src/internal-packages/crud/lib/component/types.jsx new file mode 100644 index 00000000000..1a320040788 --- /dev/null +++ b/src/internal-packages/crud/lib/component/types.jsx @@ -0,0 +1,78 @@ +'use strict'; + +const React = require('react'); +const Element = require('hadron-document').Element; +const TypeChecker = require('hadron-type-checker'); + +/** + * General types component. + */ +class Types extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + this.state = { type: this.element.currentType }; + } + + /** + * Render a type list. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
    + +
      + {this.castableTypes()} +
    +
    + ); + } + + castableTypes() { + return _.map(TypeChecker.castableTypes(this.castableValue()), (type) => { + return ( +
  • + {type} +
  • + ); + }); + } + + castableValue() { + if (this.element.elements) { + if (this.element.currentType === 'Object') { + return {}; + } + return _.map(this.element.elements, (element) => { + return element.currentValue; + }); + } + return this.element.currentValue; + } + + handleTypeChange(evt) { + this.element.edit(TypeChecker.cast(this.castableValue(), evt.target.innerText)); + this.setState({ type: this.element.currentType }); + } +} + +Types.displayName = 'Types'; + +module.exports = Types; diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index f9d0ed3c61c..221ff1f9f98 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -109,17 +109,82 @@ ol.document-property-body:hover { padding-left: 4px; width: 100px; text-align: right; + border-color: #ffffff; + } + + .caret { + visibility: hidden; + margin-right: 0px; } .dropdown-menu { + li { + span { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + font-size: 11px; + color: #333333; + white-space: nowrap; + } + span:hover { + color: #313030; + text-decoration: none; + background: #e6e6e6; + } + } + } + } + + li.document-property.non-expandable:hover { + background-color: #ebebed !important; + + input { + background-color: #ebebed !important; + } + + .line-number { + background-color: #ebebed !important; + } + + .actions { + visibility: visible; + } + .types { + .btn { + border-color: #8c8c8c; + } + .caret { + visibility: visible; + } } } - li.document-property:hover { + div.document-property-header:hover { + background-color: #ebebed !important; + + input { + background-color: #ebebed !important; + } + + .line-number { + background-color: #ebebed !important; + } + .actions { visibility: visible; } + + .types { + .btn { + border-color: #8c8c8c; + } + .caret { + visibility: visible; + } + } } li.document-property { From 1eb2194720e535220fe08a7c59f98726ff7219c8 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 20 Jun 2016 11:41:54 -0400 Subject: [PATCH 17/52] INT-1160: Listen in the types component --- src/internal-packages/crud/lib/component/types.jsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/internal-packages/crud/lib/component/types.jsx b/src/internal-packages/crud/lib/component/types.jsx index 1a320040788..c06e5ea756f 100644 --- a/src/internal-packages/crud/lib/component/types.jsx +++ b/src/internal-packages/crud/lib/component/types.jsx @@ -17,6 +17,10 @@ class Types extends React.Component { constructor(props) { super(props); this.element = props.element; + this.element.on(Element.Events.Added, this.handleModification.bind(this)); + this.element.on(Element.Events.Edited, this.handleModification.bind(this)); + this.element.on(Element.Events.Removed, this.handleModification.bind(this)); + this.element.on(Element.Events.Reverted, this.handleModification.bind(this)); this.state = { type: this.element.currentType }; } @@ -67,6 +71,10 @@ class Types extends React.Component { return this.element.currentValue; } + handleModification() { + this.setState({ type: this.element.currentType }); + } + handleTypeChange(evt) { this.element.edit(TypeChecker.cast(this.castableValue(), evt.target.innerText)); this.setState({ type: this.element.currentType }); From 4c2adfff007c61c9b4256652594c481d9b901e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Sch=C3=A4ffner-Gurney?= Date: Mon, 20 Jun 2016 15:05:21 -0400 Subject: [PATCH 18/52] quick initial style pass --- src/app/styles/palette.less | 4 + .../crud/lib/component/edit-footer.jsx | 4 +- src/internal-packages/crud/styles/crud.less | 109 ++++++++++-------- 3 files changed, 67 insertions(+), 50 deletions(-) diff --git a/src/app/styles/palette.less b/src/app/styles/palette.less index ec3ffb376c1..8f96636c041 100644 --- a/src/app/styles/palette.less +++ b/src/app/styles/palette.less @@ -44,6 +44,7 @@ @pw: #fff; @cautionOrange: @alertOrange; @errorBackground: #fdd0d1; +@greenBg: #e9f2e3; /* Text Colors */ /* default text color is @gray1 */ @@ -76,7 +77,10 @@ /* Alert Colors */ @alertOrange: #fbb129; +@alertOrangeBg: #fff4dc; +@alertOrangeBorder: #a06c29; @alertRed: #ef4c4c; +@alertRedBg: #feeded; @alertBlue: #43b1e5; /* Semantic Colors */ diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/edit-footer.jsx index 2071390d3b0..a351e87a0b5 100644 --- a/src/internal-packages/crud/lib/component/edit-footer.jsx +++ b/src/internal-packages/crud/lib/component/edit-footer.jsx @@ -43,8 +43,8 @@ class EditFooter extends React.Component { if (this.state.modified) { return (
    - - + +
    ); } diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 221ff1f9f98..47987b9d6ec 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -1,57 +1,59 @@ .document-footer { - height: 25px; + font-family: "Akzidenz", "Helvetica Neue", Helvetica, Arial, sans-serif; + height: 28px; vertical-align: middle; top: 10px; position: relative; .edit-message { - float: left; + font-size: 14px; font-style: italic; padding-left: 10px; + padding-top: 4px; + color: @pw; } .document-footer-actions { - float: right; - padding-right: 10px; + position: absolute; + right: 10px; + top: 2px; padding-top: 1px; .cancel { font-weight: bold; - text-transform: uppercase; - background-color: #FFFFFF; - border: 0px; } .update { font-weight: bold; - text-transform: uppercase; - border: 1px solid #B8860B; - border-radius: 4px; + border-radius: 3px; } } &.modified { - - background-color: #FFA500; - - .edit-message { - color: #FFFFFF; - font-style: italic; - } + background-color: @alertOrange; .document-footer-actions { .cancel { - background-color: #FFA500; - color: #B8860B; + color: @alertOrangeBorder; } .update { - background-color: #FFEFD5; - color: #B8860B; + color: @alertOrangeBorder; + border-color: @alertOrangeBorder; + + &:hover { + background-color: rgba(255,255,255,0.7); + } } } } + &.in-progress { + background-color: @chart1; + } + &.success { + background-color: @green2; + } } ol.document-property-body:hover { @@ -78,7 +80,7 @@ ol.document-property-body:hover { .line-number { display: inline-block; - color: #999999; + color: @gray4; width: 18px; height: 17px; text-align: center; @@ -100,21 +102,19 @@ ol.document-property-body:hover { height: 17px; .btn { + background-color: transparent; + color: @gray4; + border: none; text-transform: none; font-size: 11px; - border-radius: 4px; - padding-top: 1px; - padding-bottom: 1px; - padding-right: 4px; - padding-left: 4px; - width: 100px; - text-align: right; - border-color: #ffffff; + border-radius: 8px; + padding: 1px 12px; } .caret { visibility: hidden; margin-right: 0px; + margin-left: 4px; } .dropdown-menu { @@ -138,14 +138,14 @@ ol.document-property-body:hover { } li.document-property.non-expandable:hover { - background-color: #ebebed !important; + background-color: @gray8; input { - background-color: #ebebed !important; - } + background-color: @gray8; - .line-number { - background-color: #ebebed !important; + &:focus { + background-color: @pw; + } } .actions { @@ -154,7 +154,8 @@ ol.document-property-body:hover { .types { .btn { - border-color: #8c8c8c; + background-color: @gray6; + color: @gray0; } .caret { visibility: visible; @@ -199,41 +200,53 @@ ol.document-property-body:hover { } &.added { - background-color: #98FB98 !important; + background-color: @greenBg; input { - background-color: #98FB98 !important; + background-color: @greenBg; + + &:focus { + background-color: @pw; + } } .line-number { - background-color: #008000 !important; - color: #FFFFFF; + background-color: @green2; + color: @pw; } } &.edited { - background-color: #FFEFD5; + background-color: @alertOrangeBg; input { - background-color: #FFEFD5; + background-color: @alertOrangeBg; + + &:focus { + background-color: @pw; + } } .line-number { - background-color: #FFA500; - color: #FFFFFF; + background-color: @alertOrange; + color: @pw; } } &.removed { - background-color: #FFB6C1; + background-color: @alertRedBg; input { - background-color: #FFB6C1; + background-color: @alertRedBg; + + &:focus { + background-color: @pw; + } } .line-number { - background-color: #FF0000; - color: #FFFFFF; + background-color: @alertRed; + color: @pw; } } } From 433860bf122b8492681389ee706c2a271ef5a1db Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 20 Jun 2016 15:59:11 -0400 Subject: [PATCH 19/52] INT-1160: Updating key events --- package.json | 2 +- .../crud/lib/component/editable-key.jsx | 13 +++- .../crud/lib/component/editable-value.jsx | 59 ++++--------------- .../crud/lib/component/types.jsx | 11 +--- 4 files changed, 25 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index bb8916551d1..3dda28f6c8c 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "hadron-auto-update-manager": "^0.0.12", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.2.1", - "hadron-document": "^0.8.3", + "hadron-document": "^0.9.0", "hadron-ipc": "^0.0.7", "hadron-module-cache": "^0.0.3", "hadron-package-manager": "0.1.0", diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 868990f820e..a4235b8ee1e 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -28,9 +28,13 @@ class EditableKey extends React.Component { this.state = { key: this.element.currentKey, editing: false }; } + /** + * Focus on this field on mount, so the tab can do it's job and move + * to the value field. + */ componentDidMount() { if (this.element.isAdded()) { - if (this.isEditable() && this._node) { + if (!this.isEditable() && this._node) { this._node.focus(); } } @@ -85,8 +89,13 @@ class EditableKey extends React.Component { } } + /** + * Is this component editable? + * + * @returns {Boolean} If the component is editable. + */ isEditable() { - return this.element.key !== '_id' && this.element.parentElement.type !== 'Array'; + return this.element.isKeyEditable() && this.element.parentElement.currentType !== 'Array'; } /** diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index 646079a0b4f..9d13b978898 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -28,14 +28,6 @@ class EditableValue extends React.Component { this.state = { value: this.element.currentValue, editing: false }; } - componentDidMount() { - if (this.element.isAdded()) { - if (this.element.parentElement.type === 'Array' && this._node) { - this._node.focus(); - } - } - } - /** * Render a single editable value. * @@ -45,56 +37,33 @@ class EditableValue extends React.Component { return ( this._node = c} className={this.style()} onBlur={this.handleBlur.bind(this)} onFocus={this.handleFocus.bind(this)} onChange={this.handleChange.bind(this)} - onKeyUp={this.handleKeyUp.bind(this)} + onKeyDown={this.handleKeyDown.bind(this)} value={this.element.currentValue} /> ); } - handleKeyUp(evt) { - if (evt.keyCode === 13) { - var value = evt.target.value; - if (value === '{') { - this.changeElementToObject(); - } else if (value === '[') { - this.changeElementToArray(); - } else { - this.addElementToParent(); - } - } - } - - addElementToParent() { - var parentElement = this.element.parentElement; - if (parentElement.type === 'Array') { - var length = parentElement.elements.length; - parentElement.add(String(length), ''); - } else { - parentElement.add('', ''); + /** + * When hitting a key on the last element some special things may happen. + * + * @param {Event} evt - The event. + */ + handleKeyDown(evt) { + if (evt.keyCode === 9 && !evt.shiftKey) { + this.element.next(); } } - changeElementToObject() { - this.element.edit({}); - this.element.add('', ''); - } - - changeElementToArray() { - this.element.edit([]); - this.element.add('0', ''); - } - /** * Handles changes to the element value. * * @param {Event} evt - The event. */ handleChange(evt) { - if (this.isEditable()) { + if (this.element.isValueEditable()) { this.element.edit(evt.target.value); this.setState({ value: this.element.currentValue }); } @@ -104,7 +73,7 @@ class EditableValue extends React.Component { * Handle focus on the value. */ handleFocus() { - if (this.isEditable()) { + if (this.element.isValueEditable()) { this.setState({ editing: true }); } } @@ -113,15 +82,11 @@ class EditableValue extends React.Component { * Handle blur from the value. */ handleBlur() { - if (this.isEditable()) { + if (this.element.isValueEditable()) { this.setState({ editing: false }); } } - isEditable() { - return this.element.key !== '_id'; - } - /** * Get the style for the value of the element. * diff --git a/src/internal-packages/crud/lib/component/types.jsx b/src/internal-packages/crud/lib/component/types.jsx index c06e5ea756f..758426620dc 100644 --- a/src/internal-packages/crud/lib/component/types.jsx +++ b/src/internal-packages/crud/lib/component/types.jsx @@ -17,11 +17,6 @@ class Types extends React.Component { constructor(props) { super(props); this.element = props.element; - this.element.on(Element.Events.Added, this.handleModification.bind(this)); - this.element.on(Element.Events.Edited, this.handleModification.bind(this)); - this.element.on(Element.Events.Removed, this.handleModification.bind(this)); - this.element.on(Element.Events.Reverted, this.handleModification.bind(this)); - this.state = { type: this.element.currentType }; } /** @@ -35,6 +30,7 @@ class Types extends React.Component { - - - ); - } + /** + * Render the actions for the footer. + * + * @returns {Component} The react component. + */ + renderActions() { return ( -
    +
    + {this.renderButtons()} +
    ); } - style() { - var style = 'document-footer'; - if (this.state.updating) { - style = style.concat(' in-progress'); - } else if (this.state.updated) { - style = style.concat(' success'); - } else if (this.state.errored) { - style = style.concat(' error'); - } else if (this.state.modified) { - style = style.concat(' modified'); + /** + * Render the buttons for the footer. + * + * @returns {Component} The react component. + */ + renderButtons() { + if (this.state.mode === ERROR || this.state.mode === EDITING) { + return [ this.renderCancelButton(), this.renderUpdateButton() ]; } - return style; } - handleCancel() { - this.doc.cancel(); - this.setState({ modified: false }); + /** + * Render the cancel button. + * + * @returns {Component} The react component. + */ + renderCancelButton() { + return ( + + ); } - handleUpdate() { - var object = this.props.doc.generateObject(); - this.setState({ updating: true, errored: false, message: 'Updating document' }); - Actions.updateDocument(object); + /** + * Render the cancel button. + * + * @returns {Component} The react component. + */ + renderUpdateButton() { + return ( + + ); } /** - * Handle modification to the document. + * Get the style of the footer based on the current mode. + * + * @returns {String} The style. */ - handleModification() { - this.setState({ modified: this.doc.isModified(), errored: false, message: 'Document Modified' }); + style() { + return `document-footer ${MODES[this.state.mode]}`; } } diff --git a/src/internal-packages/crud/lib/store/document-update-store.js b/src/internal-packages/crud/lib/store/document-update-store.js index a4f93550c58..40bb64e0c83 100644 --- a/src/internal-packages/crud/lib/store/document-update-store.js +++ b/src/internal-packages/crud/lib/store/document-update-store.js @@ -22,11 +22,11 @@ const DocumentUpdateStore = Reflux.createStore({ _updateDocument: function(object) { var ns = NamespaceStore.ns; var filter = { _id: object._id }; - app.dataService.updateOne(ns, filter, object, {}, (error, result) => { + app.dataService.findOneAndReplace(ns, filter, object, { returnOriginal: false }, (error, doc) => { if (error) { - this.trigger(object._id, false, error.message); + this.trigger(object._id, false, error); } else { - this.trigger(object._id, true); + this.trigger(object._id, true, doc); } }); } From ff40ae525ba797bb02ab5748ebd6fc9fb2726b1b Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 21 Jun 2016 14:44:51 -0400 Subject: [PATCH 24/52] INT-1160: Hadron document v0.10.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d41414c44a..4e2fedab51e 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "hadron-auto-update-manager": "^0.0.12", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.2.1", - "hadron-document": "^0.9.0", + "hadron-document": "^0.10.0", "hadron-ipc": "^0.0.7", "hadron-module-cache": "^0.0.3", "hadron-package-manager": "0.1.0", From 82431a795464890afdfb3a4b11086da5ebeb232b Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 21 Jun 2016 17:35:53 -0400 Subject: [PATCH 25/52] INT-1160: Fixing oid rendering in edit mode --- .../crud/lib/component/document-list-item.jsx | 34 ++++++++++++------- .../crud/lib/component/edit-footer.jsx | 5 +-- .../crud/lib/component/editable-value.jsx | 28 ++++++++++----- src/internal-packages/crud/styles/crud.less | 17 ++++++++++ 4 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index 7b901638f33..c52f1d4ac68 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -57,11 +57,11 @@ class DocumentListItem extends React.Component { * @param {Error, Document} object - The error or document. */ handleStoreTrigger(id, success, object) { - console.log('################## TRIGGER #################'); - console.log(object); - if (id === this.doc._id) { - if (success) { - this.handleSuccess(object); + if (this.state.editing) { + if (id === this.doc._id) { + if (success) { + this.handleSuccess(object); + } } } } @@ -81,19 +81,29 @@ class DocumentListItem extends React.Component {
    {this.elements()}
    -
    - - -
    + {this.renderActions()} - {this.footer()} + {this.renderFooter()} ); } - footer() { + renderActions() { + if (!this.state.editing) { + return ( +
    + + +
    + ); + } + } + + renderFooter() { if (this.state.editing) { - return (); + return ( + + ); } } diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/edit-footer.jsx index d6b5387ae89..38a4d188994 100644 --- a/src/internal-packages/crud/lib/component/edit-footer.jsx +++ b/src/internal-packages/crud/lib/component/edit-footer.jsx @@ -91,8 +91,6 @@ class EditFooter extends React.Component { */ handleUpdate() { var object = this.props.doc.generateObject(); - console.log('##################### UPDATING ######################'); - console.log(object); this.setState({ mode: PROGRESS, message: UPDATING }); Actions.updateDocument(object); } @@ -159,6 +157,9 @@ class EditFooter extends React.Component { if (this.state.mode === ERROR || this.state.mode === EDITING) { return [ this.renderCancelButton(), this.renderUpdateButton() ]; } + if (this.state.mode === VIEWING) { + return [ this.renderCancelButton() ]; + } } /** diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index 9d13b978898..bbfcf08ec52 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -1,6 +1,7 @@ 'use strict'; const React = require('react'); +const ElementFactory = require('hadron-component-registry').ElementFactory; /** * The editing class constant. @@ -34,15 +35,26 @@ class EditableValue extends React.Component { * @returns {React.Component} The element component. */ render() { + return this.renderComponent(); + } + + renderComponent() { + if (this.element.isValueEditable()) { + return ( + + ); + } return ( - +
    + {String(this.element.currentValue)} +
    ); } diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 19021774278..38e1679d410 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -56,6 +56,23 @@ } &.error { background-color: red; + + .document-footer-actions { + + .cancel { + color: @alertRedBg; + } + } + } + &.viewing { + background-color: #F8F8F8; + + .document-footer-actions { + + .cancel { + color: #B8B8B8; + } + } } } From c7bd940df21eedb017d1f88a2547c158997350f2 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 11:51:38 -0400 Subject: [PATCH 26/52] INT-1160: Refactoring stores --- .../crud/lib/component/document-list-item.jsx | 186 ++++++++++++------ .../crud/lib/component/edit-footer.jsx | 25 ++- 2 files changed, 139 insertions(+), 72 deletions(-) diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document-list-item.jsx index c52f1d4ac68..a126a9beb72 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document-list-item.jsx @@ -1,9 +1,11 @@ 'use strict'; const _ = require('lodash'); +const app = require('ampersand-app'); const React = require('react'); +const Reflux = require('reflux'); const ElementFactory = require('hadron-component-registry').ElementFactory; -const DocumentUpdateStore = require('../store/document-update-store'); +const NamespaceStore = require('hadron-reflux-store').NamespaceStore; const HadronDocument = require('hadron-document'); const Element = require('hadron-document').Element; const EditableElement = require('./editable-element'); @@ -33,85 +35,131 @@ class DocumentListItem extends React.Component { super(props); this.doc = props.doc; this.state = { doc: this.doc, editing: false }; + + // Actions need to be scoped to the single document component and not + // global singletons. + this.actions = Reflux.createActions([ 'update', 'delete' ]); + + // The update store needs to be scoped to a document and not a global + // singleton. + this.updateStore = this.createUpdateStore(this.actions); + } + + /** + * Create the scoped update store. + * + * @param {Action} actions - The component reflux actions. + * + * @returns {Store} The scoped store. + */ + createUpdateStore(actions) { + return Reflux.createStore({ + + /** + * Initialize the store. + */ + init: function() { + this.ns = NamespaceStore.ns; + this.listenTo(actions.update, this.update); + }, + + /** + * Update the document in the database. + * + * @param {Object} object - The replacement document. + */ + update: function(object) { + app.dataService.findOneAndReplace( + this.ns, + { _id: object._id }, + object, + { returnOriginal: false }, + this.handleResult + ); + }, + + /** + * Handle the result from the driver. + * + * @param {Error} error - The error. + * @param {Object} doc - The document. + * + * @returns {Object} The trigger event. + */ + handleResult: function(error, doc) { + return (error) ? this.trigger(false, error) : this.trigger(true, doc); + } + }); } /** * Subscribe to the update store on mount. */ componentDidMount() { - this.unsubscribe = DocumentUpdateStore.listen(this.handleStoreTrigger.bind(this)); + this.unsubscribeUpdate = this.updateStore.listen(this.handleStoreUpdate.bind(this)); } /** * Unsubscribe from the udpate store on unmount. */ componentWillUnmount() { - this.unsubscribe(); + this.unsubscribeUpdate(); } /** * Handles a trigger from the store. * - * @param {ObjectId) id - The object id of the document. * @param {Boolean} success - If the update succeeded. * @param {Error, Document} object - The error or document. */ - handleStoreTrigger(id, success, object) { + handleStoreUpdate(success, object) { if (this.state.editing) { - if (id === this.doc._id) { - if (success) { - this.handleSuccess(object); - } + if (success) { + this.handleSuccess(object); } } } + /** + * Handle a sucessful update. + * + * @param {Object} doc - The updated document. + */ handleSuccess(doc) { this.doc = doc; this.setState({ doc: doc, editing: false }); } /** - * Render a single document list item. + * Handle the editing of the document. */ - render() { - return ( -
  • -
      -
      - {this.elements()} -
      - {this.renderActions()} -
    - {this.renderFooter()} -
  • - ); - } + handleEdit() { + var doc = new HadronDocument(this.doc); + doc.on(Element.Events.Added, this.handleModify.bind(this)); + doc.on(Element.Events.Removed, this.handleModify.bind(this)); + doc.on(HadronDocument.Events.Cancel, this.handleCancel.bind(this)); - renderActions() { - if (!this.state.editing) { - return ( -
    - - -
    - ); - } + this.setState({ doc: doc, editing: true }); } - renderFooter() { - if (this.state.editing) { - return ( - - ); - } + /** + * Handles canceling edits to the document. + */ + handleCancel() { + this.setState({ doc: this.doc, editing: false }); } - handleAdd() { - this.setState({}); + /** + * Handles document deletion. + */ + handleDelete() { + } - handleRemove() { + /** + * Handles modification to the document. + */ + handleModify() { this.setState({}); } @@ -135,36 +183,56 @@ class DocumentListItem extends React.Component { */ editableElements() { return _.map(this.state.doc.elements, (element) => { - return this.elementComponent(element); + return ( + + ); }); } /** - * Handle the editing of the document. + * Render a single document list item. */ - handleEdit() { - var doc = new HadronDocument(this.doc); - doc.on(Element.Events.Added, this.handleAdd.bind(this)); - doc.on(Element.Events.Removed, this.handleRemove.bind(this)); - doc.on("Document::Cancel", this.handleCancel.bind(this)); - this.setState({ doc: doc, editing: true }); - } - - handleCancel() { - this.setState({ doc: this.doc, editing: false }); + render() { + return ( +
  • +
      +
      + {this.elements()} +
      + {this.renderActions()} +
    + {this.renderFooter()} +
  • + ); } - handleDelete() { - + /** + * Render the actions. + * + * @returns {Component} The actions component. + */ + renderActions() { + if (!this.state.editing) { + return ( +
    + + +
    + ); + } } /** - * Get the component for the element value. + * Render the footer component. * - * @returns {EditableValue,EditableExpandableElement} The element. + * @returns {Component} The footer component. */ - elementComponent(element) { - return React.createElement(EditableElement, { key: element.uuid, element: element }); + renderFooter() { + if (this.state.editing) { + return ( + + ); + } } } diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/edit-footer.jsx index 38a4d188994..bc08e82b86b 100644 --- a/src/internal-packages/crud/lib/component/edit-footer.jsx +++ b/src/internal-packages/crud/lib/component/edit-footer.jsx @@ -3,8 +3,6 @@ const _ = require('lodash'); const React = require('react'); const Element = require('hadron-document').Element; -const DocumentUpdateStore = require('../store/document-update-store'); -const Actions = require('../actions'); const PROGRESS = 'Progress'; const SUCCESS = 'Success'; @@ -38,10 +36,14 @@ class EditFooter extends React.Component { constructor(props) { super(props); this.doc = props.doc; + this.updateStore = props.updateStore; + this.actions = props.actions; + this.doc.on(Element.Events.Added, this.handleModification.bind(this)); this.doc.on(Element.Events.Edited, this.handleModification.bind(this)); this.doc.on(Element.Events.Removed, this.handleModification.bind(this)); this.doc.on(Element.Events.Reverted, this.handleModification.bind(this)); + this.state = { mode: VIEWING, message: EMPTY }; } @@ -49,14 +51,14 @@ class EditFooter extends React.Component { * Subscribe to the update store on mount. */ componentDidMount() { - this.unsubscribe = DocumentUpdateStore.listen(this.handleStoreTrigger.bind(this)); + this.unsubscribeUpdate = this.updateStore.listen(this.handleStoreUpdate.bind(this)); } /** * Unsubscribe from the udpate store on unmount. */ componentWillUnmount() { - this.unsubscribe(); + this.unsubscribeUpdate(); } /** @@ -92,7 +94,7 @@ class EditFooter extends React.Component { handleUpdate() { var object = this.props.doc.generateObject(); this.setState({ mode: PROGRESS, message: UPDATING }); - Actions.updateDocument(object); + this.actions.update(object); } /** @@ -105,17 +107,14 @@ class EditFooter extends React.Component { /** * Handles a trigger from the store. * - * @param {ObjectId) id - The object id of the document. * @param {Boolean} success - If the update succeeded. * @param {Error, Document} object - The error or document. */ - handleStoreTrigger(id, success, object) { - if (id === this.doc.doc._id) { - if (success) { - this.handleSuccess(); - } else { - this.handleError(object); - } + handleStoreUpdate(success, object) { + if (success) { + this.handleSuccess(); + } else { + this.handleError(object); } } From a94bd2aa57ddf0fabec47c95f00ccfc95e21063b Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 11:51:59 -0400 Subject: [PATCH 27/52] INT-1160: Remove singleton update store --- .../crud/lib/store/document-update-store.js | 35 ------------------- 1 file changed, 35 deletions(-) delete mode 100644 src/internal-packages/crud/lib/store/document-update-store.js diff --git a/src/internal-packages/crud/lib/store/document-update-store.js b/src/internal-packages/crud/lib/store/document-update-store.js deleted file mode 100644 index 40bb64e0c83..00000000000 --- a/src/internal-packages/crud/lib/store/document-update-store.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -const Reflux = require('reflux'); -const app = require('ampersand-app'); -const NamespaceStore = require('hadron-reflux-store').NamespaceStore; -const Actions = require('../actions'); - -const DocumentUpdateStore = Reflux.createStore({ - - /** - * Initialize the document update store. - */ - init: function() { - this.listenTo(Actions.updateDocument, this._updateDocument); - }, - - /** - * Update the document. - * - * @param {Object} object - The updated object. - */ - _updateDocument: function(object) { - var ns = NamespaceStore.ns; - var filter = { _id: object._id }; - app.dataService.findOneAndReplace(ns, filter, object, { returnOriginal: false }, (error, doc) => { - if (error) { - this.trigger(object._id, false, error); - } else { - this.trigger(object._id, true, doc); - } - }); - } -}); - -module.exports = DocumentUpdateStore; From c518d894c9ee0d3706a8fa6f13653093b37d12ed Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 12:20:16 -0400 Subject: [PATCH 28/52] INT-1160: Delete a document, no parent update --- src/internal-packages/crud/lib/actions.js | 6 +- .../crud/lib/component/document-list.jsx | 8 +- .../{document-list-item.jsx => document.jsx} | 82 +++++++++++++++++-- .../crud/lib/component/edit-footer.jsx | 37 +++++++++ .../crud/lib/store/document-list-store.js | 8 +- 5 files changed, 122 insertions(+), 19 deletions(-) rename src/internal-packages/crud/lib/component/{document-list-item.jsx => document.jsx} (73%) diff --git a/src/internal-packages/crud/lib/actions.js b/src/internal-packages/crud/lib/actions.js index d93fd2fc8fa..8ed06c40b75 100644 --- a/src/internal-packages/crud/lib/actions.js +++ b/src/internal-packages/crud/lib/actions.js @@ -2,10 +2,6 @@ const Reflux = require('reflux'); -const Actions = Reflux.createActions([ - 'updateDocument', - 'documentUpdateSucceeded', - 'documentUpdateFailed' -]); +const Actions = Reflux.createActions([ 'documentRemoved' ]); module.exports = Actions; diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index 5dca238d8ff..aec40ad908f 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -5,7 +5,7 @@ const React = require('react'); const ReactDOM = require('react-dom'); const app = require('ampersand-app'); const Action = require('hadron-action'); -const DocumentListItem = require('./document-list-item'); +const Document = require('./document'); const DocumentListStore = require('../store/document-list-store'); /** @@ -102,7 +102,9 @@ class DocumentList extends React.Component { */ _documentListItems(docs) { return _.map(docs, (doc) => { - return React.createElement(DocumentListItem, { doc: doc, key: doc._id }); + return ( + + ); }); } @@ -145,6 +147,6 @@ class DocumentList extends React.Component { } DocumentList.displayName = 'DocumentList'; -DocumentList.DocumentListItem = DocumentListItem; +DocumentList.Document = Document; module.exports = DocumentList; diff --git a/src/internal-packages/crud/lib/component/document-list-item.jsx b/src/internal-packages/crud/lib/component/document.jsx similarity index 73% rename from src/internal-packages/crud/lib/component/document-list-item.jsx rename to src/internal-packages/crud/lib/component/document.jsx index a126a9beb72..e2e33d0e2c1 100644 --- a/src/internal-packages/crud/lib/component/document-list-item.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -8,6 +8,7 @@ const ElementFactory = require('hadron-component-registry').ElementFactory; const NamespaceStore = require('hadron-reflux-store').NamespaceStore; const HadronDocument = require('hadron-document'); const Element = require('hadron-document').Element; +const Actions = require('../actions'); const EditableElement = require('./editable-element'); const EditFooter = require('./edit-footer'); @@ -24,7 +25,7 @@ const LIST_ITEM_CLASS = 'document-list-item'; /** * Component for a single document in a list of documents. */ -class DocumentListItem extends React.Component { +class Document extends React.Component { /** * The component constructor. @@ -38,11 +39,12 @@ class DocumentListItem extends React.Component { // Actions need to be scoped to the single document component and not // global singletons. - this.actions = Reflux.createActions([ 'update', 'delete' ]); + this.actions = Reflux.createActions([ 'update', 'remove' ]); // The update store needs to be scoped to a document and not a global // singleton. this.updateStore = this.createUpdateStore(this.actions); + this.removeStore = this.createRemoveStore(this.actions); } /** @@ -92,11 +94,53 @@ class DocumentListItem extends React.Component { }); } + /** + * Create the scoped remove store. + * + * @param {Action} actions - The component reflux actions. + * + * @returns {Store} The scoped store. + */ + createRemoveStore(actions) { + return Reflux.createStore({ + + /** + * Initialize the store. + */ + init: function() { + this.ns = NamespaceStore.ns; + this.listenTo(actions.remove, this.remove); + }, + + /** + * Remove the document from the collection. + * + * @param {Object} object - The object to delete. + */ + remove: function(object) { + app.dataService.deleteOne(this.ns, { _id: object._id }, {}, this.handleResult); + }, + + /** + * Handle the result from the driver. + * + * @param {Error} error - The error. + * @param {Object} doc - The document. + * + * @returns {Object} The trigger event. + */ + handleResult: function(error, result) { + return (error) ? this.trigger(false, error) : this.trigger(true, result); + } + }); + } + /** * Subscribe to the update store on mount. */ componentDidMount() { this.unsubscribeUpdate = this.updateStore.listen(this.handleStoreUpdate.bind(this)); + this.unsubscribeRemove = this.removeStore.listen(this.handleStoreRemove.bind(this)); } /** @@ -104,6 +148,7 @@ class DocumentListItem extends React.Component { */ componentWillUnmount() { this.unsubscribeUpdate(); + this.unsubscribeRemove(); } /** @@ -115,7 +160,21 @@ class DocumentListItem extends React.Component { handleStoreUpdate(success, object) { if (this.state.editing) { if (success) { - this.handleSuccess(object); + this.handleUpdateSuccess(object); + } + } + } + + /** + * Handles a trigger from the store. + * + * @param {Boolean} success - If the update succeeded. + * @param {Error, Document} object - The error or document. + */ + handleStoreRemove(success) { + if (this.state.editing) { + if (success) { + this.handleRemoveSuccess(); } } } @@ -125,11 +184,20 @@ class DocumentListItem extends React.Component { * * @param {Object} doc - The updated document. */ - handleSuccess(doc) { + handleUpdateSuccess(doc) { this.doc = doc; this.setState({ doc: doc, editing: false }); } + /** + * Handle a sucessful update. + * + * @param {Object} doc - The updated document. + */ + handleRemoveSuccess() { + Actions.documentRemoved(this.doc._id); + } + /** * Handle the editing of the document. */ @@ -153,7 +221,7 @@ class DocumentListItem extends React.Component { * Handles document deletion. */ handleDelete() { - + this.actions.remove(this.doc); } /** @@ -236,6 +304,6 @@ class DocumentListItem extends React.Component { } } -DocumentListItem.displayName = 'DocumentListItem'; +Document.displayName = 'Document'; -module.exports = DocumentListItem; +module.exports = Document; diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/edit-footer.jsx index bc08e82b86b..3bcce0272a5 100644 --- a/src/internal-packages/crud/lib/component/edit-footer.jsx +++ b/src/internal-packages/crud/lib/component/edit-footer.jsx @@ -4,12 +4,34 @@ const _ = require('lodash'); const React = require('react'); const Element = require('hadron-document').Element; +/** + * The progress mode. + */ const PROGRESS = 'Progress'; + +/** + * The success mode. + */ const SUCCESS = 'Success'; + +/** + * The error mode. + */ const ERROR = 'Error'; + +/** + * The editing mode. + */ const EDITING = 'Editing'; + +/** + * The viewing mode. + */ const VIEWING = 'Viewing'; +/** + * Map of modes to styles. + */ const MODES = { 'Progress': 'in-progress', 'Success': 'success', @@ -18,9 +40,24 @@ const MODES = { 'Viewing': 'viewing' } +/** + * The empty message. + */ const EMPTY = ''; + +/** + * The modified message. + */ const MODIFIED = 'Document Modified.'; + +/** + * The updating message. + */ const UPDATING = 'Updating Document.'; + +/** + * The updated message. + */ const UPDATED = 'Document Updated.'; /** diff --git a/src/internal-packages/crud/lib/store/document-list-store.js b/src/internal-packages/crud/lib/store/document-list-store.js index ef325eb930b..3c6d24e49d4 100644 --- a/src/internal-packages/crud/lib/store/document-list-store.js +++ b/src/internal-packages/crud/lib/store/document-list-store.js @@ -14,8 +14,8 @@ const DocumentListStore = Reflux.createStore({ * Initialize the document list store. */ init: function() { - this.listenTo(Action.filterChanged, this._resetDocuments); - this.listenTo(Action.fetchNextDocuments, this._fetchNextDocuments); + this.listenTo(Action.filterChanged, this.resetDocuments); + this.listenTo(Action.fetchNextDocuments, this.nextDocuments); }, /** @@ -23,7 +23,7 @@ const DocumentListStore = Reflux.createStore({ * * @param {Object} filter - The query filter. */ - _resetDocuments: function(filter) { + resetDocuments: function(filter) { var ns = NamespaceStore.ns; if (ns) { app.dataService.count(ns, filter, {}, (err, count) => { @@ -40,7 +40,7 @@ const DocumentListStore = Reflux.createStore({ * * @param {Integer} currentPage - The current page in the view. */ - _fetchNextDocuments: function(currentPage) { + nextDocuments: function(currentPage) { var ns = NamespaceStore.ns; if (ns) { var filter = app.queryOptions.query.serialize(); From 8f4719030d353c912b7c78a710308934ce394788 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 12:38:45 -0400 Subject: [PATCH 29/52] INT-1160: Split actions into their own component --- .../crud/lib/component/document-actions.jsx | 36 +++++++++++++++++++ .../crud/lib/component/document.jsx | 10 +++--- 2 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/document-actions.jsx diff --git a/src/internal-packages/crud/lib/component/document-actions.jsx b/src/internal-packages/crud/lib/component/document-actions.jsx new file mode 100644 index 00000000000..4587d8277be --- /dev/null +++ b/src/internal-packages/crud/lib/component/document-actions.jsx @@ -0,0 +1,36 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for actions on the document. + */ +class DocumentActions extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the actions. + * + * @returns {Component} The actions component. + */ + render() { + return ( +
    + + +
    + ); + } +} + +DocumentActions.displayName = 'DocumentActions'; + +module.exports = DocumentActions; diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index e2e33d0e2c1..ef350910029 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -11,6 +11,7 @@ const Element = require('hadron-document').Element; const Actions = require('../actions'); const EditableElement = require('./editable-element'); const EditFooter = require('./edit-footer'); +const DocumentActions = require('./document-actions'); /** * The class for the document itself. @@ -275,17 +276,16 @@ class Document extends React.Component { } /** - * Render the actions. + * Render the actions component. * * @returns {Component} The actions component. */ renderActions() { if (!this.state.editing) { return ( -
    - - -
    + ); } } From 8682708cb39d8528623da8c20d230c9ac6dcb98a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 12:41:22 -0400 Subject: [PATCH 30/52] INT-1160: Rename footer component --- .../lib/component/{edit-footer.jsx => document-footer.jsx} | 6 +++--- src/internal-packages/crud/lib/component/document.jsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/internal-packages/crud/lib/component/{edit-footer.jsx => document-footer.jsx} (97%) diff --git a/src/internal-packages/crud/lib/component/edit-footer.jsx b/src/internal-packages/crud/lib/component/document-footer.jsx similarity index 97% rename from src/internal-packages/crud/lib/component/edit-footer.jsx rename to src/internal-packages/crud/lib/component/document-footer.jsx index 3bcce0272a5..18324baa142 100644 --- a/src/internal-packages/crud/lib/component/edit-footer.jsx +++ b/src/internal-packages/crud/lib/component/document-footer.jsx @@ -63,7 +63,7 @@ const UPDATED = 'Document Updated.'; /** * Component for a the edit document footer. */ -class EditFooter extends React.Component { +class DocumentFooter extends React.Component { /** * The component constructor. @@ -242,6 +242,6 @@ class EditFooter extends React.Component { } } -EditFooter.displayName = 'EditFooter'; +DocumentFooter.displayName = 'DocumentFooter'; -module.exports = EditFooter; +module.exports = DocumentFooter; diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index ef350910029..50c4d8e5620 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -10,8 +10,8 @@ const HadronDocument = require('hadron-document'); const Element = require('hadron-document').Element; const Actions = require('../actions'); const EditableElement = require('./editable-element'); -const EditFooter = require('./edit-footer'); const DocumentActions = require('./document-actions'); +const DocumentFooter = require('./document-footer'); /** * The class for the document itself. @@ -298,7 +298,7 @@ class Document extends React.Component { renderFooter() { if (this.state.editing) { return ( - + ); } } From e117b1ddba86d937b6162ec56b777a037a0466ae Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 14:01:13 -0400 Subject: [PATCH 31/52] INT-1160: Splitting up document list global stores --- .../crud/lib/component/document-list.jsx | 126 ++++++++++-------- .../crud/lib/store/document-list-store.js | 55 -------- .../lib/store/load-more-documents-store.js | 34 +++++ .../lib/store/reset-document-list-store.js | 35 +++++ 4 files changed, 139 insertions(+), 111 deletions(-) delete mode 100644 src/internal-packages/crud/lib/store/document-list-store.js create mode 100644 src/internal-packages/crud/lib/store/load-more-documents-store.js create mode 100644 src/internal-packages/crud/lib/store/reset-document-list-store.js diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index aec40ad908f..c8341652771 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -6,7 +6,8 @@ const ReactDOM = require('react-dom'); const app = require('ampersand-app'); const Action = require('hadron-action'); const Document = require('./document'); -const DocumentListStore = require('../store/document-list-store'); +const ResetDocumentListStore = require('../store/reset-document-list-store'); +const LoadMoreDocumentsStore = require('../store/load-more-documents-store'); /** * The full document list container class. @@ -23,40 +24,32 @@ const SCROLL_EVENT = 'scroll'; */ class DocumentList extends React.Component { + /** + * Attach the scroll event to the parent container. + */ + attachScrollEvent() { + this.documentListNode = ReactDOM.findDOMNode(this); + this.documentListNode.parentNode.addEventListener( + SCROLL_EVENT, + this.handleScroll.bind(this) + ); + } + /** * Fetch the state when the component mounts. */ componentDidMount() { - this._attachScrollEvent(); - this.unsubscribe = DocumentListStore.listen((documents, reset, count) => { - if (reset) { - // If resetting, then we need to go back to page one with - // the documents as the filter changed. The loaded count and - // total count are reset here as well. - this.setState({ - docs: this._documentListItems(documents), - currentPage: 1, - count: count, - loadedCount: documents.length - }); - } else { - // If not resetting we append the documents to the existing - // list and increment the page. The loaded count is incremented - // by the number of new documents. - this.setState({ - docs: this.state.docs.concat(this._documentListItems(documents)), - currentPage: (this.state.currentPage + 1), - loadedCount: (this.state.loadedCount + documents.length) - }); - } - }); + this.attachScrollEvent(); + this.unsubscribeReset = ResetDocumentListStore.listen(this.handleReset.bind(this)); + this.unsubscribeLoadMore = LoadMoreDocumentsStore.listen(this.handleLoadMore.bind(this)); } /** * Unsibscribe from the document list store when unmounting. */ componentWillUnmount() { - this.unsubscribe(); + this.unsubscribeReset(); + this.unsubscribeLoadMore(); } /** @@ -70,41 +63,36 @@ class DocumentList extends React.Component { } /** - * Render the document list. + * Handle the loading of more documents. * - * @returns {React.Component} The document list. + * @param {Array} documents - The next batch of documents. */ - render() { - return ( -
      - {this.state.docs} -
    - ); - } - - /** - * Attach the scroll event to the parent container. - */ - _attachScrollEvent() { - this.documentListNode = ReactDOM.findDOMNode(this); - this.documentListNode.parentNode.addEventListener( - SCROLL_EVENT, - this._handleScroll.bind(this) - ); + handleLoadMore(documents) { + // If not resetting we append the documents to the existing + // list and increment the page. The loaded count is incremented + // by the number of new documents. + this.setState({ + docs: this.state.docs.concat(this.renderDocuments(documents)), + currentPage: (this.state.currentPage + 1), + loadedCount: (this.state.loadedCount + documents.length) + }); } /** - * Get the document list item components. + * Handle the reset of the document list. * - * @param {Array} docs - The raw documents. - * - * @return {Array} The document list item components. + * @param {Array} documents - The documents. + * @param {Integer} count - The count. */ - _documentListItems(docs) { - return _.map(docs, (doc) => { - return ( - - ); + handleReset(documents, count) { + // If resetting, then we need to go back to page one with + // the documents as the filter changed. The loaded count and + // total count are reset here as well. + this.setState({ + docs: this.renderDocuments(documents), + currentPage: 1, + count: count, + loadedCount: documents.length }); } @@ -113,12 +101,12 @@ class DocumentList extends React.Component { * * @param {Event} evt - The scroll event. */ - _handleScroll(evt) { + handleScroll(evt) { var container = evt.srcElement; if (container.scrollTop > (this.documentListNode.offsetHeight - this._scrollDelta())) { // If we are scrolling downwards, and have hit the distance to initiate a scroll // from the end of the list, we will fire the event to load more documents. - this._nextBatch(); + this.loadMore(); } } @@ -126,12 +114,38 @@ class DocumentList extends React.Component { * Get the next batch of documents. Will only fire if there are more documents * in the collection to load. */ - _nextBatch() { + loadMore() { if (this.state.loadedCount < this.state.count) { Action.fetchNextDocuments(this.state.currentPage); } } + /** + * Render the document list. + * + * @returns {React.Component} The document list. + */ + render() { + return ( +
      + {this.state.docs} +
    + ); + } + + /** + * Get the document list item components. + * + * @param {Array} docs - The raw documents. + * + * @return {Array} The document list item components. + */ + renderDocuments(docs) { + return _.map(docs, (doc) => { + return (); + }); + } + /** * Get the distance in pixels from the end of the document list to the point when * scrolling where we want to load more documents. diff --git a/src/internal-packages/crud/lib/store/document-list-store.js b/src/internal-packages/crud/lib/store/document-list-store.js deleted file mode 100644 index 3c6d24e49d4..00000000000 --- a/src/internal-packages/crud/lib/store/document-list-store.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; - -const Reflux = require('reflux'); -const app = require('ampersand-app'); -const NamespaceStore = require('hadron-reflux-store').NamespaceStore; -const Action = require('hadron-action'); - -/** - * The reflux store for the list of documents. - */ -const DocumentListStore = Reflux.createStore({ - - /** - * Initialize the document list store. - */ - init: function() { - this.listenTo(Action.filterChanged, this.resetDocuments); - this.listenTo(Action.fetchNextDocuments, this.nextDocuments); - }, - - /** - * This function is called when the collection filter changes. - * - * @param {Object} filter - The query filter. - */ - resetDocuments: function(filter) { - var ns = NamespaceStore.ns; - if (ns) { - app.dataService.count(ns, filter, {}, (err, count) => { - var options = { limit: 20, sort: [[ '_id', 1 ]] }; - app.dataService.find(ns, filter, options, (error, documents) => { - this.trigger(documents, true, count); - }); - }); - } - }, - - /** - * Fetch the next page of documents. - * - * @param {Integer} currentPage - The current page in the view. - */ - nextDocuments: function(currentPage) { - var ns = NamespaceStore.ns; - if (ns) { - var filter = app.queryOptions.query.serialize(); - var options = { skip: (currentPage * 20), limit: 20, sort: [[ '_id', 1 ]] }; - app.dataService.find(ns, filter, options, (error, documents) => { - this.trigger(documents, false); - }); - } - } -}); - -module.exports = DocumentListStore; diff --git a/src/internal-packages/crud/lib/store/load-more-documents-store.js b/src/internal-packages/crud/lib/store/load-more-documents-store.js new file mode 100644 index 00000000000..8442be6481b --- /dev/null +++ b/src/internal-packages/crud/lib/store/load-more-documents-store.js @@ -0,0 +1,34 @@ +'use strict'; + +const Reflux = require('reflux'); +const app = require('ampersand-app'); +const NamespaceStore = require('hadron-reflux-store').NamespaceStore; +const Action = require('hadron-action'); + +/** + * The reflux store for loading more documents. + */ +const LoadMoreDocumentsStore = Reflux.createStore({ + + /** + * Initialize the reset document list store. + */ + init: function() { + this.listenTo(Action.fetchNextDocuments, this.loadMoreDocuments); + }, + + /** + * Fetch the next page of documents. + * + * @param {Integer} currentPage - The current page in the view. + */ + loadMoreDocuments: function(currentPage) { + var filter = app.queryOptions.query.serialize(); + var options = { skip: (currentPage * 20), limit: 20, sort: [[ '_id', 1 ]] }; + app.dataService.find(NamespaceStore.ns, filter, options, (error, documents) => { + this.trigger(documents); + }); + } +}); + +module.exports = LoadMoreDocumentsStore; diff --git a/src/internal-packages/crud/lib/store/reset-document-list-store.js b/src/internal-packages/crud/lib/store/reset-document-list-store.js new file mode 100644 index 00000000000..c7c764f3483 --- /dev/null +++ b/src/internal-packages/crud/lib/store/reset-document-list-store.js @@ -0,0 +1,35 @@ +'use strict'; + +const Reflux = require('reflux'); +const app = require('ampersand-app'); +const NamespaceStore = require('hadron-reflux-store').NamespaceStore; +const Action = require('hadron-action'); + +/** + * The reflux store for resetting the document list. + */ +const ResetDocumentListStore = Reflux.createStore({ + + /** + * Initialize the reset document list store. + */ + init: function() { + this.listenTo(Action.filterChanged, this.reset); + }, + + /** + * This function is called when the collection filter changes. + * + * @param {Object} filter - The query filter. + */ + reset: function(filter) { + app.dataService.count(NamespaceStore.ns, filter, {}, (err, count) => { + var options = { limit: 20, sort: [[ '_id', 1 ]] }; + app.dataService.find(NamespaceStore.ns, filter, options, (error, documents) => { + this.trigger(documents, count); + }); + }); + }, +}); + +module.exports = ResetDocumentListStore; From 6f794cdc951e64dcdf58882e6d044ccc93d86599 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 14:40:05 -0400 Subject: [PATCH 32/52] INT-1160: Finish delete document --- .../crud/lib/component/document-list.jsx | 19 +++++++++++++ .../crud/lib/component/document.jsx | 6 ++-- .../crud/lib/store/remove-document-store.js | 28 +++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/internal-packages/crud/lib/store/remove-document-store.js diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index c8341652771..8dcd3d0e2f7 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -5,9 +5,11 @@ const React = require('react'); const ReactDOM = require('react-dom'); const app = require('ampersand-app'); const Action = require('hadron-action'); +const ObjectID = require('bson').ObjectID; const Document = require('./document'); const ResetDocumentListStore = require('../store/reset-document-list-store'); const LoadMoreDocumentsStore = require('../store/load-more-documents-store'); +const RemoveDocumentStore = require('../store/remove-document-store'); /** * The full document list container class. @@ -42,6 +44,7 @@ class DocumentList extends React.Component { this.attachScrollEvent(); this.unsubscribeReset = ResetDocumentListStore.listen(this.handleReset.bind(this)); this.unsubscribeLoadMore = LoadMoreDocumentsStore.listen(this.handleLoadMore.bind(this)); + this.unsubscribeRemove = RemoveDocumentStore.listen(this.handleRemove.bind(this)); } /** @@ -50,6 +53,7 @@ class DocumentList extends React.Component { componentWillUnmount() { this.unsubscribeReset(); this.unsubscribeLoadMore(); + this.unsubscribeRemove(); } /** @@ -96,6 +100,21 @@ class DocumentList extends React.Component { }); } + handleRemove(id) { + // Reset the list minus the document with the id. + var index = _.findIndex(this.state.docs, (component) => { + if (id instanceof ObjectID) { + return id.equals(component.props.doc._id); + } + return component.props.doc._id === id; + }); + this.state.docs.splice(index, 1); + this.setState({ + docs: this.state.docs, + loadedCount: (this.state.loadedCount - 1) + }); + } + /** * Handle the scroll event of the parent container. * diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index 50c4d8e5620..466327aeb33 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -173,10 +173,8 @@ class Document extends React.Component { * @param {Error, Document} object - The error or document. */ handleStoreRemove(success) { - if (this.state.editing) { - if (success) { - this.handleRemoveSuccess(); - } + if (success) { + this.handleRemoveSuccess(); } } diff --git a/src/internal-packages/crud/lib/store/remove-document-store.js b/src/internal-packages/crud/lib/store/remove-document-store.js new file mode 100644 index 00000000000..c930a6c7daf --- /dev/null +++ b/src/internal-packages/crud/lib/store/remove-document-store.js @@ -0,0 +1,28 @@ +'use strict'; + +const Reflux = require('reflux'); +const Actions = require('../actions'); + +/** + * The reflux store for removing a document from the list. + */ +const RemoveDocumentStore = Reflux.createStore({ + + /** + * Initialize the reset document list store. + */ + init: function() { + this.listenTo(Actions.documentRemoved, this.remove); + }, + + /** + * This function is called when when a document is deleted. + * + * @param {Object} id - The document id. + */ + remove: function(id) { + this.trigger(id); + }, +}); + +module.exports = RemoveDocumentStore; From 33665cabf8b45297edd2f2ba1704b8957aaee1a0 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 15:01:42 -0400 Subject: [PATCH 33/52] INT-1160: Refactor edit and delete buttons --- .../lib/component/delete-document-button.jsx | 35 +++++++++++++++++++ .../crud/lib/component/document-actions.jsx | 6 ++-- .../crud/lib/component/document-list.jsx | 11 +++--- .../lib/component/edit-document-button.jsx | 35 +++++++++++++++++++ 4 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/delete-document-button.jsx create mode 100644 src/internal-packages/crud/lib/component/edit-document-button.jsx diff --git a/src/internal-packages/crud/lib/component/delete-document-button.jsx b/src/internal-packages/crud/lib/component/delete-document-button.jsx new file mode 100644 index 00000000000..1140329d5d8 --- /dev/null +++ b/src/internal-packages/crud/lib/component/delete-document-button.jsx @@ -0,0 +1,35 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the edit document button. + */ +class DeleteDocumentButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +DeleteDocumentButton.displayName = 'DeleteDocumentButton'; + +module.exports = DeleteDocumentButton; diff --git a/src/internal-packages/crud/lib/component/document-actions.jsx b/src/internal-packages/crud/lib/component/document-actions.jsx index 4587d8277be..75e14087460 100644 --- a/src/internal-packages/crud/lib/component/document-actions.jsx +++ b/src/internal-packages/crud/lib/component/document-actions.jsx @@ -1,6 +1,8 @@ 'use strict'; const React = require('react'); +const EditDocumentButton = require('./edit-document-button'); +const DeleteDocumentButton = require('./delete-document-button'); /** * Component for actions on the document. @@ -24,8 +26,8 @@ class DocumentActions extends React.Component { render() { return (
    - - + +
    ); } diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index 8dcd3d0e2f7..091eebc4a3a 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -100,8 +100,12 @@ class DocumentList extends React.Component { }); } + /** + * Handles removal of a document from the document list. + * + * @param {Object} id - The id of the removed document. + */ handleRemove(id) { - // Reset the list minus the document with the id. var index = _.findIndex(this.state.docs, (component) => { if (id instanceof ObjectID) { return id.equals(component.props.doc._id); @@ -109,10 +113,7 @@ class DocumentList extends React.Component { return component.props.doc._id === id; }); this.state.docs.splice(index, 1); - this.setState({ - docs: this.state.docs, - loadedCount: (this.state.loadedCount - 1) - }); + this.setState({ docs: this.state.docs, loadedCount: (this.state.loadedCount - 1) }); } /** diff --git a/src/internal-packages/crud/lib/component/edit-document-button.jsx b/src/internal-packages/crud/lib/component/edit-document-button.jsx new file mode 100644 index 00000000000..483a012a881 --- /dev/null +++ b/src/internal-packages/crud/lib/component/edit-document-button.jsx @@ -0,0 +1,35 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the edit document button. + */ +class EditDocumentButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +EditDocumentButton.displayName = 'EditDocumentButton'; + +module.exports = EditDocumentButton; From 106d43199b72b14bacf042af4109f8c19934c8e9 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 16:18:36 -0400 Subject: [PATCH 34/52] INT-1160: Updating footer buttons and styles --- .../crud/lib/component/cancel-edit-button.jsx | 38 +++++++++++ .../crud/lib/component/document-footer.jsx | 68 ++----------------- .../crud/lib/component/document.jsx | 10 ++- .../crud/lib/component/update-button.jsx | 38 +++++++++++ src/internal-packages/crud/styles/crud.less | 6 +- 5 files changed, 96 insertions(+), 64 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/cancel-edit-button.jsx create mode 100644 src/internal-packages/crud/lib/component/update-button.jsx diff --git a/src/internal-packages/crud/lib/component/cancel-edit-button.jsx b/src/internal-packages/crud/lib/component/cancel-edit-button.jsx new file mode 100644 index 00000000000..4b4d4fd6181 --- /dev/null +++ b/src/internal-packages/crud/lib/component/cancel-edit-button.jsx @@ -0,0 +1,38 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the cancel button. + */ +class CancelEditButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +CancelEditButton.displayName = 'CancelEditButton'; + +module.exports = CancelEditButton; diff --git a/src/internal-packages/crud/lib/component/document-footer.jsx b/src/internal-packages/crud/lib/component/document-footer.jsx index 18324baa142..7cd63ccd006 100644 --- a/src/internal-packages/crud/lib/component/document-footer.jsx +++ b/src/internal-packages/crud/lib/component/document-footer.jsx @@ -3,6 +3,8 @@ const _ = require('lodash'); const React = require('react'); const Element = require('hadron-document').Element; +const CancelEditButton = require('./cancel-edit-button'); +const UpdateButton = require('./update-button'); /** * The progress mode. @@ -166,72 +168,14 @@ class DocumentFooter extends React.Component {
    {this.state.message}
    - {this.renderActions()} - - ); - } - - /** - * Render the actions for the footer. - * - * @returns {Component} The react component. - */ - renderActions() { - return ( -
    - {this.renderButtons()} +
    + + +
    ); } - /** - * Render the buttons for the footer. - * - * @returns {Component} The react component. - */ - renderButtons() { - if (this.state.mode === ERROR || this.state.mode === EDITING) { - return [ this.renderCancelButton(), this.renderUpdateButton() ]; - } - if (this.state.mode === VIEWING) { - return [ this.renderCancelButton() ]; - } - } - - /** - * Render the cancel button. - * - * @returns {Component} The react component. - */ - renderCancelButton() { - return ( - - ); - } - - /** - * Render the cancel button. - * - * @returns {Component} The react component. - */ - renderUpdateButton() { - return ( - - ); - } - /** * Get the style of the footer based on the current mode. * diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index 466327aeb33..3d7dcc5fc33 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -261,7 +261,7 @@ class Document extends React.Component { */ render() { return ( -
  • +
    1. {this.elements()} @@ -300,6 +300,14 @@ class Document extends React.Component { ); } } + + style() { + var style = LIST_ITEM_CLASS; + if (this.state.editing) { + style = style.concat(' editing'); + } + return style; + } } Document.displayName = 'Document'; diff --git a/src/internal-packages/crud/lib/component/update-button.jsx b/src/internal-packages/crud/lib/component/update-button.jsx new file mode 100644 index 00000000000..874f5a56733 --- /dev/null +++ b/src/internal-packages/crud/lib/component/update-button.jsx @@ -0,0 +1,38 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the update button. + */ +class UpdateButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +UpdateButton.displayName = 'UpdateButton'; + +module.exports = UpdateButton; diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 38e1679d410..efebd8b0fbd 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -1,8 +1,12 @@ +li.document-list-item.editing { + box-shadow: 2px 5px 8px gainsboro; +} + .document-footer { font-family: "Akzidenz", "Helvetica Neue", Helvetica, Arial, sans-serif; height: 28px; vertical-align: middle; - top: 10px; + top: 13px; position: relative; .edit-message { From cf9163da82d7b9e40195aa4fb5103cbbeaa3990b Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Jun 2016 16:48:30 -0400 Subject: [PATCH 35/52] INT-1160: Add hotspot --- .../crud/lib/component/document.jsx | 6 ++- .../crud/lib/component/hotspot.jsx | 41 +++++++++++++++++++ src/internal-packages/crud/styles/crud.less | 4 ++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/internal-packages/crud/lib/component/hotspot.jsx diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index 3d7dcc5fc33..86f2ef637f3 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -12,6 +12,7 @@ const Actions = require('../actions'); const EditableElement = require('./editable-element'); const DocumentActions = require('./document-actions'); const DocumentFooter = require('./document-footer'); +const Hotspot = require('./hotspot'); /** * The class for the document itself. @@ -249,11 +250,14 @@ class Document extends React.Component { * @returns {Array} The editable elements. */ editableElements() { - return _.map(this.state.doc.elements, (element) => { + var elements = _.map(this.state.doc.elements, (element) => { return ( ); }); + var lastElement = elements[elements.length - 1].props.element; + elements.push(); + return elements; } /** diff --git a/src/internal-packages/crud/lib/component/hotspot.jsx b/src/internal-packages/crud/lib/component/hotspot.jsx new file mode 100644 index 00000000000..c02f33bc39b --- /dev/null +++ b/src/internal-packages/crud/lib/component/hotspot.jsx @@ -0,0 +1,41 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for add element hotspot. + */ +class Hotspot extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.element = props.element; + } + + /** + * When clicking on a hotspot we append to the parent. + */ + handleClick() { + this.element.next(); + } + + /** + * Render the hotspot. + * + * @returns {Component} The hotspot component. + */ + render() { + return ( +
      + ); + } +} + +Hotspot.displayName = 'Hotspot'; + +module.exports = Hotspot; diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index efebd8b0fbd..ab37921e610 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -274,6 +274,10 @@ ol.document-property-body:hover { } } + .hotspot { + height: 10px; + cursor: text; + } } .document-actions { From ebb5fef201e7c3eb9d1c5d51ad028e86f950d518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Sch=C3=A4ffner-Gurney?= Date: Wed, 22 Jun 2016 17:19:08 -0400 Subject: [PATCH 36/52] CRUD style tuning --- src/app/documents/index.less | 17 ++++++++------ src/app/styles/caret.less | 1 - src/internal-packages/crud/styles/crud.less | 25 ++++++++++++++------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/app/documents/index.less b/src/app/documents/index.less index d5c0589749b..e6adb739b64 100644 --- a/src/app/documents/index.less +++ b/src/app/documents/index.less @@ -115,8 +115,8 @@ ol.document-list { display: inline-block; width: 12px; height: 1em; - margin-left: 2px; - margin-right: 10px; + margin-left: -8px !important; // remove important hack later + margin-right: 4px; .caret-right; } @@ -131,18 +131,21 @@ ol.document-list { } ol.document-property-body { - // margin-left: 21px; - padding-left: 36px; - // border-left: 1px dotted @gray6; + padding-left: 0; display: none; + + .document-property-key, + .editable-key { + margin-left: 16px; + } } &.expanded { > .document-property-header { > .caret { .caret-down; vertical-align: bottom; - margin-left: 4px; - margin-right: 8px; + margin-left: -10px !important; // remove important hack later + margin-right: 2px; } } > ol.document-property-body { diff --git a/src/app/styles/caret.less b/src/app/styles/caret.less index f7a6d94939a..ba2a2982c3d 100644 --- a/src/app/styles/caret.less +++ b/src/app/styles/caret.less @@ -2,7 +2,6 @@ display: inline-block; width: 0; height: 0; - margin-left: 2px; vertical-align: middle; } .caret-down { diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index ab37921e610..9d3a06e948d 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -108,8 +108,7 @@ ol.document-property-body:hover { height: 17px; text-align: center; position: absolute; - left: -20px; - margin-right: 18px; + left: -18px; &::before { counter-increment: line; @@ -136,8 +135,8 @@ ol.document-property-body:hover { .caret { visibility: hidden; - margin-right: 0px; - margin-left: 4px; + // margin-right: 0px; + // margin-left: 4px; } .dropdown-menu { @@ -187,11 +186,13 @@ ol.document-property-body:hover { } li.document-property { + // position: relative; .actions { display: inline-block; visibility: hidden; width: 18px; + margin-right: 8px; text-align: center; cursor: pointer; color: #999999; @@ -291,25 +292,33 @@ ol.document-property-body:hover { } input.editable-key { + position: relative; font-weight: bold; border: none; padding-left: 1px; + z-index: 1; &.editing { border: 1px solid #999999; - box-shadow: 0px 2px 4px 0px #999999; - margin-bottom: 4px; + box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.2); + z-index: 10; + margin-top: -1px; + margin-bottom: -1px; } } input.editable-value { + position: relative; border: none; padding-left: 1px; + z-index: 1; &.editing { border: 1px solid #999999; - box-shadow: 0px 2px 4px 0px #999999; - margin-bottom: 4px; + box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.2); + z-index: 10; + margin-top: -1px; + margin-bottom: -1px; } } From 17740714deb20846952fb999cdcd194dd27a8779 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 13:01:50 -0400 Subject: [PATCH 37/52] INT-1160: Fix min key, max key, binary display --- package.json | 2 +- src/app/documents/index.less | 9 +++++++++ .../crud/lib/component/editable-element.jsx | 8 ++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4e2fedab51e..0f2a02387ae 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "hadron-action": "^0.0.4", "hadron-auto-update-manager": "^0.0.12", "hadron-compile-cache": "^0.1.0", - "hadron-component-registry": "^0.2.1", + "hadron-component-registry": "^0.3.0", "hadron-document": "^0.10.0", "hadron-ipc": "^0.0.7", "hadron-module-cache": "^0.0.3", diff --git a/src/app/documents/index.less b/src/app/documents/index.less index e6adb739b64..c7aa5229df5 100644 --- a/src/app/documents/index.less +++ b/src/app/documents/index.less @@ -98,6 +98,15 @@ ol.document-list { } } + .document-property.code > .document-property-value { + &::before { + content: "Code('"; + } + &::after { + content: "')"; + } + } + li.document-property.array, li.document-property.object { display: block; margin-left: -16px; diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index f3342754bc1..70658e6974b 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -130,7 +130,7 @@ class EditableElement extends React.Component { */ elementComponents() { return _.map(this.element.elements, (element) => { - return React.createElement(EditableElement, { key: element.uuid, element: element }); + return (); }); } @@ -141,11 +141,11 @@ class EditableElement extends React.Component { */ action() { if (this.element.isEdited() || this.element.isRemoved()) { - return React.createElement(RevertAction, { element: this.element }); + return (); } else if (this.element.key === '_id') { - return React.createElement(NoAction, { element: this.element }); + return (); } - return React.createElement(RemoveAction, { element: this.element }); + return (RemoveAction element={this.element}); } handleAdd() { From 2881fae43533635ea627ec7b66e43657d78ef45a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 13:48:27 -0400 Subject: [PATCH 38/52] INT-1160: Handle all types in editable list --- .../crud/lib/component/binary-value.jsx | 71 +++++++++++++++++++ .../crud/lib/component/code-value.jsx | 52 ++++++++++++++ .../crud/lib/component/editable-element.jsx | 60 ++++++++++++++-- .../crud/lib/component/editable-value.jsx | 27 +++---- .../crud/lib/component/max-key-value.jsx | 41 +++++++++++ .../crud/lib/component/min-key-value.jsx | 41 +++++++++++ .../crud/lib/component/objectid-value.jsx | 41 +++++++++++ .../crud/lib/component/timestamp-value.jsx | 41 +++++++++++ 8 files changed, 350 insertions(+), 24 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/binary-value.jsx create mode 100644 src/internal-packages/crud/lib/component/code-value.jsx create mode 100644 src/internal-packages/crud/lib/component/max-key-value.jsx create mode 100644 src/internal-packages/crud/lib/component/min-key-value.jsx create mode 100644 src/internal-packages/crud/lib/component/objectid-value.jsx create mode 100644 src/internal-packages/crud/lib/component/timestamp-value.jsx diff --git a/src/internal-packages/crud/lib/component/binary-value.jsx b/src/internal-packages/crud/lib/component/binary-value.jsx new file mode 100644 index 00000000000..2513b27b835 --- /dev/null +++ b/src/internal-packages/crud/lib/component/binary-value.jsx @@ -0,0 +1,71 @@ +'use strict'; + +const React = require('react'); +const truncate = require('hadron-component-registry').truncate; + +/** + * Base 64 constant. + */ +const BASE_64 = 'base64'; + +/** + * The new UUID type. + */ +const UUID = 4; + +/** + * The old UUID type. + */ +const UUID_OLD = 3; + +/** + * The document value class. + */ +const VALUE_CLASS = 'document-property-value'; + +/** + * Binary value component. + */ +class BinaryValue extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.value = props.element.currentValue; + } + + /** + * Render a single binary value. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
      + {this.renderValue()} +
      + ); + } + + /** + * Render the value. + * + * @returns {Component} The component. + */ + renderValue() { + var type = this.value.sub_type; + var buffer = this.value.buffer; + if (type === UUID || type === UUID_OLD) { + return `Binary('${truncate(buffer.toString())}')`; + } + return `Binary('${truncate(buffer.toString(BASE_64))}')`; + } +} + +BinaryValue.displayName = 'BinaryValue'; + +module.exports = BinaryValue; diff --git a/src/internal-packages/crud/lib/component/code-value.jsx b/src/internal-packages/crud/lib/component/code-value.jsx new file mode 100644 index 00000000000..00e96bd5972 --- /dev/null +++ b/src/internal-packages/crud/lib/component/code-value.jsx @@ -0,0 +1,52 @@ +'use strict'; + +const React = require('react'); +const truncate = require('hadron-component-registry').truncate; + +/** + * The document value class. + */ +const VALUE_CLASS = 'document-property-value'; + +/** + * Code value component. + */ +class CodeValue extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.value = props.element.currentValue; + } + + /** + * Render a single max key value. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
      + {this.renderValue()} +
      + ); + } + + /** + * Render the value. + * + * @returns {Component} The component. + */ + renderValue() { + var code = this.value.code; + return `Code('${truncate(code)}')`; + } +} + +CodeValue.displayName = 'CodeValue'; + +module.exports = CodeValue; diff --git a/src/internal-packages/crud/lib/component/editable-element.jsx b/src/internal-packages/crud/lib/component/editable-element.jsx index 70658e6974b..2e133f2824b 100644 --- a/src/internal-packages/crud/lib/component/editable-element.jsx +++ b/src/internal-packages/crud/lib/component/editable-element.jsx @@ -59,8 +59,23 @@ const LABEL_CLASS = 'document-property-type-label'; */ const EXPANDED = 'expanded'; +/** + * The non-expandable class. + */ const NON_EXPANDABLE = 'non-expandable'; +/** + * Mappings for non editable value components. + */ +const VALUE_MAPPINGS = { + 'Binary': './binary-value', + 'MinKey': './min-key-value', + 'MaxKey': './max-key-value', + 'Code': './code-value', + 'Timestamp': './timestamp-value', + 'ObjectID': './objectid-value' +}; + /** * General editable element component. */ @@ -90,25 +105,48 @@ class EditableElement extends React.Component { return this.element.elements ? this.renderExpandable() : this.renderNonExpandable(); } + /** + * Render a non-expandable element. + * + * @returns {Component} The component. + */ renderNonExpandable() { return (
    2. - {this.action()} + {this.renderAction()} : - + {this.renderValue()}
    3. ); } + /** + * Render the value for the component. + * + * @returns {Component} The value component. + */ + renderValue() { + if (this.element.isValueEditable()) { + return (); + } + var props = { element: this.element }; + return React.createElement(this.valueComponent(this.element.currentType), props); + } + + /** + * Render an expandable element. + * + * @returns {Component} The component. + */ renderExpandable() { return (
    4. - {this.action()} + {this.renderAction()}
      : @@ -139,15 +177,18 @@ class EditableElement extends React.Component { * * @returns {Component} The component. */ - action() { + renderAction() { if (this.element.isEdited() || this.element.isRemoved()) { return (); } else if (this.element.key === '_id') { return (); } - return (RemoveAction element={this.element}); + return (); } + /** + * Handle the addition of an element. + */ handleAdd() { this.setState({ expanded: true }); } @@ -202,6 +243,15 @@ class EditableElement extends React.Component { } return style; } + + /** + * Get the value component for the type. + * + * @returns {Component} The value component. + */ + valueComponent(type) { + return require(VALUE_MAPPINGS[type]); + } } EditableElement.displayName = 'EditableElement'; diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index bbfcf08ec52..6838868bc81 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -35,26 +35,15 @@ class EditableValue extends React.Component { * @returns {React.Component} The element component. */ render() { - return this.renderComponent(); - } - - renderComponent() { - if (this.element.isValueEditable()) { - return ( - - ); - } return ( -
      - {String(this.element.currentValue)} -
      + ); } diff --git a/src/internal-packages/crud/lib/component/max-key-value.jsx b/src/internal-packages/crud/lib/component/max-key-value.jsx new file mode 100644 index 00000000000..b0468c82a42 --- /dev/null +++ b/src/internal-packages/crud/lib/component/max-key-value.jsx @@ -0,0 +1,41 @@ +'use strict'; + +const React = require('react'); + +/** + * The document value class. + */ +const VALUE_CLASS = 'document-property-value'; + +/** + * MaxKey value component. + */ +class MaxKeyValue extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.value = props.element.currentValue; + } + + /** + * Render a single max key value. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
      + MaxKey +
      + ); + } +} + +MaxKeyValue.displayName = 'MaxKeyValue'; + +module.exports = MaxKeyValue; diff --git a/src/internal-packages/crud/lib/component/min-key-value.jsx b/src/internal-packages/crud/lib/component/min-key-value.jsx new file mode 100644 index 00000000000..9751e98281f --- /dev/null +++ b/src/internal-packages/crud/lib/component/min-key-value.jsx @@ -0,0 +1,41 @@ +'use strict'; + +const React = require('react'); + +/** + * The document value class. + */ +const VALUE_CLASS = 'document-property-value'; + +/** + * MinKey value component. + */ +class MinKeyValue extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.value = props.element.currentValue; + } + + /** + * Render a single min key value. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
      + MinKey +
      + ); + } +} + +MinKeyValue.displayName = 'MinKeyValue'; + +module.exports = MinKeyValue; diff --git a/src/internal-packages/crud/lib/component/objectid-value.jsx b/src/internal-packages/crud/lib/component/objectid-value.jsx new file mode 100644 index 00000000000..90d7a77cbc6 --- /dev/null +++ b/src/internal-packages/crud/lib/component/objectid-value.jsx @@ -0,0 +1,41 @@ +'use strict'; + +const React = require('react'); + +/** + * The document value class. + */ +const VALUE_CLASS = 'document-property-value'; + +/** + * ObjectID value component. + */ +class ObjectIDValue extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.value = props.element.currentValue; + } + + /** + * Render a single object id value. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
      + {String(this.value)} +
      + ); + } +} + +ObjectIDValue.displayName = 'ObjectIDValue'; + +module.exports = ObjectIDValue; diff --git a/src/internal-packages/crud/lib/component/timestamp-value.jsx b/src/internal-packages/crud/lib/component/timestamp-value.jsx new file mode 100644 index 00000000000..54a953246d0 --- /dev/null +++ b/src/internal-packages/crud/lib/component/timestamp-value.jsx @@ -0,0 +1,41 @@ +'use strict'; + +const React = require('react'); + +/** + * The document value class. + */ +const VALUE_CLASS = 'document-property-value'; + +/** + * Timestamp value component. + */ +class TimestampValue extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.value = props.element.currentValue; + } + + /** + * Render a single timestamp value. + * + * @returns {React.Component} The element component. + */ + render() { + return ( +
      + {String(this.value)} +
      + ); + } +} + +TimestampValue.displayName = 'TimestampValue'; + +module.exports = TimestampValue; From 2c25b9e9cad13d9a4f162cfec29493eb4a9c2fd3 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 17:05:05 -0400 Subject: [PATCH 39/52] INT-1160: Adding base insert modal --- package.json | 3 +- src/internal-packages/crud/lib/actions.js | 5 +- .../lib/component/clone-document-button.jsx | 35 ++++++++++ .../crud/lib/component/code-value.jsx | 12 +--- .../lib/component/delete-document-button.jsx | 2 +- .../crud/lib/component/document-actions.jsx | 2 + .../crud/lib/component/document.jsx | 8 ++- .../lib/component/edit-document-button.jsx | 2 +- .../crud/lib/component/editable-key.jsx | 12 ++++ .../crud/lib/component/editable-value.jsx | 23 ++++--- .../lib/component/insert-document-dialog.jsx | 56 ++++++++++++++++ .../crud/lib/component/insert-document.jsx | 67 +++++++++++++++++++ .../crud/lib/component/types.jsx | 49 ++++++++++++-- .../open-insert-document-dialog-store.js | 29 ++++++++ src/internal-packages/crud/styles/crud.less | 4 ++ 15 files changed, 278 insertions(+), 31 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/clone-document-button.jsx create mode 100644 src/internal-packages/crud/lib/component/insert-document-dialog.jsx create mode 100644 src/internal-packages/crud/lib/component/insert-document.jsx create mode 100644 src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js diff --git a/package.json b/package.json index 0f2a02387ae..cde5e218cc8 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "hadron-module-cache": "^0.0.3", "hadron-package-manager": "0.1.0", "hadron-reflux-store": "^0.0.2", - "hadron-type-checker": "^0.1.0", + "hadron-type-checker": "^0.3.0", "highlight.js": "^8.9.1", "jquery": "^2.1.4", "kerberos": "mongodb-js/kerberos#bc619b1b9213eb4cdae786cf3fb916fc7be66758", @@ -139,6 +139,7 @@ "qs": "^5.2.0", "raf": "^3.1.0", "react": "^0.14.8", + "react-bootstrap": "^0.29.5", "react-dom": "^0.14.8", "semver": "^5.1.0", "storage-mixin": "^0.6.2", diff --git a/src/internal-packages/crud/lib/actions.js b/src/internal-packages/crud/lib/actions.js index 8ed06c40b75..cd2295ccf10 100644 --- a/src/internal-packages/crud/lib/actions.js +++ b/src/internal-packages/crud/lib/actions.js @@ -2,6 +2,9 @@ const Reflux = require('reflux'); -const Actions = Reflux.createActions([ 'documentRemoved' ]); +const Actions = Reflux.createActions([ + 'documentRemoved', + 'openInsertDocumentDialog' +]); module.exports = Actions; diff --git a/src/internal-packages/crud/lib/component/clone-document-button.jsx b/src/internal-packages/crud/lib/component/clone-document-button.jsx new file mode 100644 index 00000000000..1d90ba60353 --- /dev/null +++ b/src/internal-packages/crud/lib/component/clone-document-button.jsx @@ -0,0 +1,35 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the clone document button. + */ +class CloneDocumentButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +CloneDocumentButton.displayName = 'CloneDocumentButton'; + +module.exports = CloneDocumentButton; diff --git a/src/internal-packages/crud/lib/component/code-value.jsx b/src/internal-packages/crud/lib/component/code-value.jsx index 00e96bd5972..48c7c1f0538 100644 --- a/src/internal-packages/crud/lib/component/code-value.jsx +++ b/src/internal-packages/crud/lib/component/code-value.jsx @@ -31,20 +31,10 @@ class CodeValue extends React.Component { render() { return (
      - {this.renderValue()} + {truncate(this.value.code)}
      ); } - - /** - * Render the value. - * - * @returns {Component} The component. - */ - renderValue() { - var code = this.value.code; - return `Code('${truncate(code)}')`; - } } CodeValue.displayName = 'CodeValue'; diff --git a/src/internal-packages/crud/lib/component/delete-document-button.jsx b/src/internal-packages/crud/lib/component/delete-document-button.jsx index 1140329d5d8..f91f549473c 100644 --- a/src/internal-packages/crud/lib/component/delete-document-button.jsx +++ b/src/internal-packages/crud/lib/component/delete-document-button.jsx @@ -23,7 +23,7 @@ class DeleteDocumentButton extends React.Component { */ render() { return ( - ); diff --git a/src/internal-packages/crud/lib/component/document-actions.jsx b/src/internal-packages/crud/lib/component/document-actions.jsx index 75e14087460..bbfc67b666c 100644 --- a/src/internal-packages/crud/lib/component/document-actions.jsx +++ b/src/internal-packages/crud/lib/component/document-actions.jsx @@ -3,6 +3,7 @@ const React = require('react'); const EditDocumentButton = require('./edit-document-button'); const DeleteDocumentButton = require('./delete-document-button'); +const CloneDocumentButton = require('./clone-document-button'); /** * Component for actions on the document. @@ -28,6 +29,7 @@ class DocumentActions extends React.Component {
      +
      ); } diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index 86f2ef637f3..76272f1fb3d 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -217,6 +217,11 @@ class Document extends React.Component { this.setState({ doc: this.doc, editing: false }); } + handleClone() { + console.log('Cloning document...'); + // Actions.openInsertDocumentDialog(this.doc); + } + /** * Handles document deletion. */ @@ -287,7 +292,8 @@ class Document extends React.Component { return ( + remove={this.handleDelete.bind(this)} + clone={this.handleClone.bind(this)} /> ); } } diff --git a/src/internal-packages/crud/lib/component/edit-document-button.jsx b/src/internal-packages/crud/lib/component/edit-document-button.jsx index 483a012a881..c356b7e59b4 100644 --- a/src/internal-packages/crud/lib/component/edit-document-button.jsx +++ b/src/internal-packages/crud/lib/component/edit-document-button.jsx @@ -23,7 +23,7 @@ class EditDocumentButton extends React.Component { */ render() { return ( - ); diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index a4235b8ee1e..0d7d00650da 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -55,10 +55,22 @@ class EditableKey extends React.Component { onBlur={this.handleBlur.bind(this)} onFocus={this.handleFocus.bind(this)} onChange={this.handleChange.bind(this)} + onKeyDown={this.handleKeyDown.bind(this)} value={this.element.currentKey} /> ); } + /** + * When hitting a key on the last element some special things may happen. + * + * @param {Event} evt - The event. + */ + handleKeyDown(evt) { + if (evt.keyCode === 27) { + this._node.blur(); + } + } + /** * Handles changes to the element key. * diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index 6838868bc81..4c2449edeab 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -1,7 +1,9 @@ 'use strict'; +const _ = require('lodash'); const React = require('react'); const ElementFactory = require('hadron-component-registry').ElementFactory; +const TypeChecker = require('hadron-type-checker'); /** * The editing class constant. @@ -37,6 +39,7 @@ class EditableValue extends React.Component { render() { return ( this._node = c} type='text' className={this.style()} onBlur={this.handleBlur.bind(this)} @@ -55,6 +58,8 @@ class EditableValue extends React.Component { handleKeyDown(evt) { if (evt.keyCode === 9 && !evt.shiftKey) { this.element.next(); + } else if (evt.keyCode === 27) { + this._node.blur(); } } @@ -64,28 +69,28 @@ class EditableValue extends React.Component { * @param {Event} evt - The event. */ handleChange(evt) { - if (this.element.isValueEditable()) { - this.element.edit(evt.target.value); - this.setState({ value: this.element.currentValue }); + var value = evt.target.value; + var currentType = this.element.currentType; + if (_.includes(TypeChecker.castableTypes(value), currentType)) { + this.element.edit(TypeChecker.cast(value, currentType)); + } else { + this.element.edit(value); } + this.setState({ value: this.element.currentValue }); } /** * Handle focus on the value. */ handleFocus() { - if (this.element.isValueEditable()) { - this.setState({ editing: true }); - } + this.setState({ editing: true }); } /** * Handle blur from the value. */ handleBlur() { - if (this.element.isValueEditable()) { - this.setState({ editing: false }); - } + this.setState({ editing: false }); } /** diff --git a/src/internal-packages/crud/lib/component/insert-document-dialog.jsx b/src/internal-packages/crud/lib/component/insert-document-dialog.jsx new file mode 100644 index 00000000000..2c0bb4371f7 --- /dev/null +++ b/src/internal-packages/crud/lib/component/insert-document-dialog.jsx @@ -0,0 +1,56 @@ +'use strict'; + +const React = require('react'); +const Modal = require('react-bootstrap').Modal; +const OpenInsertDocumentDialogStore = require('../store/open-insert-document-dialog-store'); +const InsertDocument = require('./insert-document'); + +/** + * Component for the insert document dialog. + */ +class InsertDocumentDialog extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.state = { open: false }; + } + + componentWillMount() { + this.unsubscribeOpen = OpenInsertDocumentDialogStore.listen(this.handleStoreOpen.bind(this)); + } + + componentWillUnmount() { + this.unsubscribeOpen(); + } + + handleStoreOpen(doc) { + console.log(doc); + this.setState({ doc: doc, open: true }); + } + + render() { + return ( + + + Insert Document + + + + + + + + + + ); + } +} + +InsertDocumentDialog.displayName = 'InsertDocumentDialog'; + +module.exports = InsertDocumentDialog; diff --git a/src/internal-packages/crud/lib/component/insert-document.jsx b/src/internal-packages/crud/lib/component/insert-document.jsx new file mode 100644 index 00000000000..afc79400f89 --- /dev/null +++ b/src/internal-packages/crud/lib/component/insert-document.jsx @@ -0,0 +1,67 @@ +'use strict'; + +const _ = require('lodash'); +const React = require('react'); +const EditableElement = require('./editable-element'); +const Hotspot = require('./hotspot'); + +/** + * The class for the document itself. + */ +const DOCUMENT_CLASS = 'document-property-body'; + +/** + * The class for the list item wrapper. + */ +const LIST_ITEM_CLASS = 'document-list-item'; + +/** + * Component for a single document in a list of documents. + */ +class InsertDocument extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.doc = props.doc; + } + + /** + * Render a single document list item. + */ + render() { + return ( +
    5. +
        +
        + {this.renderElements(this.doc)} +
        +
      +
    6. + ); + } + + /** + * Get the editable elements. + * + * @returns {Array} The editable elements. + */ + renderElements() { + var elements = _.map(this.doc.elements, (element) => { + return ( + + ); + }); + var lastElement = elements[elements.length - 1].props.element; + elements.push(); + return elements; + } +} + +InsertDocument.displayName = 'InsertDocument'; + +module.exports = InsertDocument; diff --git a/src/internal-packages/crud/lib/component/types.jsx b/src/internal-packages/crud/lib/component/types.jsx index 758426620dc..88de6fbf48e 100644 --- a/src/internal-packages/crud/lib/component/types.jsx +++ b/src/internal-packages/crud/lib/component/types.jsx @@ -19,12 +19,30 @@ class Types extends React.Component { this.element = props.element; } + /** + * Handles a change in the type. + * + * @param {Event} evt - The event. + */ + handleTypeChange(evt) { + this.element.edit(TypeChecker.cast(this.castableValue(), evt.target.innerText)); + } + /** * Render a type list. * * @returns {React.Component} The element component. */ render() { + return this.element.isValueEditable() ? this.renderDropdown() : this.renderLabel(); + } + + /** + * Render the type list dropdown. + * + * @returns {Component} The react component. + */ + renderDropdown() { return (
        - {this.castableTypes()} + {this.renderTypes()}
      ); } - castableTypes() { + /** + * Render the type list label. + * + * @returns {Component} The react component. + */ + renderLabel() { + return ( +
      + {this.element.currentType} +
      + ); + } + + /** + * Render the types + * + * @returns {Component} The react component. + */ + renderTypes() { return _.map(TypeChecker.castableTypes(this.castableValue()), (type) => { return (
    7. @@ -55,6 +91,11 @@ class Types extends React.Component { }); } + /** + * Get the castable value for this value. + * + * @returns {Object} The cast value. + */ castableValue() { if (this.element.elements) { if (this.element.currentType === 'Object') { @@ -66,10 +107,6 @@ class Types extends React.Component { } return this.element.currentValue; } - - handleTypeChange(evt) { - this.element.edit(TypeChecker.cast(this.castableValue(), evt.target.innerText)); - } } Types.displayName = 'Types'; diff --git a/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js new file mode 100644 index 00000000000..eb3e4d8246c --- /dev/null +++ b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js @@ -0,0 +1,29 @@ +'use strict'; + +const Reflux = require('reflux'); +const Actions = require('../actions'); +const HadronDocument = require('hadron-document'); + +/** + * The reflux store for opening the insert document dialog. + */ +const OpenInsertDocumentDialogStore = Reflux.createStore({ + + /** + * Initialize the reset document list store. + */ + init: function() { + this.listenTo(Actions.openInsertDocumentDialog, this.openInsertDocumentDialog); + }, + + /** + * Open the insert document dialog. + * + * @param {Object} doc - The document to open the dialog with. + */ + openInsertDocumentDialog: function(doc) { + this.trigger(new HadronDocument(doc)); + } +}); + +module.exports = OpenInsertDocumentDialogStore; diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 9d3a06e948d..6a0a2661281 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -123,6 +123,10 @@ ol.document-property-body:hover { color: #999999; height: 17px; + .type-label { + padding: 1px 12px; + } + .btn { background-color: transparent; color: @gray4; From 763b89f60b16dcc37b1bea72c6a0186e2a9abd1a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 17:44:38 -0400 Subject: [PATCH 40/52] INT-1160: Open insert document modal with clone --- package.json | 2 +- .../lib/component/cancel-insert-button.jsx | 38 +++++++++++++++++++ .../crud/lib/component/document-list.jsx | 2 + .../crud/lib/component/document.jsx | 2 +- .../crud/lib/component/insert-button.jsx | 38 +++++++++++++++++++ .../lib/component/insert-document-dialog.jsx | 12 ++++++ .../crud/lib/component/insert-document.jsx | 21 ++++++---- src/internal-packages/crud/styles/crud.less | 10 +++++ 8 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/cancel-insert-button.jsx create mode 100644 src/internal-packages/crud/lib/component/insert-button.jsx diff --git a/package.json b/package.json index cde5e218cc8..619753c3eef 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "qs": "^5.2.0", "raf": "^3.1.0", "react": "^0.14.8", - "react-bootstrap": "^0.29.5", + "react-bootstrap": "0.29.5", "react-dom": "^0.14.8", "semver": "^5.1.0", "storage-mixin": "^0.6.2", diff --git a/src/internal-packages/crud/lib/component/cancel-insert-button.jsx b/src/internal-packages/crud/lib/component/cancel-insert-button.jsx new file mode 100644 index 00000000000..f971e79eb0b --- /dev/null +++ b/src/internal-packages/crud/lib/component/cancel-insert-button.jsx @@ -0,0 +1,38 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the cancel button. + */ +class CancelInsertButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +CancelInsertButton.displayName = 'CancelInsertButton'; + +module.exports = CancelInsertButton; diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index 091eebc4a3a..f39add09e8c 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -10,6 +10,7 @@ const Document = require('./document'); const ResetDocumentListStore = require('../store/reset-document-list-store'); const LoadMoreDocumentsStore = require('../store/load-more-documents-store'); const RemoveDocumentStore = require('../store/remove-document-store'); +const InsertDocumentDialog = require('./insert-document-dialog'); /** * The full document list container class. @@ -149,6 +150,7 @@ class DocumentList extends React.Component { return (
        {this.state.docs} +
      ); } diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index 76272f1fb3d..94612c14c89 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -219,7 +219,7 @@ class Document extends React.Component { handleClone() { console.log('Cloning document...'); - // Actions.openInsertDocumentDialog(this.doc); + Actions.openInsertDocumentDialog(this.doc); } /** diff --git a/src/internal-packages/crud/lib/component/insert-button.jsx b/src/internal-packages/crud/lib/component/insert-button.jsx new file mode 100644 index 00000000000..86efe53ddef --- /dev/null +++ b/src/internal-packages/crud/lib/component/insert-button.jsx @@ -0,0 +1,38 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the insert button. + */ +class InsertButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +InsertButton.displayName = 'InsertButton'; + +module.exports = InsertButton; diff --git a/src/internal-packages/crud/lib/component/insert-document-dialog.jsx b/src/internal-packages/crud/lib/component/insert-document-dialog.jsx index 2c0bb4371f7..0966390a998 100644 --- a/src/internal-packages/crud/lib/component/insert-document-dialog.jsx +++ b/src/internal-packages/crud/lib/component/insert-document-dialog.jsx @@ -4,6 +4,8 @@ const React = require('react'); const Modal = require('react-bootstrap').Modal; const OpenInsertDocumentDialogStore = require('../store/open-insert-document-dialog-store'); const InsertDocument = require('./insert-document'); +const CancelInsertButton = require('./cancel-insert-button'); +const InsertButton = require('./insert-button'); /** * Component for the insert document dialog. @@ -33,6 +35,14 @@ class InsertDocumentDialog extends React.Component { this.setState({ doc: doc, open: true }); } + handleCancel() { + this.setState({ open: false }); + } + + handleInsert() { + this.setState({ open: false }); + } + render() { return ( @@ -45,6 +55,8 @@ class InsertDocumentDialog extends React.Component { + + ); diff --git a/src/internal-packages/crud/lib/component/insert-document.jsx b/src/internal-packages/crud/lib/component/insert-document.jsx index afc79400f89..7b8782ef46c 100644 --- a/src/internal-packages/crud/lib/component/insert-document.jsx +++ b/src/internal-packages/crud/lib/component/insert-document.jsx @@ -10,6 +10,11 @@ const Hotspot = require('./hotspot'); */ const DOCUMENT_CLASS = 'document-property-body'; +/** + * The full document list container class. + */ +const LIST_CLASS = 'document-list'; + /** * The class for the list item wrapper. */ @@ -35,13 +40,15 @@ class InsertDocument extends React.Component { */ render() { return ( -
    8. -
        -
        - {this.renderElements(this.doc)} -
        -
      -
    9. +
        +
      1. +
          +
          + {this.renderElements(this.doc)} +
          +
        +
      2. +
      ); } diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 6a0a2661281..092980d5363 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -341,3 +341,13 @@ input.editable-value { .document-property.date > .editable-value { color: firebrick; } + +.modal-body { + .document-elements { + width: 100%; + } +} + +.modal-footer { + +} From e1b439d070296e68a826436167a0d19e7cc8cf27 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 17:52:51 -0400 Subject: [PATCH 41/52] INT-1160: Styling insert button --- src/internal-packages/crud/styles/crud.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 092980d5363..79bef0bf60d 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -349,5 +349,9 @@ input.editable-value { } .modal-footer { - + .btn.insert { + border-color: green; + background-color: @green2; + color: #FFFFFF; + } } From 4f044accb19a944b246c1c22b32e867b4c0842c9 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 18:01:37 -0400 Subject: [PATCH 42/52] INT-1160: Shift elements on clone --- .../crud/lib/store/open-insert-document-dialog-store.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js index eb3e4d8246c..ae2e0b6c674 100644 --- a/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js +++ b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js @@ -22,7 +22,11 @@ const OpenInsertDocumentDialogStore = Reflux.createStore({ * @param {Object} doc - The document to open the dialog with. */ openInsertDocumentDialog: function(doc) { - this.trigger(new HadronDocument(doc)); + var hadronDoc = new HadronDocument(doc); + // We need to remove the _id or we will get an duplicate key error on + // insert, and we currently do not allow editing of the _id field. + hadronDoc.elements.shift(); + this.trigger(hadronDoc); } }); From 42007dea82f3e995f317212e35711876a0cd56d0 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 18:06:57 -0400 Subject: [PATCH 43/52] INT-1160: Handle events in insert dialog --- .../crud/lib/component/insert-document.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/internal-packages/crud/lib/component/insert-document.jsx b/src/internal-packages/crud/lib/component/insert-document.jsx index 7b8782ef46c..50af5544133 100644 --- a/src/internal-packages/crud/lib/component/insert-document.jsx +++ b/src/internal-packages/crud/lib/component/insert-document.jsx @@ -2,6 +2,7 @@ const _ = require('lodash'); const React = require('react'); +const Element = require('hadron-document').Element; const EditableElement = require('./editable-element'); const Hotspot = require('./hotspot'); @@ -33,6 +34,12 @@ class InsertDocument extends React.Component { constructor(props) { super(props); this.doc = props.doc; + this.doc.on(Element.Events.Added, this.handleModify.bind(this)); + this.doc.on(Element.Events.Removed, this.handleModify.bind(this)); + } + + handleModify() { + this.setState({}); } /** From eacc12090327cedb65026812e8ebd682d92f65f8 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 18:19:27 -0400 Subject: [PATCH 44/52] INT-1160: New documents are in added state --- package.json | 2 +- .../crud/lib/component/insert-document.jsx | 3 ++ .../open-insert-document-dialog-store.js | 2 +- src/internal-packages/crud/styles/crud.less | 30 +++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 619753c3eef..16f8ae3fb89 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "hadron-auto-update-manager": "^0.0.12", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.3.0", - "hadron-document": "^0.10.0", + "hadron-document": "^0.11.0", "hadron-ipc": "^0.0.7", "hadron-module-cache": "^0.0.3", "hadron-package-manager": "0.1.0", diff --git a/src/internal-packages/crud/lib/component/insert-document.jsx b/src/internal-packages/crud/lib/component/insert-document.jsx index 50af5544133..50ec1236ef2 100644 --- a/src/internal-packages/crud/lib/component/insert-document.jsx +++ b/src/internal-packages/crud/lib/component/insert-document.jsx @@ -38,6 +38,9 @@ class InsertDocument extends React.Component { this.doc.on(Element.Events.Removed, this.handleModify.bind(this)); } + /** + * Handle modifications to the document. + */ handleModify() { this.setState({}); } diff --git a/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js index ae2e0b6c674..7ab304d1d0a 100644 --- a/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js +++ b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js @@ -22,7 +22,7 @@ const OpenInsertDocumentDialogStore = Reflux.createStore({ * @param {Object} doc - The document to open the dialog with. */ openInsertDocumentDialog: function(doc) { - var hadronDoc = new HadronDocument(doc); + var hadronDoc = new HadronDocument(doc, true); // We need to remove the _id or we will get an duplicate key error on // insert, and we currently do not allow editing of the _id field. hadronDoc.elements.shift(); diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 79bef0bf60d..86b770b926d 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -345,6 +345,36 @@ input.editable-value { .modal-body { .document-elements { width: 100%; + + li.document-property { + + .actions { + display: inline-block; + visibility: hidden; + width: 18px; + margin-right: 8px; + text-align: center; + cursor: pointer; + color: #999999; + } + + &.added { + background-color: #FFFFFF; + + input { + background-color: #FFFFFF; + + &:focus { + background-color: @pw; + } + } + + .line-number { + background-color: #FFFFFF; + color: #999999; + } + } + } } } From 6d62b9014cbe189245e67e4cc4c9b856d6c34fad Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 23 Jun 2016 18:47:29 -0400 Subject: [PATCH 45/52] INT-1160: Documents are inserting --- src/internal-packages/crud/lib/actions.js | 3 +- .../crud/lib/component/document-list.jsx | 17 ++++++++ .../lib/component/insert-document-dialog.jsx | 3 +- .../crud/lib/store/insert-document-store.jsx | 42 +++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/internal-packages/crud/lib/store/insert-document-store.jsx diff --git a/src/internal-packages/crud/lib/actions.js b/src/internal-packages/crud/lib/actions.js index cd2295ccf10..4ddd3f84356 100644 --- a/src/internal-packages/crud/lib/actions.js +++ b/src/internal-packages/crud/lib/actions.js @@ -4,7 +4,8 @@ const Reflux = require('reflux'); const Actions = Reflux.createActions([ 'documentRemoved', - 'openInsertDocumentDialog' + 'openInsertDocumentDialog', + 'insertDocument' ]); module.exports = Actions; diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index f39add09e8c..fe229f63c51 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -10,6 +10,7 @@ const Document = require('./document'); const ResetDocumentListStore = require('../store/reset-document-list-store'); const LoadMoreDocumentsStore = require('../store/load-more-documents-store'); const RemoveDocumentStore = require('../store/remove-document-store'); +const InsertDocumentStore = require('../store/insert-document-store'); const InsertDocumentDialog = require('./insert-document-dialog'); /** @@ -46,6 +47,7 @@ class DocumentList extends React.Component { this.unsubscribeReset = ResetDocumentListStore.listen(this.handleReset.bind(this)); this.unsubscribeLoadMore = LoadMoreDocumentsStore.listen(this.handleLoadMore.bind(this)); this.unsubscribeRemove = RemoveDocumentStore.listen(this.handleRemove.bind(this)); + this.unsibscribeInsert = InsertDocumentStore.listen(this.handleInsert.bind(this)); } /** @@ -55,6 +57,7 @@ class DocumentList extends React.Component { this.unsubscribeReset(); this.unsubscribeLoadMore(); this.unsubscribeRemove(); + this.unsubscribeInsert(); } /** @@ -131,6 +134,20 @@ class DocumentList extends React.Component { } } + shouldComponentUpdate(nextProps, nextState) { + return (nextState.docs.length !== this.state.docs.length) || + (nextState.currentPage !== this.state.currentPage) || + (nextState.loadedCount !== this.state.loadedCount); + } + + handleInsert(success, object) { + if (success) { + this.setState({ count: this.state.count + 1 }); + // Figure out skip and limit options from state. + this.loadMore(); + } + } + /** * Get the next batch of documents. Will only fire if there are more documents * in the collection to load. diff --git a/src/internal-packages/crud/lib/component/insert-document-dialog.jsx b/src/internal-packages/crud/lib/component/insert-document-dialog.jsx index 0966390a998..39bf9f65240 100644 --- a/src/internal-packages/crud/lib/component/insert-document-dialog.jsx +++ b/src/internal-packages/crud/lib/component/insert-document-dialog.jsx @@ -6,6 +6,7 @@ const OpenInsertDocumentDialogStore = require('../store/open-insert-document-dia const InsertDocument = require('./insert-document'); const CancelInsertButton = require('./cancel-insert-button'); const InsertButton = require('./insert-button'); +const Actions = require('../actions'); /** * Component for the insert document dialog. @@ -31,7 +32,6 @@ class InsertDocumentDialog extends React.Component { } handleStoreOpen(doc) { - console.log(doc); this.setState({ doc: doc, open: true }); } @@ -41,6 +41,7 @@ class InsertDocumentDialog extends React.Component { handleInsert() { this.setState({ open: false }); + Actions.insertDocument(this.state.doc.generateObject()); } render() { diff --git a/src/internal-packages/crud/lib/store/insert-document-store.jsx b/src/internal-packages/crud/lib/store/insert-document-store.jsx new file mode 100644 index 00000000000..770f52afa22 --- /dev/null +++ b/src/internal-packages/crud/lib/store/insert-document-store.jsx @@ -0,0 +1,42 @@ +'use strict'; + +const Reflux = require('reflux'); +const app = require('ampersand-app'); +const NamespaceStore = require('hadron-reflux-store').NamespaceStore; +const Actions = require('../actions'); + +/** + * The reflux store for inserting documents. + */ +const InsertDocumentStore = Reflux.createStore({ + + /** + * Initialize the insert document list store. + */ + init: function() { + this.listenTo(Actions.insertDocument, this.insertDocument); + }, + + /** + * Insert the document. + * + * @param {Document} doc - The document to insert. + */ + insertDocument: function(doc) { + app.dataService.insertOne(NamespaceStore.ns, doc, {}, this.handleResult.bind(this)); + }, + + /** + * Handle the result from the driver. + * + * @param {Error} error - The error. + * @param {Object} doc - The document. + * + * @returns {Object} The trigger event. + */ + handleResult: function(error, doc) { + return (error) ? this.trigger(false, error) : this.trigger(true, doc); + } +}); + +module.exports = InsertDocumentStore; From 31e8c0be25a847e514d4ef599d5785f3ec7811cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Sch=C3=A4ffner-Gurney?= Date: Thu, 23 Jun 2016 21:02:52 -0400 Subject: [PATCH 46/52] some style overrides to fix alignment in json view of explain tab --- src/app/explain-plan/index.less | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/app/explain-plan/index.less b/src/app/explain-plan/index.less index 28483502905..164985881af 100644 --- a/src/app/explain-plan/index.less +++ b/src/app/explain-plan/index.less @@ -1,5 +1,27 @@ .explain-container { + // hacks for json view on explain tab + ol.document-list li.document-list-item ol.document-property-body li.document-property.array ol.document-property-body .document-property-key, + ol.document-list li.document-list-item ol.document-property-body li.document-property.object ol.document-property-body .document-property-key { + margin-left: 0; + } + + ol.document-list li.document-list-item ol.document-property-body li.document-property.array.expanded > ol.document-property-body, + ol.document-list li.document-list-item ol.document-property-body li.document-property.object.expanded > ol.document-property-body { + margin-left: 16px; + } + + ol.document-list li.document-list-item ol.document-property-body li.document-property.array.expanded, + ol.document-list li.document-list-item ol.document-property-body li.document-property.object.expanded { + margin-left: 0; + } + + ol.document-list li.document-list-item ol.document-property-body li.document-property.array, + ol.document-list li.document-list-item ol.document-property-body li.document-property.object { + margin-left: 0; + } + // end hacks + .summary-container { background: @pw; padding: 12px; @@ -59,7 +81,6 @@ float: left; margin-right: 24px; } - } i.link { From 743b02e30f85e3a0bc3752fa597a48c6c01ffb67 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 24 Jun 2016 10:28:39 -0400 Subject: [PATCH 47/52] INT-1160: Smarter skip/limit on document list --- .../crud/lib/component/document-list.jsx | 11 +++++------ .../crud/lib/store/load-more-documents-store.js | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index fe229f63c51..d52f8c4f51d 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -67,7 +67,7 @@ class DocumentList extends React.Component { */ constructor(props) { super(props); - this.state = { docs: [], currentPage: 0 }; + this.state = { docs: [], nextSkip: 0 }; } /** @@ -81,7 +81,7 @@ class DocumentList extends React.Component { // by the number of new documents. this.setState({ docs: this.state.docs.concat(this.renderDocuments(documents)), - currentPage: (this.state.currentPage + 1), + nextSkip: (this.state.nextSkip + documents.length), loadedCount: (this.state.loadedCount + documents.length) }); } @@ -98,7 +98,7 @@ class DocumentList extends React.Component { // total count are reset here as well. this.setState({ docs: this.renderDocuments(documents), - currentPage: 1, + nextSkip: documents.length, count: count, loadedCount: documents.length }); @@ -136,14 +136,13 @@ class DocumentList extends React.Component { shouldComponentUpdate(nextProps, nextState) { return (nextState.docs.length !== this.state.docs.length) || - (nextState.currentPage !== this.state.currentPage) || + (nextState.nextSkip !== this.state.nextSkip) || (nextState.loadedCount !== this.state.loadedCount); } handleInsert(success, object) { if (success) { this.setState({ count: this.state.count + 1 }); - // Figure out skip and limit options from state. this.loadMore(); } } @@ -154,7 +153,7 @@ class DocumentList extends React.Component { */ loadMore() { if (this.state.loadedCount < this.state.count) { - Action.fetchNextDocuments(this.state.currentPage); + Action.fetchNextDocuments(this.state.nextSkip); } } diff --git a/src/internal-packages/crud/lib/store/load-more-documents-store.js b/src/internal-packages/crud/lib/store/load-more-documents-store.js index 8442be6481b..22c955b50c1 100644 --- a/src/internal-packages/crud/lib/store/load-more-documents-store.js +++ b/src/internal-packages/crud/lib/store/load-more-documents-store.js @@ -20,11 +20,11 @@ const LoadMoreDocumentsStore = Reflux.createStore({ /** * Fetch the next page of documents. * - * @param {Integer} currentPage - The current page in the view. + * @param {Integer} skip - The number of documents to skip. */ - loadMoreDocuments: function(currentPage) { + loadMoreDocuments: function(skip) { var filter = app.queryOptions.query.serialize(); - var options = { skip: (currentPage * 20), limit: 20, sort: [[ '_id', 1 ]] }; + var options = { skip: skip, limit: 20, sort: [[ '_id', 1 ]] }; app.dataService.find(NamespaceStore.ns, filter, options, (error, documents) => { this.trigger(documents); }); From 296f1c8bab2979056b1fc61030a25d4f85819cdd Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 24 Jun 2016 10:48:28 -0400 Subject: [PATCH 48/52] INT-1160: Styling on error, fix nextSkip on delete --- .../crud/lib/component/document-footer.jsx | 2 +- .../crud/lib/component/document-list.jsx | 30 ++++++++++++++----- .../crud/lib/component/editable-key.jsx | 3 +- .../crud/lib/component/editable-value.jsx | 3 +- src/internal-packages/crud/styles/crud.less | 2 ++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/internal-packages/crud/lib/component/document-footer.jsx b/src/internal-packages/crud/lib/component/document-footer.jsx index 7cd63ccd006..8a3cec0b642 100644 --- a/src/internal-packages/crud/lib/component/document-footer.jsx +++ b/src/internal-packages/crud/lib/component/document-footer.jsx @@ -165,7 +165,7 @@ class DocumentFooter extends React.Component { render() { return (
      -
      +
      {this.state.message}
      diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index d52f8c4f51d..853a4edec20 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -117,7 +117,11 @@ class DocumentList extends React.Component { return component.props.doc._id === id; }); this.state.docs.splice(index, 1); - this.setState({ docs: this.state.docs, loadedCount: (this.state.loadedCount - 1) }); + this.setState({ + docs: this.state.docs, + loadedCount: (this.state.loadedCount - 1), + nextSkip: (this.state.nextSkip - 1) + }); } /** @@ -134,12 +138,12 @@ class DocumentList extends React.Component { } } - shouldComponentUpdate(nextProps, nextState) { - return (nextState.docs.length !== this.state.docs.length) || - (nextState.nextSkip !== this.state.nextSkip) || - (nextState.loadedCount !== this.state.loadedCount); - } - + /** + * Handle insert of a new document. + * + * @param {Boolean} success - If the insert was successful. + * @param {Object} object - The new document or error. + */ handleInsert(success, object) { if (success) { this.setState({ count: this.state.count + 1 }); @@ -184,6 +188,18 @@ class DocumentList extends React.Component { }); } + /** + * Determine if the component should update. + * + * @param {Object} nextProps - The next properties. + * @param {Object} nextState - The next state. + */ + shouldComponentUpdate(nextProps, nextState) { + return (nextState.docs.length !== this.state.docs.length) || + (nextState.nextSkip !== this.state.nextSkip) || + (nextState.loadedCount !== this.state.loadedCount); + } + /** * Get the distance in pixels from the end of the document list to the point when * scrolling where we want to load more documents. diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 0d7d00650da..81d2aac1c73 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -25,7 +25,7 @@ class EditableKey extends React.Component { constructor(props) { super(props); this.element = props.element; - this.state = { key: this.element.currentKey, editing: false }; + this.state = { editing: false }; } /** @@ -79,7 +79,6 @@ class EditableKey extends React.Component { handleChange(evt) { if (this.isEditable()) { this.element.rename(evt.target.value); - this.setState({ key: this.element.currentKey }); } } diff --git a/src/internal-packages/crud/lib/component/editable-value.jsx b/src/internal-packages/crud/lib/component/editable-value.jsx index 4c2449edeab..5857e763d53 100644 --- a/src/internal-packages/crud/lib/component/editable-value.jsx +++ b/src/internal-packages/crud/lib/component/editable-value.jsx @@ -28,7 +28,7 @@ class EditableValue extends React.Component { constructor(props) { super(props); this.element = props.element; - this.state = { value: this.element.currentValue, editing: false }; + this.state = { editing: false }; } /** @@ -76,7 +76,6 @@ class EditableValue extends React.Component { } else { this.element.edit(value); } - this.setState({ value: this.element.currentValue }); } /** diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 86b770b926d..5159ec9b196 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -15,6 +15,8 @@ li.document-list-item.editing { padding-left: 10px; padding-top: 4px; color: @pw; + overflow: hidden; + height: 28px; } .document-footer-actions { From b0364308eb57f80f191031cd71f245faa31a0d61 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 24 Jun 2016 10:52:37 -0400 Subject: [PATCH 49/52] INT-1160: Fix added style on converted elements --- src/internal-packages/crud/styles/crud.less | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 5159ec9b196..ffd12697396 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -204,11 +204,11 @@ ol.document-property-body:hover { color: #999999; } - &.added { - background-color: @greenBg; + &.edited { + background-color: @alertOrangeBg; input { - background-color: @greenBg; + background-color: @alertOrangeBg; &:focus { background-color: @pw; @@ -216,16 +216,16 @@ ol.document-property-body:hover { } .line-number { - background-color: @green2; + background-color: @alertOrange; color: @pw; } } - &.edited { - background-color: @alertOrangeBg; + &.added { + background-color: @greenBg; input { - background-color: @alertOrangeBg; + background-color: @greenBg; &:focus { background-color: @pw; @@ -233,7 +233,7 @@ ol.document-property-body:hover { } .line-number { - background-color: @alertOrange; + background-color: @green2; color: @pw; } } From 0cd83e1896bb305aacc5d67da2d82001dee1a817 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 24 Jun 2016 11:15:36 -0400 Subject: [PATCH 50/52] INT-1160: CRUD goes behind feature flag --- src/app/models/preferences.js | 8 +++++++ .../crud/lib/component/document-actions.jsx | 21 ++++++++++++++----- .../crud/lib/component/editable-key.jsx | 3 ++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/app/models/preferences.js b/src/app/models/preferences.js index 69234b853cb..63b6be38544 100644 --- a/src/app/models/preferences.js +++ b/src/app/models/preferences.js @@ -144,6 +144,14 @@ var Preferences = Model.extend(storageMixin, { required: true, default: false }, + /** + * Allow single document CRUD. + */ + singleDocumentCrud: { + type: 'boolean', + required: true, + default: false + }, /** * Switches to enable/disable various authentication / ssl types * diff --git a/src/internal-packages/crud/lib/component/document-actions.jsx b/src/internal-packages/crud/lib/component/document-actions.jsx index bbfc67b666c..7b073d80666 100644 --- a/src/internal-packages/crud/lib/component/document-actions.jsx +++ b/src/internal-packages/crud/lib/component/document-actions.jsx @@ -1,10 +1,16 @@ 'use strict'; const React = require('react'); +const app = require('ampersand-app'); const EditDocumentButton = require('./edit-document-button'); const DeleteDocumentButton = require('./delete-document-button'); const CloneDocumentButton = require('./clone-document-button'); +/** + * The feature flag. + */ +const FEATURE = 'singleDocumentCrud'; + /** * Component for actions on the document. */ @@ -25,12 +31,17 @@ class DocumentActions extends React.Component { * @returns {Component} The actions component. */ render() { + if (app.isFeatureEnabled(FEATURE)) { + return ( +
      + + + +
      + ); + } return ( -
      - - - -
      +
      ); } } diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 81d2aac1c73..823852868ac 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -77,8 +77,9 @@ class EditableKey extends React.Component { * @param {Event} evt - The event. */ handleChange(evt) { + var value = evt.target.value; if (this.isEditable()) { - this.element.rename(evt.target.value); + this.element.rename(value); } } From 90768a12cb676633fd978a71158210d6855e7a8d Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 24 Jun 2016 11:42:53 -0400 Subject: [PATCH 51/52] INT-1160: Validate duplicate keys --- package.json | 2 +- .../crud/lib/component/editable-key.jsx | 35 +++++++++++++++++-- src/internal-packages/crud/styles/crud.less | 8 +++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 16f8ae3fb89..8aae2403061 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "hadron-auto-update-manager": "^0.0.12", "hadron-compile-cache": "^0.1.0", "hadron-component-registry": "^0.3.0", - "hadron-document": "^0.11.0", + "hadron-document": "^0.12.0", "hadron-ipc": "^0.0.7", "hadron-module-cache": "^0.0.3", "hadron-package-manager": "0.1.0", diff --git a/src/internal-packages/crud/lib/component/editable-key.jsx b/src/internal-packages/crud/lib/component/editable-key.jsx index 823852868ac..c08af915e99 100644 --- a/src/internal-packages/crud/lib/component/editable-key.jsx +++ b/src/internal-packages/crud/lib/component/editable-key.jsx @@ -7,6 +7,11 @@ const React = require('react'); */ const EDITING = 'editing'; +/** + * The duplicate key value. + */ +const DUPLICATE = 'duplicate'; + /** * The document key class. */ @@ -25,7 +30,7 @@ class EditableKey extends React.Component { constructor(props) { super(props); this.element = props.element; - this.state = { editing: false }; + this.state = { duplcate: false, editing: false }; } /** @@ -56,10 +61,22 @@ class EditableKey extends React.Component { onFocus={this.handleFocus.bind(this)} onChange={this.handleChange.bind(this)} onKeyDown={this.handleKeyDown.bind(this)} - value={this.element.currentKey} /> + value={this.element.currentKey} + title={this.renderTitle()} /> ); } + /** + * Render the title. + * + * @returns {String} The title. + */ + renderTitle() { + if (this.state.duplicate) { + return `Duplicate key: '${this.element.currentKey}'` + } + return this.element.currentKey; + } /** * When hitting a key on the last element some special things may happen. * @@ -79,6 +96,11 @@ class EditableKey extends React.Component { handleChange(evt) { var value = evt.target.value; if (this.isEditable()) { + if (this.element.isDuplicateKey(value)) { + this.setState({ duplicate: true }); + } else if (this.state.duplicate) { + this.setState({ duplicate: false }); + } this.element.rename(value); } } @@ -116,7 +138,14 @@ class EditableKey extends React.Component { * @returns {String} The key style. */ style() { - return this.state.editing ? `${KEY_CLASS} ${EDITING}` : KEY_CLASS; + var style = KEY_CLASS; + if (this.state.editing) { + style = style.concat(` ${EDITING}`); + } + if (this.state.duplicate) { + style = style.concat(` ${DUPLICATE}`); + } + return style; } } diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index ffd12697396..7edeb05b2f4 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -310,6 +310,14 @@ input.editable-key { z-index: 10; margin-top: -1px; margin-bottom: -1px; + + &.duplicate { + border: 1px solid red; + } + } + + &.duplicate { + color: red; } } From 2a26eac7637eaa4d14847fe87a191430cd154786 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 24 Jun 2016 13:55:18 -0400 Subject: [PATCH 52/52] INT-1160: Add insert new document --- src/app/documents/document-list.js | 3 +- .../crud/lib/component/document-list.jsx | 36 ++++-- .../crud/lib/component/document.jsx | 4 +- .../crud/lib/component/hotspot.jsx | 7 +- .../crud/lib/component/insert-document.jsx | 5 +- .../component/open-insert-dialog-button.jsx | 38 +++++++ .../crud/lib/component/sampling-message.jsx | 104 ++++++++++++++++++ .../open-insert-document-dialog-store.js | 4 +- src/internal-packages/crud/styles/crud.less | 5 + 9 files changed, 192 insertions(+), 14 deletions(-) create mode 100644 src/internal-packages/crud/lib/component/open-insert-dialog-button.jsx create mode 100644 src/internal-packages/crud/lib/component/sampling-message.jsx diff --git a/src/app/documents/document-list.js b/src/app/documents/document-list.js index 00e4ecc652c..a4cb8ba0351 100644 --- a/src/app/documents/document-list.js +++ b/src/app/documents/document-list.js @@ -25,7 +25,8 @@ var DocumentListView = View.extend({ Action.filterChanged(app.queryOptions.query.serialize()); }, render: function() { - ReactDOM.render(React.createElement(this.documentList), this.el.parentNode); + var container = this.el.parentNode.parentNode.parentNode; + ReactDOM.render(React.createElement(this.documentList), container); return this; }, reset: function() { diff --git a/src/internal-packages/crud/lib/component/document-list.jsx b/src/internal-packages/crud/lib/component/document-list.jsx index 853a4edec20..426520e13aa 100644 --- a/src/internal-packages/crud/lib/component/document-list.jsx +++ b/src/internal-packages/crud/lib/component/document-list.jsx @@ -12,6 +12,8 @@ const LoadMoreDocumentsStore = require('../store/load-more-documents-store'); const RemoveDocumentStore = require('../store/remove-document-store'); const InsertDocumentStore = require('../store/insert-document-store'); const InsertDocumentDialog = require('./insert-document-dialog'); +const SamplingMessage = require('./sampling-message'); +const Actions = require('../actions'); /** * The full document list container class. @@ -23,6 +25,11 @@ const LIST_CLASS = 'document-list'; */ const SCROLL_EVENT = 'scroll'; +/** + * Base empty doc for insert dialog. + */ +const EMPTY_DOC = { '': '' }; + /** * Component for the entire document list. */ @@ -32,8 +39,7 @@ class DocumentList extends React.Component { * Attach the scroll event to the parent container. */ attachScrollEvent() { - this.documentListNode = ReactDOM.findDOMNode(this); - this.documentListNode.parentNode.addEventListener( + this._node.parentNode.addEventListener( SCROLL_EVENT, this.handleScroll.bind(this) ); @@ -131,13 +137,20 @@ class DocumentList extends React.Component { */ handleScroll(evt) { var container = evt.srcElement; - if (container.scrollTop > (this.documentListNode.offsetHeight - this._scrollDelta())) { + if (container.scrollTop > (this._node.offsetHeight - this._scrollDelta())) { // If we are scrolling downwards, and have hit the distance to initiate a scroll // from the end of the list, we will fire the event to load more documents. this.loadMore(); } } + /** + * Handle opening of the insert dialog. + */ + handleOpenInsert() { + Actions.openInsertDocumentDialog(EMPTY_DOC); + } + /** * Handle insert of a new document. * @@ -168,10 +181,17 @@ class DocumentList extends React.Component { */ render() { return ( -
        - {this.state.docs} - -
      +
      + +
      +
      +
        this._node = c}> + {this.state.docs} + +
      +
      +
      +
      ); } @@ -208,7 +228,7 @@ class DocumentList extends React.Component { */ _scrollDelta() { if (!this.scrollDelta) { - this.scrollDelta = this.documentListNode.offsetHeight; + this.scrollDelta = this._node.offsetHeight; } return this.scrollDelta; } diff --git a/src/internal-packages/crud/lib/component/document.jsx b/src/internal-packages/crud/lib/component/document.jsx index 94612c14c89..4b4a4f3a332 100644 --- a/src/internal-packages/crud/lib/component/document.jsx +++ b/src/internal-packages/crud/lib/component/document.jsx @@ -217,8 +217,10 @@ class Document extends React.Component { this.setState({ doc: this.doc, editing: false }); } + /** + * Handle cloning of the document. + */ handleClone() { - console.log('Cloning document...'); Actions.openInsertDocumentDialog(this.doc); } diff --git a/src/internal-packages/crud/lib/component/hotspot.jsx b/src/internal-packages/crud/lib/component/hotspot.jsx index c02f33bc39b..ecdc70ec4d5 100644 --- a/src/internal-packages/crud/lib/component/hotspot.jsx +++ b/src/internal-packages/crud/lib/component/hotspot.jsx @@ -14,6 +14,7 @@ class Hotspot extends React.Component { */ constructor(props) { super(props); + this.doc = props.doc; this.element = props.element; } @@ -21,7 +22,11 @@ class Hotspot extends React.Component { * When clicking on a hotspot we append to the parent. */ handleClick() { - this.element.next(); + if (this.element && this.element.parentElement) { + this.element.next(); + } else { + this.doc.add('', ''); + } } /** diff --git a/src/internal-packages/crud/lib/component/insert-document.jsx b/src/internal-packages/crud/lib/component/insert-document.jsx index 50ec1236ef2..b2b1ad5265e 100644 --- a/src/internal-packages/crud/lib/component/insert-document.jsx +++ b/src/internal-packages/crud/lib/component/insert-document.jsx @@ -73,8 +73,9 @@ class InsertDocument extends React.Component { ); }); - var lastElement = elements[elements.length - 1].props.element; - elements.push(); + var lastComponent = elements[elements.length - 1]; + var lastElement = lastComponent ? lastComponent.props.element : null; + elements.push(); return elements; } } diff --git a/src/internal-packages/crud/lib/component/open-insert-dialog-button.jsx b/src/internal-packages/crud/lib/component/open-insert-dialog-button.jsx new file mode 100644 index 00000000000..c13261c1543 --- /dev/null +++ b/src/internal-packages/crud/lib/component/open-insert-dialog-button.jsx @@ -0,0 +1,38 @@ +'use strict'; + +const React = require('react'); + +/** + * Component for the open insert dialog button. + */ +class OpenInsertDialogButton extends React.Component { + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + } + + /** + * Render the button. + * + * @returns {Component} The button component. + */ + render() { + return ( + + ); + } +} + +OpenInsertDialogButton.displayName = 'OpenInsertDialogButton'; + +module.exports = OpenInsertDialogButton; diff --git a/src/internal-packages/crud/lib/component/sampling-message.jsx b/src/internal-packages/crud/lib/component/sampling-message.jsx new file mode 100644 index 00000000000..04cbd669622 --- /dev/null +++ b/src/internal-packages/crud/lib/component/sampling-message.jsx @@ -0,0 +1,104 @@ +'use strict'; + +const React = require('react'); +const app = require('ampersand-app'); +const ResetDocumentListStore = require('../store/reset-document-list-store'); +const RemoveDocumentStore = require('../store/remove-document-store'); +const InsertDocumentStore = require('../store/insert-document-store'); +const OpenInsertDialogButton = require('./open-insert-dialog-button'); + +/** + * The feature flag. + */ +const FEATURE = 'singleDocumentCrud'; + +/** + * Component for the sampling message. + */ +class SamplingMessage extends React.Component { + + /** + * Fetch the state when the component mounts. + */ + componentDidMount() { + this.unsubscribeReset = ResetDocumentListStore.listen(this.handleReset.bind(this)); + this.unsubscribeRemove = RemoveDocumentStore.listen(this.handleRemove.bind(this)); + this.unsibscribeInsert = InsertDocumentStore.listen(this.handleInsert.bind(this)); + } + + /** + * Unsibscribe from the document list store when unmounting. + */ + componentWillUnmount() { + this.unsubscribeReset(); + this.unsubscribeRemove(); + this.unsubscribeInsert(); + } + + /** + * The component constructor. + * + * @param {Object} props - The properties. + */ + constructor(props) { + super(props); + this.state = { count: 0 }; + } + + /** + * Handle the reset of the document list. + * + * @param {Array} documents - The documents. + * @param {Integer} count - The count. + */ + handleReset(documents, count) { + this.setState({ count: count }); + } + + /** + * Handles removal of a document from the document list. + */ + handleRemove() { + this.setState({ count: this.state.count - 1 }); + } + + /** + * Handle insert of a new document. + * + * @param {Boolean} success - If the insert was successful. + * @param {Object} object - The new document or error. + */ + handleInsert(success, object) { + if (success) { + this.setState({ count: this.state.count + 1 }); + } + } + + /** + * Render the sampling message. + * + * @returns {React.Component} The document list. + */ + render() { + return ( +
      + Query returned {this.state.count} documents. + + {this.renderInsertButton()} +
      + ); + } + + /** + * Render the insert button. + */ + renderInsertButton() { + if (app.isFeatureEnabled(FEATURE)) { + return (); + } + } +} + +SamplingMessage.displayName = 'SamplingMessage'; + +module.exports = SamplingMessage; diff --git a/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js index 7ab304d1d0a..67fc1392043 100644 --- a/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js +++ b/src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js @@ -25,7 +25,9 @@ const OpenInsertDocumentDialogStore = Reflux.createStore({ var hadronDoc = new HadronDocument(doc, true); // We need to remove the _id or we will get an duplicate key error on // insert, and we currently do not allow editing of the _id field. - hadronDoc.elements.shift(); + if (hadronDoc.elements[0].currentKey === '_id') { + hadronDoc.elements.shift(); + } this.trigger(hadronDoc); } }); diff --git a/src/internal-packages/crud/styles/crud.less b/src/internal-packages/crud/styles/crud.less index 7edeb05b2f4..fec01559378 100644 --- a/src/internal-packages/crud/styles/crud.less +++ b/src/internal-packages/crud/styles/crud.less @@ -2,6 +2,11 @@ li.document-list-item.editing { box-shadow: 2px 5px 8px gainsboro; } +.column.main { + .sampling-message { + } +} + .document-footer { font-family: "Akzidenz", "Helvetica Neue", Helvetica, Arial, sans-serif; height: 28px;