feat(sets): added notes field to sets. Displayed both at top of page, if not empty and in the metadata section, where it can be changed
This commit is contained in:
@@ -30,6 +30,7 @@ class BrickSet(RebrickableSet):
|
||||
insert_query: str = 'set/insert'
|
||||
update_purchase_date_query: str = 'set/update/purchase_date'
|
||||
update_purchase_price_query: str = 'set/update/purchase_price'
|
||||
update_description_query: str = 'set/update/description'
|
||||
|
||||
# Delete a set
|
||||
def delete(self, /) -> None:
|
||||
@@ -370,3 +371,36 @@ class BrickSet(RebrickableSet):
|
||||
# Update purchase price url
|
||||
def url_for_purchase_price(self, /) -> str:
|
||||
return url_for('set.update_purchase_price', id=self.fields.id)
|
||||
|
||||
# Update description
|
||||
def update_description(self, json: Any | None, /) -> Any:
|
||||
value = json.get('value', None) # type: ignore
|
||||
|
||||
if value == '':
|
||||
value = None
|
||||
|
||||
self.fields.description = value
|
||||
|
||||
rows, _ = BrickSQL().execute_and_commit(
|
||||
self.update_description_query,
|
||||
parameters=self.sql_parameters()
|
||||
)
|
||||
|
||||
if rows != 1:
|
||||
raise DatabaseException('Could not update the description for set {set} ({id})'.format( # noqa: E501
|
||||
set=self.fields.set,
|
||||
id=self.fields.id,
|
||||
))
|
||||
|
||||
# Info
|
||||
logger.info('Description changed to "{value}" for set {set} ({id})'.format( # noqa: E501
|
||||
value=value,
|
||||
set=self.fields.set,
|
||||
id=self.fields.id,
|
||||
))
|
||||
|
||||
return value
|
||||
|
||||
# Update description url
|
||||
def url_for_description(self, /) -> str:
|
||||
return url_for('set.update_description', id=self.fields.id)
|
||||
|
||||
@@ -4,6 +4,7 @@ SELECT
|
||||
"bricktracker_sets"."purchase_date",
|
||||
"bricktracker_sets"."purchase_location",
|
||||
"bricktracker_sets"."purchase_price",
|
||||
"bricktracker_sets"."description",
|
||||
"rebrickable_sets"."set",
|
||||
"rebrickable_sets"."number",
|
||||
"rebrickable_sets"."version",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
UPDATE "bricktracker_sets"
|
||||
SET "description" = :description
|
||||
WHERE "bricktracker_sets"."id" IS NOT DISTINCT FROM :id
|
||||
@@ -158,6 +158,18 @@ def update_purchase_price(*, id: str) -> Response:
|
||||
return jsonify({'value': value})
|
||||
|
||||
|
||||
# Change the value of description
|
||||
@set_page.route('/<id>/description', methods=['POST'])
|
||||
@login_required
|
||||
@exception_handler(__file__, json=True)
|
||||
def update_description(*, id: str) -> Response:
|
||||
brickset = BrickSet().select_light(id)
|
||||
|
||||
value = brickset.update_description(request.json)
|
||||
|
||||
return jsonify({'value': value})
|
||||
|
||||
|
||||
# Change the state of a owner
|
||||
@set_page.route('/<id>/owner/<metadata_id>', methods=['POST'])
|
||||
@login_required
|
||||
|
||||
@@ -38,6 +38,11 @@ class BrickChanger {
|
||||
listener = "change";
|
||||
break;
|
||||
|
||||
case "TEXTAREA":
|
||||
this.html_type = "textarea";
|
||||
listener = "change";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error(`Unsupported HTML tag type for BrickChanger: ${this.html_element.tagName}`);
|
||||
}
|
||||
@@ -131,6 +136,7 @@ class BrickChanger {
|
||||
|
||||
case "text":
|
||||
case "select":
|
||||
case "textarea":
|
||||
value = this.html_element.value;
|
||||
break;
|
||||
|
||||
|
||||
@@ -65,6 +65,30 @@
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro textarea(name, id, prefix, url, value, all=none, read_only=none, icon=none, rows=3, delete=false) %}
|
||||
{% if all or read_only %}
|
||||
{{ value }}
|
||||
{% else %}
|
||||
<label class="visually-hidden" for="{{ prefix }}-{{ id }}">{{ name }}</label>
|
||||
<div class="input-group">
|
||||
{% if icon %}<span class="input-group-text px-1"><i class="ri-{{ icon }} me-1"></i><span class="ms-1 d-none d-md-inline"> {{ name }}</span></span>{% endif %}
|
||||
<textarea class="form-control form-control-sm flex-shrink-1 px-1" id="{{ prefix }}-{{ id }}" rows="{{ rows }}"
|
||||
{% if g.login.is_authenticated() and not delete %}
|
||||
data-changer-id="{{ id }}" data-changer-prefix="{{ prefix }}" data-changer-url="{{ url }}"
|
||||
{% else %}
|
||||
disabled
|
||||
{% endif %}
|
||||
autocomplete="off">{% if value %}{{ value }}{% endif %}</textarea>
|
||||
{% if g.login.is_authenticated() and not delete %}
|
||||
<span id="status-{{ prefix }}-{{ id }}" class="input-group-text ri-save-line px-1"></span>
|
||||
<button id="clear-{{ prefix }}-{{ id }}" type="button" class="btn btn-sm btn-light btn-outline-danger border px-1"><i class="ri-eraser-line"></i></button>
|
||||
{% else %}
|
||||
<span class="input-group-text ri-prohibited-line px-1"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro filter_toggle(filter_id) %}
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary filter-toggle"
|
||||
|
||||
@@ -60,6 +60,13 @@
|
||||
{# Render badges in configured order based on context (grid view vs detail view) #}
|
||||
{{ badge.render_ordered_badges(item, brickset_tags, brickset_owners, brickset_storages, brickset_purchase_locations, solo=solo, last=last, context='detail' if solo else 'grid') }}
|
||||
</div>
|
||||
{% if item.fields.description %}
|
||||
<div class="card-body border-bottom-0 {% if not solo %}p-1{% endif %} pt-0"{% if current_viewing %} style="border-color: var(--bs-border-color) !important; border-width: 1px !important;"{% endif %}>
|
||||
<div class="alert alert-info mb-0 {% if not solo %}p-1 small{% endif %}" role="alert">
|
||||
<i class="ri-sticky-note-line me-1"></i>{{ item.fields.description }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not tiny and brickset_statuses | length %}
|
||||
<ul class="list-group list-group-flush card-check border-bottom-0"{% if current_viewing %} style="border-color: var(--bs-border-color) !important; border-width: 1px !important;"{% endif %}>
|
||||
{% for status in brickset_statuses %}
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
<hr>
|
||||
<a href="{{ url_for('admin.admin', open_purchase_location=true) }}" class="btn btn-primary" role="button"><i class="ri-settings-4-line"></i> Manage the set purchase locations</a>
|
||||
{{ accordion.footer() }}
|
||||
{{ accordion.header('Notes', 'notes', 'set-management', icon='sticky-note-line') }}
|
||||
{{ form.textarea('Notes', item.fields.id, 'description', item.url_for_description(), item.fields.description, rows=4, delete=delete) }}
|
||||
{{ accordion.footer() }}
|
||||
{{ accordion.header('Storage', 'storage', 'set-management', icon='archive-2-line') }}
|
||||
{% if brickset_storages | length %}
|
||||
{{ form.select('Storage', item.fields.id, brickset_storages.as_prefix(), brickset_storages.url_for_set_value(item.fields.id), item.fields.storage, brickset_storages, icon='building-line', delete=delete) }}
|
||||
|
||||
Reference in New Issue
Block a user