diff --git a/client/src/pages/locations/index.tsx b/client/src/pages/locations/index.tsx index e2cd862..12149ef 100644 --- a/client/src/pages/locations/index.tsx +++ b/client/src/pages/locations/index.tsx @@ -2,13 +2,14 @@ import { IResourceComponentsProps, useInvalidate, useList, useNavigation, useTra import { Button, theme } from "antd"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; -import React from "react"; +import React, { useEffect, useMemo } from "react"; import { DndProvider, useDrag, useDrop } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; import { EditOutlined, EyeOutlined } from "@ant-design/icons"; import { Link } from "react-router-dom"; import SpoolIcon from "../../components/spoolIcon"; +import { useGetSetting, useSetSetting } from "../../utils/querySettings"; import { ISpool } from "../spools/model"; import { setSpoolLocation } from "./functions"; import "./locations.css"; @@ -115,9 +116,27 @@ function LocationContainer({ title, spools }: { title: string; spools: ISpool[] ); } +function useLocations(): string[] { + const query = useGetSetting("locations"); + + return useMemo(() => { + if (!query.data) return []; + + try { + return JSON.parse(query.data.value) as string[]; + } catch { + console.warn("Failed to parse locations", query.data.value); + return []; + } + }, [query.data]); +} + export const Locations: React.FC = () => { const t = useTranslate(); + const settingsLocations = useLocations(); + const setLocationsSetting = useSetSetting("locations"); + const { data, isLoading, isError } = useList({ resource: "spool", meta: { @@ -130,6 +149,54 @@ export const Locations: React.FC = () => { }, }); + // Grab spools and sort by ID + const spools = data?.data ?? []; + spools.sort((a, b) => a.id - b.id); + + // Group spools by location + const spoolLocations = useMemo(() => { + const grouped: Record = {}; + spools.forEach((spool) => { + const loc = spool.location ?? t("spool.no_location"); + if (!grouped[loc]) { + grouped[loc] = []; + } + grouped[loc].push(spool); + }); + return grouped; + }, [spools]); + + // Create list of locations that's sorted + const locationsList = useMemo(() => { + // Start with the locations from the spools + let allLocs = [...Object.keys(spoolLocations), ...settingsLocations]; + + // Remove duplicates + allLocs = [...new Set(allLocs)]; + + allLocs.sort((a, b) => { + // Sort alphabetically + return a.localeCompare(b); + }); + + return allLocs; + }, [spoolLocations, settingsLocations]); + + // Create containers + const containers = locationsList.map((loc) => { + return ; + }); + + // Update locations settings so it always includes all spool locations + useEffect(() => { + // Check if they're not the same + if (JSON.stringify(locationsList.sort()) !== JSON.stringify(settingsLocations.sort())) { + console.log("Updating locations settings", locationsList, settingsLocations); + // Update settings + setLocationsSetting.mutate(locationsList); + } + }, [spoolLocations]); + if (isLoading) { return
Loading...
; } @@ -138,28 +205,6 @@ export const Locations: React.FC = () => { return
Failed to load spools
; } - const spools = data?.data ?? []; - spools.sort((a, b) => a.id - b.id); - - // Locations is all the unique locations of the spools - const spoolLocations: Record = {}; - spools.forEach((spool) => { - const loc = spool.location ?? t("spool.no_location"); - if (!spoolLocations[loc]) { - spoolLocations[loc] = []; - } - spoolLocations[loc].push(spool); - }); - - const locationsList = Object.keys(spoolLocations); - locationsList.sort((a, b) => { - return a.localeCompare(b); - }); - - const containers = locationsList.map((loc) => { - return ; - }); - return (
{containers}
diff --git a/client/src/pages/locations/locations.css b/client/src/pages/locations/locations.css index 9723a39..76b1cf2 100644 --- a/client/src/pages/locations/locations.css +++ b/client/src/pages/locations/locations.css @@ -13,6 +13,7 @@ display: flex; flex-direction: column; gap: 0.5em; + min-height: 3em; max-height: 100em; overflow-y: scroll; } diff --git a/spoolman/settings.py b/spoolman/settings.py index ccd3ad5..bb7217c 100644 --- a/spoolman/settings.py +++ b/spoolman/settings.py @@ -68,3 +68,5 @@ register_setting("extra_fields_vendor", SettingType.ARRAY, json.dumps([])) register_setting("extra_fields_filament", SettingType.ARRAY, json.dumps([])) register_setting("extra_fields_spool", SettingType.ARRAY, json.dumps([])) register_setting("base_url", SettingType.STRING, json.dumps("")) + +register_setting("locations", SettingType.ARRAY, json.dumps([]))