From 70fa07d0a0ee479d1c69f8b2e240d14b168ecec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Alexander=20Str=C3=B8mseng?= Date: Fri, 14 Jun 2024 17:34:33 +0200 Subject: [PATCH 01/11] fix: :bug: fix root package npm run dev (#409) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d65ffd2..f4635ff 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "frontend": "cd frontend && npm run dev", "backend": "cd backend && npm run develop", - "dev": "concurrently \"npm run server\" \"npm run client\"" + "dev": "concurrently \"npm run backend\" \"npm run frontend\"" }, "author": "", "license": "", From c44343929dd63d551ba80ac6414b8e9ded0f4907 Mon Sep 17 00:00:00 2001 From: Graulitard <127958528+Graulitard@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:07:07 +0200 Subject: [PATCH 02/11] #333 orbital graph added (#415) * Fetching data from Space-Track, fixing some bugs, adding cron tasks for updating database with tool functions * Orbital chart done, using backend data without refetching from the backend server * Clean code of orbitalDataGraph, restore strapi files, adding cronTask to the 3rd of each month. * Adding package*.json files * ESLint fixed * Updating strapi env * Reseting frontend/package.json * Prettier checked * Updating for ESlint check --- backend/config/functions/cronTask.js | 37 ++ backend/config/functions/satelliteUtils.js | 54 ++ backend/config/middlewares.js | 12 +- backend/config/server.js | 7 + .../content-types/satellite/schema.json | 3 + .../api/satellite/controllers/satellite.js | 2 +- .../src/api/satellite/services/satellite.js | 5 +- backend/types/generated/contentTypes.d.ts | 1 + frontend/package-lock.json | 197 ++++++- frontend/package.json | 4 +- .../ScrollBarThumb.tsx | 141 +++++ .../[satelliteSlug]/launchDateCountDown.tsx | 2 +- .../[satelliteSlug]/orbitDataGraph.tsx | 496 ++++++++++++++++++ .../app/satellites/[satelliteSlug]/page.tsx | 15 + frontend/src/components/layout/Footer.tsx | 4 +- frontend/src/lib/tada/graphql-env.d.ts | 6 +- package-lock.json | 463 ++++++++++++++++ package.json | 4 + start_project.sh | 0 19 files changed, 1423 insertions(+), 30 deletions(-) create mode 100644 backend/config/functions/cronTask.js create mode 100644 backend/config/functions/satelliteUtils.js create mode 100644 frontend/src/app/satellites/[satelliteSlug]/_orbitDataGraphComponents/ScrollBarThumb.tsx create mode 100644 frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx mode change 100644 => 100755 start_project.sh diff --git a/backend/config/functions/cronTask.js b/backend/config/functions/cronTask.js new file mode 100644 index 0000000..da4c945 --- /dev/null +++ b/backend/config/functions/cronTask.js @@ -0,0 +1,37 @@ +// backend/config/functions/cronTask.js +/* + * Function to fetch data from Space-Track such as Eccentricy, SMA, Inclination every month + * and update the database with the new data + */ +'use strict'; + +const { fetchOrbitalData } = require('./satelliteUtils'); + +module.exports = { + updateAllSatellitesData: { + task: async ({ strapi }) => { + try { + // Fetching all satellites + const satellites = await strapi.entityService.findMany('api::satellite.satellite'); + + // Waiting for all promises to be resolved + await Promise.all( + satellites.map(async satellite => { + try { + setTimeout(async () => { + await fetchOrbitalData(strapi, satellite.id); + }, 10000); + } catch (error) { + console.error(error); + } + }) + ); + } catch (error) { + console.error(error); + } + }, + options: { + rule: "0 0 0 3 * *", // Every month on the 3rd at midnight + }, + }, +}; diff --git a/backend/config/functions/satelliteUtils.js b/backend/config/functions/satelliteUtils.js new file mode 100644 index 0000000..bc9abdc --- /dev/null +++ b/backend/config/functions/satelliteUtils.js @@ -0,0 +1,54 @@ +// backend/utils/satelliteUtils.js +const axios = require('axios'); + +async function fetchOrbitalData(strapi, contextId) { + try { + // Fetching the satellite + const satellite = await strapi.entityService.findOne('api::satellite.satellite', contextId); + const noradId = satellite.catalogNumberNORAD; + + // Authentication to Space-Track + const authResponse = await axios.post('https://www.space-track.org/ajaxauth/login', { + identity: 'floridg@stud.ntnu.no', + password: 'Vm5JxTtD3-hYBdq' + }); + + if (authResponse.status === 200) { + // Fetching data from Space-Track + const satelliteResponse = await axios.get(`https://www.space-track.org/basicspacedata/query/class/gp_history/NORAD_CAT_ID/${noradId}/orderby/TLE_LINE1%20ASC/EPOCH/1950-07-02--2024-07-02/format/json`, { + headers: { + Cookie: authResponse.headers['set-cookie'] + } + }); + + if (satelliteResponse.status === 200) { + // Collecting data + const satelliteData = satelliteResponse.data; + const historicalOrbitalData = satelliteData.map(data => ({ + epoch: data.EPOCH, + inclination: data.INCLINATION, + eccentricity: data.ECCENTRICITY, + semiMajorAxis: data.SEMIMAJOR_AXIS + })); + + // Updating the satellite with the new data + const updatedSatellite = await strapi.entityService.update('api::satellite.satellite', contextId, { + data: { + historicalOrbitalData: historicalOrbitalData, + }, + }); + return updatedSatellite; + } else { + throw new Error('Error while fetching data from Space-Track'); + } + } else { + throw new Error('Authentication failed'); + } + } catch (error) { + console.error('Error while fetching data to Space-Track: ', error); + } +} + +module.exports = { + fetchOrbitalData, +}; diff --git a/backend/config/middlewares.js b/backend/config/middlewares.js index 6eaf586..72ae482 100644 --- a/backend/config/middlewares.js +++ b/backend/config/middlewares.js @@ -5,7 +5,17 @@ module.exports = [ 'strapi::cors', 'strapi::poweredBy', 'strapi::query', - 'strapi::body', + { + name: "strapi::body", + config: { + formLimit: "256mb", // modify form body + jsonLimit: "256mb", // modify JSON body + textLimit: "256mb", // modify text body + formidable: { + maxFileSize: 200 * 1024 * 1024, // multipart data, modify here limit of uploaded file size + }, + }, + }, 'strapi::session', 'strapi::favicon', 'strapi::public', diff --git a/backend/config/server.js b/backend/config/server.js index fe927ab..796c641 100644 --- a/backend/config/server.js +++ b/backend/config/server.js @@ -1,3 +1,5 @@ +const cronTask = require('./functions/cronTask'); + module.exports = ({ env }) => ({ host: env("HOST", "127.0.0.1"), port: env.int("PORT", 1337), @@ -7,4 +9,9 @@ module.exports = ({ env }) => ({ webhooks: { populateRelations: env.bool("WEBHOOKS_POPULATE_RELATIONS", false), }, + cron: { + // Enable or disable the cron tasks + enabled: env.bool("CRON_ENABLED", true), + tasks: cronTask, + }, }); diff --git a/backend/src/api/satellite/content-types/satellite/schema.json b/backend/src/api/satellite/content-types/satellite/schema.json index 166acba..f06a1ec 100644 --- a/backend/src/api/satellite/content-types/satellite/schema.json +++ b/backend/src/api/satellite/content-types/satellite/schema.json @@ -51,6 +51,9 @@ }, "massKg": { "type": "float" + }, + "historicalOrbitalData": { + "type": "json" } } } diff --git a/backend/src/api/satellite/controllers/satellite.js b/backend/src/api/satellite/controllers/satellite.js index d4d610a..0f4851d 100644 --- a/backend/src/api/satellite/controllers/satellite.js +++ b/backend/src/api/satellite/controllers/satellite.js @@ -6,4 +6,4 @@ const { createCoreController } = require('@strapi/strapi').factories; -module.exports = createCoreController('api::satellite.satellite'); +module.exports = createCoreController('api::satellite.satellite'); \ No newline at end of file diff --git a/backend/src/api/satellite/services/satellite.js b/backend/src/api/satellite/services/satellite.js index 6dfd176..409d67a 100644 --- a/backend/src/api/satellite/services/satellite.js +++ b/backend/src/api/satellite/services/satellite.js @@ -4,6 +4,9 @@ * satellite service */ + const { createCoreService } = require('@strapi/strapi').factories; -module.exports = createCoreService('api::satellite.satellite'); +module.exports = { + ...createCoreService('api::satellite.satellite') +}; diff --git a/backend/types/generated/contentTypes.d.ts b/backend/types/generated/contentTypes.d.ts index 8b89107..d247214 100644 --- a/backend/types/generated/contentTypes.d.ts +++ b/backend/types/generated/contentTypes.d.ts @@ -1073,6 +1073,7 @@ export interface ApiSatelliteSatellite extends Schema.CollectionType { slug: Attribute.UID<'api::satellite.satellite', 'name'> & Attribute.Required; massKg: Attribute.Float; + historicalOrbitalData: Attribute.JSON; createdAt: Attribute.DateTime; updatedAt: Attribute.DateTime; publishedAt: Attribute.DateTime; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b9e6f82..d5610dc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@apollo/client": "^3.9.0-alpha.5", "@apollo/experimental-nextjs-app-support": "^0.7.0", - "@gsap/react": "^2.1.0", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", @@ -29,7 +28,7 @@ "@visx/shape": "^3.5.0", "@visx/vendor": "^3.5.0", "add": "^2.0.6", - "chart.js": "^4.4.1", + "chart.js": "^4.4.3", "chartjs-adapter-luxon": "^1.3.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -38,7 +37,6 @@ "framer-motion": "^11.0.24", "globe.gl": "^2.32.2", "gql.tada": "^1.6.2", - "gsap": "^3.12.5", "lucide-react": "^0.314.0", "luxon": "^3.4.4", "next": "14.1.0", @@ -52,10 +50,12 @@ "playwright": "^1.43.1", "qs": "^6.11.2", "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.13", "react-markdown": "^9.0.1", "react-plotly.js": "^2.6.0", + "recharts": "^2.12.7", "satellite.js": "^5.0.0", "shadcn-ui": "^0.8.0", "tailwind-merge": "^2.2.0", @@ -1670,15 +1670,6 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@gsap/react": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@gsap/react/-/react-2.1.0.tgz", - "integrity": "sha512-pwdFXvOM5IsRZXpWTKkQoEjb3/iUjDCU1BCJDlE6pHgVjG+7Ep/7+sszUgqVZ2Jc0mR8gnhtDWyx5cQAT4kwQw==", - "dependencies": { - "gsap": "^3.12.4", - "react": ">=16" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -5337,6 +5328,11 @@ "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==" }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, "node_modules/@types/d3-format": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", @@ -5389,6 +5385,11 @@ "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==" }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -8061,14 +8062,14 @@ } }, "node_modules/chart.js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", - "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", "dependencies": { "@kurkle/color": "^0.3.0" }, "engines": { - "pnpm": ">=7" + "pnpm": ">=8" } }, "node_modules/chartjs-adapter-luxon": { @@ -8969,6 +8970,14 @@ "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", "peer": true }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, "node_modules/d3-force": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", @@ -9206,6 +9215,11 @@ } } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "node_modules/decode-named-character-reference": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", @@ -9421,6 +9435,15 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dompurify": { "version": "2.4.7", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz", @@ -10711,6 +10734,11 @@ "es5-ext": "~0.10.14" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -10819,6 +10847,14 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -11969,11 +12005,6 @@ "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", "peer": true }, - "node_modules/gsap": { - "version": "3.12.5", - "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.12.5.tgz", - "integrity": "sha512-srBfnk4n+Oe/ZnMIOXt3gT605BX9x5+rh/prT2F1SsNJsU1XuMiP0E2aptW481OnonOGACZWBqseH5Z7csHxhQ==" - }, "node_modules/h3-js": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.1.0.tgz", @@ -16009,6 +16040,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -16128,6 +16168,20 @@ } } }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -16150,6 +16204,21 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -16208,6 +16277,36 @@ "node": ">=4" } }, + "node_modules/recharts": { + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.7.tgz", + "integrity": "sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^16.10.2", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -19262,6 +19361,62 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/victory-vendor/node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/victory-vendor/node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/victory-vendor/node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/victory-vendor/node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, "node_modules/vite": { "version": "5.2.9", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.9.tgz", diff --git a/frontend/package.json b/frontend/package.json index ab91f44..c2e1a78 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,7 +37,7 @@ "@visx/shape": "^3.5.0", "@visx/vendor": "^3.5.0", "add": "^2.0.6", - "chart.js": "^4.4.1", + "chart.js": "^4.4.3", "chartjs-adapter-luxon": "^1.3.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -59,10 +59,12 @@ "playwright": "^1.43.1", "qs": "^6.11.2", "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.13", "react-markdown": "^9.0.1", "react-plotly.js": "^2.6.0", + "recharts": "^2.12.7", "satellite.js": "^5.0.0", "shadcn-ui": "^0.8.0", "tailwind-merge": "^2.2.0", diff --git a/frontend/src/app/satellites/[satelliteSlug]/_orbitDataGraphComponents/ScrollBarThumb.tsx b/frontend/src/app/satellites/[satelliteSlug]/_orbitDataGraphComponents/ScrollBarThumb.tsx new file mode 100644 index 0000000..c936914 --- /dev/null +++ b/frontend/src/app/satellites/[satelliteSlug]/_orbitDataGraphComponents/ScrollBarThumb.tsx @@ -0,0 +1,141 @@ +"use client"; + +import React, { useState, useEffect, useRef } from "react"; + +export interface ScrollBarThumbProps { + scrollBarThumbWidth: number; + svgContainerRect: { topLeft: number; width: number; height: number }; + /* eslint-disable no-unused-vars*/ + handleChartScroll: ( + thumbX: number, + svgContainerRect: ScrollBarThumbProps["svgContainerRect"], + ) => void; + /* eslint-enable no-unused-vars*/ +} + +const ScrollBarThumb: React.FC = ({ + scrollBarThumbWidth, + svgContainerRect, + handleChartScroll, +}) => { + const isDragging = useRef(false); + { + /* SB is used for ScrollBar */ + } + const [sBThumbX, setSBThumbX] = useState(0); + const thumbRef = useRef(null); + // Distance between the left of the thumb and the mouse click + const distThumbClick = useRef(null); + + /* Be careful useEffect runs before parent props are received */ + useEffect(() => { + const handleMouseUp = () => { + if (thumbRef.current) { + isDragging.current = false; + } + }; + + const handleMouseMove = (e: MouseEvent) => { + if (isDragging.current && thumbRef.current) { + // Scrollbar starts at the right of the svg container and goes to the left by increasing SBThumbX + setSBThumbX(() => { + // Calculating min and max x positions following the SBThumbX axis for moving the thumb with mouse movement + const minX = 0.5; + const maxX = svgContainerRect.width - scrollBarThumbWidth; + // newPos represents left border of the thumb + const newPos = + svgContainerRect.topLeft + + svgContainerRect.width - + scrollBarThumbWidth - + (e.clientX - + (distThumbClick.current + ? distThumbClick.current + : 0)); + + // If mouse movement isn't in the scrollable area + if (newPos <= minX) { + return minX; + } else if (newPos >= maxX) { + return maxX; + } + return newPos; + }); + + // Change the displayed data on the chart + handleChartScroll( + Math.round( + thumbRef.current.getBoundingClientRect().x * 10, + ) / 10, + svgContainerRect, + ); + } + }; + + window.addEventListener("mouseup", handleMouseUp); + window.addEventListener("mousemove", handleMouseMove); + + // Managing the resize of the thumb + if ( + thumbRef.current && + thumbRef.current.getBoundingClientRect().x < + svgContainerRect.topLeft + ) { + setSBThumbX(svgContainerRect.width - scrollBarThumbWidth); + } + + return () => { + window.removeEventListener("mouseup", handleMouseUp); + window.removeEventListener("mousemove", handleMouseMove); + }; + }, [scrollBarThumbWidth, svgContainerRect]); + + const handleMouseDown = ( + e: React.MouseEvent, + ) => { + // If the thumb is clicked with left mouse button, we start dragging + if (thumbRef.current && e.button === 0) { + isDragging.current = true; + distThumbClick.current = + e.clientX - thumbRef.current.getBoundingClientRect().left; + } + }; + + return ( + <> + + + + + + + ); +}; + +export default ScrollBarThumb; diff --git a/frontend/src/app/satellites/[satelliteSlug]/launchDateCountDown.tsx b/frontend/src/app/satellites/[satelliteSlug]/launchDateCountDown.tsx index e791be4..eef6d79 100644 --- a/frontend/src/app/satellites/[satelliteSlug]/launchDateCountDown.tsx +++ b/frontend/src/app/satellites/[satelliteSlug]/launchDateCountDown.tsx @@ -1,7 +1,7 @@ "use client"; import React, { useState, useEffect } from "react"; -type LaunchDateCountDownProps = { +export type LaunchDateCountDownProps = { launchDate: string | Date | undefined; }; diff --git a/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx b/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx new file mode 100644 index 0000000..5c6295f --- /dev/null +++ b/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx @@ -0,0 +1,496 @@ +"use client"; + +import React, { useState, useLayoutEffect, useRef } from "react"; +import { + XAxis, + CartesianGrid, + Line, + LineChart, + Tooltip, + YAxis, + ResponsiveContainer, + Legend, +} from "recharts"; +import { LaunchDateCountDownProps } from "./launchDateCountDown"; +import ScrollBarThumb, { + ScrollBarThumbProps, +} from "./_orbitDataGraphComponents/ScrollBarThumb"; + +type OrbitDataProps = { + launchDateString: LaunchDateCountDownProps["launchDate"]; + orbitalData: any; +}; + +type ChartData = { + epoch: Date; + inclination: number; + eccentricity: number; + semiMajorAxis: number; +}; + +const OrbitDataGraph: React.FC = ({ + launchDateString, + orbitalData, +}) => { + // href for the svg component, tracking the size of the container + const svgContainer = useRef(null); + const [svgSize, setSvgSize] = useState({ width: 0, height: 200 }); + { + /* SB use for ScrollBar*/ + } + const [scrollBarThumbWidth, setSBThumbWidth] = useState(0); + // scrollBarTimeFrame is how many months the scrollbar thumb represents + const scrollBarTimeFrame = useRef(0); + // Chart Data + const [chartData, setChartData] = useState([]); + + // Handling button for zooming in and out of the graph on a time scale + const launchDate = launchDateString + ? new Date(launchDateString) + : new Date(); + const calculateMonthsDiff = () => { + const currentDate = new Date(); + return ( + currentDate.getMonth() - + launchDate.getMonth() + + 12 * (currentDate.getFullYear() - launchDate.getFullYear()) + ); + }; + + const months = calculateMonthsDiff(); + + const handleZoomClick = (e: React.MouseEvent) => { + // We round the width of the scrollbar thumb at one decimal + const period = e.currentTarget.textContent; + const regExp = new RegExp("^([1234567890]+)([my])$"); + const match = period?.match(regExp); + let SBThumbWidth = 0; + + if (period === "All") { + SBThumbWidth = svgSize.width * 0.8 - 40.5; + scrollBarTimeFrame.current = months; + setSBThumbWidth(SBThumbWidth); + } else { + const number = match ? parseInt(match[1]) : 0; + const periodType = match ? match[2] : ""; + + if (periodType === "m") { + scrollBarTimeFrame.current = number; + SBThumbWidth = + Math.round((svgSize.width * 0.8 * number * 10) / months) / + 10; + setSBThumbWidth(SBThumbWidth); + } else if (periodType === "y") { + scrollBarTimeFrame.current = number * 12; + SBThumbWidth = + Math.round( + (svgSize.width * 0.8 * number * 12 * 10) / months, + ) / 10; + setSBThumbWidth(SBThumbWidth); + } + } + // Updating chart due to resizing the scrollbar thumb + if (svgContainer.current) { + handleChartScroll( + svgContainer.current.getBoundingClientRect().x + + 0.9 * svgContainer.current.getBoundingClientRect().width - + 20.5 - + SBThumbWidth, + { + topLeft: + svgContainer.current.getBoundingClientRect().x + + svgSize.width * 0.1 + + 20.5, + width: svgSize.width * 0.8 - 40.5, + height: 20, + }, + ); + } + }; + + // Callback function for updating the chart when the scrollbar thumb is moved + const handleChartScroll = ( + thumbX: number, + svgContainerRect: ScrollBarThumbProps["svgContainerRect"], + ) => { + // Ratio of the thumb left border position to the svg container width + const dateRatio = + (thumbX - svgContainerRect.topLeft) / svgContainerRect.width; + // Taking the last date of the data period (first date is the launch date) + const lastDataDate = new Date( + orbitalData[orbitalData.length - 1].epoch.slice(0, 23) + "Z", + ); + // Calculating the displayed period in milliseconds + const displayedPeriodMs = lastDataDate.getTime() - launchDate.getTime(); + // Calculating the first and last date of the chart + const firstChartDate = new Date( + launchDate.getTime() + displayedPeriodMs * dateRatio, + ); + const lastChartDate = new Date(firstChartDate); + lastChartDate.setMonth( + firstChartDate.getMonth() + scrollBarTimeFrame.current, + ); + + // Filtering the data to display only the data in the selected period + const filteredData = orbitalData + .filter((data: any) => { + const dataDate = new Date(data.epoch.slice(0, 23) + "Z"); + return dataDate >= firstChartDate && dataDate <= lastChartDate; + }) + .map((data: any) => { + return { + ...data, + epoch: new Date(data.epoch.slice(0, 23) + "Z"), + }; + }); + + setChartData(filteredData); + }; + + // Layout effect to track the size of the container and update the svg size + useLayoutEffect(() => { + const updateSize = () => { + if (svgContainer.current) { + // Update svg container size + const width = svgContainer.current.offsetWidth; + setSvgSize((prevSvgSize) => { + return { width: width, height: prevSvgSize.height }; + }); + // Initially set the scrollbar thumb width to represent 1/10 of the total period + !scrollBarTimeFrame.current + ? (scrollBarTimeFrame.current = Math.round(months / 10)) + : null; + // Setting the scrollbar thumb width + const newSBThumbWidth = + Math.round( + (width * 0.8 * scrollBarTimeFrame.current * 10) / + months, + ) / 10; + setSBThumbWidth(newSBThumbWidth); + handleChartScroll( + svgContainer.current.getBoundingClientRect().x + + 0.9 * + svgContainer.current.getBoundingClientRect().width - + 20.5 - + newSBThumbWidth, + { + topLeft: + svgContainer.current.getBoundingClientRect().x + + width * 0.1 + + 20.5, + width: width * 0.8 - 40.5, + height: 20, + }, + ); + } + }; + window.addEventListener("resize", updateSize); + updateSize(); + + return () => window.removeEventListener("resize", updateSize); + }, []); + + return ( + <> + {orbitalData && ( +
+
+

Zoom :

+ {/* Scrollbar thumb represents the zoom period selected, in case it fits bad we don't display + ie. containerSize > SBThumbWidth > 20px */} + {Math.round((svgSize.width * 0.8 * 1 * 10) / months) / + 10 < + svgSize.width && + Math.round( + (svgSize.width * 0.8 * 1 * 10) / months, + ) / + 10 > + 20 && ( + + )} + {Math.round((svgSize.width * 0.8 * 3 * 10) / months) / + 10 < + svgSize.width && + Math.round( + (svgSize.width * 0.8 * 3 * 10) / months, + ) / + 10 > + 40 && ( + + )} + {Math.round((svgSize.width * 0.8 * 6 * 10) / months) / + 10 < + svgSize.width && + Math.round( + (svgSize.width * 0.8 * 6 * 10) / months, + ) / + 10 > + 40 && ( + + )} + {Math.round((svgSize.width * 0.8 * 12 * 10) / months) / + 10 < + svgSize.width && + Math.round( + (svgSize.width * 0.8 * 12 * 10) / months, + ) / + 10 > + 40 && ( + + )} + {Math.round( + (svgSize.width * 0.8 * 12 * 5 * 10) / months, + ) / + 10 < + svgSize.width && + Math.round( + (svgSize.width * 0.8 * 12 * 5 * 10) / months, + ) / + 10 > + 40 && ( + + )} + {Math.round( + (svgSize.width * 0.8 * 12 * 10 * 10) / months, + ) / + 10 < + svgSize.width && + Math.round( + (svgSize.width * 0.8 * 12 * 10 * 10) / months, + ) / + 10 > + 40 && ( + + )} + {Math.round( + (svgSize.width * 0.8 * 12 * 20 * 10) / months, + ) / + 10 < + svgSize.width && + Math.round( + (svgSize.width * 0.8 * 12 * 20 * 10) / months, + ) / + 10 > + 40 && ( + + )} + + +
+
+ {/* Chart */} + + + + + + { + return new Intl.DateTimeFormat( + "en-US", + { month: "short", day: "numeric" }, + ).format(date); + }} + interval={ + Math.floor(chartData.length / 6) - 1 + } + /> + 0.999 * dataMin, + (dataMax: number) => dataMax * 1.001, + ]} + tick={{ fill: "#8884d8" }} + tickFormatter={(tick: number) => + tick.toFixed(1) + } + tickLine={false} + > + 0.9 * dataMin, + (dataMax: number) => dataMax * 1.1, + ]} + tick={{ fill: "#82ca9d" }} + tickFormatter={(tick: number) => + tick.toFixed(4) + } + tickLine={false} + > + 0.999 * dataMin, + (dataMax: number) => dataMax * 1.001, + ]} + tick={{ fill: "#ff0000" }} + tickFormatter={(tick: number) => + tick.toFixed(0) + } + tickLine={false} + > + + { + return new Intl.DateTimeFormat( + "en-US", + { + month: "short", + day: "numeric", + year: "numeric", + hour: "numeric", + minute: "numeric", + second: "numeric", + }, + ).format(date); + }} + contentStyle={{ backgroundColor: "black" }} + /> + + + + + {/* Scrollbar for time navigation */} + + + + + + + {/* Scrollbar left navigation arrow */} + + + + + {/* Scrollbar right navigation arrow */} + + + + + {/* Scrollbar thumb */} + + + +
+
+ )} + + ); +}; + +export default OrbitDataGraph; diff --git a/frontend/src/app/satellites/[satelliteSlug]/page.tsx b/frontend/src/app/satellites/[satelliteSlug]/page.tsx index 21857ed..5ee8338 100644 --- a/frontend/src/app/satellites/[satelliteSlug]/page.tsx +++ b/frontend/src/app/satellites/[satelliteSlug]/page.tsx @@ -13,6 +13,7 @@ import Image from "next/image"; import { SatelliteNumber } from "@/lib/store"; import { graphql } from "@/lib/tada/graphql"; import { getClient } from "@/lib/ApolloClient"; +import OrbitDataGraph from "./orbitDataGraph"; export interface ProjectOrSatellite { id: string; @@ -154,6 +155,19 @@ export default async function SatelliteInfoPage({ + {/* Orbit data */} +
+ {/*Pass the satNum and the launchDate as props to OrbitDataGraph*/} + {noradId ? ( + satAttributes?.launchDate ? ( + + ) : null + ) : null} +
+ {/* Related projects */}
{relatedProjects?.length != 0 ? ( @@ -189,6 +203,7 @@ const GET_SATELLITE_INFO = graphql(` name massKg missionStatus + historicalOrbitalData satelliteImage { data { attributes { diff --git a/frontend/src/components/layout/Footer.tsx b/frontend/src/components/layout/Footer.tsx index 4d6f1fc..05759fe 100644 --- a/frontend/src/components/layout/Footer.tsx +++ b/frontend/src/components/layout/Footer.tsx @@ -6,6 +6,7 @@ import NTNULogo from "./NTNULogo"; * It includes the NTNU logo, social media links, and contact information. */ export default function Footer() { + const now = new Date(); return (
@@ -50,7 +51,8 @@ export default function Footer() {

- © 2021 NTNU Small Satellite Lab + © 2017 - {now.getFullYear()} NTNU Small + Satellite Lab

diff --git a/frontend/src/lib/tada/graphql-env.d.ts b/frontend/src/lib/tada/graphql-env.d.ts index 942501c..09074e1 100644 --- a/frontend/src/lib/tada/graphql-env.d.ts +++ b/frontend/src/lib/tada/graphql-env.d.ts @@ -79,12 +79,12 @@ export type introspection = { 'PublicationState': { name: 'PublicationState'; enumValues: 'LIVE' | 'PREVIEW'; }; 'Query': { kind: 'OBJECT'; name: 'Query'; fields: { 'article': { name: 'article'; type: { kind: 'OBJECT'; name: 'ArticleEntityResponse'; ofType: null; } }; 'articles': { name: 'articles'; type: { kind: 'OBJECT'; name: 'ArticleEntityResponseCollection'; ofType: null; } }; 'author': { name: 'author'; type: { kind: 'OBJECT'; name: 'AuthorEntityResponse'; ofType: null; } }; 'authors': { name: 'authors'; type: { kind: 'OBJECT'; name: 'AuthorEntityResponseCollection'; ofType: null; } }; 'featuredImage': { name: 'featuredImage'; type: { kind: 'OBJECT'; name: 'FeaturedImageEntityResponse'; ofType: null; } }; 'hero': { name: 'hero'; type: { kind: 'OBJECT'; name: 'HeroEntityResponse'; ofType: null; } }; 'homeFeaturedProjects': { name: 'homeFeaturedProjects'; type: { kind: 'OBJECT'; name: 'HomeFeaturedProjectsEntityResponse'; ofType: null; } }; 'homeMissionStatement': { name: 'homeMissionStatement'; type: { kind: 'OBJECT'; name: 'HomeMissionStatementEntityResponse'; ofType: null; } }; 'i18NLocale': { name: 'i18NLocale'; type: { kind: 'OBJECT'; name: 'I18NLocaleEntityResponse'; ofType: null; } }; 'i18NLocales': { name: 'i18NLocales'; type: { kind: 'OBJECT'; name: 'I18NLocaleEntityResponseCollection'; ofType: null; } }; 'me': { name: 'me'; type: { kind: 'OBJECT'; name: 'UsersPermissionsMe'; ofType: null; } }; 'project': { name: 'project'; type: { kind: 'OBJECT'; name: 'ProjectEntityResponse'; ofType: null; } }; 'projects': { name: 'projects'; type: { kind: 'OBJECT'; name: 'ProjectEntityResponseCollection'; ofType: null; } }; 'satellite': { name: 'satellite'; type: { kind: 'OBJECT'; name: 'SatelliteEntityResponse'; ofType: null; } }; 'satellites': { name: 'satellites'; type: { kind: 'OBJECT'; name: 'SatelliteEntityResponseCollection'; ofType: null; } }; 'uploadFile': { name: 'uploadFile'; type: { kind: 'OBJECT'; name: 'UploadFileEntityResponse'; ofType: null; } }; 'uploadFiles': { name: 'uploadFiles'; type: { kind: 'OBJECT'; name: 'UploadFileEntityResponseCollection'; ofType: null; } }; 'uploadFolder': { name: 'uploadFolder'; type: { kind: 'OBJECT'; name: 'UploadFolderEntityResponse'; ofType: null; } }; 'uploadFolders': { name: 'uploadFolders'; type: { kind: 'OBJECT'; name: 'UploadFolderEntityResponseCollection'; ofType: null; } }; 'usersPermissionsRole': { name: 'usersPermissionsRole'; type: { kind: 'OBJECT'; name: 'UsersPermissionsRoleEntityResponse'; ofType: null; } }; 'usersPermissionsRoles': { name: 'usersPermissionsRoles'; type: { kind: 'OBJECT'; name: 'UsersPermissionsRoleEntityResponseCollection'; ofType: null; } }; 'usersPermissionsUser': { name: 'usersPermissionsUser'; type: { kind: 'OBJECT'; name: 'UsersPermissionsUserEntityResponse'; ofType: null; } }; 'usersPermissionsUsers': { name: 'usersPermissionsUsers'; type: { kind: 'OBJECT'; name: 'UsersPermissionsUserEntityResponseCollection'; ofType: null; } }; }; }; 'ResponseCollectionMeta': { kind: 'OBJECT'; name: 'ResponseCollectionMeta'; fields: { 'pagination': { name: 'pagination'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'Pagination'; ofType: null; }; } }; }; }; - 'Satellite': { kind: 'OBJECT'; name: 'Satellite'; fields: { 'catalogNumberNORAD': { name: 'catalogNumberNORAD'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'content': { name: 'content'; type: { kind: 'SCALAR'; name: 'JSON'; ofType: null; } }; 'createdAt': { name: 'createdAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; 'launchDate': { name: 'launchDate'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; 'massKg': { name: 'massKg'; type: { kind: 'SCALAR'; name: 'Float'; ofType: null; } }; 'missionStatus': { name: 'missionStatus'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'name': { name: 'name'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'projects': { name: 'projects'; type: { kind: 'OBJECT'; name: 'ProjectRelationResponseCollection'; ofType: null; } }; 'publishedAt': { name: 'publishedAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; 'satelliteImage': { name: 'satelliteImage'; type: { kind: 'OBJECT'; name: 'UploadFileEntityResponse'; ofType: null; } }; 'slug': { name: 'slug'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'updatedAt': { name: 'updatedAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; }; }; + 'Satellite': { kind: 'OBJECT'; name: 'Satellite'; fields: { 'catalogNumberNORAD': { name: 'catalogNumberNORAD'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'content': { name: 'content'; type: { kind: 'SCALAR'; name: 'JSON'; ofType: null; } }; 'createdAt': { name: 'createdAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; 'historicalOrbitalData': { name: 'historicalOrbitalData'; type: { kind: 'SCALAR'; name: 'JSON'; ofType: null; } }; 'launchDate': { name: 'launchDate'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; 'massKg': { name: 'massKg'; type: { kind: 'SCALAR'; name: 'Float'; ofType: null; } }; 'missionStatus': { name: 'missionStatus'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'name': { name: 'name'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'projects': { name: 'projects'; type: { kind: 'OBJECT'; name: 'ProjectRelationResponseCollection'; ofType: null; } }; 'publishedAt': { name: 'publishedAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; 'satelliteImage': { name: 'satelliteImage'; type: { kind: 'OBJECT'; name: 'UploadFileEntityResponse'; ofType: null; } }; 'slug': { name: 'slug'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'updatedAt': { name: 'updatedAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; } }; }; }; 'SatelliteEntity': { kind: 'OBJECT'; name: 'SatelliteEntity'; fields: { 'attributes': { name: 'attributes'; type: { kind: 'OBJECT'; name: 'Satellite'; ofType: null; } }; 'id': { name: 'id'; type: { kind: 'SCALAR'; name: 'ID'; ofType: null; } }; }; }; 'SatelliteEntityResponse': { kind: 'OBJECT'; name: 'SatelliteEntityResponse'; fields: { 'data': { name: 'data'; type: { kind: 'OBJECT'; name: 'SatelliteEntity'; ofType: null; } }; }; }; 'SatelliteEntityResponseCollection': { kind: 'OBJECT'; name: 'SatelliteEntityResponseCollection'; fields: { 'data': { name: 'data'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'SatelliteEntity'; ofType: null; }; }; }; } }; 'meta': { name: 'meta'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'ResponseCollectionMeta'; ofType: null; }; } }; }; }; - 'SatelliteFiltersInput': { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; inputFields: [{ name: 'id'; type: { kind: 'INPUT_OBJECT'; name: 'IDFilterInput'; ofType: null; }; defaultValue: null }, { name: 'name'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'catalogNumberNORAD'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'content'; type: { kind: 'INPUT_OBJECT'; name: 'JSONFilterInput'; ofType: null; }; defaultValue: null }, { name: 'projects'; type: { kind: 'INPUT_OBJECT'; name: 'ProjectFiltersInput'; ofType: null; }; defaultValue: null }, { name: 'missionStatus'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'launchDate'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'slug'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'massKg'; type: { kind: 'INPUT_OBJECT'; name: 'FloatFilterInput'; ofType: null; }; defaultValue: null }, { name: 'createdAt'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'updatedAt'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'publishedAt'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'and'; type: { kind: 'LIST'; name: never; ofType: { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; ofType: null; }; }; defaultValue: null }, { name: 'or'; type: { kind: 'LIST'; name: never; ofType: { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; ofType: null; }; }; defaultValue: null }, { name: 'not'; type: { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; ofType: null; }; defaultValue: null }]; }; - 'SatelliteInput': { kind: 'INPUT_OBJECT'; name: 'SatelliteInput'; inputFields: [{ name: 'name'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'catalogNumberNORAD'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'content'; type: { kind: 'SCALAR'; name: 'JSON'; ofType: null; }; defaultValue: null }, { name: 'satelliteImage'; type: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; defaultValue: null }, { name: 'projects'; type: { kind: 'LIST'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; }; defaultValue: null }, { name: 'missionStatus'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'launchDate'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; defaultValue: null }, { name: 'slug'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'massKg'; type: { kind: 'SCALAR'; name: 'Float'; ofType: null; }; defaultValue: null }, { name: 'publishedAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; defaultValue: null }]; }; + 'SatelliteFiltersInput': { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; inputFields: [{ name: 'id'; type: { kind: 'INPUT_OBJECT'; name: 'IDFilterInput'; ofType: null; }; defaultValue: null }, { name: 'name'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'catalogNumberNORAD'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'content'; type: { kind: 'INPUT_OBJECT'; name: 'JSONFilterInput'; ofType: null; }; defaultValue: null }, { name: 'projects'; type: { kind: 'INPUT_OBJECT'; name: 'ProjectFiltersInput'; ofType: null; }; defaultValue: null }, { name: 'missionStatus'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'launchDate'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'slug'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'massKg'; type: { kind: 'INPUT_OBJECT'; name: 'FloatFilterInput'; ofType: null; }; defaultValue: null }, { name: 'historicalOrbitalData'; type: { kind: 'INPUT_OBJECT'; name: 'JSONFilterInput'; ofType: null; }; defaultValue: null }, { name: 'createdAt'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'updatedAt'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'publishedAt'; type: { kind: 'INPUT_OBJECT'; name: 'DateTimeFilterInput'; ofType: null; }; defaultValue: null }, { name: 'and'; type: { kind: 'LIST'; name: never; ofType: { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; ofType: null; }; }; defaultValue: null }, { name: 'or'; type: { kind: 'LIST'; name: never; ofType: { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; ofType: null; }; }; defaultValue: null }, { name: 'not'; type: { kind: 'INPUT_OBJECT'; name: 'SatelliteFiltersInput'; ofType: null; }; defaultValue: null }]; }; + 'SatelliteInput': { kind: 'INPUT_OBJECT'; name: 'SatelliteInput'; inputFields: [{ name: 'name'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'catalogNumberNORAD'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'content'; type: { kind: 'SCALAR'; name: 'JSON'; ofType: null; }; defaultValue: null }, { name: 'satelliteImage'; type: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; defaultValue: null }, { name: 'projects'; type: { kind: 'LIST'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; }; defaultValue: null }, { name: 'missionStatus'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'launchDate'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; defaultValue: null }, { name: 'slug'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'massKg'; type: { kind: 'SCALAR'; name: 'Float'; ofType: null; }; defaultValue: null }, { name: 'historicalOrbitalData'; type: { kind: 'SCALAR'; name: 'JSON'; ofType: null; }; defaultValue: null }, { name: 'publishedAt'; type: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; defaultValue: null }]; }; 'SatelliteRelationResponseCollection': { kind: 'OBJECT'; name: 'SatelliteRelationResponseCollection'; fields: { 'data': { name: 'data'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'SatelliteEntity'; ofType: null; }; }; }; } }; }; }; 'String': unknown; 'StringFilterInput': { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; inputFields: [{ name: 'and'; type: { kind: 'LIST'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'or'; type: { kind: 'LIST'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'not'; type: { kind: 'INPUT_OBJECT'; name: 'StringFilterInput'; ofType: null; }; defaultValue: null }, { name: 'eq'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'eqi'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'ne'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'nei'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'startsWith'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'endsWith'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'contains'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'notContains'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'containsi'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'notContainsi'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'gt'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'gte'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'lt'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'lte'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'null'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; defaultValue: null }, { name: 'notNull'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; defaultValue: null }, { name: 'in'; type: { kind: 'LIST'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'notIn'; type: { kind: 'LIST'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'between'; type: { kind: 'LIST'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }]; }; diff --git a/package-lock.json b/package-lock.json index 35c0c79..3badb7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,12 @@ "name": "it2901-smallsatlab-hypso", "version": "1.0.0", "dependencies": { + "@types/recharts": "^1.8.29", + "ci": "^2.3.0", "concurrently": "^8.2.2", + "node-schedule": "^2.1.1", "openapi-typescript": "^6.7.4", + "recharts": "^2.12.7", "three-glow-mesh": "^0.1.2" } }, @@ -64,6 +68,96 @@ "node": ">= 8" } }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/recharts": { + "version": "1.8.29", + "resolved": "https://registry.npmjs.org/@types/recharts/-/recharts-1.8.29.tgz", + "integrity": "sha512-ulKklaVsnFIIhTQsQw226TnOibrddW1qUQNFVhoQEyY1Z7FRQrNecFCGt7msRuJseudzE9czVawZb17dK/aPXw==", + "dependencies": { + "@types/d3-shape": "^1", + "@types/react": "*" + } + }, + "node_modules/@types/recharts/node_modules/@types/d3-path": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.11.tgz", + "integrity": "sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==" + }, + "node_modules/@types/recharts/node_modules/@types/d3-shape": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.12.tgz", + "integrity": "sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==", + "dependencies": { + "@types/d3-path": "^1" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -136,6 +230,17 @@ "node": ">=8" } }, + "node_modules/ci": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ci/-/ci-2.3.0.tgz", + "integrity": "sha512-0MGXkzJKkwV3enG7RUxjJKdiAkbaZ7visCjitfpCN2BQjv02KGRMxCHLv4RPokkjJ4xR33FLMAXweS+aQ0pFSQ==", + "bin": { + "ci": "dist/cli.js" + }, + "funding": { + "url": "https://github.com/privatenumber/ci?sponsor=1" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -149,6 +254,14 @@ "node": ">=12" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -205,6 +318,132 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -220,6 +459,20 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -233,6 +486,19 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -294,6 +560,14 @@ "node": ">=8" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -329,6 +603,11 @@ "node": ">=0.12.0" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -345,6 +624,30 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -365,6 +668,27 @@ "node": ">=8.6" } }, + "node_modules/node-schedule": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", + "dependencies": { + "cron-parser": "^4.2.0", + "long-timeout": "0.1.1", + "sorted-array-functions": "^1.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/openapi-typescript": { "version": "6.7.4", "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.7.4.tgz", @@ -392,6 +716,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -411,6 +745,95 @@ } ] }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/recharts": { + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.7.tgz", + "integrity": "sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^16.10.2", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -463,6 +886,15 @@ "tslib": "^2.1.0" } }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/shell-quote": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", @@ -471,6 +903,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sorted-array-functions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", + "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==" + }, "node_modules/spawn-command": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", @@ -525,6 +962,11 @@ "three": ">= 0.102.0" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -560,6 +1002,27 @@ "node": ">=14.0" } }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index f4635ff..27d4d0e 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,12 @@ "author": "", "license": "", "dependencies": { + "@types/recharts": "^1.8.29", + "ci": "^2.3.0", "concurrently": "^8.2.2", + "node-schedule": "^2.1.1", "openapi-typescript": "^6.7.4", + "recharts": "^2.12.7", "three-glow-mesh": "^0.1.2" } } diff --git a/start_project.sh b/start_project.sh old mode 100644 new mode 100755 From 3ad2de8f22211ee277966dc7c9043cfa316e4e28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:22:31 +0200 Subject: [PATCH 03/11] build(deps-dev): bump ws from 8.16.0 to 8.18.0 in /frontend (#416) Bumps [ws](https://github.com/websockets/ws) from 8.16.0 to 8.18.0. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.16.0...8.18.0) --- updated-dependencies: - dependency-name: ws dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frontend/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d5610dc..675d61c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20321,9 +20321,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "engines": { "node": ">=10.0.0" From a6f2865294fb93732f842296308d6e7b89a30174 Mon Sep 17 00:00:00 2001 From: Graulitard <127958528+Graulitard@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:25:53 +0200 Subject: [PATCH 04/11] Fixing deployment issue (#417) * Fetching data from Space-Track, fixing some bugs, adding cron tasks for updating database with tool functions * Orbital chart done, using backend data without refetching from the backend server * Clean code of orbitalDataGraph, restore strapi files, adding cronTask to the 3rd of each month. * Adding package*.json files * ESLint fixed * Updating strapi env * Reseting frontend/package.json * Prettier checked * Updating for ESlint check * Adding backend env file --- backend/.env | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 backend/.env diff --git a/backend/.env b/backend/.env new file mode 100644 index 0000000..83d5b8d --- /dev/null +++ b/backend/.env @@ -0,0 +1,14 @@ +# All these should be set in the GitHub Repository actions and secrets at https://github.com/NTNU-SmallSat-Lab/outreach-website/settings/variables/actions +# Any changes done here will not be reflected in the production environment +# All variables named toBeGenerated should be generated with the command `openssl rand -base64 32` +HOST=0.0.0.0 +PORT=1337 +STRAPI_URL="https://hypso.space/strapi/" +APP_KEYS="LlikgA/Dce0U0qy3b3jp5FwdipVsgLrUlbC4EiJczsg=,rweQcOIfQvkiQAcOPjRujpitslVAEesx4fkT09qMhNY=" +API_TOKEN_SALT="Nh97EoxmLk6zqzG5HXn/9NvpPHeTNs8Sz2XHIXGry1A=" +ADMIN_JWT_SECRET="jqFr2Ocz4j7xqK/wJMdfq+QSIlEnIuNchX3l0PD9bqk=" +TRANSFER_TOKEN_SALT="3JKja5Orq7jWr+HOfF/VKLgL9o2rvgX14NnOfskzo/k=" +JWT_SECRET="VHe12SBqQRQcnIAhUMbMfCbBLj8EvIkmcGRO7FZKMPM=" + +DATABASE_CLIENT=sqlite +DATABASE_FILENAME=dbLocation.sqlite # in dev, will use backend root dir, in prod, will be from server os root dir so should be /var/data/strapi.db or similar From b3c397e817875164b0c6807856dfd3ebedc7b2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Alexander=20Str=C3=B8mseng?= Date: Wed, 24 Jul 2024 19:16:17 +0200 Subject: [PATCH 05/11] feat(CI/CD): Try to enable manual redeployment runs --- .github/workflows/autoredeploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/autoredeploy.yml b/.github/workflows/autoredeploy.yml index 59e5abf..75dbca4 100644 --- a/.github/workflows/autoredeploy.yml +++ b/.github/workflows/autoredeploy.yml @@ -2,6 +2,7 @@ name: Server auto deploy on: push: branches: ["main"] + workflow_dispatch: jobs: docker-build: From 0ae44adfec2089aed135ec63f1d00640edff96ff Mon Sep 17 00:00:00 2001 From: Graulitard <127958528+Graulitard@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:48:35 +0200 Subject: [PATCH 06/11] Fix last bugs (#418) * Fetching data from Space-Track, fixing some bugs, adding cron tasks for updating database with tool functions * Orbital chart done, using backend data without refetching from the backend server * Clean code of orbitalDataGraph, restore strapi files, adding cronTask to the 3rd of each month. * Adding package*.json files * ESLint fixed * Updating strapi env * Reseting frontend/package.json * Prettier checked * Updating for ESlint check * Adding backend env file From 44532e2936c6d45e221866cc3affaa627565c7ab Mon Sep 17 00:00:00 2001 From: Graulitard <127958528+Graulitard@users.noreply.github.com> Date: Mon, 29 Jul 2024 11:22:48 +0200 Subject: [PATCH 07/11] Updating for security reason (#419) * Fetching data from Space-Track, fixing some bugs, adding cron tasks for updating database with tool functions * Orbital chart done, using backend data without refetching from the backend server * Clean code of orbitalDataGraph, restore strapi files, adding cronTask to the 3rd of each month. * Adding package*.json files * ESLint fixed * Updating strapi env * Reseting frontend/package.json * Prettier checked * Updating for ESlint check * Adding backend env file * Revert "Adding backend env file" This reverts commit 88a46fb157ab99a06248e064b1c228fdde788dd0. From fe064c8c65f32d8c095666a310d3c29d3dd4ee0b Mon Sep 17 00:00:00 2001 From: Florian Graule Date: Mon, 29 Jul 2024 11:39:52 +0200 Subject: [PATCH 08/11] Update for cleaning main branch This reverts commit a6f2865294fb93732f842296308d6e7b89a30174. --- backend/.env | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 backend/.env diff --git a/backend/.env b/backend/.env deleted file mode 100644 index 83d5b8d..0000000 --- a/backend/.env +++ /dev/null @@ -1,14 +0,0 @@ -# All these should be set in the GitHub Repository actions and secrets at https://github.com/NTNU-SmallSat-Lab/outreach-website/settings/variables/actions -# Any changes done here will not be reflected in the production environment -# All variables named toBeGenerated should be generated with the command `openssl rand -base64 32` -HOST=0.0.0.0 -PORT=1337 -STRAPI_URL="https://hypso.space/strapi/" -APP_KEYS="LlikgA/Dce0U0qy3b3jp5FwdipVsgLrUlbC4EiJczsg=,rweQcOIfQvkiQAcOPjRujpitslVAEesx4fkT09qMhNY=" -API_TOKEN_SALT="Nh97EoxmLk6zqzG5HXn/9NvpPHeTNs8Sz2XHIXGry1A=" -ADMIN_JWT_SECRET="jqFr2Ocz4j7xqK/wJMdfq+QSIlEnIuNchX3l0PD9bqk=" -TRANSFER_TOKEN_SALT="3JKja5Orq7jWr+HOfF/VKLgL9o2rvgX14NnOfskzo/k=" -JWT_SECRET="VHe12SBqQRQcnIAhUMbMfCbBLj8EvIkmcGRO7FZKMPM=" - -DATABASE_CLIENT=sqlite -DATABASE_FILENAME=dbLocation.sqlite # in dev, will use backend root dir, in prod, will be from server os root dir so should be /var/data/strapi.db or similar From 9d17fd26ea0a28e8d0812ecbe20506e2b1212caf Mon Sep 17 00:00:00 2001 From: Graulitard <127958528+Graulitard@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:56:35 +0200 Subject: [PATCH 09/11] Fix cron jobs issue and update footer information (#420) * Fetching data from Space-Track, fixing some bugs, adding cron tasks for updating database with tool functions * Orbital chart done, using backend data without refetching from the backend server * Clean code of orbitalDataGraph, restore strapi files, adding cronTask to the 3rd of each month. * Adding package*.json files * ESLint fixed * Updating strapi env * Reseting frontend/package.json * Prettier checked * Updating for ESlint check * Adding backend env file * Revert "Adding backend env file" This reverts commit 88a46fb157ab99a06248e064b1c228fdde788dd0. * Try fixing cron job, error caused by Strapi reloading after updating db * Fix cron jobs issue and update Footer info --- backend/config/functions/cronTask.js | 38 ++++++++++++++-------- backend/config/functions/satelliteUtils.js | 23 +++---------- frontend/src/components/layout/Footer.tsx | 14 +++----- 3 files changed, 33 insertions(+), 42 deletions(-) diff --git a/backend/config/functions/cronTask.js b/backend/config/functions/cronTask.js index da4c945..55d1b98 100644 --- a/backend/config/functions/cronTask.js +++ b/backend/config/functions/cronTask.js @@ -11,23 +11,33 @@ module.exports = { updateAllSatellitesData: { task: async ({ strapi }) => { try { - // Fetching all satellites - const satellites = await strapi.entityService.findMany('api::satellite.satellite'); - - // Waiting for all promises to be resolved + // Fetch all satellites + const satellites = await strapi.entityService.findMany('api::satellite.satellite', { + fields: ['id', 'catalogNumberNORAD'], + filters: { + catalogNumberNORAD: { $ne: null }, + } + }); await Promise.all( - satellites.map(async satellite => { - try { - setTimeout(async () => { - await fetchOrbitalData(strapi, satellite.id); - }, 10000); - } catch (error) { - console.error(error); - } - }) - ); + satellites.map(async (satellite) => { + const fetchedData = await fetchOrbitalData(satellite.catalogNumberNORAD); + return { id: satellite.id, historicalOrbitalData: fetchedData }; + })).then(async (historicalOrbitalData) => { + await strapi.db.transaction(async (trx) => { + // Fetch data for each satellite + historicalOrbitalData.map(async (satellite) => { + // Update the database with the new data + const updatedSat = await strapi.entityService.update('api::satellite.satellite', satellite.id, { + data: { + historicalOrbitalData: satellite.historicalOrbitalData, + }, + }, { trx }); + }) + }); + }) } catch (error) { console.error(error); + return; } }, options: { diff --git a/backend/config/functions/satelliteUtils.js b/backend/config/functions/satelliteUtils.js index bc9abdc..c98c0b9 100644 --- a/backend/config/functions/satelliteUtils.js +++ b/backend/config/functions/satelliteUtils.js @@ -1,12 +1,8 @@ // backend/utils/satelliteUtils.js const axios = require('axios'); -async function fetchOrbitalData(strapi, contextId) { +async function fetchOrbitalData(noradId) { try { - // Fetching the satellite - const satellite = await strapi.entityService.findOne('api::satellite.satellite', contextId); - const noradId = satellite.catalogNumberNORAD; - // Authentication to Space-Track const authResponse = await axios.post('https://www.space-track.org/ajaxauth/login', { identity: 'floridg@stud.ntnu.no', @@ -15,7 +11,9 @@ async function fetchOrbitalData(strapi, contextId) { if (authResponse.status === 200) { // Fetching data from Space-Track - const satelliteResponse = await axios.get(`https://www.space-track.org/basicspacedata/query/class/gp_history/NORAD_CAT_ID/${noradId}/orderby/TLE_LINE1%20ASC/EPOCH/1950-07-02--2024-07-02/format/json`, { + + const today = new Date(); + const satelliteResponse = await axios.get(`https://www.space-track.org/basicspacedata/query/class/gp_history/NORAD_CAT_ID/${noradId}/orderby/TLE_LINE1%20ASC/orderby/TLE_LINE1%20ASC/format/json`, { headers: { Cookie: authResponse.headers['set-cookie'] } @@ -30,19 +28,8 @@ async function fetchOrbitalData(strapi, contextId) { eccentricity: data.ECCENTRICITY, semiMajorAxis: data.SEMIMAJOR_AXIS })); - - // Updating the satellite with the new data - const updatedSatellite = await strapi.entityService.update('api::satellite.satellite', contextId, { - data: { - historicalOrbitalData: historicalOrbitalData, - }, - }); - return updatedSatellite; - } else { - throw new Error('Error while fetching data from Space-Track'); + return historicalOrbitalData; } - } else { - throw new Error('Authentication failed'); } } catch (error) { console.error('Error while fetching data to Space-Track: ', error); diff --git a/frontend/src/components/layout/Footer.tsx b/frontend/src/components/layout/Footer.tsx index 05759fe..d91613b 100644 --- a/frontend/src/components/layout/Footer.tsx +++ b/frontend/src/components/layout/Footer.tsx @@ -18,28 +18,22 @@ export default function Footer() {
From ea768b302ebcfc6fbcbec24e9ccd3095c363a5bc Mon Sep 17 00:00:00 2001 From: Graulitard <127958528+Graulitard@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:25:48 +0200 Subject: [PATCH 10/11] Florian (#421) * Fetching data from Space-Track, fixing some bugs, adding cron tasks for updating database with tool functions * Orbital chart done, using backend data without refetching from the backend server * Clean code of orbitalDataGraph, restore strapi files, adding cronTask to the 3rd of each month. * Adding package*.json files * ESLint fixed * Updating strapi env * Reseting frontend/package.json * Prettier checked * Updating for ESlint check * Adding backend env file * Revert "Adding backend env file" This reverts commit 88a46fb157ab99a06248e064b1c228fdde788dd0. * Try fixing cron job, error caused by Strapi reloading after updating db * Fix cron jobs issue and update Footer info * Fixing not available satellites --- backend/config/functions/satelliteUtils.js | 1 - .../app/satellites/SatelliteResponsiveTable.tsx | 17 ++++++++--------- .../[satelliteSlug]/orbitDataGraph.tsx | 5 +++++ .../src/app/satellites/[satelliteSlug]/page.tsx | 5 +++-- frontend/src/components/layout/Footer.tsx | 2 +- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/backend/config/functions/satelliteUtils.js b/backend/config/functions/satelliteUtils.js index c98c0b9..a43f2af 100644 --- a/backend/config/functions/satelliteUtils.js +++ b/backend/config/functions/satelliteUtils.js @@ -11,7 +11,6 @@ async function fetchOrbitalData(noradId) { if (authResponse.status === 200) { // Fetching data from Space-Track - const today = new Date(); const satelliteResponse = await axios.get(`https://www.space-track.org/basicspacedata/query/class/gp_history/NORAD_CAT_ID/${noradId}/orderby/TLE_LINE1%20ASC/orderby/TLE_LINE1%20ASC/format/json`, { headers: { diff --git a/frontend/src/app/satellites/SatelliteResponsiveTable.tsx b/frontend/src/app/satellites/SatelliteResponsiveTable.tsx index 72bd56d..484472e 100644 --- a/frontend/src/app/satellites/SatelliteResponsiveTable.tsx +++ b/frontend/src/app/satellites/SatelliteResponsiveTable.tsx @@ -99,15 +99,14 @@ export default function SatelliteResponsiveTable({ /> )) : (satellites ?? []).map((satellite) => ( - - handleRowClick( - satellite.attributes?.slug ?? "", - ) - } - > + + handleRowClick(satellite.attributes?.slug ?? "") + } : {})} + > {satellite.attributes?.name} diff --git a/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx b/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx index 5c6295f..b97b3b9 100644 --- a/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx +++ b/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx @@ -194,6 +194,11 @@ const OrbitDataGraph: React.FC = ({ <> {orbitalData && (
+
+

Orbital parameters history (source :

+ Space Track +

)

+

Zoom :

{/* Scrollbar thumb represents the zoom period selected, in case it fits bad we don't display diff --git a/frontend/src/app/satellites/[satelliteSlug]/page.tsx b/frontend/src/app/satellites/[satelliteSlug]/page.tsx index 5ee8338..f25c948 100644 --- a/frontend/src/app/satellites/[satelliteSlug]/page.tsx +++ b/frontend/src/app/satellites/[satelliteSlug]/page.tsx @@ -155,9 +155,10 @@ export default async function SatelliteInfoPage({
- {/* Orbit data */} + + {/* Container for graph of historical orbital data */}
- {/*Pass the satNum and the launchDate as props to OrbitDataGraph*/} + {/*Pass the historicalData and the launchDate as props to OrbitDataGraph*/} {noradId ? ( satAttributes?.launchDate ? (
- NTNU Small Satellite Lab + NTNU Small Satellite Lab Trondheim, Norway

Norwegian University of Science and Technology

From 59a34329faf181f09df0b5e3283c3783b48c4730 Mon Sep 17 00:00:00 2001 From: Graulitard <127958528+Graulitard@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:26:00 +0200 Subject: [PATCH 11/11] Fix featured projects preview image bug, prettier checked (#422) * Fetching data from Space-Track, fixing some bugs, adding cron tasks for updating database with tool functions * Orbital chart done, using backend data without refetching from the backend server * Clean code of orbitalDataGraph, restore strapi files, adding cronTask to the 3rd of each month. * Adding package*.json files * ESLint fixed * Updating strapi env * Reseting frontend/package.json * Prettier checked * Updating for ESlint check * Try fixing cron job, error caused by Strapi reloading after updating db * Fix cron jobs issue and update Footer info * Fixing not available satellites * Fix FeaturedProjects preview images bug * Prettier updated --- .../app/_homeComponents/FeaturedProjects.tsx | 17 +++++++------- .../satellites/SatelliteResponsiveTable.tsx | 22 ++++++++++++------- .../[satelliteSlug]/orbitDataGraph.tsx | 9 ++++++-- frontend/src/components/layout/Footer.tsx | 7 +++++- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/frontend/src/app/_homeComponents/FeaturedProjects.tsx b/frontend/src/app/_homeComponents/FeaturedProjects.tsx index 11af6d0..69fff6b 100644 --- a/frontend/src/app/_homeComponents/FeaturedProjects.tsx +++ b/frontend/src/app/_homeComponents/FeaturedProjects.tsx @@ -19,14 +19,6 @@ export default async function FeaturedProjects() { featuredProjects?.featuredProject3, ]; - let image_url = undefined; - if (STRAPI_URL) { - image_url = - STRAPI_URL + - featuredProjects?.featuredProject1?.data?.attributes?.previewImage - ?.data?.attributes?.url; - } - return (

@@ -50,6 +42,13 @@ export default async function FeaturedProjects() { if (!project?.data?.attributes?.title) { return null; } + let previewImage = + project?.data?.attributes?.previewImage?.data + ?.attributes?.url; + + if (STRAPI_URL && previewImage != undefined) { + previewImage = STRAPI_URL + previewImage; + } return ( ); })} diff --git a/frontend/src/app/satellites/SatelliteResponsiveTable.tsx b/frontend/src/app/satellites/SatelliteResponsiveTable.tsx index 484472e..8010028 100644 --- a/frontend/src/app/satellites/SatelliteResponsiveTable.tsx +++ b/frontend/src/app/satellites/SatelliteResponsiveTable.tsx @@ -99,14 +99,20 @@ export default function SatelliteResponsiveTable({ /> )) : (satellites ?? []).map((satellite) => ( - - handleRowClick(satellite.attributes?.slug ?? "") - } : {})} - > + + handleRowClick( + satellite.attributes + ?.slug ?? "", + ), + } + : {})} + > + {satellite.attributes?.name} diff --git a/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx b/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx index b97b3b9..3d368be 100644 --- a/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx +++ b/frontend/src/app/satellites/[satelliteSlug]/orbitDataGraph.tsx @@ -194,9 +194,14 @@ const OrbitDataGraph: React.FC = ({ <> {orbitalData && (
-
+

Orbital parameters history (source :

- Space Track + + Space Track +

)

diff --git a/frontend/src/components/layout/Footer.tsx b/frontend/src/components/layout/Footer.tsx index 87b85a0..bdb23f9 100644 --- a/frontend/src/components/layout/Footer.tsx +++ b/frontend/src/components/layout/Footer.tsx @@ -53,7 +53,12 @@ export default function Footer() {
- NTNU Small Satellite Lab + + NTNU Small Satellite Lab + Trondheim, Norway

Norwegian University of Science and Technology