Commit 57bc4267 authored by Remi Rampin's avatar Remi Rampin

Merge branch 'highlights-count' into 'master'

Show number of highlights in each tag

Closes #28

See merge request !3
parents efadaa0d cf8b09e5
Pipeline #66392444 passed with stage
in 1 minute and 58 seconds
......@@ -188,6 +188,8 @@ class Command(Base):
nullable=True) # Not ForeignKey, document can go away
payload = Column(JSON, nullable=False)
tag_count_changes = None
__table_args__ = (
Index('idx_project_document', 'project_id', 'document_id'),
)
......@@ -402,6 +404,15 @@ class HighlightTag(Base):
tag = relationship('Tag')
Tag.highlights_count = column_property(
select(
[functions.count(HighlightTag.highlight_id)],
).where(
HighlightTag.tag_id == Tag.id,
).correlate_except(HighlightTag)
)
def connect(db_url):
"""Connect to the database using an environment variable.
"""
......
......@@ -646,6 +646,9 @@ function linkTag(elem, tag_path) {
linkTag(document.getElementById('load-all-tags'), '');
function addTag(tag) {
if(!('count' in tag) && tag.id in tags) {
tag.count = tags[tag.id].count;
}
tags[tag.id] = tag;
updateTagsList();
}
......@@ -703,8 +706,10 @@ function updateTagsList() {
' <a class="expand-marker">&nbsp;</a> ' +
' <a id="tag-link-' + tag.id + '">' + escapeHtml(tag.path) + '</a>' +
' </div>' +
' <a href="javascript:editTag(' + tag.id + ');" class="badge badge-primary badge-pill">' + gettext("edit") + '</a>' +
//' <span href="#" class="badge badge-primary badge-pill">?</span>' + // TODO: highlight count
' <div style="white-space: nowrap;">' +
' <span href="#" class="badge badge-secondary badge-pill" id="tag-' + tag.id + '-count">' + tag.count + '</span>' +
' <a href="javascript:editTag(' + tag.id + ');" class="badge badge-primary badge-pill">' + gettext("edit") + '</a>' +
' </div>' +
'</div>' +
'<ul class="sublist"></div>';
tags_list.insertBefore(elem, before);
......@@ -760,6 +765,13 @@ function updateTagsList() {
updateTagsList();
function updateTagCount(id, delta) {
var elem = document.getElementById('tag-' + id + '-count');
var value = parseInt(elem.textContent);
value += delta;
elem.textContent = value;
}
var tag_add_modal = document.getElementById('tag-add-modal');
function createTag() {
......@@ -1504,6 +1516,12 @@ function longPollForEvents() {
removeMember(result.member_remove[i]);
}
}
if('tag_count_changes' in result) {
var entries = Object.entries(result.tag_count_changes);
for(var i = 0; i < entries.length; ++i) {
updateTagCount(entries[i][0], entries[i][1]);
}
}
last_event = result.id;
// Re-open connection
......
......@@ -400,7 +400,7 @@ class HighlightAdd(BaseHandler):
highlight_id=hl.id,
tag_id=tag,
)
for tag in obj.get('tags', [])
for tag in set(obj.get('tags', []))
])
cmd = database.Command.highlight_add(
self.current_user,
......@@ -408,6 +408,7 @@ class HighlightAdd(BaseHandler):
hl,
obj.get('tags', []),
)
cmd.tag_count_changes = {tag: 1 for tag in obj.get('tags')}
self.db.add(cmd)
self.db.commit()
self.db.refresh(cmd)
......@@ -438,6 +439,16 @@ class HighlightUpdate(BaseHandler):
if 'end_offset' in obj:
hl.end_offset = obj['end_offset']
if 'tags' in obj:
# Obtain old tags from database
old_tags = (
self.db.query(database.HighlightTag)
.filter(database.HighlightTag.highlight == hl)
.all()
)
old_tags = set(hl_tag.tag_id for hl_tag in old_tags)
new_tags = set(obj['tags'])
# Update tags in database
(
self.db.query(database.HighlightTag)
.filter(database.HighlightTag.highlight == hl)
......@@ -447,14 +458,26 @@ class HighlightUpdate(BaseHandler):
highlight_id=hl.id,
tag_id=tag,
)
for tag in obj.get('tags', [])
for tag in new_tags
])
# Compute the change in tag counts
tag_count_changes = {}
for tag in old_tags - new_tags:
tag_count_changes[tag] = -1
for tag in new_tags - old_tags:
tag_count_changes[tag] = 1
else:
new_tags = None
tag_count_changes = None
cmd = database.Command.highlight_add(
self.current_user,
document,
hl,
obj.get('tags', []),
sorted(new_tags),
)
cmd.tag_count_changes = tag_count_changes
self.db.add(cmd)
self.db.commit()
self.db.refresh(cmd)
......@@ -473,12 +496,19 @@ class HighlightUpdate(BaseHandler):
if hl is None or hl.document_id != document.id:
self.set_status(404)
return self.send_json({'error': "No such highlight"})
old_tags = list(
self.db.query(database.HighlightTag)
.filter(database.HighlightTag.highlight == hl)
.all()
)
old_tags = [hl_tag.tag_id for hl_tag in old_tags]
self.db.delete(hl)
cmd = database.Command.highlight_delete(
self.current_user,
document,
hl.id,
)
cmd.tag_count_changes = {tag: -1 for tag in old_tags}
self.db.add(cmd)
self.db.commit()
self.db.refresh(cmd)
......@@ -683,6 +713,9 @@ class ProjectEvents(BaseHandler):
else:
raise ValueError("Unknown command type %r" % type_)
if cmd.tag_count_changes is not None:
result['tag_count_changes'] = cmd.tag_count_changes
result['id'] = cmd.id
return self.send_json(result)
......
......@@ -450,7 +450,8 @@ class Project(BaseHandler):
{
str(tag.id): {'id': tag.id,
'path': tag.path,
'description': tag.description}
'description': tag.description,
'count': tag.highlights_count}
for tag in project.tags
},
sort_keys=True,
......
......@@ -348,11 +348,16 @@ class TestMultiuser(MyHTTPTestCase):
' var last_event = -1;\n'
' var documents = {};\n'
' var highlights = {};\n'
' var tags = {"1": {"description": "Further review required", '
'"id": 1, "path": "interesting"}, "2": '
'{"description": "Known people", "id": 2, "path": "people"}};\n'
' var tags = %s;\n'
' var members = {"admin": {"privileges": "ADMIN"}};\n'
'</script>',
'</script>' % (
json.dumps({
"1": {"count": 0, "description": "Further review required",
"id": 1, "path": "interesting"},
"2": {"count": 0, "description": "Known people",
"id": 2, "path": "people"},
}),
),
)
# Start polling
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment