diff --git a/client/coral-embed-stream/src/CommentStream.js b/client/coral-embed-stream/src/CommentStream.js
index 00a24077f..56c8610cf 100644
--- a/client/coral-embed-stream/src/CommentStream.js
+++ b/client/coral-embed-stream/src/CommentStream.js
@@ -75,6 +75,7 @@ class CommentStream extends Component {
// Set up messaging between embedded Iframe an parent component
// Using recommended Pym init code which violates .eslint standards
new Pym.Child({ polling: 500 })
+ this.props.getItemsQuery('assetTest')
}
render () {
@@ -95,65 +96,87 @@ class CommentStream extends Component {
// TODO: Replace teststream id with id from params
- return
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {
+ rootItem ?
+
+
+ {
+ rootItem.related.comment.map((commentId) => {
+ const comment = this.props.items[commentId]
+ return
-
-
-
+
+
+
-
-
-
-
-
-
-
+ item_id={commentId}/>
+
+
+ {
+ comment.related &&
+ comment.related.child &&
+ comment.related.child.map((replyId) => {
+ let reply = this.props.items[replyId]
+ return
+ })
+ }
+
+ })
+ }
+
+
+ :'Loading'
+ }
+
+
+
}
}
diff --git a/client/coral-framework/__tests__/dynamic-containers/DynamicContainer.spec.js b/client/coral-framework/__tests__/dynamic-containers/DynamicContainer.spec.js
deleted file mode 100644
index 55b6f32e1..000000000
--- a/client/coral-framework/__tests__/dynamic-containers/DynamicContainer.spec.js
+++ /dev/null
@@ -1,184 +0,0 @@
-import {expect} from 'chai'
-import React from 'react'
-import DynamicContainer from '../../dynamic-containers/DynamicContainer'
-import {shallow, mount} from 'enzyme'
-
-describe('DynamicContainer', () => {
- let props
- beforeEach(() => {
- props = {
- item_id: '1',
- items: {
- '1': {
- item_id: '1',
- type: 'comment',
- data: {
- content: 'stuff'
- },
- related: {
- author: '2',
- likes: ['4', '5']
- }
-
- },
- '2': {
- item_id: '2',
- type: 'user',
- data: {
- name: 'Janice'
- },
- related: {
- likes: ['4', '5'],
- employer: '3'
- }
- },
- '3': {
- item_id: '3',
- type: 'employer',
- data: {
- name: 'Coral'
- }
- },
- '4': {
- item_id: '4',
- type: 'like',
- data: {
- name: 'Regina'
- }
- },
- '5': {
- item_id: '5',
- type: 'like',
- data: {
- name: 'Fatima'
- }
- }
- },
- name: 'test'
- }
- })
- describe('mapPropsFromItems', () => {
- it('should retrieve objects based on a simple graphQL query', () => {
- let query = '(type: \'comment\'){content}'
- let output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- content: 'stuff'
- })
- })
- it('should traverse the graph and return an appropriately formatted set of properties', () => {
- let query = '(type: \'comment\'){content,author(type: \'user\'){name}}'
- let output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- content: 'stuff',
- author: {
- name: 'Janice'
- }
- })
- })
- it('should traverse a deeply nested query', () => {
- let query = '(type: \'comment\'){content,author(type:"user"){employer(type:"employer"){name}}}'
- let output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- content: 'stuff',
- author: {
- employer: {
- name: 'Coral'
- }
- }
- })
- })
- it('should traverse a one to many relationship', () => {
- const query = '(type: \'comment\'){author(type: \'user\'){likes(type: \'like\'){name}},content}'
- const output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- content: 'stuff',
- author: {
- likes: [
- {
- name: 'Regina'
- },
- {
- name: 'Fatima'
- }
- ]
- }
- })
- })
- it('should traverse complex one to many relationships', () => {
- const query = '(type: "comment"){author(type: "user"){employer(type: "employer"){name},likes(type: "likes"){name},name},content,likes(type: "likes"){item_id}}'
- const output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- author: {
- employer: {
- name: 'Coral'
- },
- likes: [
- {
- name: 'Regina'
- },
- {
- name: 'Fatima'
- }
- ],
- name: 'Janice'
- },
- content: 'stuff',
- likes: [
- {
- item_id: '4'
- },
- {
- item_id: '5'
- }
- ]
- })
- })
-
- it('should traverse complex relationships efficiently', () => {
- let query = '(type: \'comment\'){content}'
- const start = new Date().getTime()
- for (var i = 0; i < 1000; i++) {
- new DynamicContainer(props).getPropsFromItems(query, 1)
- }
- const end = new Date().getTime()
- expect(end-start).to.be.below(100)
- })
-
- it('should not require a type declaration at the beginning of a query', () => {
- let query = '{content}'
- const output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- content: 'stuff'
- })
- })
-
- it('should return an undefined object if a relationship traversal is undefined', () => {
- let query = '{unicorns(type:"notExist"){rainbows}}'
- const output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- unicorns: undefined
- })
- })
-
- it('should return an undefined object if a parameter is undefined', () => {
- let query = '{does_not_exist}'
- const output = new DynamicContainer(props).getPropsFromItems(query, 1)
- expect(output).to.deep.equal({
- does_not_exist: undefined
- })
- })
- })
-
- describe('render', () => {
- it('should render a set of child components with the appropriate data', () => {
- const render = shallow(
-
-
- )
- expect(render.node.props.children[0].props).to.have.property('content')
- .and.to.equal('stuff')
- expect(render.node.props.children[1].props).to.have.property('author')
- .and.to.deep.equal({name: 'Janice'})
- })
- })
-})
diff --git a/client/coral-framework/__tests__/dynamic-containers/MapContainer.spec.js b/client/coral-framework/__tests__/dynamic-containers/MapContainer.spec.js
deleted file mode 100644
index f6bb29477..000000000
--- a/client/coral-framework/__tests__/dynamic-containers/MapContainer.spec.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from 'react'
-import {shallow} from 'enzyme'
-import {expect} from 'chai'
-import MapContainer from '../../dynamic-containers/MapContainer'
-
-describe('', () => {
- let items
- beforeEach (() => {
- items = {
- a: {
- item_id: 'a',
- type: 'stream',
- data: {
- url: "http://a.site"
- },
- related: {
- comment: ['b', 'c']
- }
- }
- }
- })
- it('should map children and pass them the appropriate item ids', () => {
- const map = shallow(
-
-
- )
- expect(map.node.props.className).to.equal('mapcomment')
- expect(map.node.props.children.length).to.equal(2)
- expect(map.node.props.children[0]).to.have.property('key')
- .and.to.equal('b')
- expect(map.node.props.children[0].props.children[0].props).to.have.property('item_id')
- .and.to.equal('b')
- expect(map.node.props.children[1]).to.have.property('key')
- .and.to.equal('c')
- expect(map.node.props.children[1].props.children[0].props).to.have.property('item_id')
- .and.to.equal('c')
- })
- it('should pass its items and config objects on to its children', () => {
- const map = shallow(
-
-
- )
- expect(map.node.props.children[0].props.children[0].props).to.have.property('items')
- .and.to.deep.equal(items)
- expect(map.node.props.children[1].props.children[0].props).to.have.property('items')
- .and.to.deep.equal(items)
- })
-})
diff --git a/client/coral-framework/__tests__/dynamic-containers/RootContainer.spec.js b/client/coral-framework/__tests__/dynamic-containers/RootContainer.spec.js
deleted file mode 100644
index 346d13dd7..000000000
--- a/client/coral-framework/__tests__/dynamic-containers/RootContainer.spec.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import React from 'react'
-import {shallow, mount} from 'enzyme'
-import {expect} from 'chai'
-
-import RootContainer from '../../dynamic-containers/RootContainer'
-
-describe('', () => {
- let items
- beforeEach(() => {
- items = {
- 'a': {
- type: 'stream',
- data: {comments: ['b', 'c']}
- }
- }
- })
- describe('render', () => {
- it('should render child containers with the appropriate id', () => {
- const render = shallow( {}}>
-
-
- )
- expect(render.hasClass('rootContainer')).to.be.true
- expect(render.props().children[0].props).to.have.property('item_id')
- .and.to.equal('a')
- expect(render.props().children[1].props).to.have.property('item_id')
- .and.to.equal('a')
- })
- it('should render child containers with the appropriate items', () => {
- const render = shallow( {}}>
-
-
- )
- expect(render.props().children[0].props).to.have.property('items')
- .and.to.deep.equal(items)
- expect(render.props().children[1].props).to.have.property('items')
- .and.to.deep.equal(items)
- })
- })
-})
diff --git a/client/coral-framework/dynamic-containers/DynamicContainer.js b/client/coral-framework/dynamic-containers/DynamicContainer.js
deleted file mode 100644
index 1f9e470c9..000000000
--- a/client/coral-framework/dynamic-containers/DynamicContainer.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import React, {Component, PropTypes, Children, cloneElement} from 'react'
-
-class DynamicContainer extends Component {
-
- constructor (props) {
- super(props)
- this.getPropsFromItems = this.getPropsFromItems.bind(this)
- }
-
- static propTypes = {
- name: PropTypes.string,
- items: PropTypes.object,
- item_id: PropTypes.string
- }
-
- traverseEdges (edges, index, query) {
- let bracketCount = 0
- let subqueryLength = 0
- let subquery = query.slice(index).reduce((subquery, char, i) => {
- if (bracketCount === 0 && i !== 0) {
- return subquery
- }
- subqueryLength++
- switch (char) {
- case '{':
- bracketCount++
- break
- case '}':
- bracketCount--
- break
- }
- const result = subquery += char
- return result
- }, '')
- query.splice(index, subqueryLength-1)
- return edges ? edges.reduce((array, edge) => {
- array.push(this.getPropsFromItems(subquery, edge))
- return array
- }, []) : undefined
- }
-
- getPropsFromItems (query, id) {
- let idStack = [id.toString()]
- let relationshipStack = []
- let result = {}
-
- query.split('').reduce((string, char, i, q) => {
- const id = idStack[idStack.length - 1]
- if (!this.props.items[id]) {
- return ''
- }
- let object = relationshipStack.reduce((object, relationship) => {
- return object[relationship]
- }, result)
- if (/[^{},]/i.test(char)) {
- return string + char
- }
- // Ignore spaces
- if (/\s/.test(char)) {
- return string
- }
- switch (char) {
- case '{':
- if (!string) {
- return string
- }
- const rgx = /(.*)\(type:\s?('|")(.+)('|")\)|^{/.exec(string)
- if (!rgx) {
- console.warn('Invalid graphQL: ' + string + ' in ' + query)
- console.warn('Expecting format {relationship(type:"itemType"{prop1, prop2}')
- return ''
- }
-
- const edge = rgx[1]
- const type = rgx[3]
- let typetest
- if (edge && this.props.items[id].related) {
- idStack.push(this.props.items[id].related[edge])
- relationshipStack.push(edge)
- let val = this.props.items[id].related[edge]
- if (!val || val.constructor === Array) {
- object[edge] = this.traverseEdges(val, i, q)
- idStack.pop()
- relationshipStack.pop()
- } else {
- object[edge] = {}
- }
- typetest = this.props.items[val]
- } else {
- typetest = this.props.items[id]
- }
- if (typetest && typetest.type !== type) {
- console.warn('Received unexpected type when getting props, expected ' + edge + ' of type ' + type + ' but found ' + typetest.type + '.')
- }
- break
- case '}':
- idStack.pop()
- relationshipStack.pop()
- if (!string) {
- return string
- }
- if (string === 'item_id' ||
- string === 'type' ||
- string === 'created_at' ||
- string === 'updated_at') {
- object[string] = this.props.items[id][string]
- } else {
- object[string] = this.props.items[id].data[string]
- }
- break
- case ',':
- if (!string) {
- return string
- }
- if (string === 'item_id' ||
- string === 'type' ||
- string === 'created_at' ||
- string === 'updated_at') {
- object[string] = this.props.items[id][string]
- } else {
- object[string] = this.props.items[id].data[string]
- }
- break
- }
- return ''
- }, '')
- return result
- }
-
- render () {
- return
- {
- Children.map(this.props.children, (child) => {
- if (child.type.name === 'DynamicContainer' || child.type.name === 'MapContainer') {
- return cloneElement(child, {
- item_id: this.props.item_id,
- items: this.props.items
- })
- }
- if (!child.props.data) {
- return child
- }
- const props = this.getPropsFromItems(child.props.data, this.props.item_id)
- return cloneElement(
- child,
- {
- data: undefined,
- ...props
- })
- })
- }
-
- }
-}
-
-export default DynamicContainer
diff --git a/client/coral-framework/dynamic-containers/MapContainer.js b/client/coral-framework/dynamic-containers/MapContainer.js
deleted file mode 100644
index 44b915b2e..000000000
--- a/client/coral-framework/dynamic-containers/MapContainer.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React, {Children, cloneElement} from 'react'
-
-/*
-* Maps a set of children onto an array of item ids
-* e.g. Displaying a stream of comments
-*
-* @props
-* id- The id of the item with the property to be mapped.
-* mapOver- The property to be mapped. Should be an array of ids.
-* items- All items in the redux store.
-*/
-
-const MapContainer = ({items, item_id, mapOver, children}) => {
- if (!items[item_id] || !items[item_id].related) {
- return null
- }
- const itemArray = items[item_id].related[mapOver]
- if (!itemArray) {
- return null
- }
- return
- {
- itemArray.map((item) => {
- return
- {
- Children.map(children, (ChildComponent) => {
- let elem = cloneElement(
- ChildComponent,
- {
- item_id: item,
- items: items
- })
- return elem
- })
- }
-
- })
- }
-
-}
-
-export default MapContainer
diff --git a/client/coral-framework/dynamic-containers/README.md b/client/coral-framework/dynamic-containers/README.md
deleted file mode 100644
index 6f77ac8e6..000000000
--- a/client/coral-framework/dynamic-containers/README.md
+++ /dev/null
@@ -1,171 +0,0 @@
-# Dynamic React Containers
-
-Dynamic inject React components in the spot that they're needed with the data that they need. In combination with Coral's Shelf API, they also handle all configuration of and communication with the backend. With Dynamic Containers you can write a component, say what data it needs, say where you want it to show up and the rest is handled magically. All of this is accomplished by placing your components in containers and passing them a `data` variable:
-
-**app.js**
-```
-import React, {Component} from 'react';
-import ReactDOM from 'react-dom';
-import {RootContainer, Container} from 'dynamic-react-components'
-import {Title} from 'components'
-
-class App extends Component {
-
- render() {
- return
-
-
-
-
- }
-}
-
-ReactDOM.render(, document.getElementById('app'));
-```
-
-This allows you to use simple react components which get exactly the data they expect.
-
-**Title.js**
-```
-import React from 'react';
-
-const Title = (props) => {
- return {props.title}
-};
-
-export default Title;
-```
-
-## What's going on here??
-
-Data in this application is stored in a graph of items. The root container defines a root item, a starting place in that graph. Each container looks at the graphql in the "data" props of its children, then walks the graph and delivers that child the data that it needs. This is a little more complex than simply passing props, but has some big advantages.
-
-1) It's easy to pass arbitrary data to an arbitrary component in your application, no more worrying about context or needing to pass props down a hierarchy.
-
-2) Flux store and dispatch is handled for you. You get a few CRUD functions for items that handle the majority of use cases, and can defined custom actions for any other cases that pop up.
-
-3) No need to configure a server. By adding up the graphQL statements in your config files the server knows exactly the data structure your application needs and how to optimize that data structure for the kinds of traversal you'll be doing.
-
-Let's review the concepts describes in these files:
-
-**app.js**
-- *RootContainer*: Wraps all other containers and provides an id of a root item.
-- *Container*: A div where an array of components can be injected.
-- *data*: A graphQL string describing the data used by this application.
-
-## Traversing the Graph
-
-A blog that just shows a title isn't very interesting, let's add some more information:
-
-**app.js**
-```
-import React, {Component} from 'react'
-import ReactDOM from 'react-dom'
-import {RootContainer, Container} from 'dynamic-react-components'
-import {Author, Title, Content} from 'components'
-
-class App extends Component {
-
- render() {
- return
-
-
-
-
-
-
- }
-}
-
-ReactDOM.render(, document.getElementById('app'))
-```
-
-Now we've added an author and content to our blog post. Note that for the Author component we used graphQL to traverse the graph from `blogpost` to `author` in order to get the author's name. When making these traversals it's important to include a "type", this allows the back end to optimize using these query statements.
-
-If three seperate components seems like overkill for this task, we can combine them like so:
-
-**app.js**
-```
-import React, {Component} from 'react'
-import ReactDOM from 'react-dom'
-import {RootContainer, Container} from 'dynamic-react-components'
-import {Blogpost} from 'components'
-
-class App extends Component {
-
- render() {
- return
-
-
-
-
- }
-}
-
-ReactDOM.render(, document.getElementById('app'))
-```
-
-Dynamic components lets you pull data from an arbitrary set of items in the graph into a single component for display.
-
-## GraphQL
-
-Currently, dynamic components only support basic graphQL and the `type` argument. Alias, mutations, fragments, and variables are not currently supported. When traversing a graph, as in `{author(type:"user"){name}}`, the "type" argument is required. This allows for validation and provides needed information to the back end.
-
-## Iterating over arrays
-
-What if I want to display multiple blog posts? Enter the **MapContainer** component:
-
-**app.js**
-```
-import React, {Component} from 'react';
-import ReactDOM from 'react-dom';
-import {RootContainer, Container} from 'dynamic-react-components'
-import {Blogpost} from 'components'
-
-class App extends Component {
-
- render() {
- return
-
-
-
-
-
-
- }
-}
-
-ReactDOM.render(, document.getElementById('app'));
-```
-
-Now our RootContainer is passed a different kind of item, a contentStream with an array of blogpost ids that looks something like this:
-
-```
-{
- type: 'contentStream',
- posts: ['id1','id2']
-}
-```
-
- MapContainer iterates over these ids, passing its children an id of type blogpost (*not* type contentstream). The resulting page would look something like this:
-
-```
-
-
-
-
-
-
Title 1
-
Author 1
-
Content 1
-
-
-
Title 2
-
Author 2
-
Content 2
-
-
-
-
-
- ```
diff --git a/client/coral-framework/dynamic-containers/RootContainer.js b/client/coral-framework/dynamic-containers/RootContainer.js
deleted file mode 100644
index 42ed1c4ef..000000000
--- a/client/coral-framework/dynamic-containers/RootContainer.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import React, {Component, PropTypes, Children, cloneElement} from 'react'
-
-/*
-* Renders a set of dynamic components bases on a root id
-*
-*/
-
-class RootContainer extends Component {
-
- static propTypes = {
- rootId: PropTypes.string.isRequired,
- items: PropTypes.object.isRequired,
- type: PropTypes.string.isRequired,
- getItemsQuery: PropTypes.func.isRequired
- }
-
- componentDidMount () {
- const {getItemsQuery, rootId} = this.props
- getItemsQuery(rootId)
- }
-
- render () {
- const {items, rootId, type, children} = this.props
- if (items[rootId] && items[rootId].type !== type) {
- console.warn('Id passed to RootContainer gets an object of an unexpected type. Expected ' + type + ' but got ' + items[rootId].type)
- }
- return
- {
- items[rootId] &&
- Children.map(children, (ChildComponent) => {
- return cloneElement(
- ChildComponent,
- {
- item_id: rootId,
- items: items
- })
- })
- }
-
- }
-}
-
-export default RootContainer
diff --git a/client/coral-plugin-comment-count/CommentCount.js b/client/coral-plugin-comment-count/CommentCount.js
index a3f63b7cd..861fc5df3 100644
--- a/client/coral-plugin-comment-count/CommentCount.js
+++ b/client/coral-plugin-comment-count/CommentCount.js
@@ -2,14 +2,16 @@ import React from 'react'
const name = 'coral-plugin-comment-count'
-const CommentCount = ({comment}) => {
+const CommentCount = ({items, item_id}) => {
let count = 0
- if (comment) {
- count += comment.length
- for (var i=0; i < comment.length; i++) {
- if (comment[i].child) {
- count += comment[i].child.length
- }
+ if (items[item_id]) {
+ count += items[item_id].related.comment.length
+ }
+ const itemKeys = Object.keys(items)
+ for (var i=0; i < itemKeys.length; i++) {
+ const item = items[itemKeys[i]]
+ if (item.type === 'comment' && item.related && item.related.child) {
+ count += item.related.child.length
}
}