From beabdf4aa0a7e496524db07b029bd9089488e7fc Mon Sep 17 00:00:00 2001 From: mseng10 Date: Sun, 9 Jun 2024 13:22:30 -0500 Subject: [PATCH 1/8] STYLE: System card tuning --- client/react/src/pages/Home.js | 2 - client/react/src/pages/System.js | 74 +++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/client/react/src/pages/Home.js b/client/react/src/pages/Home.js index 9c5375e..08a0e00 100644 --- a/client/react/src/pages/Home.js +++ b/client/react/src/pages/Home.js @@ -101,8 +101,6 @@ const Home = () => { )} - - setIsNewPlantFormOpen(false)} diff --git a/client/react/src/pages/System.js b/client/react/src/pages/System.js index f8e5a72..39eeded 100644 --- a/client/react/src/pages/System.js +++ b/client/react/src/pages/System.js @@ -7,6 +7,12 @@ import TungstenSharpIcon from '@mui/icons-material/TungstenSharp'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import { CardActionArea, CardHeader } from '@mui/material'; +import Avatar from '@mui/material/Avatar'; +import GrassOutlinedIcon from '@mui/icons-material/GrassOutlined'; +import { green } from '@mui/material/colors'; +import IconButton from '@mui/material/IconButton'; +import ReportGmailerrorredSharpIcon from '@mui/icons-material/ReportGmailerrorredSharp'; +import CardActions from '@mui/material/CardActions'; const System = ({ system, full }) => { if (!system) { @@ -51,37 +57,53 @@ const System = ({ system, full }) => { + + + } title={system.name} + subheader={system.created_on} /> - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + ); From cab774125221ccec55762d308bdb7445060339d3 Mon Sep 17 00:00:00 2001 From: mseng10 Date: Sun, 9 Jun 2024 18:09:23 -0500 Subject: [PATCH 2/8] ENH: Beginning of the create system layout change --- client/react/src/App.css | 2 - client/react/src/App.js | 5 +- client/react/src/forms/NewSystemForm.js | 134 +++++++++++++----------- 3 files changed, 75 insertions(+), 66 deletions(-) diff --git a/client/react/src/App.css b/client/react/src/App.css index 594ba7a..9ea8f1d 100644 --- a/client/react/src/App.css +++ b/client/react/src/App.css @@ -125,7 +125,6 @@ h1, h2 { .left { width: 128px; - display:inline; float:left; } @@ -135,7 +134,6 @@ h1, h2 { .right { width: 256px; - display:inline; float:right; } diff --git a/client/react/src/App.js b/client/react/src/App.js index 79259bd..49cb8ab 100644 --- a/client/react/src/App.js +++ b/client/react/src/App.js @@ -8,7 +8,7 @@ import React from 'react'; import { Routes, Route } from 'react-router-dom'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; -import { green, pink, lightBlue, blueGrey, teal, brown } from '@mui/material/colors'; +import { green, pink, lightBlue, blueGrey, teal, brown, yellow } from '@mui/material/colors'; import Plants from './pages/Plants'; import System from './pages/System'; import Home from './pages/Home'; @@ -34,6 +34,9 @@ const darkTheme = createTheme({ }, repot: { main: brown[500], + }, + light: { + main: yellow[500] } }, }); diff --git a/client/react/src/forms/NewSystemForm.js b/client/react/src/forms/NewSystemForm.js index c363aa6..3ad9006 100644 --- a/client/react/src/forms/NewSystemForm.js +++ b/client/react/src/forms/NewSystemForm.js @@ -83,70 +83,78 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { border: 'none', }} > - +
-
- - - - - - - - - -
-
- setName(event.target.value)} - /> - setHumidity(event.target.value)} - variant="standard" - /> - setTempurature(event.target.value)} - variant="standard" - /> - setDuration(event.target.value)} - variant="standard" - /> - setDistance(event.target.value)} - variant="standard" - /> -
+ +
+ + + + + + + + + +
+
+ setName(event.target.value)} + /> + setHumidity(event.target.value)} + variant="standard" + /> + setTempurature(event.target.value)} + variant="standard" + /> +
+
+ +
+ setDuration(event.target.value)} + variant="standard" + color="light" + /> + setDistance(event.target.value)} + variant="standard" + color="light" + /> +
+
From 9f0bf4556279c243fe30dca6a8cfe0f6b8128096 Mon Sep 17 00:00:00 2001 From: mseng10 Date: Sun, 9 Jun 2024 20:23:24 -0500 Subject: [PATCH 3/8] STYLE: duration and distance fields --- client/react/src/App.css | 6 +- client/react/src/forms/NewSystemForm.js | 87 ++++++++++++++++++------- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/client/react/src/App.css b/client/react/src/App.css index 9ea8f1d..ea3cd13 100644 --- a/client/react/src/App.css +++ b/client/react/src/App.css @@ -124,16 +124,16 @@ h1, h2 { } .left { - width: 128px; + width: 50%; float:left; } .left_button { - font-size: 112px !important; + font-size: 124px !important; } .right { - width: 256px; + width: 50%; float:right; } diff --git a/client/react/src/forms/NewSystemForm.js b/client/react/src/forms/NewSystemForm.js index 3ad9006..9f85a16 100644 --- a/client/react/src/forms/NewSystemForm.js +++ b/client/react/src/forms/NewSystemForm.js @@ -7,7 +7,10 @@ import ButtonGroup from '@mui/material/ButtonGroup'; import CheckSharpIcon from '@mui/icons-material/CheckSharp'; import CloseSharpIcon from '@mui/icons-material/CloseSharp'; import PointOfSaleIcon from '@mui/icons-material/PointOfSale'; - +import Slider from '@mui/material/Slider'; +import Stack from '@mui/material/Stack'; +import AvTimerSharpIcon from '@mui/icons-material/AvTimerSharp'; +import StraightenSharpIcon from '@mui/icons-material/StraightenSharp'; const NewSystemForm = ({ isOpen, onRequestClose }) => { const [name, setName] = useState(''); @@ -69,6 +72,36 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { setSubmitted(false); }; + const durationMarks = [ + { + value: 6, + label: '6', + }, + { + value: 12, + label: '12', + }, + { + value: 18, + label: '18', + } + ] + + const measureMarks = [ + { + value: 12, + label: '12"', + }, + { + value: 24, + label: '24"', + }, + { + value: 36, + label: '36"', + } + ]; + return ( { border: 'none', }} > - +
- +
- + @@ -129,31 +162,39 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { />
- -
- + + + setDuration(event.target.value)} variant="standard" - color="light" + defaultValue={12} + step={1} + marks={durationMarks} + min={6} + max={18} + valueLabelDisplay="auto" /> - + + + setDistance(event.target.value)} variant="standard" - color="light" + defaultValue={24} + step={2} + marks={measureMarks} + min={12} + max={36} + valueLabelDisplay="auto" /> -
+
From c98898a058aba46604658c50dbe7ee29e5f6e2fc Mon Sep 17 00:00:00 2001 From: mseng10 Date: Sun, 9 Jun 2024 21:06:02 -0500 Subject: [PATCH 4/8] ENH: Description field --- client/react/src/forms/NewSystemForm.js | 114 ++++++++++++++++++------ server/app.py | 3 +- server/models/system.py | 4 +- 3 files changed, 93 insertions(+), 28 deletions(-) diff --git a/client/react/src/forms/NewSystemForm.js b/client/react/src/forms/NewSystemForm.js index 9f85a16..8ff6b22 100644 --- a/client/react/src/forms/NewSystemForm.js +++ b/client/react/src/forms/NewSystemForm.js @@ -11,13 +11,17 @@ import Slider from '@mui/material/Slider'; import Stack from '@mui/material/Stack'; import AvTimerSharpIcon from '@mui/icons-material/AvTimerSharp'; import StraightenSharpIcon from '@mui/icons-material/StraightenSharp'; +import InvertColorsSharpIcon from '@mui/icons-material/InvertColorsSharp'; +import DeviceThermostatSharpIcon from '@mui/icons-material/DeviceThermostatSharp'; + const NewSystemForm = ({ isOpen, onRequestClose }) => { const [name, setName] = useState(''); - const [humidity, setHumidity] = useState(0); - const [temperature, setTempurature] = useState(0); - const [duration, setDuration] = useState(0); - const [distance, setDistance] = useState(0); + const [description, setDescription] = useState('') + const [humidity, setHumidity] = useState(60); + const [temperature, setTempurature] = useState(68); + const [duration, setDuration] = useState(12); + const [distance, setDistance] = useState(24); const [allSystems, setAllSystems] = useState([]); @@ -51,7 +55,7 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { clearForm(); onRequestClose(); } - }, [submitted, name, temperature, humidity, distance, duration, onRequestClose]); + }, [submitted, name, description, temperature, humidity, distance, duration, onRequestClose]); const handleSubmit = (event) => { event.preventDefault(); @@ -65,6 +69,7 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { const clearForm = () => { setName(''); + setDescription(''); setTempurature(0); setHumidity(0); setDistance(0); @@ -72,6 +77,39 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { setSubmitted(false); }; + // Target temperature marks + const temperatureMarks = [ + { + value: 48, + label: '48', + }, + { + value: 68, + label: '68°F', + }, + { + value: 80, + label: '80°F', + } + ]; + + // Humidity field marks + const humidityMarks = [ + { + value: 0, + label: '0%', + }, + { + value: 60, + label: '60%', + }, + { + value: 100, + label: '100%', + } + ]; + + // Duration field marks const durationMarks = [ { value: 6, @@ -85,9 +123,10 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { value: 18, label: '18', } - ] + ]; - const measureMarks = [ + // Lighting field marks + const distanceMarks = [ { value: 12, label: '12"', @@ -139,31 +178,54 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { value={name} variant="standard" onChange={(event) => setName(event.target.value)} + color='info' /> setDescription(event.target.value)} + variant="standard" fullWidth - required - type="number" - label="Humidity" - value={humidity} + margin="normal" + color='info' + /> + +
+ + + + setHumidity(event.target.value)} variant="standard" + defaultValue={12} + step={1} + marks={humidityMarks} + min={0} + max={100} + valueLabelDisplay="auto" /> - + + + setTempurature(event.target.value)} variant="standard" + step={2} + marks={temperatureMarks} + min={48} + max={80} + valueLabelDisplay="auto" /> - - - - + + { valueLabelDisplay="auto" /> - - + + { variant="standard" defaultValue={24} step={2} - marks={measureMarks} + marks={distanceMarks} min={12} max={36} valueLabelDisplay="auto" diff --git a/server/app.py b/server/app.py index 2f015be..3347f5b 100644 --- a/server/app.py +++ b/server/app.py @@ -175,7 +175,8 @@ def create_system(): temperature=new_system_json["temperature"], humidity=new_system_json["humidity"], duration=new_system_json["duration"], - distance=new_system_json["distance"] + distance=new_system_json["distance"], + description=new_system_json["description"] ) # Add the new system object to the session diff --git a/server/models/system.py b/server/models/system.py index b5ef602..81a4941 100644 --- a/server/models/system.py +++ b/server/models/system.py @@ -60,7 +60,8 @@ class Light(Base): __tablename__ = "light" id = Column(Integer(), primary_key=True) - name = Column(String(100), nullable=False) + name = Column(String(100), nullable=True) + description = Column(String(400), nullable=False) created_on = Column(DateTime(), default=datetime.now) updated_on = Column(DateTime(), default=datetime.now) cost = Column(Integer()) @@ -80,6 +81,7 @@ def to_json(self): return { "id": self.id, "name": self.name, + "description": self.description "cost": self.cost, "created_on": self.created_on, "updated_on": self.updated_on, From 9a13385f77786f25728c06a31530676b9e4b16d3 Mon Sep 17 00:00:00 2001 From: mseng10 Date: Mon, 10 Jun 2024 18:41:40 -0500 Subject: [PATCH 5/8] STYLE: Home page buttons refactor --- client/react/src/App.css | 4 ++ client/react/src/pages/Home.js | 97 ++++++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/client/react/src/App.css b/client/react/src/App.css index ea3cd13..ea70082 100644 --- a/client/react/src/App.css +++ b/client/react/src/App.css @@ -141,6 +141,10 @@ h1, h2 { outline: 0!important; } +.center { + margin-left: auto; + margin-right: auto;} + #back { position: fixed; left: 0; diff --git a/client/react/src/pages/Home.js b/client/react/src/pages/Home.js index 08a0e00..720615c 100644 --- a/client/react/src/pages/Home.js +++ b/client/react/src/pages/Home.js @@ -17,6 +17,7 @@ import VisibilitySharpIcon from '@mui/icons-material/VisibilitySharp'; import ReportGmailerrorredSharpIcon from '@mui/icons-material/ReportGmailerrorredSharp'; import NewLightForm from '../forms/NewLightForm'; import TungstenSharpIcon from '@mui/icons-material/TungstenSharp'; +import Modal from '@mui/material/Modal'; const Home = () => { @@ -64,42 +65,80 @@ const Home = () => { setIsViewButtonsOpen(true)}> - setIsCreateButtonsOpen(true)}> + console.log("WIP")}> {isCreateButtonsOpen && ( - - setIsNewPlantFormOpen(true)}> - - - setIsNewSystemFormOpen(true)}> - - - setIsNewGenusFormOpen(true)}> - - - setIsNewLightFormOpen(true)}> - - - setIsCreateButtonsOpen(false)}> - - - + + + + setIsNewPlantFormOpen(true)}> + + + setIsCreateButtonsOpen(false)}> + + + + + setIsNewSystemFormOpen(true)}> + + + setIsNewGenusFormOpen(true)}> + + + setIsNewLightFormOpen(true)}> + + + + + )} {isViewButtonsOpen && ( - - { navigate("/plants")}}> - - - { navigate("/systems")}}> - - - setIsViewButtonsOpen(false)}> - - - + + + + { navigate("/plants")}}> + + + { navigate("/systems")}}> + + + setIsViewButtonsOpen(false)}> + + + + + )} Date: Mon, 10 Jun 2024 18:55:54 -0500 Subject: [PATCH 6/8] ENH: Beginning of data collection --- server/data/genuses/cactus_genuses.csv | 2 + server/data/genuses/succulent_genuses.csv | 93 +++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 server/data/genuses/cactus_genuses.csv create mode 100644 server/data/genuses/succulent_genuses.csv diff --git a/server/data/genuses/cactus_genuses.csv b/server/data/genuses/cactus_genuses.csv new file mode 100644 index 0000000..3274d21 --- /dev/null +++ b/server/data/genuses/cactus_genuses.csv @@ -0,0 +1,2 @@ +Acanthocereus tetragonus (FairY Castle Castle) +Cephalocereus senilis (Old Man Cactus) \ No newline at end of file diff --git a/server/data/genuses/succulent_genuses.csv b/server/data/genuses/succulent_genuses.csv new file mode 100644 index 0000000..bedb458 --- /dev/null +++ b/server/data/genuses/succulent_genuses.csv @@ -0,0 +1,93 @@ +Agave +Yucca +Argyroderma +Cheiridopsis +Conophytum +Dactylopis +Faucaria +Fenestraria +Frithia +Glottiphyllum +Lapidaria +Lithops +Nananthus +Pleisopilos +Titanopsis +Delosperma +Mestoklema +Trichodiadema +Sphalmanthus +Aloe +Astroloba +Gasteria +Haworthia +Adenium (Desert Rose) +Pachypodium (Madagascar Palm) +Plumeria (Frangipani) +Caralluma +Duvalia +Edithcolea +Hoodia +Huernia +Orbea +Piranthus +Stapelia +Tavaresia +Brachystema +Ceropegia +Hoya (String-of-Hearts, Rosary-Vine, Wax Vine, Hindu Rope) +Dyckia +Hechtia +Orthophytum +Tillandsia +Opuntia (Pricklypear) +Cylindropuntia (cholla) +Tephrocactus +Ariocarpus +Astrophytum +Borzicactus +Copiapoa +Coryphantha +Echinocactus +Echinocereus +Echinopsis +Ferocactus +Frailea +Gymnocalycium +Lobivia +Mammillaria +Neoporteria +Notocactus +Parodia +Rebutia +Sulcorebutia +Discocactus +Melocactus +Carnegia +Cephalocereus +Cereus +Nyctocereus +Pachycereus +Cleistocactus +Espostoa +Oreocereus +Disocactus +Epiphyllum +xEpicactus +Rhipsalis +Schlumbergera +Selenicereus (Christmas Cactus) +Adromischus +Cotyledon +Crassula +Kalanchoe +Tylecodon +Dudleya +Echeveria +Graptopetalum +Pachyphytum +Tacitus +Aeonium +Sempervivum +Sedum +Euphorbia \ No newline at end of file From 21a20107e03c626333635074366a4e056623e286 Mon Sep 17 00:00:00 2001 From: mseng10 Date: Mon, 10 Jun 2024 19:49:43 -0500 Subject: [PATCH 7/8] EMH: Bring back type model --- client/react/src/App.js | 8 +- client/react/src/forms/NewGenusForm.js | 4 +- client/react/src/forms/NewSystemForm.js | 3 +- client/react/src/forms/NewTypeForm.js | 146 ++++++++++++++++++++++++ client/react/src/pages/Home.js | 37 ++++-- server/app.py | 45 +++++++- server/models/plant.py | 57 ++++++++- server/models/system.py | 4 +- 8 files changed, 284 insertions(+), 20 deletions(-) create mode 100644 client/react/src/forms/NewTypeForm.js diff --git a/client/react/src/App.js b/client/react/src/App.js index 49cb8ab..e7c4899 100644 --- a/client/react/src/App.js +++ b/client/react/src/App.js @@ -8,7 +8,7 @@ import React from 'react'; import { Routes, Route } from 'react-router-dom'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; -import { green, pink, lightBlue, blueGrey, teal, brown, yellow } from '@mui/material/colors'; +import { green, pink, lightBlue, blueGrey, teal, brown, yellow, lightGreen} from '@mui/material/colors'; import Plants from './pages/Plants'; import System from './pages/System'; import Home from './pages/Home'; @@ -37,6 +37,12 @@ const darkTheme = createTheme({ }, light: { main: yellow[500] + }, + type: { + main: lightGreen[500] + }, + genus: { + main: teal[500] } }, }); diff --git a/client/react/src/forms/NewGenusForm.js b/client/react/src/forms/NewGenusForm.js index 42d184d..f335dc8 100644 --- a/client/react/src/forms/NewGenusForm.js +++ b/client/react/src/forms/NewGenusForm.js @@ -80,7 +80,7 @@ const NewGenusForm = ({ isOpen, onRequestClose }) => {
- + @@ -98,6 +98,7 @@ const NewGenusForm = ({ isOpen, onRequestClose }) => { label="Genus Name" value={name} variant="standard" + color="genus" onChange={(event) => setName(event.target.value)} /> { label="Watering (days)" value={watering} onChange={(event) => setWatering(event.target.value)} + color="genus" variant="standard" />
diff --git a/client/react/src/forms/NewSystemForm.js b/client/react/src/forms/NewSystemForm.js index 8ff6b22..5d7ad4f 100644 --- a/client/react/src/forms/NewSystemForm.js +++ b/client/react/src/forms/NewSystemForm.js @@ -197,7 +197,8 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { setHumidity(event.target.value)} diff --git a/client/react/src/forms/NewTypeForm.js b/client/react/src/forms/NewTypeForm.js new file mode 100644 index 0000000..d1433d4 --- /dev/null +++ b/client/react/src/forms/NewTypeForm.js @@ -0,0 +1,146 @@ +import React, { useState, useEffect } from 'react'; +import Modal from '@mui/material/Modal'; +import TextField from '@mui/material/TextField'; +import Box from '@mui/material/Box'; +import IconButton from '@mui/material/IconButton'; +import ButtonGroup from '@mui/material/ButtonGroup'; +import CheckSharpIcon from '@mui/icons-material/CheckSharp'; +import CloseSharpIcon from '@mui/icons-material/CloseSharp'; +import CallSplitSharpIcon from '@mui/icons-material/CallSplitSharp'; +import Autocomplete from '@mui/material/Autocomplete'; + + +const NewTypeForm = ({ isOpen, onRequestClose }) => { + const [name, setName] = useState(''); + const [description, setDescription] = useState(''); + const [genus, setGenus] = useState(''); + + const [allGenuses, setAllGenuses] = useState([]); + + const [submitted, setSubmitted] = useState(false); // Initialize submitted state + + useEffect(() => { + if (isOpen) { + fetch('http://127.0.0.1:5000/genus') + .then((response) => response.json()) + .then((data) => setAllGenuses(data)) + .catch((error) => console.error('Error fetching genus data:', error)); + } + }, []); + + useEffect(() => { + if (submitted) { + const requestOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name: name, description: description, genus_id: genus.id }) + }; + fetch('http://127.0.0.1:5000/type', requestOptions) + .then(response => response.json()) + .then(data => { + // handle the response data if needed + // maybe update some state based on the response + console.log(data); + }) + .catch(error => console.error('Error posting type data:', error)); + clearForm(); + onRequestClose(); + } + }, [submitted, name, description, genus, onRequestClose]); + + const handleSubmit = (event) => { + event.preventDefault(); + if (allGenuses.find(genus => genus.name === name)) { + return; + } + setSubmitted(true); // Update submitted state + }; + + const handleCancel = () => { + clearForm(); + onRequestClose(); + }; + + const clearForm = () => { + setName(''); + setDescription(''); + setGenus(null); + setSubmitted(false); + }; + + return ( + + + +
+ + + + + + + + + +
+
+ setName(event.target.value)} + /> + setDescription(event.target.value)} + /> + option.name)} + onChange={(event) => setGenus(allGenuses[event.target.value])} + renderInput={(params) => ( + + )} + /> +
+ +
+
+ ); +}; + +export default NewTypeForm; + + diff --git a/client/react/src/pages/Home.js b/client/react/src/pages/Home.js index 720615c..126f9ce 100644 --- a/client/react/src/pages/Home.js +++ b/client/react/src/pages/Home.js @@ -16,9 +16,10 @@ import CloseSharpIcon from '@mui/icons-material/CloseSharp'; import VisibilitySharpIcon from '@mui/icons-material/VisibilitySharp'; import ReportGmailerrorredSharpIcon from '@mui/icons-material/ReportGmailerrorredSharp'; import NewLightForm from '../forms/NewLightForm'; +import NewTypeForm from '../forms/NewTypeForm'; import TungstenSharpIcon from '@mui/icons-material/TungstenSharp'; import Modal from '@mui/material/Modal'; - +import CallSplitSharpIcon from '@mui/icons-material/CallSplitSharp'; const Home = () => { // Navigation @@ -35,6 +36,7 @@ const Home = () => { const [isNewSystemFormOpen, setIsNewSystemFormOpen] = useState(false); const [isNewGenusFormOpen, setIsNewGenusFormOpen] = useState(false); const [isNewLightFormOpen, setIsNewLightFormOpen] = useState(false); + const [isNewTypeFormOpen, setIsNewTypeFormOpen] = useState(false); useEffect(() => { // Fetch plant data from the server @@ -94,21 +96,38 @@ const Home = () => { setIsNewPlantFormOpen(true)}> - setIsCreateButtonsOpen(false)}> - + setIsNewTypeFormOpen(true)}> + + + setIsNewGenusFormOpen(true)}> + - + setIsNewSystemFormOpen(true)}> - setIsNewGenusFormOpen(true)}> - - setIsNewLightFormOpen(true)}> + + setIsCreateButtonsOpen(false)}> + + +
)} @@ -156,6 +175,10 @@ const Home = () => { isOpen={isNewLightFormOpen} onRequestClose={() => setIsNewLightFormOpen(false)} /> + setIsNewTypeFormOpen(false)} + /> ); diff --git a/server/app.py b/server/app.py index 3347f5b..7952bf4 100644 --- a/server/app.py +++ b/server/app.py @@ -15,7 +15,7 @@ from sqlalchemy.engine import URL # Local application imports -from models.plant import Plant, Genus +from models.plant import Plant, Genus,Base from models.system import System, Light # Load database configuration from JSON file @@ -33,8 +33,8 @@ ) engine = create_engine(url) -# Base.metadata.drop_all(engine) -# Base.metadata.create_all(engine) +Base.metadata.drop_all(engine) +Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) @@ -143,6 +143,45 @@ def create_genus(): return jsonify({"message": "Genus added successfully"}), 201 +@app.route("/type", methods=["GET"]) +def get_types(): + """ + Retrieve all types from the database. + """ + logger.info("Received request to retrieve all plant types") + + session = Session() + types = session.query(Type).all() + session.close() + # Transform types to JSON format + types_json = [_type.to_json() for _type in types] + # Return JSON response + return jsonify(types_json) + + +@app.route("/type", methods=["POST"]) +def create_type(): + """ + Create a new type and add it to the database. + """ + logger.info("Attempting to create type") + + new_type_data = request.get_json() + + # Create a new Type object + new_type = Type( + name=new_type_data["name"], + description=new_type_data["description"], + genus_id=new_type_data["genus_id"] + ) + + # Add the new type object to the session + db = Session() + db.add(new_type) + db.commit() + db.close() + + return jsonify({"message": "Type added successfully"}), 201 @app.route("/system", methods=["GET"]) def get_systems(): diff --git a/server/models/plant.py b/server/models/plant.py index 4382372..110416b 100644 --- a/server/models/plant.py +++ b/server/models/plant.py @@ -20,10 +20,12 @@ class Plant(Base): __tablename__ = "plant" id = Column(Integer(), primary_key=True) - name = Column(String(100), nullable=False) created_on = Column(DateTime(), default=datetime.now) cost = Column(Integer(), default=0, nullable=False) size = Column(Integer(), default=0, nullable=False) # inches + type_id: Mapped[int] = mapped_column( + ForeignKey("type.id", ondelete="CASCADE") + ) # Type of Genus genus_id: Mapped[int] = mapped_column( ForeignKey("genus.id", ondelete="CASCADE") ) # Genus of Plant @@ -39,7 +41,7 @@ def __repr__(self) -> str: return f"{self.id}" def to_json(self): - """Convert to json for front end.""" + """Convert to json.""" return { "id": self.id, "name": self.name, @@ -52,6 +54,39 @@ def to_json(self): "system_id": self.system_id, } +class Type(Base): + """Type of genus""" + + __tablename__ = "type" + + id = Column(Integer(), primary_key=True) + created_on = Column(DateTime(), default=datetime.now) + name = Column(String(100), nullable=False, unique=True) + description = Column(String(400), nullable=True) + updated_on = Column(DateTime(), nullable=True, onupdate=datetime.now) + + genus_id: Mapped[int] = mapped_column( + ForeignKey("genus.id", ondelete="CASCADE") + ) # Genus of Plant + + plants: Mapped[List["Plant"]] = relationship( + "Plant", backref="genus", passive_deletes=True + ) # Available plants of this type + + def __repr__(self) -> str: + return f"{self.name}" + + def to_json(self): + """Convert to json.""" + return { + "id": self.id, + "name": self.name, + "description": self.description, + "created_on": self.created_on, + "updated_on": self.updated_on, + "genus_id": self.genus_id, + "system_id": self.system_id, + } class Genus(Base): """Genus of plant.""" @@ -61,16 +96,28 @@ class Genus(Base): id = Column(Integer(), primary_key=True) created_on = Column(DateTime(), default=datetime.now) name = Column(String(100), nullable=False, unique=True) + description = Column(String(400), nullable=True) watering = Column(Integer(), nullable=False) # days updated_on = Column(DateTime(), nullable=True, onupdate=datetime.now) + types: Mapped[List["Type"]] = relationship( + "Type", backref="genus", passive_deletes=True + ) # Available types of this genus + plants: Mapped[List["Plant"]] = relationship( "Plant", backref="genus", passive_deletes=True - ) # Available plants of this genus + ) # Available plants of this type def __repr__(self) -> str: return f"{self.name}" def to_json(self): - """Convert to json for front end.""" - return {"id": self.id, "name": self.name, "watering": self.watering} + """Convert to json.""" + return { + "id": self.id, + "name": self.name, + "watering": self.watering, + "description": self.description, + "created_on": self.created_on, + "updated_on": self.updated_on + } diff --git a/server/models/system.py b/server/models/system.py index 81a4941..1842521 100644 --- a/server/models/system.py +++ b/server/models/system.py @@ -35,7 +35,7 @@ class System(Base): distance = Column(Integer(), nullable=False) # inches lights: Mapped[List["Light"]] = relationship( "Light", backref="system", passive_deletes=True - ) # Available plants of this system + ) # Available lights of this system def __repr__(self) -> str: return f"{self.name}" @@ -47,6 +47,7 @@ def to_json(self): "name": self.name, "created_on": self.created_on, "updated_on": self.updated_on, + "description": self.description, "humidity": self.humidity, "temperature": self.temperature, "duration": self.duration, @@ -81,7 +82,6 @@ def to_json(self): return { "id": self.id, "name": self.name, - "description": self.description "cost": self.cost, "created_on": self.created_on, "updated_on": self.updated_on, From b54f90b719e5ccbc13ccbaab6948cdee5d22a537 Mon Sep 17 00:00:00 2001 From: mseng10 Date: Mon, 10 Jun 2024 19:56:42 -0500 Subject: [PATCH 8/8] BUG: Lint --- server/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/app.py b/server/app.py index 7952bf4..a94fb3d 100644 --- a/server/app.py +++ b/server/app.py @@ -15,7 +15,7 @@ from sqlalchemy.engine import URL # Local application imports -from models.plant import Plant, Genus,Base +from models.plant import Plant, Genus,Base, Type from models.system import System, Light # Load database configuration from JSON file