Skip to content

Commit

Permalink
Improved the room loading
Browse files Browse the repository at this point in the history
  • Loading branch information
scmmmh committed Nov 20, 2023
1 parent 6d3e5a8 commit 8af86c4
Show file tree
Hide file tree
Showing 17 changed files with 271 additions and 106 deletions.
2 changes: 1 addition & 1 deletion dev/.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
COMPOSE_PROJECT_NAME=museum-map
CONFIG_PATH=./
IMAGES_PATH=./tmp/images
IMAGES_PATH=../tmp/images
2 changes: 1 addition & 1 deletion museum_map/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from museum_map.models.floor import Floor, FloorModel, FloorTopic, FloorTopicModel # noqa
from museum_map.models.group import Group # noqa
from museum_map.models.item import Item, ItemModel # noqa
from museum_map.models.room import Room # noqa
from museum_map.models.room import Room, RoomModel # noqa
from museum_map.settings import settings

async_engine = create_async_engine(settings.db.dsn)
Expand Down
45 changes: 31 additions & 14 deletions museum_map/models/room.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Models for the rooms."""
from pydantic import BaseModel, ConfigDict, field_validator
from sqlalchemy import Column, ForeignKey, Index, Integer, Unicode
from sqlalchemy.orm import relationship
from sqlalchemy_json import NestedMutableJson
Expand All @@ -6,6 +8,8 @@


class Room(Base):
"""Database model representing one room."""

__tablename__ = "rooms"

id = Column(Integer, primary_key=True) # noqa: A003
Expand All @@ -21,21 +25,34 @@ class Room(Base):
sample = relationship("Item", primaryjoin="Room.item_id == Item.id")
items = relationship("Item", back_populates="room", order_by="Item.sequence", primaryjoin="Room.id == Item.room_id")

def as_jsonapi(self):
data = {
"type": "rooms",
"id": str(self.id),
"attributes": {"number": self.number, "label": self.label, "position": self.position},
"relationships": {
"floor": {"data": {"type": "floors", "id": str(self.floor_id)}},
"items": {"data": [{"type": "items", "id": str(item.id)} for item in self.items]},
},
}
if self.sample:
data["relationships"]["sample"] = {"data": {"type": "items", "id": str(self.sample.id)}}
return data


Index(Room.floor_id)
Index(Room.group_id)
Index(Room.item_id)


class RoomModel(BaseModel):
"""Pydantic model representing a room."""

id: int # noqa: A003
number: str
label: str
position: dict
group: int
floor: int
sample: int
items: list[int]

model_config = ConfigDict(from_attributes=True)

@field_validator("items", mode="before")
@classmethod
def convert_models_to_ids(cls, value: list[any]) -> str:
"""Convert the lists of child models to lists of ids."""
return [v.id for v in value]

@field_validator("group", "floor", "sample", mode="before")
@classmethod
def convert_model_to_ids(cls, value: list[any]) -> str:
"""Convert the child models to ids."""
return value.id
3 changes: 2 additions & 1 deletion museum_map/server/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@

from museum_map.__about__ import __tables__, __version__
from museum_map.models import db_session
from museum_map.server.api import floor_topics, floors, picks
from museum_map.server.api import floor_topics, floors, picks, rooms

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api")
router.include_router(floors.router)
router.include_router(floor_topics.router)
router.include_router(picks.router)
router.include_router(rooms.router)


@router.get("/")
Expand Down
30 changes: 30 additions & 0 deletions museum_map/server/api/rooms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Routes for accessing the room data."""
import logging
from typing import Annotated

from fastapi import APIRouter, Depends, Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from museum_map.models import Room, RoomModel, db_session

router = APIRouter(prefix="/rooms")
logger = logging.getLogger(__name__)


@router.get("/", response_model=list[RoomModel])
async def get_floors(
dbsession: Annotated[AsyncSession, Depends(db_session)], rid: Annotated[list[int] | None, Query()] = None
):
"""Retrieve all floors."""
query = (
select(Room)
.options(selectinload(Room.group))
.options(selectinload(Room.floor))
.options(selectinload(Room.items))
.options(selectinload(Room.sample))
)
if rid is not None:
query = query.filter(Room.id.in_(rid))
return (await dbsession.execute(query)).scalars()
19 changes: 19 additions & 0 deletions museum_map/server/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions museum_map/server/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@sveltejs/vite-plugin-svelte": "^2.4.2",
"@tsconfig/svelte": "^5.0.0",
"autoprefixer": "^10.4.15",
"deepcopy": "^2.1.0",
"history": "^5.3.0",
"phaser": "^3.55.2",
"svelte": "^4.0.5",
Expand Down
3 changes: 2 additions & 1 deletion museum_map/server/frontend/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
class="container mx-auto bg-neutral-700 text-white shadow-lg shadow-black font-serif tracking-default"
>
<Route path="/"><Lobby /></Route>
<Route path="/floor/:id"
<Route path="/floor/:fid"
>{#if Floor !== null}<svelte:component this={Floor} />{/if}</Route
>
<Route path="/floor/:fid/room/:rid"><Room /></Route>
</main>
{:else}
<div
Expand Down
34 changes: 24 additions & 10 deletions museum_map/server/frontend/src/components/Thumbnail.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { tracker } from "../store";
import { derived } from "svelte/store";
import { tracker, rooms, fetchRooms, floors } from "../store";
export let item: Item;
export let noLink = false;
Expand All @@ -22,17 +23,28 @@
}
}
function linkTo(item: Item) {
if (item && item.room) {
return "#/room/" + item.room + "/" + item.id;
} else {
return "/";
}
}
function loaded() {
dispatch("load");
}
const itemRoom = derived(rooms, (rooms) => {
const room = rooms[item.room];
if (room === undefined) {
fetchRooms([item.room]);
}
return room;
});
const itemFloor = derived([itemRoom, floors], ([itemRoom, floors]) => {
if (itemRoom && floors) {
for (let floor of floors) {
if (floor.id === itemRoom.floor) {
return floor;
}
}
}
return null;
});
</script>

{#if item !== null}
Expand All @@ -58,7 +70,9 @@
</div>
{:else}
<a
href={linkTo(item)}
href="/floor/{$itemFloor ? $itemFloor.id : -1}/room/{$itemRoom
? $itemRoom.id
: -1}/item/{item.id}"
class="block h-full w-full overflow-hidden underline-offset-2 hover:img-brightness hover:underline focus:underline"
aria-label={item.attributes.title}
on:mouseenter={() => {
Expand Down
2 changes: 1 addition & 1 deletion museum_map/server/frontend/src/routes/Floor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Thumbnail from "../components/Thumbnail.svelte";
import {
floors,
loadRooms,
fetchRooms,
busyCounter,
localPreferences,
loadTopics,
Expand Down
4 changes: 2 additions & 2 deletions museum_map/server/frontend/src/routes/Item.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import Thumbnail from "../components/Thumbnail.svelte";
import {
cachedItems,
cachedRooms,
rooms,
loadItems,
loadRooms,
fetchRooms,
config,
tracker,
} from "../store";
Expand Down
4 changes: 2 additions & 2 deletions museum_map/server/frontend/src/routes/Room.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import Item from "./Item.svelte";
import {
floors,
cachedRooms,
loadRooms,
rooms,
fetchRooms,
cachedItems,
loadItems,
matchingItems,
Expand Down
55 changes: 8 additions & 47 deletions museum_map/server/frontend/src/simple-svelte-router/Route.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
<script lang="ts">
import { onDestroy, tick } from "svelte";
import { location } from "./store";
import type { RouterLocation } from "./store";
export let path: string;
export let handleFocus: boolean = true;
let pathComponents: string[] = [];
let routeName: string = location.registerRoute(path);
let matches = false;
let startMarker: HTMLElement | null = null;
let endMarker: HTMLElement | null = null;
Expand All @@ -33,60 +32,22 @@
}
}
/**
* Check if the current location matches the path for this Route
*
* @param location The current location
*/
function checkMatch(location: RouterLocation) {
matches = true;
for (let idx = 0; idx < pathComponents.length; idx++) {
if (idx < location.pathComponents.length) {
if (pathComponents[idx] === "*") {
continue;
} else if (pathComponents[idx].startsWith(":")) {
continue;
} else if (pathComponents[idx] === location.pathComponents[idx]) {
continue;
} else {
matches = false;
break;
}
} else {
matches = false;
break;
}
}
}
/**
* Process a location change.
*
* First check for matches and if there is one, then call the focus handling.
*
* @param location The current location
*/
function process(location: RouterLocation) {
checkMatch(location);
if (
handleFocus &&
matches &&
location.pathComponents.length == pathComponents.length
) {
const locationUnsubscribe = location.subscribe((location) => {
matches = location.currentRoute === routeName;
if (handleFocus && matches) {
tick().then(focusElement);
}
}
$: {
pathComponents = path.substring(1).split("/");
process($location);
}
const locationUnsubscribe = location.subscribe((location) => {
process(location);
});
onDestroy(locationUnsubscribe);
onDestroy(() => {
locationUnsubscribe();
location.unRegisterRoute(routeName);
});
</script>

{#if matches}
Expand Down
Loading

0 comments on commit 8af86c4

Please sign in to comment.