Set owners
This commit is contained in:
parent
2a12889695
commit
7047a28845
@ -13,11 +13,12 @@ from bricktracker.sql import close
|
|||||||
from bricktracker.version import __version__
|
from bricktracker.version import __version__
|
||||||
from bricktracker.views.add import add_page
|
from bricktracker.views.add import add_page
|
||||||
from bricktracker.views.admin.admin import admin_page
|
from bricktracker.views.admin.admin import admin_page
|
||||||
from bricktracker.views.admin.status import admin_status_page
|
|
||||||
from bricktracker.views.admin.database import admin_database_page
|
from bricktracker.views.admin.database import admin_database_page
|
||||||
from bricktracker.views.admin.image import admin_image_page
|
from bricktracker.views.admin.image import admin_image_page
|
||||||
from bricktracker.views.admin.instructions import admin_instructions_page
|
from bricktracker.views.admin.instructions import admin_instructions_page
|
||||||
|
from bricktracker.views.admin.owner import admin_owner_page
|
||||||
from bricktracker.views.admin.retired import admin_retired_page
|
from bricktracker.views.admin.retired import admin_retired_page
|
||||||
|
from bricktracker.views.admin.status import admin_status_page
|
||||||
from bricktracker.views.admin.theme import admin_theme_page
|
from bricktracker.views.admin.theme import admin_theme_page
|
||||||
from bricktracker.views.error import error_404
|
from bricktracker.views.error import error_404
|
||||||
from bricktracker.views.index import index_page
|
from bricktracker.views.index import index_page
|
||||||
@ -78,11 +79,12 @@ def setup_app(app: Flask) -> None:
|
|||||||
|
|
||||||
# Register admin routes
|
# Register admin routes
|
||||||
app.register_blueprint(admin_page)
|
app.register_blueprint(admin_page)
|
||||||
app.register_blueprint(admin_status_page)
|
|
||||||
app.register_blueprint(admin_database_page)
|
app.register_blueprint(admin_database_page)
|
||||||
app.register_blueprint(admin_image_page)
|
app.register_blueprint(admin_image_page)
|
||||||
app.register_blueprint(admin_instructions_page)
|
app.register_blueprint(admin_instructions_page)
|
||||||
app.register_blueprint(admin_retired_page)
|
app.register_blueprint(admin_retired_page)
|
||||||
|
app.register_blueprint(admin_owner_page)
|
||||||
|
app.register_blueprint(admin_status_page)
|
||||||
app.register_blueprint(admin_theme_page)
|
app.register_blueprint(admin_theme_page)
|
||||||
|
|
||||||
# An helper to make global variables available to the
|
# An helper to make global variables available to the
|
||||||
|
@ -176,8 +176,16 @@ class BrickMetadata(BrickRecord):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
# Update the selected state of this metadata item for a set
|
# Update the selected state of this metadata item for a set
|
||||||
def update_set_state(self, brickset: 'BrickSet', json: Any | None) -> Any:
|
def update_set_state(
|
||||||
state: bool = json.get('value', False) # type: ignore
|
self,
|
||||||
|
brickset: 'BrickSet',
|
||||||
|
/,
|
||||||
|
*,
|
||||||
|
json: Any | None = None,
|
||||||
|
state: bool | None = None,
|
||||||
|
) -> Any:
|
||||||
|
if state is None:
|
||||||
|
state = json.get('value', False) # type: ignore
|
||||||
|
|
||||||
parameters = self.sql_parameters()
|
parameters = self.sql_parameters()
|
||||||
parameters['set_id'] = brickset.fields.id
|
parameters['set_id'] = brickset.fields.id
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Type
|
from typing import Type, TypeVar
|
||||||
|
|
||||||
from .exceptions import NotFoundException
|
from .exceptions import NotFoundException
|
||||||
from .fields import BrickRecordFields
|
from .fields import BrickRecordFields
|
||||||
from .record_list import BrickRecordList
|
from .record_list import BrickRecordList
|
||||||
|
from .set_owner import BrickSetOwner
|
||||||
from .set_status import BrickSetStatus
|
from .set_status import BrickSetStatus
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
T = BrickSetStatus
|
T = TypeVar('T', 'BrickSetStatus', 'BrickSetOwner')
|
||||||
|
|
||||||
|
|
||||||
# Lego sets metadata list
|
# Lego sets metadata list
|
||||||
|
@ -8,12 +8,14 @@ if TYPE_CHECKING:
|
|||||||
from .part import BrickPart
|
from .part import BrickPart
|
||||||
from .rebrickable_set import RebrickableSet
|
from .rebrickable_set import RebrickableSet
|
||||||
from .set import BrickSet
|
from .set import BrickSet
|
||||||
|
from .set_owner import BrickSetOwner
|
||||||
from .set_status import BrickSetStatus
|
from .set_status import BrickSetStatus
|
||||||
from .wish import BrickWish
|
from .wish import BrickWish
|
||||||
|
|
||||||
T = TypeVar(
|
T = TypeVar(
|
||||||
'T',
|
'T',
|
||||||
'BrickSet',
|
'BrickSet',
|
||||||
|
'BrickSetOwner',
|
||||||
'BrickSetStatus',
|
'BrickSetStatus',
|
||||||
'BrickPart',
|
'BrickPart',
|
||||||
'BrickMinifigure',
|
'BrickMinifigure',
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
from .instructions_list import BrickInstructionsList
|
from .instructions_list import BrickInstructionsList
|
||||||
from .retired_list import BrickRetiredList
|
from .retired_list import BrickRetiredList
|
||||||
|
from .set_owner import BrickSetOwner
|
||||||
|
from .set_owner_list import BrickSetOwnerList
|
||||||
from .set_status import BrickSetStatus
|
from .set_status import BrickSetStatus
|
||||||
from .set_status_list import BrickSetStatusList
|
from .set_status_list import BrickSetStatusList
|
||||||
from .theme_list import BrickThemeList
|
from .theme_list import BrickThemeList
|
||||||
@ -12,6 +14,9 @@ def reload() -> None:
|
|||||||
# Reload the instructions
|
# Reload the instructions
|
||||||
BrickInstructionsList(force=True)
|
BrickInstructionsList(force=True)
|
||||||
|
|
||||||
|
# Reload the set owners
|
||||||
|
BrickSetOwnerList(BrickSetOwner, force=True)
|
||||||
|
|
||||||
# Reload the set statuses
|
# Reload the set statuses
|
||||||
BrickSetStatusList(BrickSetStatus, force=True)
|
BrickSetStatusList(BrickSetStatus, force=True)
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ from .exceptions import NotFoundException
|
|||||||
from .minifigure_list import BrickMinifigureList
|
from .minifigure_list import BrickMinifigureList
|
||||||
from .part_list import BrickPartList
|
from .part_list import BrickPartList
|
||||||
from .rebrickable_set import RebrickableSet
|
from .rebrickable_set import RebrickableSet
|
||||||
|
from .set_owner import BrickSetOwner
|
||||||
|
from .set_owner_list import BrickSetOwnerList
|
||||||
from .set_status import BrickSetStatus
|
from .set_status import BrickSetStatus
|
||||||
from .set_status_list import BrickSetStatusList
|
from .set_status_list import BrickSetStatusList
|
||||||
from .sql import BrickSQL
|
from .sql import BrickSQL
|
||||||
@ -68,6 +70,13 @@ class BrickSet(RebrickableSet):
|
|||||||
if not BrickMinifigureList.download(socket, self, refresh=refresh):
|
if not BrickMinifigureList.download(socket, self, refresh=refresh):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Save the owners
|
||||||
|
owners: list[str] = list(data.get('owners', []))
|
||||||
|
|
||||||
|
for id in owners:
|
||||||
|
owner = BrickSetOwnerList(BrickSetOwner).get(id)
|
||||||
|
owner.update_set_state(self, state=True)
|
||||||
|
|
||||||
# Commit the transaction to the database
|
# Commit the transaction to the database
|
||||||
socket.auto_progress(
|
socket.auto_progress(
|
||||||
message='Set {set}: writing to the database'.format(
|
message='Set {set}: writing to the database'.format(
|
||||||
@ -162,6 +171,7 @@ class BrickSet(RebrickableSet):
|
|||||||
|
|
||||||
# Load from database
|
# Load from database
|
||||||
if not self.select(
|
if not self.select(
|
||||||
|
owners=BrickSetOwnerList(BrickSetOwner).as_columns(),
|
||||||
statuses=BrickSetStatusList(BrickSetStatus).as_columns(all=True)
|
statuses=BrickSetStatusList(BrickSetStatus).as_columns(all=True)
|
||||||
):
|
):
|
||||||
raise NotFoundException(
|
raise NotFoundException(
|
||||||
|
@ -3,6 +3,8 @@ from typing import Self
|
|||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
|
||||||
from .record_list import BrickRecordList
|
from .record_list import BrickRecordList
|
||||||
|
from .set_owner import BrickSetOwner
|
||||||
|
from .set_owner_list import BrickSetOwnerList
|
||||||
from .set_status import BrickSetStatus
|
from .set_status import BrickSetStatus
|
||||||
from .set_status_list import BrickSetStatusList
|
from .set_status_list import BrickSetStatusList
|
||||||
from .set import BrickSet
|
from .set import BrickSet
|
||||||
@ -38,6 +40,7 @@ class BrickSetList(BrickRecordList[BrickSet]):
|
|||||||
# Load the sets from the database
|
# Load the sets from the database
|
||||||
for record in self.select(
|
for record in self.select(
|
||||||
order=self.order,
|
order=self.order,
|
||||||
|
owners=BrickSetOwnerList(BrickSetOwner).as_columns(),
|
||||||
statuses=BrickSetStatusList(BrickSetStatus).as_columns()
|
statuses=BrickSetStatusList(BrickSetStatus).as_columns()
|
||||||
):
|
):
|
||||||
brickset = BrickSet(record=record)
|
brickset = BrickSet(record=record)
|
||||||
@ -74,6 +77,7 @@ class BrickSetList(BrickRecordList[BrickSet]):
|
|||||||
for record in self.select(
|
for record in self.select(
|
||||||
order=order,
|
order=order,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
|
owners=BrickSetOwnerList(BrickSetOwner).as_columns(),
|
||||||
statuses=BrickSetStatusList(BrickSetStatus).as_columns()
|
statuses=BrickSetStatusList(BrickSetStatus).as_columns()
|
||||||
):
|
):
|
||||||
brickset = BrickSet(record=record)
|
brickset = BrickSet(record=record)
|
||||||
|
16
bricktracker/set_owner.py
Normal file
16
bricktracker/set_owner.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from .metadata import BrickMetadata
|
||||||
|
|
||||||
|
|
||||||
|
# Lego set owner metadata
|
||||||
|
class BrickSetOwner(BrickMetadata):
|
||||||
|
kind: str = 'owner'
|
||||||
|
|
||||||
|
# Set state endpoint
|
||||||
|
set_state_endpoint: str = 'set.update_owner'
|
||||||
|
|
||||||
|
# Queries
|
||||||
|
delete_query: str = 'set/metadata/owner/delete'
|
||||||
|
insert_query: str = 'set/metadata/owner/insert'
|
||||||
|
select_query: str = 'set/metadata/owner/select'
|
||||||
|
update_field_query: str = 'set/metadata/owner/update/field'
|
||||||
|
update_set_state_query: str = 'set/metadata/owner/update/state'
|
17
bricktracker/set_owner_list.py
Normal file
17
bricktracker/set_owner_list.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from .metadata_list import BrickMetadataList
|
||||||
|
from .set_owner import BrickSetOwner
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# Lego sets owner list
|
||||||
|
class BrickSetOwnerList(BrickMetadataList[BrickSetOwner]):
|
||||||
|
kind: str = 'set owners'
|
||||||
|
|
||||||
|
# Database table
|
||||||
|
table: str = 'bricktracker_set_owners'
|
||||||
|
|
||||||
|
# Queries
|
||||||
|
select_query = 'set/metadata/owner/list'
|
19
bricktracker/sql/migrations/0013.sql
Normal file
19
bricktracker/sql/migrations/0013.sql
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
-- description: Add set owners
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
-- Create a table to define each set owners: an id and a name
|
||||||
|
CREATE TABLE "bricktracker_metadata_owners" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
PRIMARY KEY("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create a table for the set owners
|
||||||
|
CREATE TABLE "bricktracker_set_owners" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
PRIMARY KEY("id"),
|
||||||
|
FOREIGN KEY("id") REFERENCES "bricktracker_sets"("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
@ -9,6 +9,9 @@ SELECT
|
|||||||
"rebrickable_sets"."number_of_parts",
|
"rebrickable_sets"."number_of_parts",
|
||||||
"rebrickable_sets"."image",
|
"rebrickable_sets"."image",
|
||||||
"rebrickable_sets"."url",
|
"rebrickable_sets"."url",
|
||||||
|
{% block owners %}
|
||||||
|
{% if owners %}{{ owners }},{% endif %}
|
||||||
|
{% endblock %}
|
||||||
{% block statuses %}
|
{% block statuses %}
|
||||||
{% if statuses %}{{ statuses }},{% endif %}
|
{% if statuses %}{{ statuses }},{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -13,6 +13,11 @@ IFNULL("minifigures_join"."total", 0) AS "total_minifigures"
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block join %}
|
{% block join %}
|
||||||
|
{% if owners %}
|
||||||
|
LEFT JOIN "bricktracker_set_owners"
|
||||||
|
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_owners"."id"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if statuses %}
|
{% if statuses %}
|
||||||
LEFT JOIN "bricktracker_set_statuses"
|
LEFT JOIN "bricktracker_set_statuses"
|
||||||
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_statuses"."id"
|
ON "bricktracker_sets"."id" IS NOT DISTINCT FROM "bricktracker_set_statuses"."id"
|
||||||
|
@ -6,6 +6,9 @@ BEGIN TRANSACTION;
|
|||||||
DELETE FROM "bricktracker_sets"
|
DELETE FROM "bricktracker_sets"
|
||||||
WHERE "bricktracker_sets"."id" IS NOT DISTINCT FROM '{{ id }}';
|
WHERE "bricktracker_sets"."id" IS NOT DISTINCT FROM '{{ id }}';
|
||||||
|
|
||||||
|
DELETE FROM "bricktracker_set_owners"
|
||||||
|
WHERE "bricktracker_set_owners"."id" IS NOT DISTINCT FROM '{{ id }}';
|
||||||
|
|
||||||
DELETE FROM "bricktracker_set_statuses"
|
DELETE FROM "bricktracker_set_statuses"
|
||||||
WHERE "bricktracker_set_statuses"."id" IS NOT DISTINCT FROM '{{ id }}';
|
WHERE "bricktracker_set_statuses"."id" IS NOT DISTINCT FROM '{{ id }}';
|
||||||
|
|
||||||
|
6
bricktracker/sql/set/metadata/owner/base.sql
Normal file
6
bricktracker/sql/set/metadata/owner/base.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT
|
||||||
|
"bricktracker_metadata_owners"."id",
|
||||||
|
"bricktracker_metadata_owners"."name"
|
||||||
|
FROM "bricktracker_metadata_owners"
|
||||||
|
|
||||||
|
{% block where %}{% endblock %}
|
9
bricktracker/sql/set/metadata/owner/delete.sql
Normal file
9
bricktracker/sql/set/metadata/owner/delete.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE "bricktracker_set_owners"
|
||||||
|
DROP COLUMN "owner_{{ id }}";
|
||||||
|
|
||||||
|
DELETE FROM "bricktracker_metadata_owners"
|
||||||
|
WHERE "bricktracker_metadata_owners"."id" IS NOT DISTINCT FROM '{{ id }}';
|
||||||
|
|
||||||
|
COMMIT;
|
14
bricktracker/sql/set/metadata/owner/insert.sql
Normal file
14
bricktracker/sql/set/metadata/owner/insert.sql
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE "bricktracker_set_owners"
|
||||||
|
ADD COLUMN "owner_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
|
INSERT INTO "bricktracker_metadata_owners" (
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
) VALUES (
|
||||||
|
'{{ id }}',
|
||||||
|
'{{ name }}'
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
1
bricktracker/sql/set/metadata/owner/list.sql
Normal file
1
bricktracker/sql/set/metadata/owner/list.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
{% extends 'set/metadata/owner/base.sql' %}
|
5
bricktracker/sql/set/metadata/owner/select.sql
Normal file
5
bricktracker/sql/set/metadata/owner/select.sql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{% extends 'set/metadata/owner/base.sql' %}
|
||||||
|
|
||||||
|
{% block where %}
|
||||||
|
WHERE "bricktracker_metadata_owners"."id" IS NOT DISTINCT FROM :id
|
||||||
|
{% endblock %}
|
3
bricktracker/sql/set/metadata/owner/update/field.sql
Normal file
3
bricktracker/sql/set/metadata/owner/update/field.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
UPDATE "bricktracker_metadata_owners"
|
||||||
|
SET "{{field}}" = :value
|
||||||
|
WHERE "bricktracker_metadata_owners"."id" IS NOT DISTINCT FROM :id
|
10
bricktracker/sql/set/metadata/owner/update/state.sql
Normal file
10
bricktracker/sql/set/metadata/owner/update/state.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
INSERT INTO "bricktracker_set_owners" (
|
||||||
|
"id",
|
||||||
|
"{{name}}"
|
||||||
|
) VALUES (
|
||||||
|
:set_id,
|
||||||
|
:state
|
||||||
|
)
|
||||||
|
ON CONFLICT("id")
|
||||||
|
DO UPDATE SET "{{name}}" = :state
|
||||||
|
WHERE "bricktracker_set_owners"."id" IS NOT DISTINCT FROM :set_id
|
@ -6,7 +6,8 @@ ALIASES: dict[str, Tuple[str, str]] = {
|
|||||||
'bricktracker_minifigures': ('Bricktracker minifigures', 'group-line'),
|
'bricktracker_minifigures': ('Bricktracker minifigures', 'group-line'),
|
||||||
'bricktracker_parts': ('Bricktracker parts', 'shapes-line'),
|
'bricktracker_parts': ('Bricktracker parts', 'shapes-line'),
|
||||||
'bricktracker_set_checkboxes': ('Bricktracker set checkboxes (legacy)', 'checkbox-line'), # noqa: E501
|
'bricktracker_set_checkboxes': ('Bricktracker set checkboxes (legacy)', 'checkbox-line'), # noqa: E501
|
||||||
'bricktracker_set_statuses': ('Bricktracker set statuses', 'checkbox-line'), # noqa: E501
|
'bricktracker_set_owners': ('Bricktracker set owners', 'checkbox-line'), # noqa: E501
|
||||||
|
'bricktracker_set_statuses': ('Bricktracker set statuses', 'user-line'), # noqa: E501
|
||||||
'bricktracker_set_storages': ('Bricktracker set storages', 'archive-2-line'), # noqa: E501
|
'bricktracker_set_storages': ('Bricktracker set storages', 'archive-2-line'), # noqa: E501
|
||||||
'bricktracker_sets': ('Bricktracker sets', 'hashtag'),
|
'bricktracker_sets': ('Bricktracker sets', 'hashtag'),
|
||||||
'bricktracker_wishes': ('Bricktracker wishes', 'gift-line'),
|
'bricktracker_wishes': ('Bricktracker wishes', 'gift-line'),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
__version__: Final[str] = '1.2.0'
|
__version__: Final[str] = '1.2.0'
|
||||||
__database_version__: Final[int] = 12
|
__database_version__: Final[int] = 13
|
||||||
|
@ -3,6 +3,8 @@ from flask_login import login_required
|
|||||||
|
|
||||||
from ..configuration_list import BrickConfigurationList
|
from ..configuration_list import BrickConfigurationList
|
||||||
from .exceptions import exception_handler
|
from .exceptions import exception_handler
|
||||||
|
from ..set_owner import BrickSetOwner
|
||||||
|
from ..set_owner_list import BrickSetOwnerList
|
||||||
from ..socket import MESSAGES
|
from ..socket import MESSAGES
|
||||||
|
|
||||||
add_page = Blueprint('add', __name__, url_prefix='/add')
|
add_page = Blueprint('add', __name__, url_prefix='/add')
|
||||||
@ -17,6 +19,7 @@ def add() -> str:
|
|||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'add.html',
|
'add.html',
|
||||||
|
brickset_owners=BrickSetOwnerList(BrickSetOwner).list(),
|
||||||
path=current_app.config['SOCKET_PATH'],
|
path=current_app.config['SOCKET_PATH'],
|
||||||
namespace=current_app.config['SOCKET_NAMESPACE'],
|
namespace=current_app.config['SOCKET_NAMESPACE'],
|
||||||
messages=MESSAGES
|
messages=MESSAGES
|
||||||
@ -32,6 +35,7 @@ def bulk() -> str:
|
|||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'add.html',
|
'add.html',
|
||||||
|
brickset_owners=BrickSetOwnerList(BrickSetOwner).list(),
|
||||||
path=current_app.config['SOCKET_PATH'],
|
path=current_app.config['SOCKET_PATH'],
|
||||||
namespace=current_app.config['SOCKET_NAMESPACE'],
|
namespace=current_app.config['SOCKET_NAMESPACE'],
|
||||||
messages=MESSAGES,
|
messages=MESSAGES,
|
||||||
|
@ -8,6 +8,8 @@ from ..exceptions import exception_handler
|
|||||||
from ...instructions_list import BrickInstructionsList
|
from ...instructions_list import BrickInstructionsList
|
||||||
from ...rebrickable_image import RebrickableImage
|
from ...rebrickable_image import RebrickableImage
|
||||||
from ...retired_list import BrickRetiredList
|
from ...retired_list import BrickRetiredList
|
||||||
|
from ...set_owner import BrickSetOwner
|
||||||
|
from ...set_owner_list import BrickSetOwnerList
|
||||||
from ...set_status import BrickSetStatus
|
from ...set_status import BrickSetStatus
|
||||||
from ...set_status_list import BrickSetStatusList
|
from ...set_status_list import BrickSetStatusList
|
||||||
from ...sql_counter import BrickCounter
|
from ...sql_counter import BrickCounter
|
||||||
@ -28,6 +30,7 @@ def admin() -> str:
|
|||||||
database_exception: Exception | None = None
|
database_exception: Exception | None = None
|
||||||
database_upgrade_needed: bool = False
|
database_upgrade_needed: bool = False
|
||||||
database_version: int = -1
|
database_version: int = -1
|
||||||
|
metadata_owners: list[BrickSetOwner] = []
|
||||||
metadata_statuses: list[BrickSetStatus] = []
|
metadata_statuses: list[BrickSetStatus] = []
|
||||||
nil_minifigure_name: str = ''
|
nil_minifigure_name: str = ''
|
||||||
nil_minifigure_url: str = ''
|
nil_minifigure_url: str = ''
|
||||||
@ -41,6 +44,7 @@ def admin() -> str:
|
|||||||
database_version = database.version
|
database_version = database.version
|
||||||
database_counters = BrickSQL().count_records()
|
database_counters = BrickSQL().count_records()
|
||||||
|
|
||||||
|
metadata_owners = BrickSetOwnerList(BrickSetOwner).list()
|
||||||
metadata_statuses = BrickSetStatusList(BrickSetStatus).list(all=True)
|
metadata_statuses = BrickSetStatusList(BrickSetStatus).list(all=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
database_exception = e
|
database_exception = e
|
||||||
@ -65,6 +69,7 @@ def admin() -> str:
|
|||||||
open_image = request.args.get('open_image', None)
|
open_image = request.args.get('open_image', None)
|
||||||
open_instructions = request.args.get('open_instructions', None)
|
open_instructions = request.args.get('open_instructions', None)
|
||||||
open_logout = request.args.get('open_logout', None)
|
open_logout = request.args.get('open_logout', None)
|
||||||
|
open_owner = request.args.get('open_owner', None)
|
||||||
open_retired = request.args.get('open_retired', None)
|
open_retired = request.args.get('open_retired', None)
|
||||||
open_status = request.args.get('open_status', None)
|
open_status = request.args.get('open_status', None)
|
||||||
open_theme = request.args.get('open_theme', None)
|
open_theme = request.args.get('open_theme', None)
|
||||||
@ -73,6 +78,7 @@ def admin() -> str:
|
|||||||
open_image is None and
|
open_image is None and
|
||||||
open_instructions is None and
|
open_instructions is None and
|
||||||
open_logout is None and
|
open_logout is None and
|
||||||
|
open_owner is None and
|
||||||
open_retired is None and
|
open_retired is None and
|
||||||
open_status is None and
|
open_status is None and
|
||||||
open_theme is None
|
open_theme is None
|
||||||
@ -81,13 +87,13 @@ def admin() -> str:
|
|||||||
return render_template(
|
return render_template(
|
||||||
'admin.html',
|
'admin.html',
|
||||||
configuration=BrickConfigurationList.list(),
|
configuration=BrickConfigurationList.list(),
|
||||||
status_error=request.args.get('status_error'),
|
|
||||||
database_counters=database_counters,
|
database_counters=database_counters,
|
||||||
database_error=request.args.get('database_error'),
|
database_error=request.args.get('database_error'),
|
||||||
database_exception=database_exception,
|
database_exception=database_exception,
|
||||||
database_upgrade_needed=database_upgrade_needed,
|
database_upgrade_needed=database_upgrade_needed,
|
||||||
database_version=database_version,
|
database_version=database_version,
|
||||||
instructions=BrickInstructionsList(),
|
instructions=BrickInstructionsList(),
|
||||||
|
metadata_owners=metadata_owners,
|
||||||
metadata_statuses=metadata_statuses,
|
metadata_statuses=metadata_statuses,
|
||||||
nil_minifigure_name=nil_minifigure_name,
|
nil_minifigure_name=nil_minifigure_name,
|
||||||
nil_minifigure_url=nil_minifigure_url,
|
nil_minifigure_url=nil_minifigure_url,
|
||||||
@ -98,8 +104,11 @@ def admin() -> str:
|
|||||||
open_image=open_image,
|
open_image=open_image,
|
||||||
open_instructions=open_instructions,
|
open_instructions=open_instructions,
|
||||||
open_logout=open_logout,
|
open_logout=open_logout,
|
||||||
|
open_owner=open_owner,
|
||||||
open_retired=open_retired,
|
open_retired=open_retired,
|
||||||
open_theme=open_theme,
|
open_theme=open_theme,
|
||||||
|
owner_error=request.args.get('owner_error'),
|
||||||
|
status_error=request.args.get('status_error'),
|
||||||
retired=BrickRetiredList(),
|
retired=BrickRetiredList(),
|
||||||
theme=BrickThemeList(),
|
theme=BrickThemeList(),
|
||||||
)
|
)
|
||||||
|
84
bricktracker/views/admin/owner.py
Normal file
84
bricktracker/views/admin/owner.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from flask import (
|
||||||
|
Blueprint,
|
||||||
|
redirect,
|
||||||
|
request,
|
||||||
|
render_template,
|
||||||
|
url_for,
|
||||||
|
)
|
||||||
|
from flask_login import login_required
|
||||||
|
from werkzeug.wrappers.response import Response
|
||||||
|
|
||||||
|
from ..exceptions import exception_handler
|
||||||
|
from ...reload import reload
|
||||||
|
from ...set_owner import BrickSetOwner
|
||||||
|
|
||||||
|
admin_owner_page = Blueprint(
|
||||||
|
'admin_owner',
|
||||||
|
__name__,
|
||||||
|
url_prefix='/admin/owner'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Add a metadata owner
|
||||||
|
@admin_owner_page.route('/add', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@exception_handler(
|
||||||
|
__file__,
|
||||||
|
post_redirect='admin.admin',
|
||||||
|
error_name='owner_error',
|
||||||
|
open_owner=True
|
||||||
|
)
|
||||||
|
def add() -> Response:
|
||||||
|
BrickSetOwner().from_form(request.form).insert()
|
||||||
|
|
||||||
|
reload()
|
||||||
|
|
||||||
|
return redirect(url_for('admin.admin', open_owner=True))
|
||||||
|
|
||||||
|
|
||||||
|
# Delete the metadata owner
|
||||||
|
@admin_owner_page.route('<id>/delete', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
@exception_handler(__file__)
|
||||||
|
def delete(*, id: str) -> str:
|
||||||
|
return render_template(
|
||||||
|
'admin.html',
|
||||||
|
delete_owner=True,
|
||||||
|
owner=BrickSetOwner().select_specific(id),
|
||||||
|
error=request.args.get('owner_error')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Actually delete the metadata owner
|
||||||
|
@admin_owner_page.route('<id>/delete', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@exception_handler(
|
||||||
|
__file__,
|
||||||
|
post_redirect='admin_owner.delete',
|
||||||
|
error_name='owner_error'
|
||||||
|
)
|
||||||
|
def do_delete(*, id: str) -> Response:
|
||||||
|
owner = BrickSetOwner().select_specific(id)
|
||||||
|
owner.delete()
|
||||||
|
|
||||||
|
reload()
|
||||||
|
|
||||||
|
return redirect(url_for('admin.admin', open_owner=True))
|
||||||
|
|
||||||
|
|
||||||
|
# Rename the metadata owner
|
||||||
|
@admin_owner_page.route('<id>/rename', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@exception_handler(
|
||||||
|
__file__,
|
||||||
|
post_redirect='admin.admin',
|
||||||
|
error_name='owner_error',
|
||||||
|
open_owner=True
|
||||||
|
)
|
||||||
|
def rename(*, id: str) -> Response:
|
||||||
|
owner = BrickSetOwner().select_specific(id)
|
||||||
|
owner.from_form(request.form).rename()
|
||||||
|
|
||||||
|
reload()
|
||||||
|
|
||||||
|
return redirect(url_for('admin.admin', open_owner=True))
|
@ -2,6 +2,8 @@ from flask import Blueprint, render_template
|
|||||||
|
|
||||||
from .exceptions import exception_handler
|
from .exceptions import exception_handler
|
||||||
from ..minifigure_list import BrickMinifigureList
|
from ..minifigure_list import BrickMinifigureList
|
||||||
|
from ..set_owner import BrickSetOwner
|
||||||
|
from ..set_owner_list import BrickSetOwnerList
|
||||||
from ..set_status import BrickSetStatus
|
from ..set_status import BrickSetStatus
|
||||||
from ..set_status_list import BrickSetStatusList
|
from ..set_status_list import BrickSetStatusList
|
||||||
from ..set_list import BrickSetList
|
from ..set_list import BrickSetList
|
||||||
@ -16,6 +18,7 @@ def index() -> str:
|
|||||||
return render_template(
|
return render_template(
|
||||||
'index.html',
|
'index.html',
|
||||||
brickset_collection=BrickSetList().last(),
|
brickset_collection=BrickSetList().last(),
|
||||||
minifigure_collection=BrickMinifigureList().last(),
|
brickset_owners=BrickSetOwnerList(BrickSetOwner).list(),
|
||||||
brickset_statuses=BrickSetStatusList(BrickSetStatus).list(),
|
brickset_statuses=BrickSetStatusList(BrickSetStatus).list(),
|
||||||
|
minifigure_collection=BrickMinifigureList().last(),
|
||||||
)
|
)
|
||||||
|
@ -16,6 +16,8 @@ from .exceptions import exception_handler
|
|||||||
from ..minifigure import BrickMinifigure
|
from ..minifigure import BrickMinifigure
|
||||||
from ..part import BrickPart
|
from ..part import BrickPart
|
||||||
from ..set import BrickSet
|
from ..set import BrickSet
|
||||||
|
from ..set_owner import BrickSetOwner
|
||||||
|
from ..set_owner_list import BrickSetOwnerList
|
||||||
from ..set_status import BrickSetStatus
|
from ..set_status import BrickSetStatus
|
||||||
from ..set_status_list import BrickSetStatusList
|
from ..set_status_list import BrickSetStatusList
|
||||||
from ..set_list import BrickSetList
|
from ..set_list import BrickSetList
|
||||||
@ -33,11 +35,25 @@ def list() -> str:
|
|||||||
return render_template(
|
return render_template(
|
||||||
'sets.html',
|
'sets.html',
|
||||||
collection=BrickSetList().all(),
|
collection=BrickSetList().all(),
|
||||||
|
brickset_owners=BrickSetOwnerList(BrickSetOwner).list(),
|
||||||
brickset_statuses=BrickSetStatusList(BrickSetStatus).list(),
|
brickset_statuses=BrickSetStatusList(BrickSetStatus).list(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Change the status of a status
|
# Change the state of a owner
|
||||||
|
@set_page.route('/<id>/owner/<metadata_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@exception_handler(__file__, json=True)
|
||||||
|
def update_owner(*, id: str, metadata_id: str) -> Response:
|
||||||
|
brickset = BrickSet().select_light(id)
|
||||||
|
owner = BrickSetOwnerList(BrickSetOwner).get(metadata_id)
|
||||||
|
|
||||||
|
state = owner.update_set_state(brickset, json=request.json)
|
||||||
|
|
||||||
|
return jsonify({'value': state})
|
||||||
|
|
||||||
|
|
||||||
|
# Change the state of a status
|
||||||
@set_page.route('/<id>/status/<metadata_id>', methods=['POST'])
|
@set_page.route('/<id>/status/<metadata_id>', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@exception_handler(__file__, json=True)
|
@exception_handler(__file__, json=True)
|
||||||
@ -98,6 +114,7 @@ def details(*, id: str) -> str:
|
|||||||
'set.html',
|
'set.html',
|
||||||
item=BrickSet().select_specific(id),
|
item=BrickSet().select_specific(id),
|
||||||
open_instructions=request.args.get('open_instructions'),
|
open_instructions=request.args.get('open_instructions'),
|
||||||
|
brickset_owners=BrickSetOwnerList(BrickSetOwner).list(),
|
||||||
brickset_statuses=BrickSetStatusList(BrickSetStatus).list(all=True),
|
brickset_statuses=BrickSetStatusList(BrickSetStatus).list(all=True),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ class BrickSetSocket extends BrickSocket {
|
|||||||
this.html_button = document.getElementById(id);
|
this.html_button = document.getElementById(id);
|
||||||
this.html_input = document.getElementById(`${id}-set`);
|
this.html_input = document.getElementById(`${id}-set`);
|
||||||
this.html_no_confim = document.getElementById(`${id}-no-confirm`);
|
this.html_no_confim = document.getElementById(`${id}-no-confirm`);
|
||||||
|
this.html_owners = document.getElementById(`${id}-owners`);
|
||||||
|
|
||||||
// Card elements
|
// Card elements
|
||||||
this.html_card = document.getElementById(`${id}-card`);
|
this.html_card = document.getElementById(`${id}-card`);
|
||||||
@ -139,10 +140,21 @@ class BrickSetSocket extends BrickSocket {
|
|||||||
this.set_list_last_set = set;
|
this.set_list_last_set = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab the owners
|
||||||
|
const owners = [];
|
||||||
|
if (this.html_owners) {
|
||||||
|
this.html_owners.querySelectorAll('input').forEach(input => {
|
||||||
|
if (input.checked) {
|
||||||
|
owners.push(input.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.spinner(true);
|
this.spinner(true);
|
||||||
|
|
||||||
this.socket.emit(this.messages.IMPORT_SET, {
|
this.socket.emit(this.messages.IMPORT_SET, {
|
||||||
set: (set !== undefined) ? set : this.html_input.value,
|
set: (set !== undefined) ? set : this.html_input.value,
|
||||||
|
owners: owners,
|
||||||
refresh: this.refresh
|
refresh: this.refresh
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -247,6 +259,10 @@ class BrickSetSocket extends BrickSocket {
|
|||||||
this.html_input.disabled = !enabled;
|
this.html_input.disabled = !enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.html_owners) {
|
||||||
|
this.html_owners.querySelectorAll('input').forEach(input => input.disabled = !enabled);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.html_card_confirm) {
|
if (this.html_card_confirm) {
|
||||||
this.html_card_confirm.disabled = !enabled;
|
this.html_card_confirm.disabled = !enabled;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,19 @@
|
|||||||
Add without confirmation
|
Add without confirmation
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
{% if brickset_owners | length %}
|
||||||
|
<h5 class="border-bottom mt-2">Owners</h5>
|
||||||
|
<div id="add-owners">
|
||||||
|
{% for owner in brickset_owners %}
|
||||||
|
{% with id=owner.as_dataset() %}
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" value="{{ owner.fields.id }}" id="{{ id }}" autocomplete="off">
|
||||||
|
<label class="form-check-label" for="{{ id }}">{{ owner.fields.name }}</label>
|
||||||
|
</div>
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<hr>
|
<hr>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<p>
|
<p>
|
||||||
|
@ -12,10 +12,12 @@
|
|||||||
<h5 class="mb-0"><i class="ri-settings-4-line"></i> Administration</h5>
|
<h5 class="mb-0"><i class="ri-settings-4-line"></i> Administration</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion accordion-flush" id="admin">
|
<div class="accordion accordion-flush" id="admin">
|
||||||
{% if delete_status %}
|
{% if delete_database %}
|
||||||
{% include 'admin/status/delete.html' %}
|
|
||||||
{% elif delete_database %}
|
|
||||||
{% include 'admin/database/delete.html' %}
|
{% include 'admin/database/delete.html' %}
|
||||||
|
{% elif delete_owner %}
|
||||||
|
{% include 'admin/owner/delete.html' %}
|
||||||
|
{% elif delete_status %}
|
||||||
|
{% include 'admin/status/delete.html' %}
|
||||||
{% elif drop_database %}
|
{% elif drop_database %}
|
||||||
{% include 'admin/database/drop.html' %}
|
{% include 'admin/database/drop.html' %}
|
||||||
{% elif import_database %}
|
{% elif import_database %}
|
||||||
@ -30,6 +32,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% include 'admin/theme.html' %}
|
{% include 'admin/theme.html' %}
|
||||||
{% include 'admin/retired.html' %}
|
{% include 'admin/retired.html' %}
|
||||||
|
{% include 'admin/owner.html' %}
|
||||||
{% include 'admin/status.html' %}
|
{% include 'admin/status.html' %}
|
||||||
{% include 'admin/database.html' %}
|
{% include 'admin/database.html' %}
|
||||||
{% include 'admin/configuration.html' %}
|
{% include 'admin/configuration.html' %}
|
||||||
|
42
templates/admin/owner.html
Normal file
42
templates/admin/owner.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{% import 'macro/accordion.html' as accordion %}
|
||||||
|
|
||||||
|
{{ accordion.header('Set owners', 'owner', 'admin', expanded=open_owner, icon='user-line', class='p-0') }}
|
||||||
|
{% if owner_error %}<div class="alert alert-danger m-2" role="alert"><strong>Error:</strong> {{ owner_error }}.</div>{% endif %}
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
{% if metadata_owners | length %}
|
||||||
|
{% for owner in metadata_owners %}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form action="{{ url_for('admin_owner.rename', id=owner.fields.id) }}" method="post" class="row row-cols-lg-auto g-3 align-items-center">
|
||||||
|
<div class="col-12 flex-grow-1">
|
||||||
|
<label class="visually-hidden" for="name-{{ owner.fields.id }}">Name</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text">Name</div>
|
||||||
|
<input type="text" class="form-control" id="name-{{ owner.fields.id }}" name="name" value="{{ owner.fields.name }}">
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="ri-edit-line"></i> Rename</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<a href="{{ url_for('admin_owner.delete', id=owner.fields.id) }}" class="btn btn-danger" role="button"><i class="ri-delete-bin-2-line"></i> Delete</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<li class="list-group-item"><i class="ri-error-warning-line"></i> No owner found.</li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form action="{{ url_for('admin_owner.add') }}" method="post" class="row row-cols-lg-auto g-3 align-items-center">
|
||||||
|
<div class="col-12 flex-grow-1">
|
||||||
|
<label class="visually-hidden" for="name">Name</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text">Name</div>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" value="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="ri-add-circle-line"></i> Add</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{ accordion.footer() }}
|
19
templates/admin/owner/delete.html
Normal file
19
templates/admin/owner/delete.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{% import 'macro/accordion.html' as accordion %}
|
||||||
|
|
||||||
|
{{ accordion.header('Set owners danger zone', 'owner-danger', 'admin', expanded=true, danger=true, class='text-end') }}
|
||||||
|
<form action="{{ url_for('admin_owner.do_delete', id=owner.fields.id) }}" method="post">
|
||||||
|
{% if owner_error %}<div class="alert alert-danger text-start" role="alert"><strong>Error:</strong> {{ owner_error }}.</div>{% endif %}
|
||||||
|
<div class="alert alert-danger text-center" role="alert">You are about to <strong>delete a set owner</strong>. This action is irreversible.</div>
|
||||||
|
<div class="row row-cols-lg-auto g-3 align-items-center">
|
||||||
|
<div class="col-12 flex-grow-1">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-text">Name</div>
|
||||||
|
<input type="text" class="form-control" value="{{ owner.fields.name }}" disabled>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="border-bottom">
|
||||||
|
<a class="btn btn-danger" href="{{ url_for('admin.admin', open_owner=true) }}" role="button"><i class="ri-arrow-left-long-line"></i> Back to the admin</a>
|
||||||
|
<button type="submit" class="btn btn-danger"><i class="ri-delete-bin-2-line"></i> Delete <strong>the set owner</strong></button>
|
||||||
|
</form>
|
||||||
|
{{ accordion.footer() }}
|
@ -50,9 +50,18 @@
|
|||||||
{{ badge(check=quantity, solo=solo, last=last, color='success', icon='close-line', collapsible='Quantity:', text=quantity, alt='Quantity') }}
|
{{ badge(check=quantity, solo=solo, last=last, color='success', icon='close-line', collapsible='Quantity:', text=quantity, alt='Quantity') }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro owner(item, owner, solo=false, last=false) %}
|
||||||
|
{% if last %}
|
||||||
|
{% set tooltip=owner.fields.name %}
|
||||||
|
{% else %}
|
||||||
|
{% set text=owner.fields.name %}
|
||||||
|
{% endif %}
|
||||||
|
{{ badge(check=item.fields[owner.as_column()], solo=solo, last=last, color='light text-success-emphasis bg-success-subtle border border-success-subtle', icon='user-line', text=text, alt='Owner', tooltip=tooltip) }}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro print(item, solo=false, last=false, header=false) %}
|
{% macro print(item, solo=false, last=false, header=false) %}
|
||||||
{% if item.fields.print %}
|
{% if item.fields.print %}
|
||||||
{{ badge(url=item.url_for_print(), solo=solo, last=last, color='light border', icon='paint-brush-line', collapsible='Print') }}
|
{{ badge(url=item.url_for_print(), solo=solo, last=last, color='light border', icon='paint-brush-line', collapsible='Print') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
data-year="{{ item.fields.year }}" data-theme="{{ item.theme.name | lower }}" data-minifigures="{{ item.fields.total_minifigures }}" data-has-minifigures="{{ (item.fields.total_minifigures > 0) | int }}"
|
data-year="{{ item.fields.year }}" data-theme="{{ item.theme.name | lower }}" data-minifigures="{{ item.fields.total_minifigures }}" data-has-minifigures="{{ (item.fields.total_minifigures > 0) | int }}"
|
||||||
data-has-missing="{{ (item.fields.total_missing > 0) | int }}" data-has-missing-instructions="{{ (not (item.instructions | length)) | int }}" data-missing="{{ item.fields.total_missing }}"
|
data-has-missing="{{ (item.fields.total_missing > 0) | int }}" data-has-missing-instructions="{{ (not (item.instructions | length)) | int }}" data-missing="{{ item.fields.total_missing }}"
|
||||||
{% for status in brickset_statuses %}data-{{ status.as_dataset() }}="{{ item.fields[status.as_column()] }}" {% endfor %}
|
{% for status in brickset_statuses %}data-{{ status.as_dataset() }}="{{ item.fields[status.as_column()] }}" {% endfor %}
|
||||||
|
{% for owner in brickset_owners %}
|
||||||
|
{% with checked=item.fields[owner.as_column()] %}
|
||||||
|
data-{{ owner.as_dataset() }}="{{ checked }}"
|
||||||
|
{% if checked %} data-owner-{{ loop.index }}="{{ owner.fields.name | lower }}"{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
>
|
>
|
||||||
{{ card.header(item, item.fields.name, solo=solo, identifier=item.fields.set) }}
|
{{ card.header(item, item.fields.name, solo=solo, identifier=item.fields.set) }}
|
||||||
@ -19,6 +25,9 @@
|
|||||||
{{ badge.parts(item.fields.number_of_parts, solo=solo, last=last) }}
|
{{ badge.parts(item.fields.number_of_parts, solo=solo, last=last) }}
|
||||||
{{ badge.total_minifigures(item.fields.total_minifigures, solo=solo, last=last) }}
|
{{ badge.total_minifigures(item.fields.total_minifigures, solo=solo, last=last) }}
|
||||||
{{ badge.total_missing(item.fields.total_missing, solo=solo, last=last) }}
|
{{ badge.total_missing(item.fields.total_missing, solo=solo, last=last) }}
|
||||||
|
{% for owner in brickset_owners %}
|
||||||
|
{{ badge.owner(item, owner, solo=solo, last=last) }}
|
||||||
|
{% endfor %}
|
||||||
{% if not last %}
|
{% if not last %}
|
||||||
{% if not solo %}
|
{% if not solo %}
|
||||||
{{ badge.instructions(item, solo=solo, last=last) }}
|
{{ badge.instructions(item, solo=solo, last=last) }}
|
||||||
|
@ -1,6 +1,20 @@
|
|||||||
{% if g.login.is_authenticated() %}
|
{% if g.login.is_authenticated() %}
|
||||||
|
{{ accordion.header('Owners', 'owner', 'set-details', icon='group-line', class='p-0') }}
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
{% if brickset_owners | length %}
|
||||||
|
{% for owner in brickset_owners %}
|
||||||
|
<li class="d-flex list-group-item list-group-item-action text-nowrap">{{ form.checkbox(item, owner, delete=delete) }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<li class="list-group-item list-group-item-action"><i class="ri-error-warning-line"></i> No owner found.</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
<div class="list-group list-group-flush border-top">
|
||||||
|
<a class="list-group-item list-group-item-action" href="{{ url_for('admin.admin', open_owner=true) }}"><i class="ri-settings-4-line"></i> Manage the set owners</a>
|
||||||
|
</div>
|
||||||
|
{{ accordion.footer() }}
|
||||||
{{ accordion.header('Management', 'management', 'set-details', expanded=true, icon='settings-4-line') }}
|
{{ accordion.header('Management', 'management', 'set-details', expanded=true, icon='settings-4-line') }}
|
||||||
<h5 class="border-bottom">Data</h5>
|
<h5 class="border-bottom">Data</h5>
|
||||||
<a href="{{ item.url_for_refresh() }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the set data</a>
|
<a href="{{ item.url_for_refresh() }}" class="btn btn-primary" role="button"><i class="ri-refresh-line"></i> Refresh the set data</a>
|
||||||
{{ accordion.footer() }}
|
{{ accordion.footer() }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<label class="visually-hidden" for="grid-search">Search</label>
|
<label class="visually-hidden" for="grid-search">Search</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text"><i class="ri-search-line"></i><span class="ms-1 d-none d-xl-inline"> Search</span></span>
|
<span class="input-group-text"><i class="ri-search-line"></i><span class="ms-1 d-none d-xl-inline"> Search</span></span>
|
||||||
<input id="grid-search" data-search-exact="name,number,parts,theme,year" class="form-control form-control-sm" type="text" placeholder="Set name, set number, set theme or number of parts..." value="">
|
<input id="grid-search" data-search-exact="name,number,parts,theme,year" data-search-list="owner" class="form-control form-control-sm" type="text" placeholder="Set, name, number of parts, theme, year, owner" value="">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@ -75,6 +75,20 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-12 flex-grow-1">
|
||||||
|
<label class="visually-hidden" for="grid-owner">Owner</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text"><i class="ri-user-line"></i><span class="ms-1 d-none d-xl-inline"> Owner</span></span>
|
||||||
|
<select id="grid-owner" class="form-select"
|
||||||
|
data-filter="metadata"
|
||||||
|
autocomplete="off">
|
||||||
|
<option value="" selected>All</option>
|
||||||
|
{% for owner in brickset_owners %}
|
||||||
|
<option value="{{ owner.as_dataset() }}">{{ owner.fields.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" data-grid="true" id="grid">
|
<div class="row" data-grid="true" id="grid">
|
||||||
{% for item in collection %}
|
{% for item in collection %}
|
||||||
|
Loading…
Reference in New Issue
Block a user