parent
1ef0419dc2
commit
06ad8b1882
12 changed files with 87 additions and 4 deletions
|
@ -7,6 +7,7 @@
|
|||
<tr>
|
||||
<th class='name'>Category name</th>
|
||||
<th class='color'>CSS color</th>
|
||||
<th class='order'>Order</th>
|
||||
<th class='usages'>Usages</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -21,7 +22,7 @@
|
|||
|
||||
<div class='messages'></div>
|
||||
|
||||
<% if (ctx.canCreate || ctx.canEditName || ctx.canEditColor || ctx.canDelete) { %>
|
||||
<% if (ctx.canCreate || ctx.canEditName || ctx.canEditColor || ctx.canEditOrder || ctx.canDelete) { %>
|
||||
<div class='buttons'>
|
||||
<input type='submit' class='save' value='Save changes'>
|
||||
</div>
|
||||
|
|
|
@ -17,6 +17,13 @@
|
|||
<%- ctx.tagCategory.color %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td class='order'>
|
||||
<% if (ctx.canEditOrder) { %>
|
||||
<%= ctx.makeNumericInput({value: ctx.tagCategory.order}) %>
|
||||
<% } else { %>
|
||||
<%- ctx.tagCategory.order %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td class='usages'>
|
||||
<% if (ctx.tagCategory.name) { %>
|
||||
<a href='<%- ctx.formatClientLink('tags', {query: 'category:' + ctx.tagCategory.name}) %>'>
|
||||
|
|
|
@ -26,6 +26,7 @@ class TagCategoriesController {
|
|||
tagCategories: this._tagCategories,
|
||||
canEditName: api.hasPrivilege("tagCategories:edit:name"),
|
||||
canEditColor: api.hasPrivilege("tagCategories:edit:color"),
|
||||
canEditOrder: api.hasPrivilege("tagCategories:edit:order"),
|
||||
canDelete: api.hasPrivilege("tagCategories:delete"),
|
||||
canCreate: api.hasPrivilege("tagCategories:create"),
|
||||
canSetDefault: api.hasPrivilege(
|
||||
|
|
|
@ -9,10 +9,12 @@ class TagCategory extends events.EventTarget {
|
|||
super();
|
||||
this._name = "";
|
||||
this._color = "#000000";
|
||||
this._order = 1;
|
||||
this._tagCount = 0;
|
||||
this._isDefault = false;
|
||||
this._origName = null;
|
||||
this._origColor = null;
|
||||
this._origOrder = null;
|
||||
}
|
||||
|
||||
get name() {
|
||||
|
@ -23,6 +25,10 @@ class TagCategory extends events.EventTarget {
|
|||
return this._color;
|
||||
}
|
||||
|
||||
get order() {
|
||||
return this._order;
|
||||
}
|
||||
|
||||
get tagCount() {
|
||||
return this._tagCount;
|
||||
}
|
||||
|
@ -43,6 +49,10 @@ class TagCategory extends events.EventTarget {
|
|||
this._color = value;
|
||||
}
|
||||
|
||||
set order(value) {
|
||||
this._order = value;
|
||||
}
|
||||
|
||||
static fromResponse(response) {
|
||||
const ret = new TagCategory();
|
||||
ret._updateFromResponse(response);
|
||||
|
@ -58,6 +68,9 @@ class TagCategory extends events.EventTarget {
|
|||
if (this.color !== this._origColor) {
|
||||
detail.color = this.color;
|
||||
}
|
||||
if (this.order !== this._origOrder) {
|
||||
detail.order = this.order;
|
||||
}
|
||||
|
||||
if (!Object.keys(detail).length) {
|
||||
return Promise.resolve();
|
||||
|
@ -104,10 +117,12 @@ class TagCategory extends events.EventTarget {
|
|||
this._version = response.version;
|
||||
this._name = response.name;
|
||||
this._color = response.color;
|
||||
this._order = response.order;
|
||||
this._isDefault = response.default;
|
||||
this._tagCount = response.usages;
|
||||
this._origName = this.name;
|
||||
this._origColor = this.color;
|
||||
this._origOrder = this.order;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,13 @@ class TagCategoriesView extends events.EventTarget {
|
|||
);
|
||||
}
|
||||
|
||||
const orderInput = rowNode.querySelector(".order input");
|
||||
if (orderInput) {
|
||||
orderInput.addEventListener("change", (e) =>
|
||||
this._evtOrderChange(e, rowNode)
|
||||
);
|
||||
}
|
||||
|
||||
const removeLinkNode = rowNode.querySelector(".remove a");
|
||||
if (removeLinkNode) {
|
||||
removeLinkNode.addEventListener("click", (e) =>
|
||||
|
@ -147,6 +154,10 @@ class TagCategoriesView extends events.EventTarget {
|
|||
rowNode._tagCategory.color = e.target.value;
|
||||
}
|
||||
|
||||
_evtOrderChange(e, rowNode) {
|
||||
rowNode._tagCategory.order = e.target.value;
|
||||
}
|
||||
|
||||
_evtDeleteButtonClick(e, rowNode, link) {
|
||||
e.preventDefault();
|
||||
if (e.target.classList.contains("inactive")) {
|
||||
|
|
|
@ -130,6 +130,7 @@ privileges:
|
|||
'tag_categories:create': moderator
|
||||
'tag_categories:edit:name': moderator
|
||||
'tag_categories:edit:color': moderator
|
||||
'tag_categories:edit:order': moderator
|
||||
'tag_categories:list': anonymous
|
||||
'tag_categories:view': anonymous
|
||||
'tag_categories:delete': moderator
|
||||
|
|
|
@ -73,6 +73,11 @@ def update_tag_category(
|
|||
tag_categories.update_category_color(
|
||||
category, ctx.get_param_as_string("color")
|
||||
)
|
||||
if ctx.has_param("order"):
|
||||
auth.verify_privilege(ctx.user, "tag_categories:edit:order")
|
||||
tag_categories.update_category_order(
|
||||
category, ctx.get_param_as_int("order")
|
||||
)
|
||||
ctx.session.flush()
|
||||
snapshots.modify(category, ctx.user)
|
||||
ctx.session.commit()
|
||||
|
|
|
@ -48,6 +48,7 @@ class TagCategorySerializer(serialization.BaseSerializer):
|
|||
"color": self.serialize_color,
|
||||
"usages": self.serialize_usages,
|
||||
"default": self.serialize_default,
|
||||
"order": self.serialize_order,
|
||||
}
|
||||
|
||||
def serialize_name(self) -> Any:
|
||||
|
@ -65,6 +66,9 @@ class TagCategorySerializer(serialization.BaseSerializer):
|
|||
def serialize_default(self) -> Any:
|
||||
return self.category.default
|
||||
|
||||
def serialize_order(self) -> Any:
|
||||
return self.category.order
|
||||
|
||||
|
||||
def serialize_category(
|
||||
category: Optional[model.TagCategory], options: List[str] = []
|
||||
|
@ -117,6 +121,11 @@ def update_category_color(category: model.TagCategory, color: str) -> None:
|
|||
category.color = color
|
||||
|
||||
|
||||
def update_category_order(category: model.TagCategory, order: int) -> None:
|
||||
assert category
|
||||
category.order = order
|
||||
|
||||
|
||||
def try_get_category_by_name(
|
||||
name: str, lock: bool = False
|
||||
) -> Optional[model.TagCategory]:
|
||||
|
|
|
@ -67,6 +67,7 @@ def sort_tags(tags: List[model.Tag]) -> List[model.Tag]:
|
|||
return sorted(
|
||||
tags,
|
||||
key=lambda tag: (
|
||||
tag.category.order,
|
||||
default_category_name == tag.category.name,
|
||||
tag.category.name,
|
||||
tag.names[0].name,
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
Add order column to tag categories.
|
||||
|
||||
Revision ID: c97dc1bf184a
|
||||
Created at: 2020-09-19 17:08:03.225667
|
||||
"""
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision = "c97dc1bf184a"
|
||||
down_revision = "54de8acc6cef"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column(
|
||||
"tag_category", sa.Column("order", sa.Integer, nullable=True)
|
||||
)
|
||||
op.execute(
|
||||
sa.table("tag_category", sa.column("order"))
|
||||
.update()
|
||||
.values(order=1)
|
||||
)
|
||||
op.alter_column("tag_category", "order", nullable=False)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column("tag_category", "order")
|
|
@ -16,6 +16,7 @@ class TagCategory(Base):
|
|||
"color", sa.Unicode(32), nullable=False, default="#000000"
|
||||
)
|
||||
default = sa.Column("default", sa.Boolean, nullable=False, default=False)
|
||||
order = sa.Column("order", sa.Integer, nullable=False, default=1)
|
||||
|
||||
def __init__(self, name: Optional[str] = None) -> None:
|
||||
self.name = name
|
||||
|
|
|
@ -17,6 +17,7 @@ def inject_config(config_injector):
|
|||
"privileges": {
|
||||
"tag_categories:edit:name": model.User.RANK_REGULAR,
|
||||
"tag_categories:edit:color": model.User.RANK_REGULAR,
|
||||
"tag_categories:edit:order": model.User.RANK_REGULAR,
|
||||
"tag_categories:set_default": model.User.RANK_REGULAR,
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue