Feature: Shopping List Label Section Improvements (#2090)

* added backend for shopping list label config

* updated codegen

* refactored shopping list ops to service
removed unique contraint
removed label settings from main route/schema
added new route for label settings

* codegen

* made sure label settings output in position order

* implemented submenu for label order drag and drop

* removed redundant label and tweaked formatting

* added view by label to user preferences

* made items draggable within each label section

* moved reorder labels to its own button

* made dialog scrollable

* fixed broken model

* refactored labels to use a service
moved shopping list label logic to service
modified label seeder to use service

* added tests

* fix for first label missing the tag icon

* fixed wrong mapped type

* added statement to create existing relationships

* fix restore test, maybe
This commit is contained in:
Michael Genson
2023-02-21 21:58:41 -06:00
committed by GitHub
parent e14851531d
commit a6c46a7420
22 changed files with 715 additions and 61 deletions

View File

@@ -10,25 +10,28 @@ from mealie.routes._base.routers import MealieCrudRoute
from mealie.schema.labels import (
MultiPurposeLabelCreate,
MultiPurposeLabelOut,
MultiPurposeLabelSave,
MultiPurposeLabelSummary,
MultiPurposeLabelUpdate,
)
from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelPagination
from mealie.schema.mapper import cast
from mealie.schema.response.pagination import PaginationQuery
from mealie.services.group_services.labels_service import MultiPurposeLabelService
router = APIRouter(prefix="/groups/labels", tags=["Group: Multi Purpose Labels"], route_class=MealieCrudRoute)
@controller(router)
class MultiPurposeLabelsController(BaseUserController):
@cached_property
def service(self):
return MultiPurposeLabelService(self.repos, self.group.id)
@cached_property
def repo(self):
if not self.user:
raise Exception("No user is logged in.")
return self.repos.group_multi_purpose_labels.by_group(self.user.group_id)
return self.repos.group_multi_purpose_labels
# =======================================================================
# CRUD Operations
@@ -49,8 +52,7 @@ class MultiPurposeLabelsController(BaseUserController):
@router.post("", response_model=MultiPurposeLabelOut)
def create_one(self, data: MultiPurposeLabelCreate):
save_data = cast(data, MultiPurposeLabelSave, group_id=self.user.group_id)
return self.mixins.create_one(save_data)
return self.service.create_one(data)
@router.get("/{item_id}", response_model=MultiPurposeLabelOut)
def get_one(self, item_id: UUID4):

View File

@@ -1,7 +1,7 @@
from collections.abc import Callable
from functools import cached_property
from fastapi import APIRouter, Depends, Query
from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import UUID4
from mealie.routes._base.base_controllers import BaseCrudController
@@ -16,6 +16,7 @@ from mealie.schema.group.group_shopping_list import (
ShoppingListItemsCollectionOut,
ShoppingListItemUpdate,
ShoppingListItemUpdateBulk,
ShoppingListMultiPurposeLabelUpdate,
ShoppingListOut,
ShoppingListPagination,
ShoppingListRemoveRecipeParams,
@@ -23,7 +24,6 @@ from mealie.schema.group.group_shopping_list import (
ShoppingListSummary,
ShoppingListUpdate,
)
from mealie.schema.mapper import cast
from mealie.schema.response.pagination import PaginationQuery
from mealie.schema.response.responses import SuccessResponse
from mealie.services.event_bus_service.event_types import (
@@ -89,7 +89,7 @@ def publish_list_item_events(publisher: Callable, items_collection: ShoppingList
class ShoppingListItemController(BaseCrudController):
@cached_property
def service(self):
return ShoppingListService(self.repos)
return ShoppingListService(self.repos, self.user, self.group)
@cached_property
def repo(self):
@@ -154,7 +154,7 @@ router = APIRouter(prefix="/groups/shopping/lists", tags=["Group: Shopping Lists
class ShoppingListController(BaseCrudController):
@cached_property
def service(self):
return ShoppingListService(self.repos)
return ShoppingListService(self.repos, self.user, self.group)
@cached_property
def repo(self):
@@ -179,9 +179,7 @@ class ShoppingListController(BaseCrudController):
@router.post("", response_model=ShoppingListOut, status_code=201)
def create_one(self, data: ShoppingListCreate):
save_data = cast(data, ShoppingListSave, group_id=self.user.group_id)
shopping_list = self.mixins.create_one(save_data)
shopping_list = self.service.create_one_list(data)
if shopping_list:
self.publish_event(
event_type=EventTypes.shopping_list_created,
@@ -197,14 +195,12 @@ class ShoppingListController(BaseCrudController):
@router.put("/{item_id}", response_model=ShoppingListOut)
def update_one(self, item_id: UUID4, data: ShoppingListUpdate):
shopping_list = self.mixins.update_one(data, item_id) # type: ignore
if shopping_list:
self.publish_event(
event_type=EventTypes.shopping_list_updated,
document_data=EventShoppingListData(operation=EventOperation.update, shopping_list_id=shopping_list.id),
message=self.t("notifications.generic-updated", name=shopping_list.name),
)
shopping_list = self.mixins.update_one(data, item_id)
self.publish_event(
event_type=EventTypes.shopping_list_updated,
document_data=EventShoppingListData(operation=EventOperation.update, shopping_list_id=shopping_list.id),
message=self.t("notifications.generic-updated", name=shopping_list.name),
)
return shopping_list
@@ -244,3 +240,23 @@ class ShoppingListController(BaseCrudController):
publish_list_item_events(self.publish_event, items)
return shopping_list
@router.put("/{item_id}/label-settings", response_model=ShoppingListOut)
def update_label_settings(self, item_id: UUID4, data: list[ShoppingListMultiPurposeLabelUpdate]):
for setting in data:
if setting.shopping_list_id != item_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"object {setting.id} has an invalid shopping list id",
)
self.repos.shopping_list_multi_purpose_labels.update_many(data)
updated_list = self.get_one(item_id)
self.publish_event(
event_type=EventTypes.shopping_list_updated,
document_data=EventShoppingListData(operation=EventOperation.update, shopping_list_id=updated_list.id),
message=self.t("notifications.generic-updated", name=updated_list.name),
)
return updated_list