mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add sort list service to Shopping List (#90671)
This commit is contained in:
parent
8c621699af
commit
d4d77d9395
@ -18,6 +18,8 @@ from homeassistant.helpers.typing import ConfigType
|
|||||||
from homeassistant.util.json import JsonArrayType, load_json_array
|
from homeassistant.util.json import JsonArrayType, load_json_array
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
ATTR_REVERSE,
|
||||||
|
DEFAULT_REVERSE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
EVENT_SHOPPING_LIST_UPDATED,
|
EVENT_SHOPPING_LIST_UPDATED,
|
||||||
SERVICE_ADD_ITEM,
|
SERVICE_ADD_ITEM,
|
||||||
@ -27,6 +29,7 @@ from .const import (
|
|||||||
SERVICE_INCOMPLETE_ALL,
|
SERVICE_INCOMPLETE_ALL,
|
||||||
SERVICE_INCOMPLETE_ITEM,
|
SERVICE_INCOMPLETE_ITEM,
|
||||||
SERVICE_REMOVE_ITEM,
|
SERVICE_REMOVE_ITEM,
|
||||||
|
SERVICE_SORT,
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTR_COMPLETE = "complete"
|
ATTR_COMPLETE = "complete"
|
||||||
@ -38,6 +41,9 @@ PERSISTENCE = ".shopping_list.json"
|
|||||||
|
|
||||||
SERVICE_ITEM_SCHEMA = vol.Schema({vol.Required(ATTR_NAME): cv.string})
|
SERVICE_ITEM_SCHEMA = vol.Schema({vol.Required(ATTR_NAME): cv.string})
|
||||||
SERVICE_LIST_SCHEMA = vol.Schema({})
|
SERVICE_LIST_SCHEMA = vol.Schema({})
|
||||||
|
SERVICE_SORT_SCHEMA = vol.Schema(
|
||||||
|
{vol.Optional(ATTR_REVERSE, default=DEFAULT_REVERSE): bool}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
@ -111,6 +117,10 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||||||
"""Clear all completed items from the list."""
|
"""Clear all completed items from the list."""
|
||||||
await data.async_clear_completed()
|
await data.async_clear_completed()
|
||||||
|
|
||||||
|
async def sort_list_service(call: ServiceCall) -> None:
|
||||||
|
"""Sort all items by name."""
|
||||||
|
await data.async_sort(call.data[ATTR_REVERSE])
|
||||||
|
|
||||||
data = hass.data[DOMAIN] = ShoppingData(hass)
|
data = hass.data[DOMAIN] = ShoppingData(hass)
|
||||||
await data.async_load()
|
await data.async_load()
|
||||||
|
|
||||||
@ -147,6 +157,12 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||||||
clear_completed_items_service,
|
clear_completed_items_service,
|
||||||
schema=SERVICE_LIST_SCHEMA,
|
schema=SERVICE_LIST_SCHEMA,
|
||||||
)
|
)
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SORT,
|
||||||
|
sort_list_service,
|
||||||
|
schema=SERVICE_SORT_SCHEMA,
|
||||||
|
)
|
||||||
|
|
||||||
hass.http.register_view(ShoppingListView)
|
hass.http.register_view(ShoppingListView)
|
||||||
hass.http.register_view(CreateShoppingListItemView)
|
hass.http.register_view(CreateShoppingListItemView)
|
||||||
@ -277,6 +293,16 @@ class ShoppingData:
|
|||||||
context=context,
|
context=context,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_sort(self, reverse=False, context=None):
|
||||||
|
"""Sort items by name."""
|
||||||
|
self.items = sorted(self.items, key=lambda item: item["name"], reverse=reverse)
|
||||||
|
self.hass.async_add_executor_job(self.save)
|
||||||
|
self.hass.bus.async_fire(
|
||||||
|
EVENT_SHOPPING_LIST_UPDATED,
|
||||||
|
{"action": "sorted"},
|
||||||
|
context=context,
|
||||||
|
)
|
||||||
|
|
||||||
async def async_load(self) -> None:
|
async def async_load(self) -> None:
|
||||||
"""Load items."""
|
"""Load items."""
|
||||||
|
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
DOMAIN = "shopping_list"
|
DOMAIN = "shopping_list"
|
||||||
EVENT_SHOPPING_LIST_UPDATED = "shopping_list_updated"
|
EVENT_SHOPPING_LIST_UPDATED = "shopping_list_updated"
|
||||||
|
|
||||||
|
ATTR_REVERSE = "reverse"
|
||||||
|
|
||||||
|
DEFAULT_REVERSE = False
|
||||||
|
|
||||||
SERVICE_ADD_ITEM = "add_item"
|
SERVICE_ADD_ITEM = "add_item"
|
||||||
SERVICE_REMOVE_ITEM = "remove_item"
|
SERVICE_REMOVE_ITEM = "remove_item"
|
||||||
SERVICE_COMPLETE_ITEM = "complete_item"
|
SERVICE_COMPLETE_ITEM = "complete_item"
|
||||||
@ -9,3 +13,4 @@ SERVICE_INCOMPLETE_ITEM = "incomplete_item"
|
|||||||
SERVICE_COMPLETE_ALL = "complete_all"
|
SERVICE_COMPLETE_ALL = "complete_all"
|
||||||
SERVICE_INCOMPLETE_ALL = "incomplete_all"
|
SERVICE_INCOMPLETE_ALL = "incomplete_all"
|
||||||
SERVICE_CLEAR_COMPLETED_ITEMS = "clear_completed_items"
|
SERVICE_CLEAR_COMPLETED_ITEMS = "clear_completed_items"
|
||||||
|
SERVICE_SORT = "sort"
|
||||||
|
@ -56,3 +56,14 @@ incomplete_all:
|
|||||||
clear_completed_items:
|
clear_completed_items:
|
||||||
name: Clear completed items
|
name: Clear completed items
|
||||||
description: Clear completed items from the shopping list.
|
description: Clear completed items from the shopping list.
|
||||||
|
|
||||||
|
sort:
|
||||||
|
name: Sort all items
|
||||||
|
description: Sort all items by name in the shopping list.
|
||||||
|
fields:
|
||||||
|
reverse:
|
||||||
|
name: Sort reverse
|
||||||
|
description: Whether to sort in reverse (descending) order.
|
||||||
|
default: false
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
|
@ -5,12 +5,14 @@ import pytest
|
|||||||
|
|
||||||
from homeassistant.components.shopping_list import NoMatchingShoppingListItem
|
from homeassistant.components.shopping_list import NoMatchingShoppingListItem
|
||||||
from homeassistant.components.shopping_list.const import (
|
from homeassistant.components.shopping_list.const import (
|
||||||
|
ATTR_REVERSE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
EVENT_SHOPPING_LIST_UPDATED,
|
EVENT_SHOPPING_LIST_UPDATED,
|
||||||
SERVICE_ADD_ITEM,
|
SERVICE_ADD_ITEM,
|
||||||
SERVICE_CLEAR_COMPLETED_ITEMS,
|
SERVICE_CLEAR_COMPLETED_ITEMS,
|
||||||
SERVICE_COMPLETE_ITEM,
|
SERVICE_COMPLETE_ITEM,
|
||||||
SERVICE_REMOVE_ITEM,
|
SERVICE_REMOVE_ITEM,
|
||||||
|
SERVICE_SORT,
|
||||||
)
|
)
|
||||||
from homeassistant.components.websocket_api.const import (
|
from homeassistant.components.websocket_api.const import (
|
||||||
ERR_INVALID_FORMAT,
|
ERR_INVALID_FORMAT,
|
||||||
@ -657,8 +659,6 @@ async def test_add_item_service(hass: HomeAssistant, sl_setup) -> None:
|
|||||||
{ATTR_NAME: "beer"},
|
{ATTR_NAME: "beer"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert len(hass.data[DOMAIN].items) == 1
|
assert len(hass.data[DOMAIN].items) == 1
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
|
|
||||||
@ -672,15 +672,12 @@ async def test_remove_item_service(hass: HomeAssistant, sl_setup) -> None:
|
|||||||
{ATTR_NAME: "beer"},
|
{ATTR_NAME: "beer"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_ADD_ITEM,
|
SERVICE_ADD_ITEM,
|
||||||
{ATTR_NAME: "cheese"},
|
{ATTR_NAME: "cheese"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert len(hass.data[DOMAIN].items) == 2
|
assert len(hass.data[DOMAIN].items) == 2
|
||||||
assert len(events) == 2
|
assert len(events) == 2
|
||||||
|
|
||||||
@ -690,8 +687,6 @@ async def test_remove_item_service(hass: HomeAssistant, sl_setup) -> None:
|
|||||||
{ATTR_NAME: "beer"},
|
{ATTR_NAME: "beer"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert len(hass.data[DOMAIN].items) == 1
|
assert len(hass.data[DOMAIN].items) == 1
|
||||||
assert hass.data[DOMAIN].items[0]["name"] == "cheese"
|
assert hass.data[DOMAIN].items[0]["name"] == "cheese"
|
||||||
assert len(events) == 3
|
assert len(events) == 3
|
||||||
@ -706,7 +701,6 @@ async def test_clear_completed_items_service(hass: HomeAssistant, sl_setup) -> N
|
|||||||
{ATTR_NAME: "beer"},
|
{ATTR_NAME: "beer"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert len(hass.data[DOMAIN].items) == 1
|
assert len(hass.data[DOMAIN].items) == 1
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
|
|
||||||
@ -717,7 +711,6 @@ async def test_clear_completed_items_service(hass: HomeAssistant, sl_setup) -> N
|
|||||||
{ATTR_NAME: "beer"},
|
{ATTR_NAME: "beer"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert len(hass.data[DOMAIN].items) == 1
|
assert len(hass.data[DOMAIN].items) == 1
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
|
|
||||||
@ -728,6 +721,44 @@ async def test_clear_completed_items_service(hass: HomeAssistant, sl_setup) -> N
|
|||||||
{},
|
{},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert len(hass.data[DOMAIN].items) == 0
|
assert len(hass.data[DOMAIN].items) == 0
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sort_list_service(hass: HomeAssistant, sl_setup) -> None:
|
||||||
|
"""Test sort_all service."""
|
||||||
|
|
||||||
|
for name in ("zzz", "ddd", "aaa"):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_ADD_ITEM,
|
||||||
|
{ATTR_NAME: name},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# sort ascending
|
||||||
|
events = async_capture_events(hass, EVENT_SHOPPING_LIST_UPDATED)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SORT,
|
||||||
|
{ATTR_REVERSE: False},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert hass.data[DOMAIN].items[0][ATTR_NAME] == "aaa"
|
||||||
|
assert hass.data[DOMAIN].items[1][ATTR_NAME] == "ddd"
|
||||||
|
assert hass.data[DOMAIN].items[2][ATTR_NAME] == "zzz"
|
||||||
|
assert len(events) == 1
|
||||||
|
|
||||||
|
# sort descending
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SORT,
|
||||||
|
{ATTR_REVERSE: True},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert hass.data[DOMAIN].items[0][ATTR_NAME] == "zzz"
|
||||||
|
assert hass.data[DOMAIN].items[1][ATTR_NAME] == "ddd"
|
||||||
|
assert hass.data[DOMAIN].items[2][ATTR_NAME] == "aaa"
|
||||||
|
assert len(events) == 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user