From ea6ef56380d8fdbb9a4bf1c4f1e9a71d18fad9ee Mon Sep 17 00:00:00 2001 From: raarielgrace Date: Tue, 18 Feb 2025 13:11:37 -0800 Subject: [PATCH 1/6] fix: Removed code causing docker compose up database to fail (#174) --- database/db/seed_tables/_Crops/init_crops.sql | 3 --- docker-compose.yml | 2 +- frontend/openshift.deploy.yml | 27 +++++++++---------- frontend/src/utils/APICache.ts | 3 ++- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/database/db/seed_tables/_Crops/init_crops.sql b/database/db/seed_tables/_Crops/init_crops.sql index b1585e0e..d3552313 100644 --- a/database/db/seed_tables/_Crops/init_crops.sql +++ b/database/db/seed_tables/_Crops/init_crops.sql @@ -22,6 +22,3 @@ FROM temp_crops WHERE StaticDataVersionId=14; ALTER TABLE crops DROP COLUMN StaticDataVersionId; -ALTER TABLE crops -ADD CONSTRAINT fk_crop_type -FOREIGN KEY (CropTypeId) REFERENCES crop_types(Id); diff --git a/docker-compose.yml b/docker-compose.yml index 544e597b..88d35a93 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: build: context: ./database dockerfile: Dockerfile - image: postgres:17 + # Don't put an image: prop here, it breaks the local container_name: nr-nmp-db environment: <<: *postgres-vars diff --git a/frontend/openshift.deploy.yml b/frontend/openshift.deploy.yml index 77e2b733..5f42e0bd 100644 --- a/frontend/openshift.deploy.yml +++ b/frontend/openshift.deploy.yml @@ -86,20 +86,19 @@ objects: ports: - name: container-port containerPort: 5173 - readinessProbe: - tcpSocket: - port: container-port - livenessProbe: - tcpSocket: - port: container-port - startupProbe: - tcpSocket: - port: container-port - failureThreshold: 5 - initialDelaySeconds: 90 - periodSeconds: 15 - timeoutSeconds: 10 - failureThreshold: 30 + # readinessProbe: + # tcpSocket: + # port: container-port + # livenessProbe: + # tcpSocket: + # port: container-port + # startupProbe: + # tcpSocket: + # port: container-port + # failureThreshold: 5 + # initialDelaySeconds: 90 + # periodSeconds: 15 + # timeoutSeconds: 10 resources: requests: cpu: ${CPU_REQUEST} diff --git a/frontend/src/utils/APICache.ts b/frontend/src/utils/APICache.ts index 9f067607..fc62f48a 100644 --- a/frontend/src/utils/APICache.ts +++ b/frontend/src/utils/APICache.ts @@ -1,4 +1,5 @@ import axios, { AxiosResponse } from 'axios'; +import { env } from '@/env'; class APICache { private endpointCache: { [endpoint: string]: AxiosResponse } = {}; @@ -8,7 +9,7 @@ class APICache { if (cachedValue !== undefined && cachedValue.status === 200) { return cachedValue; } - const response = await axios.get(`http://localhost:3000/${endpoint}`); + const response = await axios.get(`${env.VITE_BACKEND_URL}/${endpoint}`); this.endpointCache[endpoint] = response; return response; } From 857c212b0531946122fe2510e93bdff2beba51e9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 07:46:59 -0800 Subject: [PATCH 2/6] fix(deps): update dependency react-router-dom to v7 (#173) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 74 +++++++++++++++++++++++++------------- frontend/package.json | 2 +- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5f32e68a..5404ae08 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,7 @@ "react": "^18.3.1", "react-collapsed": "^4.2.0", "react-dom": "^18.3.1", - "react-router-dom": "^6.28.0", + "react-router-dom": "^7.0.0", "typography": "^0.16.24" }, "devDependencies": { @@ -1222,15 +1222,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@remix-run/router": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", - "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.29.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", @@ -1550,6 +1541,12 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -2401,6 +2398,15 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -5309,35 +5315,43 @@ } }, "node_modules/react-router": { - "version": "6.28.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.1.tgz", - "integrity": "sha512-2omQTA3rkMljmrvvo6WtewGdVh45SpL9hGiCI9uUrwGGfNFDIvGK4gYJsKlJoNVi6AQZcopSCballL+QGOm7fA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.2.0.tgz", + "integrity": "sha512-fXyqzPgCPZbqhrk7k3hPcCpYIlQ2ugIXDboHUzhJISFVy2DEPsmHgN588MyGmkIOv3jDgNfUE3kJi83L28s/LQ==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.21.0" + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, "node_modules/react-router-dom": { - "version": "6.28.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.1.tgz", - "integrity": "sha512-YraE27C/RdjcZwl5UCqF/ffXnZDxpJdk9Q6jw38SZHjXs7NNdpViq2l2c7fO7+4uWaEfcwfGCv3RSg4e1By/fQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.2.0.tgz", + "integrity": "sha512-cU7lTxETGtQRQbafJubvZKHEn5izNABxZhBY0Jlzdv0gqQhCPQt2J8aN5ZPjS6mQOXn5NnirWNh+FpE8TTYN0Q==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.21.0", - "react-router": "6.28.1" + "react-router": "7.2.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "react": ">=18", + "react-dom": ">=18" } }, "node_modules/reflect.getprototypeof": { @@ -5585,6 +5599,12 @@ "node": ">=10" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -6019,6 +6039,12 @@ "dev": true, "license": "0BSD" }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index be5a2e2e..f492b5ae 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,7 +22,7 @@ "react": "^18.3.1", "react-collapsed": "^4.2.0", "react-dom": "^18.3.1", - "react-router-dom": "^6.28.0", + "react-router-dom": "^7.0.0", "typography": "^0.16.24" }, "devDependencies": { From fd5096a0e53dfbef9d35400371f2e3ee65f7936d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:50:48 +0000 Subject: [PATCH 3/6] chore(deps): update dependency vite to v6 (#172) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: PaulG <144158015+PaulGarewal@users.noreply.github.com> --- frontend/package-lock.json | 495 +++++++++++++++++++++---------------- frontend/package.json | 2 +- 2 files changed, 280 insertions(+), 217 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5404ae08..52e38c93 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -39,7 +39,7 @@ "eslint-plugin-react-refresh": "^0.4.14", "prettier": "^3.3.3", "typescript": "^5.6.3", - "vite": "^5.4.11" + "vite": "^6.0.0" } }, "node_modules/@ampproject/remapping": { @@ -521,9 +521,9 @@ "peer": true }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", "cpu": [ "ppc64" ], @@ -534,13 +534,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", "cpu": [ "arm" ], @@ -551,13 +551,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", "cpu": [ "arm64" ], @@ -568,13 +568,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", "cpu": [ "x64" ], @@ -585,13 +585,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", "cpu": [ "arm64" ], @@ -602,13 +602,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", "cpu": [ "x64" ], @@ -619,13 +619,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", "cpu": [ "arm64" ], @@ -636,13 +636,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", "cpu": [ "x64" ], @@ -653,13 +653,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", "cpu": [ "arm" ], @@ -670,13 +670,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", "cpu": [ "arm64" ], @@ -687,13 +687,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", "cpu": [ "ia32" ], @@ -704,13 +704,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", "cpu": [ "loong64" ], @@ -721,13 +721,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", "cpu": [ "mips64el" ], @@ -738,13 +738,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", "cpu": [ "ppc64" ], @@ -755,13 +755,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", "cpu": [ "riscv64" ], @@ -772,13 +772,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", "cpu": [ "s390x" ], @@ -789,13 +789,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", "cpu": [ "x64" ], @@ -806,13 +806,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", "cpu": [ "x64" ], @@ -823,13 +840,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", "cpu": [ "x64" ], @@ -840,13 +874,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", "cpu": [ "x64" ], @@ -857,13 +891,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", "cpu": [ "arm64" ], @@ -874,13 +908,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", "cpu": [ "ia32" ], @@ -891,13 +925,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", "cpu": [ "x64" ], @@ -908,7 +942,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -1223,9 +1257,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", - "integrity": "sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", + "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", "cpu": [ "arm" ], @@ -1237,9 +1271,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz", - "integrity": "sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", + "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", "cpu": [ "arm64" ], @@ -1251,9 +1285,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz", - "integrity": "sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", + "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", "cpu": [ "arm64" ], @@ -1265,9 +1299,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz", - "integrity": "sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", + "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", "cpu": [ "x64" ], @@ -1279,9 +1313,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz", - "integrity": "sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", + "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", "cpu": [ "arm64" ], @@ -1293,9 +1327,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz", - "integrity": "sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", + "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", "cpu": [ "x64" ], @@ -1307,9 +1341,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz", - "integrity": "sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", + "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", "cpu": [ "arm" ], @@ -1321,9 +1355,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz", - "integrity": "sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", + "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", "cpu": [ "arm" ], @@ -1335,9 +1369,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz", - "integrity": "sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", + "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", "cpu": [ "arm64" ], @@ -1349,9 +1383,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz", - "integrity": "sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", + "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", "cpu": [ "arm64" ], @@ -1363,9 +1397,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz", - "integrity": "sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", + "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", "cpu": [ "loong64" ], @@ -1377,9 +1411,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz", - "integrity": "sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", + "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", "cpu": [ "ppc64" ], @@ -1391,9 +1425,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz", - "integrity": "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", + "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", "cpu": [ "riscv64" ], @@ -1405,9 +1439,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz", - "integrity": "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", + "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", "cpu": [ "s390x" ], @@ -1419,9 +1453,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz", - "integrity": "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", + "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", "cpu": [ "x64" ], @@ -1433,9 +1467,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz", - "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", + "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", "cpu": [ "x64" ], @@ -1447,9 +1481,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz", - "integrity": "sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", + "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", "cpu": [ "arm64" ], @@ -1461,9 +1495,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz", - "integrity": "sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", + "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", "cpu": [ "ia32" ], @@ -1475,9 +1509,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz", - "integrity": "sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", + "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", "cpu": [ "x64" ], @@ -2423,6 +2457,15 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2816,9 +2859,9 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2826,32 +2869,34 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" } }, "node_modules/escalade": { @@ -5145,9 +5190,9 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz", + "integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==", "dev": true, "funding": [ { @@ -5165,7 +5210,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -5460,9 +5505,9 @@ } }, "node_modules/rollup": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.1.tgz", - "integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==", + "version": "4.34.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", + "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5476,25 +5521,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.29.1", - "@rollup/rollup-android-arm64": "4.29.1", - "@rollup/rollup-darwin-arm64": "4.29.1", - "@rollup/rollup-darwin-x64": "4.29.1", - "@rollup/rollup-freebsd-arm64": "4.29.1", - "@rollup/rollup-freebsd-x64": "4.29.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.29.1", - "@rollup/rollup-linux-arm-musleabihf": "4.29.1", - "@rollup/rollup-linux-arm64-gnu": "4.29.1", - "@rollup/rollup-linux-arm64-musl": "4.29.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.29.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.29.1", - "@rollup/rollup-linux-riscv64-gnu": "4.29.1", - "@rollup/rollup-linux-s390x-gnu": "4.29.1", - "@rollup/rollup-linux-x64-gnu": "4.29.1", - "@rollup/rollup-linux-x64-musl": "4.29.1", - "@rollup/rollup-win32-arm64-msvc": "4.29.1", - "@rollup/rollup-win32-ia32-msvc": "4.29.1", - "@rollup/rollup-win32-x64-msvc": "4.29.1", + "@rollup/rollup-android-arm-eabi": "4.34.8", + "@rollup/rollup-android-arm64": "4.34.8", + "@rollup/rollup-darwin-arm64": "4.34.8", + "@rollup/rollup-darwin-x64": "4.34.8", + "@rollup/rollup-freebsd-arm64": "4.34.8", + "@rollup/rollup-freebsd-x64": "4.34.8", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", + "@rollup/rollup-linux-arm-musleabihf": "4.34.8", + "@rollup/rollup-linux-arm64-gnu": "4.34.8", + "@rollup/rollup-linux-arm64-musl": "4.34.8", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", + "@rollup/rollup-linux-riscv64-gnu": "4.34.8", + "@rollup/rollup-linux-s390x-gnu": "4.34.8", + "@rollup/rollup-linux-x64-gnu": "4.34.8", + "@rollup/rollup-linux-x64-musl": "4.34.8", + "@rollup/rollup-win32-arm64-msvc": "4.34.8", + "@rollup/rollup-win32-ia32-msvc": "4.34.8", + "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" } }, @@ -6252,21 +6297,21 @@ } }, "node_modules/vite": { - "version": "5.4.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.12.tgz", - "integrity": "sha512-KwUaKB27TvWwDJr1GjjWthLMATbGEbeWYZIbGZ5qFIsgPP3vWzLu4cVooqhm5/Z2SPDUMjyPVjTztm5tYKwQxA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz", + "integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.24.2", + "postcss": "^8.5.1", + "rollup": "^4.30.1" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -6275,19 +6320,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -6308,6 +6359,12 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, @@ -6440,12 +6497,18 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yocto-queue": { diff --git a/frontend/package.json b/frontend/package.json index f492b5ae..1f0fa6e4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -44,6 +44,6 @@ "eslint-plugin-react-refresh": "^0.4.14", "prettier": "^3.3.3", "typescript": "^5.6.3", - "vite": "^5.4.11" + "vite": "^6.0.0" } } From ade950a2851f9511f7302b8f14680580a2d175c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Feb 2025 12:05:57 -0800 Subject: [PATCH 4/6] chore(deps): update bcgov-nr/action-deployer-openshift action to v3.2.0 (#176) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/.deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/.deploy.yml b/.github/workflows/.deploy.yml index 1773d474..8d4feaa7 100644 --- a/.github/workflows/.deploy.yml +++ b/.github/workflows/.deploy.yml @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize - uses: bcgov-nr/action-deployer-openshift@v3.1.0 + uses: bcgov-nr/action-deployer-openshift@v3.2.0 with: oc_namespace: ${{ secrets.OC_NAMESPACE }} oc_server: ${{ vars.OC_SERVER }} @@ -88,7 +88,7 @@ jobs: parameters: -p CPU_REQUEST=${{ inputs.frontend-cpu-request }} steps: - - uses: bcgov-nr/action-deployer-openshift@v3.1.0 + - uses: bcgov-nr/action-deployer-openshift@v3.2.0 with: file: ${{ matrix.name }}/openshift.deploy.yml oc_namespace: ${{ secrets.OC_NAMESPACE }} From 42d2519d96367404af272e46de24bad9bf6b6cd0 Mon Sep 17 00:00:00 2001 From: raarielgrace Date: Fri, 21 Feb 2025 15:22:50 -0800 Subject: [PATCH 5/6] feat: [NR-NMP-113] Dairy Cattle Flow (#179) --- backend/apps/animals/admin.py | 1 + backend/apps/animals/models.py | 10 + backend/apps/animals/serializers.py | 5 + backend/apps/animals/urls.py | 1 + backend/apps/animals/views.py | 6 + .../seed_tables/_Breed/_Breed__20241212.csv | 44 +++ database/db/seed_tables/_Breed/init_breed.sql | 14 + .../_CropTypes/init_crop_types.sql | 4 +- .../_Breed/_Breed_202502180812.csv | 4 + .../db/trimmed_tables/_Breed/init_breed.sql | 7 + .../components/common/Dropdown/Dropdown.tsx | 2 +- frontend/src/constants/ManureTypeOptions.ts | 6 + .../AddAnimals/AddAnimals.tsx | 87 ++++-- .../AddAnimals/DairyCattle/DairyCattle.tsx | 279 ++++++++++++++++++ .../AddAnimals/DairyCattle/MilkingFields.tsx | 103 +++++++ .../AnimalsAndManure/AddAnimals/types.ts | 17 +- .../AnimalsAndManure/AddAnimals/utils.ts | 44 ++- 17 files changed, 594 insertions(+), 40 deletions(-) create mode 100644 database/db/seed_tables/_Breed/_Breed__20241212.csv create mode 100644 database/db/seed_tables/_Breed/init_breed.sql create mode 100644 database/db/trimmed_tables/_Breed/_Breed_202502180812.csv create mode 100644 database/db/trimmed_tables/_Breed/init_breed.sql create mode 100644 frontend/src/constants/ManureTypeOptions.ts create mode 100644 frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/DairyCattle.tsx create mode 100644 frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/MilkingFields.tsx diff --git a/backend/apps/animals/admin.py b/backend/apps/animals/admin.py index b68dd52f..cb098a56 100644 --- a/backend/apps/animals/admin.py +++ b/backend/apps/animals/admin.py @@ -3,3 +3,4 @@ admin.site.register(Animals) admin.site.register(AnimalSubtype) +admin.site.register(Breed) diff --git a/backend/apps/animals/models.py b/backend/apps/animals/models.py index 58a5bd1f..dc9030b8 100644 --- a/backend/apps/animals/models.py +++ b/backend/apps/animals/models.py @@ -24,3 +24,13 @@ class AnimalSubtype(models.Model): class Meta: managed = False db_table = 'animal_subtype' + +class Breed(models.Model): + id = models.IntegerField(primary_key=True) + breedname = models.CharField(max_length=100) + animalid = models.IntegerField() + breedmanurefactor = models.FloatField() + + class Meta: + managed = False + db_table = 'breed' diff --git a/backend/apps/animals/serializers.py b/backend/apps/animals/serializers.py index b9563085..1d1310f4 100644 --- a/backend/apps/animals/serializers.py +++ b/backend/apps/animals/serializers.py @@ -10,3 +10,8 @@ class AnimalSubtypeSerializer(serializers.ModelSerializer): class Meta: model = AnimalSubtype fields = '__all__' + +class BreedSerializer(serializers.ModelSerializer): + class Meta: + model = Breed + fields = '__all__' diff --git a/backend/apps/animals/urls.py b/backend/apps/animals/urls.py index 5c819cd7..c2d66719 100644 --- a/backend/apps/animals/urls.py +++ b/backend/apps/animals/urls.py @@ -6,4 +6,5 @@ path('animals/', AnimalsViewset.as_view({'get': 'animals'})), path('animal_subtypes/', AnimalsViewset.as_view({'get': 'animalSubtypes'})), path('animal_subtypes//', AnimalsViewset.as_view({'get': 'animalSubtypes'})), + path('breeds/', AnimalsViewset.as_view({'get': 'breeds'})), ] \ No newline at end of file diff --git a/backend/apps/animals/views.py b/backend/apps/animals/views.py index 7cd0af08..519ef5b3 100644 --- a/backend/apps/animals/views.py +++ b/backend/apps/animals/views.py @@ -21,3 +21,9 @@ def animalSubtypes(self, request, animalId=None): animals = AnimalSubtype.objects.filter(animalid=animalId) serializer = AnimalSubtypeSerializer(animals, many=True) return Response(serializer.data, status=status.HTTP_200_OK) + + @action(detail=True, methods=['get']) + def breeds(self, request): + breeds = Breed.objects.all() + serializer = BreedSerializer(breeds, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) diff --git a/database/db/seed_tables/_Breed/_Breed__20241212.csv b/database/db/seed_tables/_Breed/_Breed__20241212.csv new file mode 100644 index 00000000..8c1e9c7f --- /dev/null +++ b/database/db/seed_tables/_Breed/_Breed__20241212.csv @@ -0,0 +1,44 @@ +Id,BreedName,AnimalId,BreedManureFactor,StaticDataVersionId +1,Holstein,2,1,1 +2,Guernsey,2,0.68,1 +3,Brown Swiss,2,0.765,1 +1,Holstein,2,1,2 +2,Guernsey,2,0.68,2 +3,Brown Swiss,2,0.765,2 +1,Holstein,2,1,3 +2,Guernsey,2,0.68,3 +3,Brown Swiss,2,0.765,3 +1,Holstein,2,1,4 +2,Guernsey,2,0.68,4 +3,Brown Swiss,2,0.765,4 +1,Holstein,2,1,5 +3,Brown Swiss,2,0.765,5 +4,Ayrshire,2,0.791,5 +5,Jersey,2,0.68,5 +2,Guernsey,2,0.717,5 +4,Ayrshire,2,0.791,6 +5,Jersey,2,0.68,6 +2,Guernsey,2,0.717,6 +1,Holstein,2,1,6 +3,Brown Swiss,2,0.765,6 +1,Holstein,2,1,7 +2,Guernsey,2,0.68,7 +3,Brown Swiss,2,0.765,7 +3,Brown Swiss,2,0.765,8 +1,Holstein,2,1,8 +2,Guernsey,2,0.68,8 +2,Guernsey,2,0.68,9 +1,Holstein,2,1,9 +3,Brown Swiss,2,0.765,9 +2,Guernsey,2,0.68,10 +3,Brown Swiss,2,0.765,10 +1,Holstein,2,1,10 +1,Holstein,2,1,12 +2,Guernsey,2,0.68,12 +3,Brown Swiss,2,0.765,12 +1,Holstein,2,1,13 +2,Guernsey,2,0.68,13 +3,Brown Swiss,2,0.765,13 +1,Holstein,2,1,14 +2,Guernsey,2,0.68,14 +3,Brown Swiss,2,0.765,14 diff --git a/database/db/seed_tables/_Breed/init_breed.sql b/database/db/seed_tables/_Breed/init_breed.sql new file mode 100644 index 00000000..7e90f45b --- /dev/null +++ b/database/db/seed_tables/_Breed/init_breed.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS temp_breed ( + Id INT NOT NULL, + BreedName VARCHAR(100) NOT NULL, + AnimalId INT NOT NULL, + BreedManureFactor FLOAT NOT NULL, + StaticDataVersionId INT NOT NULL, + PRIMARY KEY (Id, StaticDataVersionId) +); +\copy temp_breed (Id, BreedName, AnimalId, BreedManureFactor, StaticDataVersionId) from 'docker-entrypoint-initdb.d/_Breed__20241212.csv' with header delimiter ',' CSV ; +SELECT * INTO breed +FROM temp_breed +WHERE StaticDataVersionId=14; +ALTER TABLE breed +DROP COLUMN StaticDataVersionId; diff --git a/database/db/seed_tables/_CropTypes/init_crop_types.sql b/database/db/seed_tables/_CropTypes/init_crop_types.sql index 94cf1923..97eba1db 100644 --- a/database/db/seed_tables/_CropTypes/init_crop_types.sql +++ b/database/db/seed_tables/_CropTypes/init_crop_types.sql @@ -9,8 +9,8 @@ CREATE TABLE IF NOT EXISTS temp_crop_types ( PRIMARY KEY (Id, StaticDataVersionId) ); \copy temp_crop_types (Id, Name, CoverCrop, CrudeProteinRequired, CustomCrop, ModifyNitrogen, StaticDataVersionId) from 'docker-entrypoint-initdb.d/_CropTypes__20241212.csv' with header delimiter ',' CSV ; -SELECT * INTO crops_types +SELECT * INTO crop_types FROM temp_crop_types WHERE StaticDataVersionId=14; -ALTER TABLE crops_types +ALTER TABLE crop_types DROP COLUMN StaticDataVersionId; diff --git a/database/db/trimmed_tables/_Breed/_Breed_202502180812.csv b/database/db/trimmed_tables/_Breed/_Breed_202502180812.csv new file mode 100644 index 00000000..5f45531a --- /dev/null +++ b/database/db/trimmed_tables/_Breed/_Breed_202502180812.csv @@ -0,0 +1,4 @@ +"id","breedname","animalid","breedmanurefactor" +1,Holstein,2,1.0 +2,Guernsey,2,0.68 +3,Brown Swiss,2,0.765 diff --git a/database/db/trimmed_tables/_Breed/init_breed.sql b/database/db/trimmed_tables/_Breed/init_breed.sql new file mode 100644 index 00000000..bc609b1a --- /dev/null +++ b/database/db/trimmed_tables/_Breed/init_breed.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS breed ( + Id INT PRIMARY KEY, + BreedName VARCHAR(100) NOT NULL, + AnimalId INT NOT NULL, + BreedManureFactor FLOAT NOT NULL +); +\copy breed (Id, BreedName, AnimalId, BreedManureFactor) from 'docker-entrypoint-initdb.d/_Breed_202502180812.csv' with header delimiter ',' CSV ; diff --git a/frontend/src/components/common/Dropdown/Dropdown.tsx b/frontend/src/components/common/Dropdown/Dropdown.tsx index c541f644..fedc61d3 100644 --- a/frontend/src/components/common/Dropdown/Dropdown.tsx +++ b/frontend/src/components/common/Dropdown/Dropdown.tsx @@ -8,7 +8,7 @@ interface DropdownProps { label: string; name: string; value: number | string; - options: { value: number; label: string }[]; + options: { value: number | string; label: string }[]; onChange: (e: React.ChangeEvent) => void; flex?: string; } diff --git a/frontend/src/constants/ManureTypeOptions.ts b/frontend/src/constants/ManureTypeOptions.ts new file mode 100644 index 00000000..6414c608 --- /dev/null +++ b/frontend/src/constants/ManureTypeOptions.ts @@ -0,0 +1,6 @@ +const manureTypeOptions: { value: string; label: string }[] = [ + { value: 'liquid', label: 'Liquid'}, + { value: 'solid', label: 'Solid' }, +]; + +export default manureTypeOptions; diff --git a/frontend/src/views/AnimalsAndManure/AddAnimals/AddAnimals.tsx b/frontend/src/views/AnimalsAndManure/AddAnimals/AddAnimals.tsx index 4b5e0ccc..18661dc8 100644 --- a/frontend/src/views/AnimalsAndManure/AddAnimals/AddAnimals.tsx +++ b/frontend/src/views/AnimalsAndManure/AddAnimals/AddAnimals.tsx @@ -10,6 +10,7 @@ import { FlexContainer, MarginWrapper } from './addAnimals.styles'; import { Column, Header } from '@/views/FieldAndSoil/FieldList/fieldList.styles'; import defaultNMPFile from '@/constants/DefaultNMPFile'; import blankNMPFileYearData from '@/constants/BlankNMPFileYearData'; +import DairyCattle from './DairyCattle/DairyCattle'; interface AddAnimalsProps { saveData: React.Dispatch>; @@ -72,22 +73,38 @@ export default function AddAnimals({ saveData }: AddAnimalsProps) { if (data === undefined || data.length === 0) { data = (nmpFile.farmDetails.FarmAnimals || []).map((id) => ({ id })); } + const dataElems = data.map((d, index) => { if (d === null) { return null; } - // TODO: Once more animal types are added, return a different elem based on type - return ( - - ); + if (d.id === '1') { + return ( + + ); + } + if (d.id === '2') { + return ( + + ); + } + throw new Error('Unexpected animal id.'); }); setFormData(data); @@ -96,25 +113,38 @@ export default function AddAnimals({ saveData }: AddAnimalsProps) { }, []); const handleAdd = (animalId: string) => { - // Right now we only handle beef cattle - if (animalId !== '1') return; + // Right now we only handle cattle + if (animalId !== '1' && animalId !== '2') return; - const { length } = formData; setFormData((prev) => { prev.push({ id: animalId }); return prev; }); + const { length } = formData; setElems((prev) => { const next = [...prev]; - next.push( - , - ); + if (animalId === '1') { + next.push( + , + ); + } else if (animalId === '2') { + next.push( + , + ); + } + return next; }); }; @@ -123,9 +153,10 @@ export default function AddAnimals({ saveData }: AddAnimalsProps) { apiCache.callEndpoint('api/animals/').then((response) => { if (response.status === 200) { const { data } = response; - const animals: { value: number; label: string }[] = ( - data as { id: number; name: string }[] - ).map((row) => ({ value: row.id, label: row.name })); + const animals: { value: number; label: string }[] = (data as { id: number; name: string }[]) + .map((row) => ({ value: row.id, label: row.name })) + // Temp, remove non-cattle as an option + .filter((opt) => opt.value === 1 || opt.value === 2); setAnimalOptions(animals); } }); @@ -134,7 +165,7 @@ export default function AddAnimals({ saveData }: AddAnimalsProps) { return (
-
+
Animal Type Annual Manure Amount diff --git a/frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/DairyCattle.tsx b/frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/DairyCattle.tsx new file mode 100644 index 00000000..5b4f54cb --- /dev/null +++ b/frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/DairyCattle.tsx @@ -0,0 +1,279 @@ +/* eslint-disable react/jsx-props-no-spreading */ +import React, { useContext, useEffect, useMemo, useState } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faEdit, faTrash } from '@fortawesome/free-solid-svg-icons'; +import { Button, Dropdown, InputField } from '@/components/common'; +import { APICacheContext } from '@/context/APICacheContext'; +import { ListItem, ListItemContainer } from '@/views/FieldAndSoil/FieldList/fieldList.styles'; +import { AnimalData, DairyCattleData, perDayPerAnimalUnit } from '../types'; +import { useEventfulCollapse } from '@/utils/useEventfulCollapse'; +import MilkingFields from './MilkingFields'; +import manureTypeOptions from '@/constants/ManureTypeOptions'; +import { calculateAnnualLiquidManure, calculateAnnualSolidManure } from '../utils'; + +const milkingCowId: string = '9'; + +interface DairyCattleSubtype { + id: number; + name: string; + liquidpergalperanimalperday: number; + solidperpoundperanimalperday: number; + washwater: number; + milkproduction: number; +} + +interface DairyCattleBreed { + id: number; + breedname: string; + breedmanurefactor: number; +} + +interface DairyCattleProps { + startData: Partial; + startExpanded?: boolean; + saveData: (data: AnimalData, index: number) => void; + onDelete: (index: number) => void; + myIndex: number; +} + +const initData: (d: Partial) => DairyCattleData = (data) => { + if (data.id !== '2') { + throw new Error('AddAnimals sent bad data to DairyCattle.'); + } + // Assign default values to breed and grazing days + return { id: '2', breed: '1', grazingDaysPerYear: 0, ...data }; +}; + +export default function DairyCattle({ + startData, + startExpanded = false, + saveData, + onDelete, + myIndex, +}: DairyCattleProps) { + const [formData, setFormData] = useState(initData(startData)); + const apiCache = useContext(APICacheContext); + + // Dairy cows have both a subtype and a breed + const [subtypes, setSubtypes] = useState([]); + const [subtypeOptions, setSubtypeOptions] = useState<{ value: number; label: string }[]>([]); + const selectedSubtypeName = useMemo(() => { + if (!formData.subtype || subtypes.length === 0) return ''; + const subtype = subtypes.find((s) => s.id.toString() === formData.subtype); + if (subtype === undefined) throw new Error('Chosen subtype is missing from list.'); + return subtype.name; + }, [formData.subtype, subtypes]); + const [breeds, setBreeds] = useState([]); + const [breedOptions, setBreedOptions] = useState<{ value: number; label: string }[]>([]); + + // Initial values for milking fields, if "Milking cow" is selected + const washWaterInit = useMemo(() => { + if (subtypes.length === 0) return undefined; + const milkingCow = subtypes.find((s) => s.id.toString() === milkingCowId); + if (milkingCow === undefined) throw new Error('Milking cow is missing from list.'); + return milkingCow.washwater; + }, [subtypes]); + const milkProductionInit = useMemo(() => { + if (subtypes.length === 0 || breeds.length === 0) return undefined; + const milkingCow = subtypes.find((s) => s.id.toString() === milkingCowId); + if (milkingCow === undefined) throw new Error('Milking cow is missing from list.'); + const breed = breeds.find((b) => b.id.toString() === formData.breed); + if (breed === undefined) throw new Error('Chosen breed is missing from list.'); + return milkingCow.milkproduction * breed.breedmanurefactor; + }, [subtypes, breeds, formData.breed]); + + const annualManure = useMemo(() => { + if ( + !formData.subtype || + !formData.animalsPerFarm || + !formData.manureType || + formData.grazingDaysPerYear === undefined || + subtypes.length === 0 + ) + return 0; + const subtype = subtypes.find((s) => s.id.toString() === formData.subtype); + if (subtype === undefined) throw new Error('Chosen subtype is missing from list.'); + const breed = breeds.find((b) => b.id.toString() === formData.breed); + if (breed === undefined) throw new Error('Chosen breed is missing from list.'); + const nonGrazingDays = 365 - formData.grazingDaysPerYear; + + let extraCoefficient; + if (formData.subtype === milkingCowId) { + if (formData.milkProduction === undefined) return 0; + const expectedMilkProduction = subtype.milkproduction * breed.breedmanurefactor; + // Due to potential floating point issues, round factor to 1 if numbers are close + const milkProdPercent = + Math.abs(expectedMilkProduction - formData.milkProduction) < 1 + ? 1 + : formData.milkProduction / expectedMilkProduction; + extraCoefficient = breed.breedmanurefactor * milkProdPercent; + } else { + extraCoefficient = breed.breedmanurefactor; + } + + if (formData.manureType === 'liquid') { + return Math.round( + calculateAnnualLiquidManure( + subtype.liquidpergalperanimalperday, + formData.animalsPerFarm, + nonGrazingDays, + extraCoefficient, + ), + ); + } + return Math.round( + calculateAnnualSolidManure( + subtype.solidperpoundperanimalperday, + formData.animalsPerFarm, + nonGrazingDays, + extraCoefficient, + ), + ); + }, [formData, subtypes, breeds]); + + useEffect(() => { + apiCache.callEndpoint('api/animal_subtypes/2/').then((response) => { + if (response.status === 200) { + const { data } = response; + // The data in the response has more properties, but we want to trim it down + const subtypez: DairyCattleSubtype[] = (data as DairyCattleSubtype[]).map((row) => ({ + id: row.id, + name: row.name, + solidperpoundperanimalperday: row.solidperpoundperanimalperday, + liquidpergalperanimalperday: row.liquidpergalperanimalperday, + washwater: row.washwater, + milkproduction: row.milkproduction, + })); + setSubtypes(subtypez); + const subtypeOptionz: { value: number; label: string }[] = ( + data as { id: number; name: string }[] + ).map((row) => ({ value: row.id, label: row.name })); + setSubtypeOptions(subtypeOptionz); + } + }); + + apiCache.callEndpoint('api/breeds/').then((response) => { + if (response.status === 200) { + const { data } = response; + // The data in the response has more properties, but we want to trim it down + const breedz: DairyCattleBreed[] = (data as DairyCattleBreed[]).map((row) => ({ + id: row.id, + breedname: row.breedname, + breedmanurefactor: row.breedmanurefactor, + })); + setBreeds(breedz); + const breedOptionz = breedz.map((breed) => ({ value: breed.id, label: breed.breedname })); + setBreedOptions(breedOptionz); + } + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const { getToggleProps, getCollapseProps, isExpanded, setExpanded } = useEventfulCollapse({ + id: `dairy-${myIndex}`, + defaultExpanded: startExpanded, + }); + + const handleSave = () => { + saveData(formData, myIndex); + setExpanded(false); + }; + + return ( + <> + {!isExpanded ? ( +
+ + {selectedSubtypeName} + {`${annualManure} ${formData.manureType === 'liquid' ? 'U.S. gallon' : 'ton'}${annualManure === 1 ? '' : 's'}`} + + + + + + {formData.washWater && formData.washWaterUnit && ( + + Milking Centre Wash Water + {`${formData.washWater * 365 * (formData.washWaterUnit === perDayPerAnimalUnit ? formData.animalsPerFarm || 0 : 1)} U.S. gallons`} +
+ + )} +
+ ) : ( +
Edit Animal
+ )} +
+ + + + + + {formData.subtype === milkingCowId && + milkProductionInit !== undefined && + washWaterInit !== undefined && ( + + )} +
+ + ); +} diff --git a/frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/MilkingFields.tsx b/frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/MilkingFields.tsx new file mode 100644 index 00000000..a7961d33 --- /dev/null +++ b/frontend/src/views/AnimalsAndManure/AddAnimals/DairyCattle/MilkingFields.tsx @@ -0,0 +1,103 @@ +import React, { useEffect, useState } from 'react'; +import { Dropdown, InputField } from '@/components/common'; +import { DairyCattleData, perDayUnit, perDayPerAnimalUnit } from '../types'; + +interface MilkingFieldsProps { + milkProductionInit: number; + washWaterInit: number; + animalsPerFarm: number; + washWaterUnit: 'PER_DAY_PER_ANIMAL' | 'PER_DAY' | undefined; + handleChange: (e: React.ChangeEvent) => void; + setFormData: (value: React.SetStateAction) => void; +} + +const washWaterOptions: { value: string; label: string }[] = [ + { value: perDayPerAnimalUnit, label: 'US gallons/day/animal' }, + { value: perDayUnit, label: 'US gallons/day' }, +]; + +export default function MilkingFields({ + milkProductionInit, + washWaterInit, + animalsPerFarm, + washWaterUnit, + handleChange, + setFormData, +}: MilkingFieldsProps) { + // I'm starting to think keeping stateful props is dumb and I should just keep the useEffects + // to get the same on-mount-and-unmount behavior, but I just wanna get this PR in atm + const [milkProduction, setMilkProduction] = useState(String(milkProductionInit)); + const [washWater, setWashWater] = useState(`${washWaterInit}.0`); + + // When the breed changes, change the milk production value + useEffect(() => { + setMilkProduction(String(milkProductionInit)); + setFormData((prev) => ({ ...prev, milkProduction: milkProductionInit })); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [milkProductionInit]); + + // On mount, set milking fields to init values + // On unmount, clear milking fields + useEffect(() => { + // Default to the first unit if one isn't chosen + setFormData((prev) => ({ + washWaterUnit: perDayPerAnimalUnit, + ...prev, + milkProduction: milkProductionInit, + washWater: washWaterInit, + })); + return () => { + setFormData((prev) => ({ ...prev, milkProduction: undefined, washWater: undefined })); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const handleUnitChange = (e: React.ChangeEvent) => { + const { value } = e.target; + if (value === perDayPerAnimalUnit && washWaterUnit === perDayUnit) { + setWashWater(`${washWaterInit}.0`); + setFormData((prev) => ({ ...prev, washWater: washWaterInit, washWaterUnit: value })); + } else if (value === perDayUnit && washWaterUnit === perDayPerAnimalUnit) { + setWashWater(String(washWaterInit * animalsPerFarm)); + setFormData((prev) => ({ + ...prev, + washWater: washWaterInit * animalsPerFarm, + washWaterUnit: value, + })); + } else { + handleChange(e); + } + }; + + return ( + <> + { + setMilkProduction(e.target.value); + handleChange(e); + }} + /> + { + setWashWater(e.target.value); + handleChange(e); + }} + /> + + + ); +} diff --git a/frontend/src/views/AnimalsAndManure/AddAnimals/types.ts b/frontend/src/views/AnimalsAndManure/AddAnimals/types.ts index 3794ee5b..e95bf3e9 100644 --- a/frontend/src/views/AnimalsAndManure/AddAnimals/types.ts +++ b/frontend/src/views/AnimalsAndManure/AddAnimals/types.ts @@ -5,8 +5,21 @@ export interface BeefCattleData { daysCollected?: number | undefined; } -// TODO: Add all subsequent animal data interfaces here -export type AnimalData = BeefCattleData; +export const perDayPerAnimalUnit = 'PER_DAY_PER_ANIMAL'; +export const perDayUnit = 'PER_DAY'; +export interface DairyCattleData { + id: '2'; + subtype?: string; + breed?: string; + manureType?: 'liquid' | 'solid'; + animalsPerFarm?: number; + grazingDaysPerYear?: number; + milkProduction?: number | undefined; + washWater?: number | undefined; + washWaterUnit?: 'PER_DAY_PER_ANIMAL' | 'PER_DAY' | undefined; +} + +export type AnimalData = BeefCattleData | DairyCattleData; // TODO: Add interfaces for the manure tab and nutrient tab export type AnimalsWorkflowData = AnimalData; diff --git a/frontend/src/views/AnimalsAndManure/AddAnimals/utils.ts b/frontend/src/views/AnimalsAndManure/AddAnimals/utils.ts index c376694a..59276574 100644 --- a/frontend/src/views/AnimalsAndManure/AddAnimals/utils.ts +++ b/frontend/src/views/AnimalsAndManure/AddAnimals/utils.ts @@ -1,12 +1,42 @@ +/* eslint-disable default-param-last */ /** - * Returns the amount of solid manure generated by an animal type in a year, in tonnes. Returns -1 if the amount cannot be calculated. - * @param solidPerPound The coefficient of solid manure per pound per animal per year + * Calculates the solid manure generated by a type of animal in a year, in US tons. + * @param poundsPerAnimal The coefficient of solid manure per pound per animal per day * @param animalsPerFarm The average number of animals on the farm * @param daysCollected The number of days manure is collected + * @param coefficient Optional spot for another coefficient to be multiplied in the calculation */ -function calculateSolidManurePerYear(solidPerPound: number, animalsPerFarm: number | undefined, daysCollected: number | undefined) { - if (animalsPerFarm === undefined || daysCollected === undefined) { - return -1; +export function calculateAnnualSolidManure( + poundsPerAnimal: number, + animalsPerFarm: number, + daysCollected: number = 365, + coefficient?: number, +) { + if (daysCollected > 365 || daysCollected < 0) { + throw new Error( + `Invalid number of collection days: can only be 0-365 but received ${daysCollected}`, + ); } - return (animalsPerFarm * solidPerPound * daysCollected) / 2000; -} \ No newline at end of file + return (poundsPerAnimal * animalsPerFarm * daysCollected * (coefficient || 1)) / 2000; // 1 US ton = 2000 pounds +} + +/** + * Calculates the liquid manure generated by a type of animal in a year, in US gallons. + * @param galsPerAnimal The coefficient of liquid manure per gallon per animal per day + * @param animalsPerFarm The average number of animals on the farm + * @param daysCollected The number of days manure is collected + * @param coefficient Optional spot for another coefficient to be multiplied in the calculation + */ +export function calculateAnnualLiquidManure( + galsPerAnimal: number, + animalsPerFarm: number, + daysCollected: number = 365, + coefficient?: number, +) { + if (daysCollected > 365 || daysCollected < 0) { + throw new Error( + `Invalid number of collection days: can only be 0-365 but received ${daysCollected}`, + ); + } + return galsPerAnimal * animalsPerFarm * daysCollected * (coefficient || 1); +} From 0aae815bf48540f62a800a7aa2754644342bfa9a Mon Sep 17 00:00:00 2001 From: dallascrichmond <113049138+dallascrichmond@users.noreply.github.com> Date: Mon, 24 Feb 2025 11:50:55 -0800 Subject: [PATCH 6/6] feat: [NMP-118-120] Manure and Imports (#180) --- backend/apps/manure/__init__.py | 0 backend/apps/manure/models.py | 23 ++ backend/apps/manure/serializers.py | 12 + backend/apps/manure/urls.py | 8 + backend/apps/manure/views.py | 19 + backend/config/settings.py | 1 + backend/config/urls.py | 1 + ...terialsConversionFactors__20241212(in).csv | 40 ++ ...it_liquid_materials_conversion_factors.sql | 14 + ...terialsConversionFactors__20241212(in).csv | 53 +++ ...nit_solid_materials_conversion_factors.sql | 16 + ...it_liquid_materials_conversion_factors.sql | 7 + ...erials_conversion_factors_202502211207.csv | 4 + ...nit_solid_materials_conversion_factors.sql | 9 + ...erials_conversion_factors_202502211120.csv | 5 + frontend/package-lock.json | 89 +++++ frontend/package.json | 1 + .../ManureAndImports/Calculations.ts | 31 ++ .../DefaultLiquidManureConversionFactors.ts | 8 + .../src/constants/DefaultManureFormData.ts | 22 ++ .../DefaultSolidManureConversionFactors.ts | 10 + frontend/src/constants/index.ts | 17 + .../types/LiquidManureConversionFactors.ts | 6 + .../src/types/SolidManureConversionFactors.ts | 8 + frontend/src/types/index.ts | 15 + .../ManureAndCompost/ManureAndCompost.tsx | 7 +- .../ManureAndImports/ManureAndImports.tsx | 342 +++++++++++++++++- .../manureAndImports.styles.ts | 79 ++++ 28 files changed, 842 insertions(+), 5 deletions(-) create mode 100644 backend/apps/manure/__init__.py create mode 100644 backend/apps/manure/models.py create mode 100644 backend/apps/manure/serializers.py create mode 100644 backend/apps/manure/urls.py create mode 100644 backend/apps/manure/views.py create mode 100644 database/db/seed_tables/_LiquidMaterialsConversionFactors/_LiquidMaterialsConversionFactors__20241212(in).csv create mode 100644 database/db/seed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql create mode 100644 database/db/seed_tables/_SolidMaterialsConversionFactors/_SolidMaterialsConversionFactors__20241212(in).csv create mode 100644 database/db/seed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql create mode 100644 database/db/trimmed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql create mode 100644 database/db/trimmed_tables/_LiquidMaterialsConversionFactors/liquid_materials_conversion_factors_202502211207.csv create mode 100644 database/db/trimmed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql create mode 100644 database/db/trimmed_tables/_SolidMaterialsConversionFactors/solid_materials_conversion_factors_202502211120.csv create mode 100644 frontend/src/calculations/ManureAndCompost/ManureAndImports/Calculations.ts create mode 100644 frontend/src/constants/DefaultLiquidManureConversionFactors.ts create mode 100644 frontend/src/constants/DefaultManureFormData.ts create mode 100644 frontend/src/constants/DefaultSolidManureConversionFactors.ts create mode 100644 frontend/src/constants/index.ts create mode 100644 frontend/src/types/LiquidManureConversionFactors.ts create mode 100644 frontend/src/types/SolidManureConversionFactors.ts create mode 100644 frontend/src/types/index.ts diff --git a/backend/apps/manure/__init__.py b/backend/apps/manure/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/apps/manure/models.py b/backend/apps/manure/models.py new file mode 100644 index 00000000..4ae489ec --- /dev/null +++ b/backend/apps/manure/models.py @@ -0,0 +1,23 @@ +from django.db import models + +class SolidMaterialsConversionFactors(models.Model): + id = models.IntegerField(primary_key=True) + inputunit = models.IntegerField() + inputunitname = models.CharField(max_length=100) + cubicyardsoutput = models.CharField(max_length=100) + cubicmetersoutput = models.CharField(max_length=100) + metrictonsoutput = models.CharField(max_length=100) + + class Meta: + managed = False + db_table = 'solid_materials_conversion_factors' + +class LiquidMaterialsConversionFactors(models.Model): + id = models.IntegerField(primary_key=True) + inputunit = models.IntegerField() + inputunitname = models.CharField(max_length=100) + usgallonsoutput = models.CharField(max_length=100) + + class Meta: + managed = False + db_table = 'liquid_materials_conversion_factors' diff --git a/backend/apps/manure/serializers.py b/backend/apps/manure/serializers.py new file mode 100644 index 00000000..a84b7468 --- /dev/null +++ b/backend/apps/manure/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import serializers +from .models import * + +class SolidMaterialsConversionFactorsSerializer(serializers.ModelSerializer): + class Meta: + model = SolidMaterialsConversionFactors + fields = '__all__' + +class LiquidMaterialsConversionFactorsSerializer(serializers.ModelSerializer): + class Meta: + model = LiquidMaterialsConversionFactors + fields = '__all__' diff --git a/backend/apps/manure/urls.py b/backend/apps/manure/urls.py new file mode 100644 index 00000000..f8d675bd --- /dev/null +++ b/backend/apps/manure/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from rest_framework import routers +from .views import SolidMaterialsConversionFactorsViewset + +urlpatterns = [ + path('solidmaterialsconversionfactors/', SolidMaterialsConversionFactorsViewset.as_view({'get': 'solidMaterialsConversionFactors'})), + path('liquidmaterialsconversionfactors/', SolidMaterialsConversionFactorsViewset.as_view({'get': 'liquidMaterialsConversionFactors'})), +] diff --git a/backend/apps/manure/views.py b/backend/apps/manure/views.py new file mode 100644 index 00000000..61abb63c --- /dev/null +++ b/backend/apps/manure/views.py @@ -0,0 +1,19 @@ +from rest_framework import status, viewsets +from rest_framework.decorators import action +from rest_framework.response import Response +from .models import * +from .serializers import * + +class SolidMaterialsConversionFactorsViewset(viewsets.ViewSet): + @action(detail=True, methods=['get']) + def solidMaterialsConversionFactors(self, request): + solid_materials_conversion_factors = SolidMaterialsConversionFactors.objects.all() + serializer = SolidMaterialsConversionFactorsSerializer(solid_materials_conversion_factors, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + + @action(detail=True, methods=['get']) + def liquidMaterialsConversionFactors(self, request): + liquid_materials_conversion_factors = LiquidMaterialsConversionFactors.objects.all() + serializer = LiquidMaterialsConversionFactorsSerializer(liquid_materials_conversion_factors, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + diff --git a/backend/config/settings.py b/backend/config/settings.py index 6ff6dc2b..f7bc54a2 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -61,6 +61,7 @@ 'apps.crops', 'apps.animals', 'apps.shared', + 'apps.manure', 'apps.fertilizers', ] diff --git a/backend/config/urls.py b/backend/config/urls.py index f4de4b58..65b0f5bf 100644 --- a/backend/config/urls.py +++ b/backend/config/urls.py @@ -29,5 +29,6 @@ path('api/', include('apps.animals.urls')), path('api/', include('apps.crops.urls')), path('api/', include('apps.shared.urls')), + path('api/', include('apps.manure.urls')), path('api/', include('apps.fertilizers.urls')), ] diff --git a/database/db/seed_tables/_LiquidMaterialsConversionFactors/_LiquidMaterialsConversionFactors__20241212(in).csv b/database/db/seed_tables/_LiquidMaterialsConversionFactors/_LiquidMaterialsConversionFactors__20241212(in).csv new file mode 100644 index 00000000..6c1b303d --- /dev/null +++ b/database/db/seed_tables/_LiquidMaterialsConversionFactors/_LiquidMaterialsConversionFactors__20241212(in).csv @@ -0,0 +1,40 @@ +Id,InputUnit,InputUnitName,USGallonsOutput,StaticDataVersionId +3,3,US gallons,1,1 +2,2,cubic meters,264.172,1 +1,1,Imp. gallons,1.20095,1 +3,3,US gallons,1,2 +2,2,cubic meters,264.172,2 +1,1,Imp. gallons,1.20095,2 +3,3,US gallons,1,3 +2,2,cubic meters,264.172,3 +1,1,Imp. gallons,1.20095,3 +3,3,US gallons,1,4 +2,2,cubic meters,264.172,4 +1,1,Imp. gallons,1.20095,4 +3,3,US gallons,1,5 +2,2,cubic meters,264.172,5 +1,1,Imp. gallons,1.20095,5 +3,3,US gallons,1,6 +2,2,cubic meters,264.172,6 +1,1,Imp. gallons,1.20095,6 +3,3,US gallons,1,7 +2,2,cubic meters,264.172,7 +1,1,Imp. gallons,1.20095,7 +3,3,US gallons,1,8 +2,2,cubic meters,264.172,8 +1,1,Imp. gallons,1.20095,8 +3,3,US gallons,1,9 +2,2,cubic meters,264.172,9 +1,1,Imp. gallons,1.20095,9 +3,3,US gallons,1,10 +2,2,cubic meters,264.172,10 +1,1,Imp. gallons,1.20095,10 +1,1,Imp. gallons,1.20095,12 +2,2,cubic meters,264.172,12 +3,3,US gallons,1,12 +1,1,Imp. gallons,1.20095,13 +2,2,cubic meters,264.172,13 +3,3,US gallons,1,13 +1,1,Imp. gallons,1.20095,14 +2,2,cubic meters,264.172,14 +3,3,US gallons,1,14 diff --git a/database/db/seed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql b/database/db/seed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql new file mode 100644 index 00000000..6fb862a6 --- /dev/null +++ b/database/db/seed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS temp_liquid_materials_conversion_factors ( + Id INT NOT NULL, + InputUnit INT NOT NULL, + InputUnitName VARCHAR(100) NOT NULL, + USGallonsOutput VARCHAR(100) NOT NULL, + StaticDataVersionId INT NOT NULL, + PRIMARY KEY (Id, StaticDataVersionId) +); +\copy temp_liquid_materials_conversion_factors (Id, InputUnit, InputUnitName, USGallonsOutput, StaticDataVersionId ) from 'docker-entrypoint-initdb.d/_LiquidMaterialsConversionFactors__20241212(in).csv' with header delimiter ',' CSV ; +SELECT * INTO liquid_materials_conversion_factors +FROM temp_liquid_materials_conversion_factors +WHERE StaticDataVersionId=14; +ALTER TABLE liquid_materials_conversion_factors +DROP COLUMN StaticDataVersionId; diff --git a/database/db/seed_tables/_SolidMaterialsConversionFactors/_SolidMaterialsConversionFactors__20241212(in).csv b/database/db/seed_tables/_SolidMaterialsConversionFactors/_SolidMaterialsConversionFactors__20241212(in).csv new file mode 100644 index 00000000..8a212e1d --- /dev/null +++ b/database/db/seed_tables/_SolidMaterialsConversionFactors/_SolidMaterialsConversionFactors__20241212(in).csv @@ -0,0 +1,53 @@ +Id,InputUnit,InputUnitName,CubicYardsOutput,CubicMetersOutput,MetricTonsOutput,StaticDataVersionId +4,6,cubic yards,1,0.764555,1*density,1 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,1 +2,4,tons,1/density,(1/density)*0.764555,1,1 +1,2,cubic meters,1.30795,1,1.30795*density,1 +4,6,cubic yards,1,0.764555,1*density,2 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,2 +2,4,tons,1/density,(1/density)*0.764555,1,2 +1,2,cubic meters,1.30795,1,1.30795*density,2 +4,6,cubic yards,1,0.764555,1*density,3 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,3 +2,4,tons,1/density,(1/density)*0.764555,1,3 +1,2,cubic meters,1.30795,1,1.30795*density,3 +4,6,cubic yards,1,0.764555,1*density,4 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,4 +2,4,tons,1/density,(1/density)*0.764555,1,4 +1,2,cubic meters,1.30795,1,1.30795*density,4 +4,6,cubic yards,1,0.764555,1*density,5 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,5 +2,4,tons,1/density,(1/density)*0.764555,1,5 +1,2,cubic meters,1.30795,1,1.30795*density,5 +4,6,cubic yards,1,0.764555,1*density,6 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,6 +2,4,tons,1/density,(1/density)*0.764555,1,6 +1,2,cubic meters,1.30795,1,1.30795*density,6 +4,6,cubic yards,1,0.764555,1*density,7 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,7 +2,4,tons,1/density,(1/density)*0.764555,1,7 +1,2,cubic meters,1.30795,1,1.30795*density,7 +4,6,cubic yards,1,0.764555,1*density,8 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,8 +2,4,tons,1/density,(1/density)*0.764555,1,8 +1,2,cubic meters,1.30795,1,1.30795*density,8 +4,6,cubic yards,1,0.764555,1*density,9 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,9 +2,4,tons,1/density,(1/density)*0.764555,1,9 +1,2,cubic meters,1.30795,1,1.30795*density,9 +4,6,cubic yards,1,0.764555,1*density,10 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,10 +2,4,tons,1/density,(1/density)*0.764555,1,10 +1,2,cubic meters,1.30795,1,1.30795*density,10 +1,2,cubic meters,1.30795,1,1.30795*density,12 +2,4,tons,1/density,(1/density)*0.764555,1,12 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,12 +4,6,cubic yards,1,0.764555,1*density,12 +1,2,cubic meters,1.30795,1,1.30795*density,13 +2,4,tons,1/density,(1/density)*0.764555,1,13 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,13 +4,6,cubic yards,1,0.764555,1*density,13 +1,2,cubic meters,1.30795,1,1.30795*density,14 +2,4,tons,1/density,(1/density)*0.764555,1,14 +3,5,tonnes,1.10231/density,(1.10231/density)*0.764555,1.10231,14 +4,6,cubic yards,1,0.764555,1*density,14 diff --git a/database/db/seed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql b/database/db/seed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql new file mode 100644 index 00000000..aad2b927 --- /dev/null +++ b/database/db/seed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS temp_solid_materials_conversion_factors ( + Id INT NOT NULL, + InputUnit INT NOT NULL, + InputUnitName VARCHAR(100) NOT NULL, + CubicYardsOutput VARCHAR(100) NOT NULL, + CubicMetersOutput VARCHAR(100) NOT NULL, + MetricTonsOutput VARCHAR(100) NOT NULL, + StaticDataVersionId INT NOT NULL, + PRIMARY KEY (Id, StaticDataVersionId) +); +\copy temp_solid_materials_conversion_factors (Id, InputUnit, InputUnitName, CubicYardsOutput, CubicMetersOutput, MetricTonsOutput, StaticDataVersionId) from 'docker-entrypoint-initdb.d/_SolidMaterialsConversionFactors__20241212(in).csv' with header delimiter ',' CSV ; +SELECT * INTO solid_materials_conversion_factors +FROM temp_solid_materials_conversion_factors +WHERE StaticDataVersionId=14; +ALTER TABLE solid_materials_conversion_factors +DROP COLUMN StaticDataVersionId; diff --git a/database/db/trimmed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql b/database/db/trimmed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql new file mode 100644 index 00000000..3950f701 --- /dev/null +++ b/database/db/trimmed_tables/_LiquidMaterialsConversionFactors/init_liquid_materials_conversion_factors.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS liquid_materials_conversion_factors ( + Id INT PRIMARY KEY, + InputUnit INT NOT NULL, + InputUnitName VARCHAR(100) NOT NULL, + USGallonsOutput VARCHAR(100) NOT NULL +); +\copy liquid_materials_conversion_factors (Id, InputUnit, InputUnitName, USGallonsOutput) from 'docker-entrypoint-initdb.d/liquid_materials_conversion_factors_202502211207.csv' with header delimiter ',' CSV ; diff --git a/database/db/trimmed_tables/_LiquidMaterialsConversionFactors/liquid_materials_conversion_factors_202502211207.csv b/database/db/trimmed_tables/_LiquidMaterialsConversionFactors/liquid_materials_conversion_factors_202502211207.csv new file mode 100644 index 00000000..93b1ccd7 --- /dev/null +++ b/database/db/trimmed_tables/_LiquidMaterialsConversionFactors/liquid_materials_conversion_factors_202502211207.csv @@ -0,0 +1,4 @@ +"id","inputunit","inputunitname","usgallonsoutput" +1,1,Imp. gallons,"1.20095" +2,2,cubic meters,"264.172" +3,3,US gallons,"1" diff --git a/database/db/trimmed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql b/database/db/trimmed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql new file mode 100644 index 00000000..d0b8287c --- /dev/null +++ b/database/db/trimmed_tables/_SolidMaterialsConversionFactors/init_solid_materials_conversion_factors.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS solid_materials_conversion_factors ( + Id INT PRIMARY KEY, + InputUnit INT NOT NULL, + InputUnitName VARCHAR(100) NOT NULL, + CubicYardsOutput VARCHAR(100) NOT NULL, + CubicMetersOutput VARCHAR(100) NOT NULL, + MetricTonsOutput VARCHAR(100) NOT NULL +); +\copy solid_materials_conversion_factors (Id, InputUnit, InputUnitName, CubicYardsOutput, CubicMetersOutput, MetricTonsOutput) from 'docker-entrypoint-initdb.d/solid_materials_conversion_factors_202502211120.csv' with header delimiter ',' CSV ; diff --git a/database/db/trimmed_tables/_SolidMaterialsConversionFactors/solid_materials_conversion_factors_202502211120.csv b/database/db/trimmed_tables/_SolidMaterialsConversionFactors/solid_materials_conversion_factors_202502211120.csv new file mode 100644 index 00000000..07664735 --- /dev/null +++ b/database/db/trimmed_tables/_SolidMaterialsConversionFactors/solid_materials_conversion_factors_202502211120.csv @@ -0,0 +1,5 @@ +"id","inputunit","inputunitname","cubicyardsoutput","cubicmetersoutput","metrictonsoutput" +1,2,cubic meters,"1.30795","1","1.30795*density" +2,4,tons,"1/density",(1/density)*0.764555,"1" +3,5,tonnes,"1.10231/density",(1.10231/density)*0.764555,"1.10231" +4,6,cubic yards,"1","0.764555","1*density" diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 52e38c93..8c500edd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,6 +14,7 @@ "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", "axios": "^1.7.9", + "mathjs": "^14.2.1", "react": "^18.3.1", "react-collapsed": "^4.2.0", "react-dom": "^18.3.1", @@ -2396,6 +2397,19 @@ "parse-unit": "^1.0.1" } }, + "node_modules/complex.js": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.2.tgz", + "integrity": "sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2574,6 +2588,12 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2909,6 +2929,12 @@ "node": ">=6" } }, + "node_modules/escape-latex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3717,6 +3743,19 @@ "node": ">= 6" } }, + "node_modules/fraction.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.2.1.tgz", + "integrity": "sha512-Ah6t/7YCYjrPUFUFsOsRLMXAdnYM+aQwmojD2Ayb/Ezr82SwES0vuyQ8qZ3QO8n9j7W14VJuVZZet8U3bhSdQQ==", + "license": "MIT", + "engines": { + "node": ">= 12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4555,6 +4594,12 @@ "node": ">= 0.4" } }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4759,6 +4804,29 @@ "node": ">= 0.4" } }, + "node_modules/mathjs": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-14.2.1.tgz", + "integrity": "sha512-vARWETUx75+kR2K9qBV20n6NYtGXCuQKX8Zo4+AhJI5LX+ukSM1NYebv+wLnJG8KMvEe9H01sJUyC5bMciA4Tg==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.25.7", + "complex.js": "^2.2.5", + "decimal.js": "^10.4.3", + "escape-latex": "^1.2.0", + "fraction.js": "^5.2.1", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^4.2.1" + }, + "bin": { + "mathjs": "bin/cli.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5631,6 +5699,12 @@ "loose-envify": "^1.1.0" } }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "license": "MIT" + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -6017,6 +6091,12 @@ "dev": true, "license": "MIT" }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "license": "MIT" + }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -6194,6 +6274,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typed-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz", + "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, "node_modules/typescript": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 1f0fa6e4..a775ced5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", "axios": "^1.7.9", + "mathjs": "^14.2.1", "react": "^18.3.1", "react-collapsed": "^4.2.0", "react-dom": "^18.3.1", diff --git a/frontend/src/calculations/ManureAndCompost/ManureAndImports/Calculations.ts b/frontend/src/calculations/ManureAndCompost/ManureAndImports/Calculations.ts new file mode 100644 index 00000000..fba0e525 --- /dev/null +++ b/frontend/src/calculations/ManureAndCompost/ManureAndImports/Calculations.ts @@ -0,0 +1,31 @@ +import { evaluate } from 'mathjs'; + +export function getDensity(moistureWholePercent: number): number { + const moisturePercentDecimal = moistureWholePercent / 100; + if (moistureWholePercent < 40) { + return 0.27; + } + if (moistureWholePercent >= 40 && moistureWholePercent <= 82) { + const result = + 7.9386 * moisturePercentDecimal ** 3 - + 16.43 * moisturePercentDecimal ** 2 + + 11.993 * moisturePercentDecimal - + 2.3975; + return result; + } + return 0.837; +} + +export function getDensityFactoredConversion(density: number, conversionFactor: string): number { + const parsedExpression = conversionFactor.replace(/density/gi, density.toString()); + const conversion = evaluate(parsedExpression); + return conversion; +} + +export function getDensityFactoredConversionUsingMoisture( + moistureWholePercent: number, + conversionFactor: string, +): number { + const density = getDensity(moistureWholePercent); + return getDensityFactoredConversion(density, conversionFactor); +} diff --git a/frontend/src/constants/DefaultLiquidManureConversionFactors.ts b/frontend/src/constants/DefaultLiquidManureConversionFactors.ts new file mode 100644 index 00000000..71064e05 --- /dev/null +++ b/frontend/src/constants/DefaultLiquidManureConversionFactors.ts @@ -0,0 +1,8 @@ +const DefaultLiquidManureConversionFactors = { + id: 0, + inputunit: 0, + inputunitname: '', + usgallonsoutput: '', +}; + +export default DefaultLiquidManureConversionFactors; diff --git a/frontend/src/constants/DefaultManureFormData.ts b/frontend/src/constants/DefaultManureFormData.ts new file mode 100644 index 00000000..ab8af4c5 --- /dev/null +++ b/frontend/src/constants/DefaultManureFormData.ts @@ -0,0 +1,22 @@ +const DefaultManureFormData = { + MaterialName: '', + ManureTypeName: '', + AnnualAmount: 0, + AnnualAmountUSGallonsVolume: 0, + AnnualAmountCubicYardsVolume: 0, + AnnualAmountCubicMetersVolume: 0, + AnnualAmountTonsWeight: 0, + AnnualAmountDisplayVolume: '', + AnnualAmountDisplayWeight: '', + Units: 0, + Moisture: '50', + StandardSolidMoisture: 0, + IsMaterialStored: false, + ManureId: '', + ManagedManureName: '', + ManureType: 0, + AssignedToStoredSystem: false, + AssignedWithNutrientAnalysis: false, +}; + +export default DefaultManureFormData; diff --git a/frontend/src/constants/DefaultSolidManureConversionFactors.ts b/frontend/src/constants/DefaultSolidManureConversionFactors.ts new file mode 100644 index 00000000..675a2159 --- /dev/null +++ b/frontend/src/constants/DefaultSolidManureConversionFactors.ts @@ -0,0 +1,10 @@ +const DefaultSolidManureConversionFactors = { + id: 0, + inputunit: 0, + inputunitname: '', + cubicyardsoutput: '', + cubicmetersoutput: '', + metrictonsoutput: '', +}; + +export default DefaultSolidManureConversionFactors; diff --git a/frontend/src/constants/index.ts b/frontend/src/constants/index.ts new file mode 100644 index 00000000..6a762d45 --- /dev/null +++ b/frontend/src/constants/index.ts @@ -0,0 +1,17 @@ +import blankNMPFileYearData from './BlankNMPFileYearData'; +import constants from './Constants'; +import DefaultLiquidManureConversionFactors from './DefaultLiquidManureConversionFactors'; +import DefaultManureFormData from './DefaultManureFormData'; +import defaultNMPFile from './DefaultNMPFile'; +import defaultNMPFileCropsData from './DefaultNMPFileCropsData'; +import DefaultSolidManureConversionFactors from './DefaultSolidManureConversionFactors'; + +export { + blankNMPFileYearData, + constants, + DefaultLiquidManureConversionFactors, + DefaultManureFormData, + defaultNMPFile, + defaultNMPFileCropsData, + DefaultSolidManureConversionFactors, +}; diff --git a/frontend/src/types/LiquidManureConversionFactors.ts b/frontend/src/types/LiquidManureConversionFactors.ts new file mode 100644 index 00000000..9e757b35 --- /dev/null +++ b/frontend/src/types/LiquidManureConversionFactors.ts @@ -0,0 +1,6 @@ +export default interface LiquidManureConversionFactors { + id?: number; + inputunit?: number; + inputunitname?: string; + usgallonsoutput?: string; +} diff --git a/frontend/src/types/SolidManureConversionFactors.ts b/frontend/src/types/SolidManureConversionFactors.ts new file mode 100644 index 00000000..1e3305be --- /dev/null +++ b/frontend/src/types/SolidManureConversionFactors.ts @@ -0,0 +1,8 @@ +export default interface SolidManureConversionFactors { + id?: number; + inputunit?: number; + inputunitname?: string; + cubicyardsoutput?: string; + cubicmetersoutput?: string; + metrictonsoutput?: string; +} diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts new file mode 100644 index 00000000..cd88bcb4 --- /dev/null +++ b/frontend/src/types/index.ts @@ -0,0 +1,15 @@ +import LiquidManureConversionFactors from './LiquidManureConversionFactors'; +import NMPFile from './NMPFile'; +import NMPFileCropData from './NMPFileCropData'; +import NMPFileFieldData from './NMPFileFieldData'; +import NMPFileImportedManureData from './NMPFileImportedManureData'; +import SolidManureConversionFactors from './SolidManureConversionFactors'; + +export type { + LiquidManureConversionFactors, + NMPFile, + NMPFileCropData, + NMPFileFieldData, + NMPFileImportedManureData, + SolidManureConversionFactors, +}; diff --git a/frontend/src/views/ManureAndCompost/ManureAndCompost.tsx b/frontend/src/views/ManureAndCompost/ManureAndCompost.tsx index 9e51c01e..589fdb77 100644 --- a/frontend/src/views/ManureAndCompost/ManureAndCompost.tsx +++ b/frontend/src/views/ManureAndCompost/ManureAndCompost.tsx @@ -19,7 +19,12 @@ export default function ManureAndCompost() { { id: 'manure-imports', label: 'Manure and Imports', - content: , + content: ( + + ), }, { id: 'nutrient-analysis', diff --git a/frontend/src/views/ManureAndCompost/ManureAndImports/ManureAndImports.tsx b/frontend/src/views/ManureAndCompost/ManureAndImports/ManureAndImports.tsx index 7b86455c..b2050229 100644 --- a/frontend/src/views/ManureAndCompost/ManureAndImports/ManureAndImports.tsx +++ b/frontend/src/views/ManureAndCompost/ManureAndImports/ManureAndImports.tsx @@ -1,9 +1,343 @@ -function ManureAndImports() { +/* eslint-disable eqeqeq */ +/* eslint-disable object-shorthand */ +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useState, useEffect, useContext } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faEdit, faTrash } from '@fortawesome/free-solid-svg-icons'; +import { APICacheContext } from '@/context/APICacheContext'; +import { + NMPFileImportedManureData, + LiquidManureConversionFactors, + SolidManureConversionFactors, +} from '@/types'; +import { + DefaultSolidManureConversionFactors, + DefaultLiquidManureConversionFactors, + DefaultManureFormData, +} from '@/constants'; +import { Button, Modal, InputField, Dropdown } from '@/components/common'; +import { getDensityFactoredConversionUsingMoisture } from '@/calculations/ManureAndCompost/ManureAndImports/Calculations'; +import { + ContentWrapper, + ButtonContainer, + ButtonWrapper, + ErrorText, + Header, + Column, + ListItem, + ListItemContainer, +} from './manureAndImports.styles'; + +interface ManureAndImportsProps { + manures: NMPFileImportedManureData[]; + setManures: (manures: NMPFileImportedManureData[]) => void; +} + +const manureTypeOptions = [ + { label: 'Select', value: 0 }, + { label: 'Liquid', value: 1 }, + { label: 'Solid', value: 2 }, +]; + +export default function ManureAndImports({ manures, setManures }: ManureAndImportsProps) { + const apiCache = useContext(APICacheContext); + const [isModalVisible, setIsModalVisible] = useState(false); + const [editIndex, setEditIndex] = useState(null); + const [errors, setErrors] = useState<{ [key: string]: string }>({}); + const [solidManureDropdownOptions, setSolidManureDropdownOptions] = useState< + SolidManureConversionFactors[] + >([DefaultSolidManureConversionFactors]); + const [liquidManureDropdownOptions, setLiquidManureDropdownOptions] = useState< + LiquidManureConversionFactors[] + >([DefaultLiquidManureConversionFactors]); + const [manureFormData, setManureFormData] = + useState(DefaultManureFormData); + + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setManureFormData({ ...manureFormData, [name]: value }); + }; + + const handleEdit = (index: number) => { + setManureFormData(manures[index]); + setEditIndex(index); + setIsModalVisible(true); + }; + + const handleDelete = (index: number) => { + const updatedManures = manures.filter((_, i) => i !== index); + setManures(updatedManures); + }; + + const validate = () => { + const newErrors: { [key: string]: string } = {}; + if (!manureFormData.MaterialName?.trim()) { + newErrors.FieldName = 'Field Name is required'; + } else if ( + manures.some( + (manure, index) => + manure.MaterialName?.trim().toLowerCase() === + (manureFormData.MaterialName ?? '').trim().toLowerCase() && index !== editIndex, + ) + ) { + newErrors.FieldName = 'Material Name must be unique'; + } + + if (!manureFormData.ManureTypeName || manureFormData.ManureTypeName === '0') { + newErrors.ManureTypeName = 'Manure Type is required'; + } + + if (!manureFormData.AnnualAmount || manureFormData.AnnualAmount <= 0) { + newErrors.AnnualAmount = 'Annual Amount is required'; + } + + if (!manureFormData.Units) { + newErrors.Units = 'Units is required'; + } + + if (manureFormData.ManureTypeName === '2' && !manureFormData.Moisture) { + newErrors.Moisture = 'Moisture is required'; + } + + return newErrors; + }; + + const handleSubmit = () => { + const validationErrors = validate(); + if (Object.keys(validationErrors).length > 0) { + setErrors(validationErrors); + return; + } + setErrors({}); + + let updatedManureFormData = {}; + + if (manureFormData.ManureTypeName === '1') { + const liquidManureConversionFactor = liquidManureDropdownOptions.find( + (item) => item.inputunit == manureFormData.Units, + ); + + const annualAmountUSGallonsVolume = + (manureFormData.AnnualAmount ?? 0) * + (liquidManureConversionFactor?.usgallonsoutput + ? parseFloat(liquidManureConversionFactor.usgallonsoutput) + : 0); + + updatedManureFormData = { + ...manureFormData, + AnnualAmountUSGallonsVolume: annualAmountUSGallonsVolume, + AnnualAmountDisplayVolume: `${Math.round((annualAmountUSGallonsVolume * 10) / 10).toString()} U.S. gallons`, + }; + } else if (manureFormData.ManureTypeName === '2') { + const solidManureConversionFactor = solidManureDropdownOptions.find( + (item) => item.inputunit == manureFormData.Units, + ); + + const annualAmountCubicMetersVolume = + (manureFormData.AnnualAmount ?? 0) * + getDensityFactoredConversionUsingMoisture( + Number(manureFormData.Moisture), + solidManureConversionFactor?.cubicmetersoutput || '', + ); + + const annualAmountCubicYardsVolume = + (manureFormData.AnnualAmount ?? 0) * + getDensityFactoredConversionUsingMoisture( + Number(manureFormData.Moisture), + solidManureConversionFactor?.cubicyardsoutput || '', + ); + + const annualAmountTonsWeight = + (manureFormData.AnnualAmount ?? 0) * + getDensityFactoredConversionUsingMoisture( + Number(manureFormData.Moisture), + solidManureConversionFactor?.metrictonsoutput || '', + ); + + updatedManureFormData = { + ...manureFormData, + AnnualAmountCubicYardsVolume: annualAmountCubicYardsVolume, + AnnualAmountCubicMetersVolume: annualAmountCubicMetersVolume, + AnnualAmountDisplayVolume: `${Math.round((annualAmountCubicYardsVolume * 10) / 10).toString()} yards³ (${Math.round((annualAmountCubicMetersVolume * 10) / 10).toString()} m³)`, + AnnualAmountDisplayWeight: `${Math.round((annualAmountTonsWeight * 10) / 10).toString()} tons`, + }; + } + + if (editIndex !== null) { + const updatedManures = manures.map((manure, index) => + index === editIndex ? updatedManureFormData : manure, + ); + setManures(updatedManures); + setEditIndex(null); + } else { + setManures([...manures, updatedManureFormData]); + } + setManureFormData(DefaultManureFormData); + setIsModalVisible(false); + }; + + useEffect(() => { + apiCache + .callEndpoint('api/liquidmaterialsconversionfactors/') + .then((response: { status?: any; data: any }) => { + if (response.status === 200) { + const { data } = response; + setLiquidManureDropdownOptions(data); + } + }); + apiCache + .callEndpoint('api/solidmaterialsconversionfactors/') + .then((response: { status?: any; data: any }) => { + if (response.status === 200) { + const { data } = response; + setSolidManureDropdownOptions(data); + } + }); + }, []); + return (
-

Manure and Imports

+ 0}> + + + + + ))} + + setIsModalVisible(false)} + footer={ + <> + +
); } - -export default ManureAndImports; diff --git a/frontend/src/views/ManureAndCompost/ManureAndImports/manureAndImports.styles.ts b/frontend/src/views/ManureAndCompost/ManureAndImports/manureAndImports.styles.ts index e69de29b..951e4146 100644 --- a/frontend/src/views/ManureAndCompost/ManureAndImports/manureAndImports.styles.ts +++ b/frontend/src/views/ManureAndCompost/ManureAndImports/manureAndImports.styles.ts @@ -0,0 +1,79 @@ +/** + * @summary Styling for ManureAndCompost view + */ +import styled from '@emotion/styled'; + +export const ContentWrapper = styled.div<{ hasManure: boolean }>` + margin-bottom: ${({ hasManure }) => (hasManure ? '170px' : '0')}; +`; + +export const ListItemContainer = styled.div` + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr auto; + gap: 10px; + align-items: center; + margin-bottom: 10px; +`; + +export const ButtonWrapper = styled.div` + bottom: 16px; + right: 16px; + padding: 5px; + button { + width: 100px; + height: 40px; + } +`; + +export const TopRightButtonWrapper = styled.div` + position: absolute; + top: 16px; + right: 16px; + button { + width: 100px; + height: 40px; + } +`; + +export const CenterButtonWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + height: 100px; + button { + width: 100px; + height: 40px; + } +`; + +export const ButtonContainer = styled.div<{ hasManure: boolean }>` + display: flex; + justify-content: ${({ hasManure }) => (hasManure ? 'flex-end' : 'center')}; + margin: 16px 0; + button { + width: 110px; + height: 40px; + } +`; + +export const Header = styled.div` + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr auto; + gap: 10px; + font-weight: bold; + margin-bottom: 10px; + border-bottom: 1px solid #ccc; + padding-bottom: 10px; +`; + +export const Column = styled.div<{ align?: string }>` + text-align: ${({ align }) => (align === 'right' ? 'right' : 'left')}; +`; + +export const ListItem = styled.div<{ align?: string }>` + text-align: ${({ align }) => (align === 'right' ? 'right' : 'left')}; +`; + +export const ErrorText = styled.div` + color: red; +`;