Skip to content

Commit 2a26eac

Browse files
committed
INT-1160: Add insert new document
1 parent 90768a1 commit 2a26eac

File tree

9 files changed

+192
-14
lines changed

9 files changed

+192
-14
lines changed

src/app/documents/document-list.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ var DocumentListView = View.extend({
2525
Action.filterChanged(app.queryOptions.query.serialize());
2626
},
2727
render: function() {
28-
ReactDOM.render(React.createElement(this.documentList), this.el.parentNode);
28+
var container = this.el.parentNode.parentNode.parentNode;
29+
ReactDOM.render(React.createElement(this.documentList), container);
2930
return this;
3031
},
3132
reset: function() {

src/internal-packages/crud/lib/component/document-list.jsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const LoadMoreDocumentsStore = require('../store/load-more-documents-store');
1212
const RemoveDocumentStore = require('../store/remove-document-store');
1313
const InsertDocumentStore = require('../store/insert-document-store');
1414
const InsertDocumentDialog = require('./insert-document-dialog');
15+
const SamplingMessage = require('./sampling-message');
16+
const Actions = require('../actions');
1517

1618
/**
1719
* The full document list container class.
@@ -23,6 +25,11 @@ const LIST_CLASS = 'document-list';
2325
*/
2426
const SCROLL_EVENT = 'scroll';
2527

28+
/**
29+
* Base empty doc for insert dialog.
30+
*/
31+
const EMPTY_DOC = { '': '' };
32+
2633
/**
2734
* Component for the entire document list.
2835
*/
@@ -32,8 +39,7 @@ class DocumentList extends React.Component {
3239
* Attach the scroll event to the parent container.
3340
*/
3441
attachScrollEvent() {
35-
this.documentListNode = ReactDOM.findDOMNode(this);
36-
this.documentListNode.parentNode.addEventListener(
42+
this._node.parentNode.addEventListener(
3743
SCROLL_EVENT,
3844
this.handleScroll.bind(this)
3945
);
@@ -131,13 +137,20 @@ class DocumentList extends React.Component {
131137
*/
132138
handleScroll(evt) {
133139
var container = evt.srcElement;
134-
if (container.scrollTop > (this.documentListNode.offsetHeight - this._scrollDelta())) {
140+
if (container.scrollTop > (this._node.offsetHeight - this._scrollDelta())) {
135141
// If we are scrolling downwards, and have hit the distance to initiate a scroll
136142
// from the end of the list, we will fire the event to load more documents.
137143
this.loadMore();
138144
}
139145
}
140146

147+
/**
148+
* Handle opening of the insert dialog.
149+
*/
150+
handleOpenInsert() {
151+
Actions.openInsertDocumentDialog(EMPTY_DOC);
152+
}
153+
141154
/**
142155
* Handle insert of a new document.
143156
*
@@ -168,10 +181,17 @@ class DocumentList extends React.Component {
168181
*/
169182
render() {
170183
return (
171-
<ol className={LIST_CLASS}>
172-
{this.state.docs}
173-
<InsertDocumentDialog />
174-
</ol>
184+
<div>
185+
<SamplingMessage insertHandler={this.handleOpenInsert.bind(this)} />
186+
<div className='column-container with-refinebar-and-message'>
187+
<div className='column main'>
188+
<ol className={LIST_CLASS} ref={(c) => this._node = c}>
189+
{this.state.docs}
190+
<InsertDocumentDialog />
191+
</ol>
192+
</div>
193+
</div>
194+
</div>
175195
);
176196
}
177197

@@ -208,7 +228,7 @@ class DocumentList extends React.Component {
208228
*/
209229
_scrollDelta() {
210230
if (!this.scrollDelta) {
211-
this.scrollDelta = this.documentListNode.offsetHeight;
231+
this.scrollDelta = this._node.offsetHeight;
212232
}
213233
return this.scrollDelta;
214234
}

src/internal-packages/crud/lib/component/document.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,10 @@ class Document extends React.Component {
217217
this.setState({ doc: this.doc, editing: false });
218218
}
219219

220+
/**
221+
* Handle cloning of the document.
222+
*/
220223
handleClone() {
221-
console.log('Cloning document...');
222224
Actions.openInsertDocumentDialog(this.doc);
223225
}
224226

src/internal-packages/crud/lib/component/hotspot.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@ class Hotspot extends React.Component {
1414
*/
1515
constructor(props) {
1616
super(props);
17+
this.doc = props.doc;
1718
this.element = props.element;
1819
}
1920

2021
/**
2122
* When clicking on a hotspot we append to the parent.
2223
*/
2324
handleClick() {
24-
this.element.next();
25+
if (this.element && this.element.parentElement) {
26+
this.element.next();
27+
} else {
28+
this.doc.add('', '');
29+
}
2530
}
2631

2732
/**

src/internal-packages/crud/lib/component/insert-document.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ class InsertDocument extends React.Component {
7373
<EditableElement key={element.uuid} element={element} />
7474
);
7575
});
76-
var lastElement = elements[elements.length - 1].props.element;
77-
elements.push(<Hotspot key='hotspot' element={lastElement} />);
76+
var lastComponent = elements[elements.length - 1];
77+
var lastElement = lastComponent ? lastComponent.props.element : null;
78+
elements.push(<Hotspot key='hotspot' doc={this.doc} element={lastElement} />);
7879
return elements;
7980
}
8081
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const React = require('react');
4+
5+
/**
6+
* Component for the open insert dialog button.
7+
*/
8+
class OpenInsertDialogButton extends React.Component {
9+
10+
/**
11+
* The component constructor.
12+
*
13+
* @param {Object} props - The properties.
14+
*/
15+
constructor(props) {
16+
super(props);
17+
}
18+
19+
/**
20+
* Render the button.
21+
*
22+
* @returns {Component} The button component.
23+
*/
24+
render() {
25+
return (
26+
<button
27+
className='btn btn-default btn-xs open-insert'
28+
type='button'
29+
onClick={this.props.handler}>
30+
+ Insert
31+
</button>
32+
);
33+
}
34+
}
35+
36+
OpenInsertDialogButton.displayName = 'OpenInsertDialogButton';
37+
38+
module.exports = OpenInsertDialogButton;
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'use strict';
2+
3+
const React = require('react');
4+
const app = require('ampersand-app');
5+
const ResetDocumentListStore = require('../store/reset-document-list-store');
6+
const RemoveDocumentStore = require('../store/remove-document-store');
7+
const InsertDocumentStore = require('../store/insert-document-store');
8+
const OpenInsertDialogButton = require('./open-insert-dialog-button');
9+
10+
/**
11+
* The feature flag.
12+
*/
13+
const FEATURE = 'singleDocumentCrud';
14+
15+
/**
16+
* Component for the sampling message.
17+
*/
18+
class SamplingMessage extends React.Component {
19+
20+
/**
21+
* Fetch the state when the component mounts.
22+
*/
23+
componentDidMount() {
24+
this.unsubscribeReset = ResetDocumentListStore.listen(this.handleReset.bind(this));
25+
this.unsubscribeRemove = RemoveDocumentStore.listen(this.handleRemove.bind(this));
26+
this.unsibscribeInsert = InsertDocumentStore.listen(this.handleInsert.bind(this));
27+
}
28+
29+
/**
30+
* Unsibscribe from the document list store when unmounting.
31+
*/
32+
componentWillUnmount() {
33+
this.unsubscribeReset();
34+
this.unsubscribeRemove();
35+
this.unsubscribeInsert();
36+
}
37+
38+
/**
39+
* The component constructor.
40+
*
41+
* @param {Object} props - The properties.
42+
*/
43+
constructor(props) {
44+
super(props);
45+
this.state = { count: 0 };
46+
}
47+
48+
/**
49+
* Handle the reset of the document list.
50+
*
51+
* @param {Array} documents - The documents.
52+
* @param {Integer} count - The count.
53+
*/
54+
handleReset(documents, count) {
55+
this.setState({ count: count });
56+
}
57+
58+
/**
59+
* Handles removal of a document from the document list.
60+
*/
61+
handleRemove() {
62+
this.setState({ count: this.state.count - 1 });
63+
}
64+
65+
/**
66+
* Handle insert of a new document.
67+
*
68+
* @param {Boolean} success - If the insert was successful.
69+
* @param {Object} object - The new document or error.
70+
*/
71+
handleInsert(success, object) {
72+
if (success) {
73+
this.setState({ count: this.state.count + 1 });
74+
}
75+
}
76+
77+
/**
78+
* Render the sampling message.
79+
*
80+
* @returns {React.Component} The document list.
81+
*/
82+
render() {
83+
return (
84+
<div className='sampling-message'>
85+
Query returned&nbsp;<b>{this.state.count}</b>&nbsp;documents.
86+
<i data-hook='schema-sampling-results' className='help'></i>
87+
{this.renderInsertButton()}
88+
</div>
89+
);
90+
}
91+
92+
/**
93+
* Render the insert button.
94+
*/
95+
renderInsertButton() {
96+
if (app.isFeatureEnabled(FEATURE)) {
97+
return (<OpenInsertDialogButton handler={this.props.insertHandler} />);
98+
}
99+
}
100+
}
101+
102+
SamplingMessage.displayName = 'SamplingMessage';
103+
104+
module.exports = SamplingMessage;

src/internal-packages/crud/lib/store/open-insert-document-dialog-store.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const OpenInsertDocumentDialogStore = Reflux.createStore({
2525
var hadronDoc = new HadronDocument(doc, true);
2626
// We need to remove the _id or we will get an duplicate key error on
2727
// insert, and we currently do not allow editing of the _id field.
28-
hadronDoc.elements.shift();
28+
if (hadronDoc.elements[0].currentKey === '_id') {
29+
hadronDoc.elements.shift();
30+
}
2931
this.trigger(hadronDoc);
3032
}
3133
});

src/internal-packages/crud/styles/crud.less

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ li.document-list-item.editing {
22
box-shadow: 2px 5px 8px gainsboro;
33
}
44

5+
.column.main {
6+
.sampling-message {
7+
}
8+
}
9+
510
.document-footer {
611
font-family: "Akzidenz", "Helvetica Neue", Helvetica, Arial, sans-serif;
712
height: 28px;

0 commit comments

Comments
 (0)