Skip to content
Snippets Groups Projects
Commit d35bc152 authored by Eike Cochu's avatar Eike Cochu
Browse files

added topic browsing and serializer

added topic serializer and deserializer
added topic browsing site
added article and topic computed property _name for safe naming
parent 4fa565cb
No related branches found
No related tags found
No related merge requests found
Showing
with 211 additions and 169 deletions
...@@ -275,30 +275,6 @@ ...@@ -275,30 +275,6 @@
}, },
"buffers": "buffers":
[ [
{
"file": "vipra-ui/app/routes/articles/show.js",
"settings":
{
"buffer_size": 643,
"line_ending": "Unix"
}
},
{
"file": "vipra-ui/app/templates/articles/show.hbs",
"settings":
{
"buffer_size": 540,
"line_ending": "Unix"
}
},
{
"file": "vipra-ui/app/models/article.js",
"settings":
{
"buffer_size": 168,
"line_ending": "Unix"
}
}
], ],
"build_system": "", "build_system": "",
"build_system_choices": "build_system_choices":
...@@ -480,22 +456,50 @@ ...@@ -480,22 +456,50 @@
"/home/eike/repos/master/ma-impl", "/home/eike/repos/master/ma-impl",
"/home/eike/repos/master/ma-impl/vipra-ui", "/home/eike/repos/master/ma-impl/vipra-ui",
"/home/eike/repos/master/ma-impl/vipra-ui/app", "/home/eike/repos/master/ma-impl/vipra-ui/app",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models", "/home/eike/repos/master/ma-impl/vipra-ui/app/models",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes", "/home/eike/repos/master/ma-impl/vipra-ui/app/routes",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles", "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics", "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles" "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/helpers",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/integration",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/integration/components",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/unit",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/adapters",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/controllers",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/helpers",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/models",
"/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/routes"
], ],
"file_history": "file_history":
[ [
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles/show.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics/list.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components/topics-list.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components/articles-list.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles/list.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles/list.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components/articles-list.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics/list.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components/topics-list.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/article.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/topic.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics/list.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components/filter-list.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles/show.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components/topic-link.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/helpers/topic-numi.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components/topic-link.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles/show.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/helpers/topicname.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/helpers/topic-name.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/styles/app.css",
"/home/eike/repos/master/ma-impl/vm/bootstrap.sh", "/home/eike/repos/master/ma-impl/vm/bootstrap.sh",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics/show.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics/show.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/router.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/router.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics/list.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/index.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/index.hbs",
"/home/eike/.config/sublime-text-3/Packages/User/Preferences.sublime-settings", "/home/eike/.config/sublime-text-3/Packages/User/Preferences.sublime-settings",
"/home/eike/.config/sublime-text-3/Packages/Default/Preferences.sublime-settings", "/home/eike/.config/sublime-text-3/Packages/Default/Preferences.sublime-settings",
...@@ -600,23 +604,7 @@ ...@@ -600,23 +604,7 @@
"/home/eike/Repositories/niels_website/web/src/intergeo-2015.html", "/home/eike/Repositories/niels_website/web/src/intergeo-2015.html",
"/home/eike/Repositories/niels_website/web/src/less/main.less", "/home/eike/Repositories/niels_website/web/src/less/main.less",
"/home/eike/Downloads/intellij/idea-IU-141.2735.5/Install-Linux-tar.txt", "/home/eike/Downloads/intellij/idea-IU-141.2735.5/Install-Linux-tar.txt",
"/home/eike/Downloads/JetBrains.IntelliJ.IDEA.Ultimate.v14.1.5.141.2735.5.Linux.Incl.KeyMaker-DVT/dvt.nfo", "/home/eike/Downloads/JetBrains.IntelliJ.IDEA.Ultimate.v14.1.5.141.2735.5.Linux.Incl.KeyMaker-DVT/dvt.nfo"
"/home/eike/Repositories/niels_website/web/src/sftp-config.json",
"/home/eike/Repositories/niels_website/web/src/impressum.html",
"/home/eike/Repositories/niels_website/web/gulpfile.js",
"/home/eike/.config/sublime-text-3/Packages/SFTP/SFTP.sublime-settings",
"/home/eike/.config/sublime-text-3/Packages/User/SFTP.sublime-settings",
"/home/eike/.config/sublime-text-3/Packages/SFTP/SFTP.py",
"/home/eike/.config/sublime-text-3/Packages/SFTP/license.txt",
"/home/eike/Repositories/niels_website/web/dist/sftp-config.json",
"/home/eike/Repositories/fu/ss15/ki/exercise-09/task01a.pl",
"/home/eike/Repositories/fu/ss15/ki/exercise-07/task3b.pl",
"/home/eike/Repositories/fu/ss15/ki/exercise-07/task3a.pl",
"/home/eike/Downloads/analyze.r",
"/home/eike/Repositories/fu/ss15/ebi/exercise-03/exercise-03.r",
"/home/eike/Repositories/fu/ss15/ebi/exercise-02/exercise-02.r",
"/home/eike/Downloads/Formularantworten150621.csv",
"/home/eike/Downloads/analyze.r.Rout"
], ],
"find": "find":
{ {
...@@ -938,96 +926,8 @@ ...@@ -938,96 +926,8 @@
"groups": "groups":
[ [
{ {
"selected": 2,
"sheets": "sheets":
[ [
{
"buffer": 0,
"file": "vipra-ui/app/routes/articles/show.js",
"semi_transient": false,
"settings":
{
"buffer_size": 643,
"regions":
{
},
"selection":
[
[
342,
342
]
],
"settings":
{
"open_with_edit": true,
"syntax": "Packages/JavaScript/JavaScript.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"stack_index": 2,
"type": "text"
},
{
"buffer": 1,
"file": "vipra-ui/app/templates/articles/show.hbs",
"semi_transient": false,
"settings":
{
"buffer_size": 540,
"regions":
{
},
"selection":
[
[
299,
299
]
],
"settings":
{
"syntax": "Packages/Handlebars/grammars/Handlebars.tmLanguage"
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"stack_index": 1,
"type": "text"
},
{
"buffer": 2,
"file": "vipra-ui/app/models/article.js",
"semi_transient": false,
"settings":
{
"buffer_size": 168,
"regions":
{
},
"selection":
[
[
168,
168
]
],
"settings":
{
"syntax": "Packages/JavaScript/JavaScript.tmLanguage"
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"stack_index": 0,
"type": "text"
}
] ]
} }
], ],
...@@ -1194,7 +1094,7 @@ ...@@ -1194,7 +1094,7 @@
"show_open_files": true, "show_open_files": true,
"show_tabs": true, "show_tabs": true,
"side_bar_visible": true, "side_bar_visible": true,
"side_bar_width": 247.0, "side_bar_width": 254.0,
"status_bar_visible": true, "status_bar_visible": true,
"template_settings": "template_settings":
{ {
......
...@@ -4,7 +4,7 @@ import java.net.URI; ...@@ -4,7 +4,7 @@ import java.net.URI;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class TopicDefinition extends de.vipra.util.model.Topic implements Linked { public class Topic extends de.vipra.util.model.Topic implements Linked {
private Map<String, String> links; private Map<String, String> links;
......
...@@ -14,8 +14,11 @@ import com.fasterxml.jackson.databind.SerializationFeature; ...@@ -14,8 +14,11 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import de.vipra.rest.model.Article; import de.vipra.rest.model.Article;
import de.vipra.rest.model.Topic;
import de.vipra.rest.serializer.ArticleDeserializer; import de.vipra.rest.serializer.ArticleDeserializer;
import de.vipra.rest.serializer.ArticleSerializer; import de.vipra.rest.serializer.ArticleSerializer;
import de.vipra.rest.serializer.TopicDeserializer;
import de.vipra.rest.serializer.TopicSerializer;
import de.vipra.util.Constants; import de.vipra.util.Constants;
@Provider @Provider
...@@ -38,6 +41,8 @@ public class ObjectMapperProvider implements ContextResolver<ObjectMapper> { ...@@ -38,6 +41,8 @@ public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
SimpleModule module = new SimpleModule(); SimpleModule module = new SimpleModule();
module.addSerializer(Article.class, new ArticleSerializer()); module.addSerializer(Article.class, new ArticleSerializer());
module.addDeserializer(Article.class, new ArticleDeserializer()); module.addDeserializer(Article.class, new ArticleDeserializer());
module.addSerializer(Topic.class, new TopicSerializer());
module.addDeserializer(Topic.class, new TopicDeserializer());
final ObjectMapper mapper = new ObjectMapper(); final ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT); mapper.enable(SerializationFeature.INDENT_OUTPUT);
......
...@@ -20,7 +20,7 @@ import de.vipra.rest.APIMediaType; ...@@ -20,7 +20,7 @@ import de.vipra.rest.APIMediaType;
import de.vipra.rest.Messages; import de.vipra.rest.Messages;
import de.vipra.rest.model.APIError; import de.vipra.rest.model.APIError;
import de.vipra.rest.model.ResponseWrapper; import de.vipra.rest.model.ResponseWrapper;
import de.vipra.rest.model.TopicDefinition; import de.vipra.rest.model.Topic;
import de.vipra.rest.service.TopicService; import de.vipra.rest.service.TopicService;
import de.vipra.util.Config; import de.vipra.util.Config;
import de.vipra.util.Mongo; import de.vipra.util.Mongo;
...@@ -45,8 +45,8 @@ public class TopicResource { ...@@ -45,8 +45,8 @@ public class TopicResource {
@Produces(APIMediaType.APPLICATION_JSONAPI) @Produces(APIMediaType.APPLICATION_JSONAPI)
public Response getTopics(@QueryParam("skip") @DefaultValue("0") int skip, public Response getTopics(@QueryParam("skip") @DefaultValue("0") int skip,
@QueryParam("limit") @DefaultValue("0") int limit) { @QueryParam("limit") @DefaultValue("0") int limit) {
List<TopicDefinition> topics = service.getMultiple(uri.getAbsolutePath(), skip, limit, null); List<Topic> topics = service.getMultiple(uri.getAbsolutePath(), skip, limit, null);
ResponseWrapper<List<TopicDefinition>> res = new ResponseWrapper<>(topics); ResponseWrapper<List<Topic>> res = new ResponseWrapper<>(topics);
res.addLink("self", uri.getAbsolutePath().toString()); res.addLink("self", uri.getAbsolutePath().toString());
return Response.ok().entity(res).build(); return Response.ok().entity(res).build();
} }
...@@ -56,13 +56,13 @@ public class TopicResource { ...@@ -56,13 +56,13 @@ public class TopicResource {
@Consumes(APIMediaType.APPLICATION_JSONAPI) @Consumes(APIMediaType.APPLICATION_JSONAPI)
@Path("{id}") @Path("{id}")
public Response getTopic(@PathParam("id") String id) { public Response getTopic(@PathParam("id") String id) {
ResponseWrapper<TopicDefinition> res = new ResponseWrapper<>(); ResponseWrapper<Topic> res = new ResponseWrapper<>();
if (id == null || id.trim().length() == 0) { if (id == null || id.trim().length() == 0) {
res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty", res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty",
String.format(Messages.BAD_REQUEST, "id cannot be empty"))); String.format(Messages.BAD_REQUEST, "id cannot be empty")));
return Response.status(Response.Status.BAD_REQUEST).entity(res).build(); return Response.status(Response.Status.BAD_REQUEST).entity(res).build();
} }
TopicDefinition topic = service.getSingle(uri.getAbsolutePath(), id); Topic topic = service.getSingle(uri.getAbsolutePath(), id);
if (topic != null) { if (topic != null) {
res.setData(topic); res.setData(topic);
return Response.ok().entity(res).build(); return Response.ok().entity(res).build();
...@@ -77,8 +77,8 @@ public class TopicResource { ...@@ -77,8 +77,8 @@ public class TopicResource {
@Consumes(APIMediaType.APPLICATION_JSONAPI) @Consumes(APIMediaType.APPLICATION_JSONAPI)
@Produces(APIMediaType.APPLICATION_JSONAPI) @Produces(APIMediaType.APPLICATION_JSONAPI)
@Path("{id}") @Path("{id}")
public Response updateTopic(@PathParam("id") String id, TopicDefinition topic) { public Response updateTopic(@PathParam("id") String id, Topic topic) {
ResponseWrapper<TopicDefinition> res = new ResponseWrapper<>(); ResponseWrapper<Topic> res = new ResponseWrapper<>();
try { try {
long updated = service.updateSingle(topic); long updated = service.updateSingle(topic);
int updatedInt = updated > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) updated; int updatedInt = updated > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) updated;
......
...@@ -46,6 +46,14 @@ public class JsonHelper { ...@@ -46,6 +46,14 @@ public class JsonHelper {
return getLong(node, name, 0L); return getLong(node, name, 0L);
} }
public static int getInt(JsonNode node, String name, int defaultValue) {
return get(node, name, defaultValue, Integer.class);
}
public static int getInt(JsonNode node, String name) {
return getInt(node, name, 0);
}
public static String dateToString(Date date) { public static String dateToString(Date date) {
DateFormat df = new SimpleDateFormat(Constants.DATETIME_FORMAT); DateFormat df = new SimpleDateFormat(Constants.DATETIME_FORMAT);
return df.format(date); return df.format(date);
......
package de.vipra.rest.serializer;
import static de.vipra.rest.serializer.JsonHelper.getString;
import static de.vipra.rest.serializer.JsonHelper.getInt;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import de.vipra.rest.model.Topic;
public class TopicDeserializer extends JsonDeserializer<Topic> {
@Override
public Topic deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Topic topic = null;
JsonNode node = p.readValueAsTree();
if (node != null) {
topic = new Topic();
if (node.has("id"))
topic.setId(getString(node, "id"));
if (node.has("attributes")) {
JsonNode attrs = node.get("attributes");
if (attrs.has("name"))
topic.setName(getString(attrs, "name"));
if (attrs.has("index"))
topic.setIndex(getInt(attrs, "index"));
if (attrs.has("words")) {
JsonNode wordsNode = attrs.get("words");
// TODO implement
}
}
}
return topic;
}
}
package de.vipra.rest.serializer;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.vipra.rest.model.Topic;
public class TopicSerializer extends JsonSerializer<Topic> {
@Override
public void serialize(Topic value, JsonGenerator gen, SerializerProvider serializer)
throws IOException, JsonProcessingException {
gen.writeStartObject();
gen.writeStringField("id", value.getId());
gen.writeStringField("type", "topic");
if (value.getLinks() != null)
gen.writeObjectField("links", value.getLinks());
gen.writeObjectFieldStart("attributes");
gen.writeNumberField("index", value.getIndex());
if (value.getName() != null)
gen.writeStringField("name", value.getName());
if (value.getWords() != null)
gen.writeObjectField("words", value.getWords());
gen.writeEndObject();
gen.writeEndObject();
}
}
...@@ -3,19 +3,19 @@ package de.vipra.rest.service; ...@@ -3,19 +3,19 @@ package de.vipra.rest.service;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import de.vipra.rest.model.TopicDefinition; import de.vipra.rest.model.Topic;
import de.vipra.util.Constants; import de.vipra.util.Constants;
import de.vipra.util.Mongo; import de.vipra.util.Mongo;
public class TopicService extends DatabaseService<TopicDefinition> { public class TopicService extends DatabaseService<Topic> {
public TopicService(Mongo mongo) { public TopicService(Mongo mongo) {
super(mongo, Constants.Collection.TOPICS, TopicDefinition.class); super(mongo, Constants.Collection.TOPICS, Topic.class);
} }
public List<TopicDefinition> getMultiple(URI base, int skip, int limit, String sortBy) { public List<Topic> getMultiple(URI base, int skip, int limit, String sortBy) {
List<TopicDefinition> topics = super.getMultiple(skip, limit, sortBy); List<Topic> topics = super.getMultiple(skip, limit, sortBy);
for (TopicDefinition topic : topics) { for (Topic topic : topics) {
topic.setWords(null); topic.setWords(null);
} }
return topics; return topics;
......
import Ember from 'ember';
export default Ember.Component.extend({
filteredArticles: Ember.computed('articles', 'filter', function() {
var keyword = this.get('filter');
var filtered = this.get('articles');
if (keyword) {
keyword = keyword.toLowerCase().trim();
filtered = this.get('articles').filter((item) => item.get('title').toLowerCase().includes(keyword));
}
return filtered;
})
});
import Ember from 'ember';
export default Ember.Component.extend({
filteredItems: Ember.computed('items', 'filter', function() {
var keyword = this.get('filter');
var filtered = this.get('items');
if (keyword) {
keyword = keyword.toLowerCase().trim();
filtered = this.get('items').filter((item) => item.get('_name').toLowerCase().includes(keyword));
}
return filtered;
})
});
\ No newline at end of file
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'span',
text: Ember.computed('topic', function() {
var topic = this.get('topic');
var text = topic.name ? topic.name : topic.id;
if(topic.hasOwnProperty('count'))
text += ` (${topic.count})`;
return text;
})
});
import Ember from 'ember';
export default Ember.Component.extend({
filteredItems: Ember.computed('items', 'filter', function() {
var keyword = this.get('filter');
var filtered = this.get('items');
if (keyword) {
keyword = keyword.toLowerCase().trim();
filtered = this.get('items').filter((item) => item.get('_name').toLowerCase().includes(keyword));
}
return filtered;
})
});
\ No newline at end of file
...@@ -5,5 +5,11 @@ export default DS.Model.extend({ ...@@ -5,5 +5,11 @@ export default DS.Model.extend({
text: DS.attr(), text: DS.attr(),
url: DS.attr(), url: DS.attr(),
date: DS.attr('date'), date: DS.attr('date'),
stats: DS.attr() stats: DS.attr(),
topics: DS.attr(),
_name: function() {
var title = this.get('title');
return title ? title : this.get('id');
}.property('title')
}); });
import DS from 'ember-data'; import DS from 'ember-data';
export default DS.Model.extend({ export default DS.Model.extend({
name: DS.attr(),
index: DS.attr(),
_name: function() {
var name = this.get('name');
return name ? name : this.get('id');
}.property('name')
}); });
...@@ -4,6 +4,6 @@ export default Ember.Route.extend({ ...@@ -4,6 +4,6 @@ export default Ember.Route.extend({
model() { model() {
return Ember.RSVP.hash({ return Ember.RSVP.hash({
topics: this.store.findAll('topic') topics: this.store.findAll('topic')
}); })
} }
}); });
\ No newline at end of file
<h1>Articles</h1> <h1>Articles</h1>
{{#link-to 'index'}}Top{{/link-to}}
{{#link-to 'articles.list'}}All{{/link-to}} {{#link-to 'articles.list'}}All{{/link-to}}
<hr> <hr>
......
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
<h2>Found articles</h2> <h2>Found articles</h2>
{{debounced-input placeholder='Filter' size='50' value='filter' debounce='150'}} {{debounced-input placeholder='Filter' size='50' valueBinding='filter' debounce='150'}}
{{article-list articles=model.articles filter=filter}} {{articles-list items=model.articles filter=filter}}
\ No newline at end of file \ No newline at end of file
...@@ -9,6 +9,12 @@ ...@@ -9,6 +9,12 @@
<dd><a href="{{model.article.url}}">{{model.article.url}}</a></dd> <dd><a href="{{model.article.url}}">{{model.article.url}}</a></dd>
</dl> </dl>
<h3>Topics</h3>
{{#each model.article.topics as |topic|}}
{{topic-link topic=topic}}
{{/each}}
<h3>Statistics</h3> <h3>Statistics</h3>
<table> <table>
......
<ol> <ol>
{{#each filteredArticles as |article|}} {{#each filteredItems as |article|}}
<li>{{#link-to 'articles.show' article.id}}{{text-marker text=article.title mark=filter}}{{/link-to}}</li> <li>{{#link-to 'articles.show' article.id}}{{text-marker text=article.title mark=filter}}{{/link-to}}</li>
{{/each}} {{/each}}
</ol> </ol>
\ No newline at end of file
{{#link-to 'topics.show' topic.id}}{{text}}{{/link-to}}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment