From e5c526a80fc59e675818fff26bba5465e04fa297 Mon Sep 17 00:00:00 2001 From: Kristian Harju Date: Fri, 27 Feb 2026 14:21:42 +0200 Subject: [PATCH 1/7] Add instructions to the card footer in the info panel card --- ui/.eslintrc.json | 1 + ui/src/App.css | 193 ++---------------- ui/src/App.jsx | 110 ++++------ ui/src/components/Footer.jsx | 1 - ui/src/components/Header.jsx | 1 - ui/src/components/InfoPanelCard.css | 299 ++++++++++++++++++++++++++++ ui/src/components/InfoPanelCard.jsx | 65 ++++++ 7 files changed, 415 insertions(+), 255 deletions(-) create mode 100644 ui/src/components/InfoPanelCard.css create mode 100644 ui/src/components/InfoPanelCard.jsx diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 64c0f28..6e13c48 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -23,6 +23,7 @@ }, "plugins": ["react-refresh"], "rules": { + "react/prop-types": "off", "react/jsx-no-target-blank": "off", "react-refresh/only-export-components": [ "warn", diff --git a/ui/src/App.css b/ui/src/App.css index 8b7e19d..2c28d9f 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -11,13 +11,19 @@ --color-white: #FFFFFF; --color-black: #000000; --color-yellow: #F1B828; + --color-yellow-hover: #e0a71f; + --color-yellow-active: #c99319; + --color-red: #bf6366; + --color-red-hover: #a65558; + --color-red-active: #8d484b; + --color-white-transparent: rgba(255, 255, 255, 0.1); } .App { min-height: 100vh; display: flex; flex-direction: column; - /* Desktop background (default) */ + /* Desktop background (default) */ background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0.00) 15.58%), radial-gradient(68.05% 68.05% at 50.79% 4.4%, rgba(12, 59, 65, 0.30) 0%, #0C3B41 100%), @@ -28,13 +34,6 @@ background-attachment: fixed; } -#infoPanel { - text-align: left; - font-style: italic; - font-weight: bold; - color: rgb(126, 52, 52); -} - /* Button Group Container */ .button-group { display: flex; @@ -65,12 +64,12 @@ } .btn--yellow:hover { - background: #e0a71f !important; + background: var(--color-yellow-hover) !important; border: 4px solid var(--color-white) !important; } .btn--yellow:active { - background: #c99319 !important; + background: var(--color-yellow-active) !important; } .btn--yellow:focus { @@ -109,7 +108,7 @@ /* Button Styles - Red (Delete API key) */ .btn--red { - background: #bf6366 !important; + background: var(--color-red) !important; border: 4px solid var(--color-white) !important; color: var(--color-white) !important; font-family: Heebo, sans-serif !important; @@ -121,12 +120,12 @@ } .btn--red:hover { - background: #a65558 !important; + background: var(--color-red-hover) !important; border: 4px solid var(--color-white) !important; } .btn--red:active { - background: #8d484b !important; + background: var(--color-red-active) !important; } .btn--red:focus { @@ -136,7 +135,7 @@ } /* Button Styles - Green (Logout) */ -.btn--green{ +.btn--green { background: var(--color-sherpa800) !important; border: 4px solid var(--color-white) !important; color: var(--color-white) !important; @@ -151,7 +150,7 @@ .btn--green:hover { border-width: 2px !important; padding: 15px 25px !important; - background: rgba(255, 255, 255, 0.1) !important; + background: var(--color-white-transparent) !important; } .btn--green:active { @@ -184,110 +183,6 @@ h3 { text-align: center; } -/* Card Styles */ -.p-card { - background: var(--color-sherpa800) !important; - border: 1px solid var(--color-sherpa600) !important; - border-radius: 8px !important; - box-shadow: none !important; -} - -.p-card .p-card-body { - padding: 32px !important; - color: var(--color-white) !important; -} - -.p-card .p-card-content { - color: var(--color-white) !important; - font-family: 'Heebo', sans-serif !important; - font-size: 16px !important; - line-height: 24px !important; - min-height: 200px; -} - -/* DataTable Styles */ -.p-datatable { - background: var(--color-sherpa800) !important; - border: 1px solid var(--color-sherpa600) !important; - border-radius: 8px !important; - overflow: hidden !important; - width: 100% !important; - table-layout: fixed !important; -} - -.p-datatable .p-datatable-table { - width: 100% !important; - table-layout: fixed !important; -} - -.p-datatable .p-datatable-header { - background: var(--color-sherpa700) !important; - border-bottom: 1px solid var(--color-sherpa600) !important; - color: var(--color-white) !important; - padding: 16px !important; -} - -.p-datatable .p-datatable-thead > tr > th { - background: var(--color-sherpa700) !important; - border: 1px solid var(--color-sherpa600) !important; - color: var(--color-white) !important; - font-family: 'Exo 2', sans-serif !important; - font-size: 16px !important; - font-weight: 600 !important; - padding: 16px !important; - box-sizing: border-box !important; -} - -.p-datatable .p-datatable-tbody > tr { - background: var(--color-sherpa800) !important; - color: var(--color-white) !important; -} - -.p-datatable .p-datatable-tbody > tr > td { - border: 1px solid var(--color-sherpa600) !important; - padding: 16px !important; - font-family: 'Heebo', sans-serif !important; - font-size: 16px !important; - overflow-wrap: break-word !important; - word-wrap: break-word !important; - box-sizing: border-box !important; -} - -.p-datatable .p-datatable-tbody > tr:hover { - background: rgba(255, 255, 255, 0.05) !important; -} - -/* Empty message in DataTable */ -.p-datatable .p-datatable-emptymessage > td { - color: var(--color-sherpa400) !important; -} - -/* DataTable Column Widths */ - .p-datatable .p-datatable-thead > tr > th:nth-child(1), - .p-datatable .p-datatable-tbody > tr > td:nth-child(1), - .p-datatable .route-column { - width: 60% !important; - } - - .p-datatable .p-datatable-thead > tr > th:nth-child(2), - .p-datatable .p-datatable-tbody > tr > td:nth-child(2), - .p-datatable .limits-column { - width: 40% !important; - } - -/* Info Panel Styling */ -#infoPanel { - color: var(--color-white); - font-family: 'Heebo', sans-serif; - font-size: 16px; - line-height: 24px; - padding: 24px; - text-align: left; - white-space: pre-line; - overflow-wrap: break-word; - word-wrap: break-word; -} - /* Uniform icons */ .icon { width: 20px; @@ -315,25 +210,6 @@ h3 { text-decoration: underline; } -/* Routes Information */ -.routes-info-box { - background-color: var(--color-sherpa700); - border: 1px solid var(--color-sherpa500); - border-radius: 8px; - padding: 12px 16px; - margin-bottom: 16px; - font-size: 14px; - color: var(--color-sherpa200); -} - -.routes-info-box .info-item { - margin-bottom: 8px; -} - -.routes-info-box .info-item:last-child { - margin-bottom: 0; -} - /* Tablet layout (600px - 1023px) */ @media (min-width: 600px) and (max-width: 1023px) { .App { @@ -352,30 +228,9 @@ h3 { line-height: 28px; } - .p-card .p-card-body { - padding: 24px !important; - } - - .p-datatable .p-datatable-thead > tr > th:nth-child(1), - .p-datatable .p-datatable-tbody > tr > td:nth-child(1), - .p-datatable .route-column { - width: 55% !important; - } - - .p-datatable .p-datatable-thead > tr > th:nth-child(2), - .p-datatable .p-datatable-tbody > tr > td:nth-child(2), - .p-datatable .limits-column { - width: 45% !important; - } - .btn--uniform { min-width: 160px !important; } - - .routes-info-box { - font-size: 13px; - padding: 10px 14px; - } } /* Mobile layout (up to 599px) */ @@ -398,22 +253,6 @@ h3 { margin: 24px 0 16px 0; } - .p-card .p-card-body { - padding: 20px !important; - } - - .p-datatable .p-datatable-thead > tr > th:nth-child(1), - .p-datatable .p-datatable-tbody > tr > td:nth-child(1), - .p-datatable .route-column { - width: 50% !important; - } - - .p-datatable .p-datatable-thead > tr > th:nth-child(2), - .p-datatable .p-datatable-tbody > tr > td:nth-child(2), - .p-datatable .limits-column { - width: 50% !important; - } - .btn--uniform { min-width: 100% !important; width: 100% !important; @@ -423,8 +262,4 @@ h3 { font-size: 14px; } - .routes-info-box { - font-size: 12px; - padding: 8px 12px; - } } \ No newline at end of file diff --git a/ui/src/App.jsx b/ui/src/App.jsx index 9c9e91c..201ee14 100644 --- a/ui/src/App.jsx +++ b/ui/src/App.jsx @@ -1,19 +1,18 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import './App.css'; import 'primereact/resources/themes/lara-light-indigo/theme.css'; import 'primereact/resources/primereact.min.css'; import '/node_modules/primeflex/primeflex.css'; import { Button } from 'primereact/button'; -import { Card } from 'primereact/card'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; +import { useAuth } from 'react-oidc-context'; +import { toast } from 'react-toastify'; import Header from './components/Header'; import Footer from './components/Footer'; - +import InfoPanelCard from './components/InfoPanelCard'; import { getAPIKey, deleteAPIKey, getRoutes } from './Services/apiService'; -import { useAuth } from 'react-oidc-context'; -import { toast } from 'react-toastify'; function App() { const auth = useAuth(); @@ -75,10 +74,10 @@ function App() { if (!isError) { const routes = data.routes; const listItems = routes.map((currElement, index) => { - return { - id: index, + return { + id: index, route: currElement.url, - limits: currElement.limits + limits: currElement.limits, }; }); setInfoMessage(generateTable(listItems)); @@ -99,13 +98,10 @@ function App() { return ( <>
- Information + Information - Your effective rate limits are determined by route configuration and your group membership. EUMETNET member users receive higher limits. + Your effective rate limits are determined by route configuration and your group membership. EUMETNET member + users receive higher limits.
@@ -141,82 +137,48 @@ function App() {
{/* */}
- + {auth.isAuthenticated ? (
{/* Button Group */}
-
- {/* Info Panel Card */} -
-

Info Panel

- -
- {infoMessage || 'Click a button above to get started'} -
-
-
+ {infoMessage}
) : (
-
+

Welcome to Developer Portal

-

+

Please log in to access your API keys and manage routes

-
@@ -228,4 +190,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/ui/src/components/Footer.jsx b/ui/src/components/Footer.jsx index e1ca884..b5e301f 100644 --- a/ui/src/components/Footer.jsx +++ b/ui/src/components/Footer.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import './Footer.css'; const Footer = () => { diff --git a/ui/src/components/Header.jsx b/ui/src/components/Header.jsx index 7104e98..0a55c4d 100644 --- a/ui/src/components/Header.jsx +++ b/ui/src/components/Header.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import './Header.css'; const Header = () => { diff --git a/ui/src/components/InfoPanelCard.css b/ui/src/components/InfoPanelCard.css new file mode 100644 index 0000000..f5b022e --- /dev/null +++ b/ui/src/components/InfoPanelCard.css @@ -0,0 +1,299 @@ +/* Main Content Area */ +.infoPanel { + text-align: left; + color: var(--color-white); + font-family: 'Heebo', sans-serif; + font-size: 16px; + line-height: 24px; + white-space: pre-line; + overflow-wrap: break-word; + word-wrap: break-word; +} + +/* Card Styles */ +.p-card { + background: var(--color-sherpa800) !important; + border: 1px solid var(--color-sherpa600) !important; + border-radius: 8px !important; + box-shadow: none !important; +} + +.p-card .p-card-body { + padding: 32px !important; + color: var(--color-white) !important; +} + +.p-card .p-card-content { + color: var(--color-white) !important; + font-family: 'Heebo', sans-serif !important; + font-size: 16px !important; + line-height: 24px !important; + min-height: 200px; +} + +/* Routes Information */ +.routes-info-box { + background-color: var(--color-sherpa700); + border: 1px solid var(--color-sherpa500); + border-radius: 8px; + padding: 12px 16px; + margin-bottom: 16px; + font-size: 14px; + color: var(--color-sherpa200); +} + +/* DataTable Styles */ +.p-datatable { + background: var(--color-sherpa800) !important; + border: 1px solid var(--color-sherpa600) !important; + border-radius: 8px !important; + overflow: hidden !important; + width: 100% !important; + table-layout: fixed !important; +} + +.p-datatable .p-datatable-table { + width: 100% !important; + table-layout: fixed !important; +} + +.p-datatable .p-datatable-header { + background: var(--color-sherpa700) !important; + border-bottom: 1px solid var(--color-sherpa600) !important; + color: var(--color-white) !important; + padding: 16px !important; +} + +.p-datatable .p-datatable-thead>tr>th { + background: var(--color-sherpa700) !important; + border: 1px solid var(--color-sherpa600) !important; + color: var(--color-white) !important; + font-family: 'Exo 2', sans-serif !important; + font-size: 16px !important; + font-weight: 600 !important; + padding: 16px !important; + box-sizing: border-box !important; +} + +.p-datatable .p-datatable-tbody>tr { + background: var(--color-sherpa800) !important; + color: var(--color-white) !important; +} + +.p-datatable .p-datatable-tbody>tr>td { + border: 1px solid var(--color-sherpa600) !important; + padding: 16px !important; + font-family: 'Heebo', sans-serif !important; + font-size: 16px !important; + overflow-wrap: break-word !important; + word-wrap: break-word !important; + box-sizing: border-box !important; +} + +.p-datatable .p-datatable-tbody>tr:hover { + background: rgba(255, 255, 255, 0.05) !important; +} + +/* Empty message in DataTable */ +.p-datatable .p-datatable-emptymessage>td { + color: var(--color-sherpa400) !important; +} + +/* DataTable Column Widths */ +.p-datatable .p-datatable-thead>tr>th:nth-child(1), +.p-datatable .p-datatable-tbody>tr>td:nth-child(1), +.p-datatable .route-column { + width: 60% !important; +} + +.p-datatable .p-datatable-thead>tr>th:nth-child(2), +.p-datatable .p-datatable-tbody>tr>td:nth-child(2), +.p-datatable .limits-column { + width: 40% !important; +} + +.routes-info-box .info-item { + margin-bottom: 8px; +} + +.routes-info-box .info-item:last-child { + margin-bottom: 0; +} + +/* Footer Container */ +.info-card-footer { + text-align: left; + font-size: 14px; + color: var(--color-white); + background-color: var(--color-sherpa900); + border-top: 1px solid var(--color-sherpa600); + padding: 24px 32px; + margin: -1px; + border-radius: 4px 4px 8px 8px; +} + +/* Footer Headings */ +.footer-title { + color: var(--color-sherpa400); + font-size: 20px; + font-family: "Exo 2", sans-serif; + font-weight: 600; + margin-bottom: 16px; + margin-top: 0; +} + +.footer-subtitle { + color: var(--color-sherpa400); + font-size: 16px; + font-weight: 600; + margin-top: 16px; + margin-bottom: 8px; +} + +.footer-section-break { + margin-top: 24px; + padding-top: 16px; + border-top: 1px solid var(--color-sherpa700); +} + +/* Footer Text */ +.footer-text { + margin: 0 0 16px 0; + line-height: 1.5; +} + +/* Code Examples */ +.code-example { + margin-bottom: 16px; +} + +.code-label { + color: var(--color-sherpa300); + font-size: 13px; +} + +.code-block { + background-color: var(--color-sherpa800); + border: 1px solid var(--color-sherpa700); + padding: 12px; + border-radius: 4px; + overflow: auto; + font-size: 13px; + margin-top: 8px; + color: var(--color-sherpa100); +} + +/* Documentation Link */ +.footer-docs-link { + margin-top: 20px; + padding-top: 16px; + border-top: 1px solid var(--color-sherpa700); + font-size: 14px; + line-height: 1.5; +} + +.footer-docs-link a { + color: var(--color-sherpa400); + text-decoration: underline; + transition: color 0.3s ease; +} + +.footer-docs-link a:hover { + color: var(--color-white); +} + +/* Tablet layout (600px - 1023px) */ +@media (min-width: 600px) and (max-width: 1023px) { + .p-card .p-card-body { + padding: 24px !important; + } + + .p-datatable .p-datatable-thead>tr>th:nth-child(1), + .p-datatable .p-datatable-tbody>tr>td:nth-child(1), + .p-datatable .route-column { + width: 55% !important; + } + + .p-datatable .p-datatable-thead>tr>th:nth-child(2), + .p-datatable .p-datatable-tbody>tr>td:nth-child(2), + .p-datatable .limits-column { + width: 45% !important; + } + + .routes-info-box { + font-size: 13px; + padding: 10px 14px; + } + + .info-card-footer { + padding: 20px 24px; + } + + .footer-title { + font-size: 18px; + } + + .footer-subtitle { + font-size: 15px; + } + + .code-block { + font-size: 12px; + } +} + +/* Mobile layout (up to 599px) */ +@media (max-width: 599px) { + .p-card .p-card-body { + padding: 20px !important; + } + + .p-datatable .p-datatable-thead>tr>th:nth-child(1), + .p-datatable .p-datatable-tbody>tr>td:nth-child(1), + .p-datatable .route-column { + width: 50% !important; + } + + .p-datatable .p-datatable-thead>tr>th:nth-child(2), + .p-datatable .p-datatable-tbody>tr>td:nth-child(2), + .p-datatable .limits-column { + width: 50% !important; + } + + .routes-info-box { + font-size: 12px; + padding: 8px 12px; + } + + .info-card-footer { + padding: 16px 20px; + } + + .footer-title { + font-size: 16px; + margin-bottom: 12px; + } + + .footer-subtitle { + font-size: 14px; + margin-top: 12px; + } + + .footer-text { + font-size: 13px; + margin-bottom: 12px; + } + + .code-label { + font-size: 12px; + } + + .code-block { + font-size: 11px; + padding: 10px; + } + + .footer-docs-link { + font-size: 13px; + } +} \ No newline at end of file diff --git a/ui/src/components/InfoPanelCard.jsx b/ui/src/components/InfoPanelCard.jsx new file mode 100644 index 0000000..8f77d92 --- /dev/null +++ b/ui/src/components/InfoPanelCard.jsx @@ -0,0 +1,65 @@ +import { Card } from 'primereact/card'; +import './InfoPanelCard.css'; + +const InfoPanelCard = ({ children }) => { + const cardFooter = ( +
+

Usage Instructions

+ +

Get API Key

+

+ Generate your API key to access MeteoGate services. The key will appear in the panel above. +

+ +

Delete API Key

+

+ Revoke your current API key if it has been compromised or is no longer needed. +

+ +

Show Routes

+

+ View available API routes and your rate limits based on your group membership. +

+ +

Using Your API Key

+

+ Include your API key in requests as a header or URL parameter. +

+ +
+ In header: +
+          {`curl -H "apikey: YOUR_API_KEY" http://gateway.meteogate.eu/route`}
+        
+
+ +
+ In URL parameter: +
+          {`curl "http://gateway.meteogate.eu/route?apikey=YOUR_API_KEY"`}
+        
+
+ +

+ For complete documentation, see{' '} + + MeteoGate Docs + +

+
+ ); + + return ( + +
+ {children || 'Click a button above to get started'} +
+
+ ); +}; + +export default InfoPanelCard; \ No newline at end of file From b2cad28868762dcbfbd9a46f96e2b30324c2047f Mon Sep 17 00:00:00 2001 From: Kristian Harju Date: Fri, 27 Feb 2026 14:34:25 +0200 Subject: [PATCH 2/7] Minor fix --- ui/src/components/InfoPanelCard.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/components/InfoPanelCard.jsx b/ui/src/components/InfoPanelCard.jsx index 8f77d92..4e12645 100644 --- a/ui/src/components/InfoPanelCard.jsx +++ b/ui/src/components/InfoPanelCard.jsx @@ -29,14 +29,14 @@ const InfoPanelCard = ({ children }) => {
In header:
-          {`curl -H "apikey: YOUR_API_KEY" http://gateway.meteogate.eu/route`}
+          {`curl -H "apikey: " https://api.meteogate.eu/route`}
         
In URL parameter:
-          {`curl "http://gateway.meteogate.eu/route?apikey=YOUR_API_KEY"`}
+          {`curl "https://api.meteogate.eu/route?apikey="`}
         
From 705c2c1bebbe643a8434640c8d97c7556ba6d0a3 Mon Sep 17 00:00:00 2001 From: Kristian Harju Date: Fri, 27 Feb 2026 14:51:14 +0200 Subject: [PATCH 3/7] Format --- ui/src/App.css | 46 ++++++++++++++--------------- ui/src/components/Footer.css | 4 +-- ui/src/components/Footer.jsx | 29 +++++------------- ui/src/components/Header.css | 6 ++-- ui/src/components/Header.jsx | 3 +- ui/src/components/InfoPanelCard.css | 38 ++++++++++++------------ ui/src/components/InfoPanelCard.jsx | 32 +++++--------------- ui/src/index.css | 15 ++++++++-- 8 files changed, 77 insertions(+), 96 deletions(-) diff --git a/ui/src/App.css b/ui/src/App.css index 2c28d9f..feca811 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -1,16 +1,16 @@ :root { - --color-sherpa100: #D9F4F4; - --color-sherpa200: #B8E8E9; - --color-sherpa300: #86D6DA; - --color-sherpa400: #63CBCF; - --color-sherpa500: #009AA1; + --color-sherpa100: #d9f4f4; + --color-sherpa200: #b8e8e9; + --color-sherpa300: #86d6da; + --color-sherpa400: #63cbcf; + --color-sherpa500: #009aa1; --color-sherpa600: #087a82; - --color-sherpa700: #0C646D; - --color-sherpa800: #004F59; - --color-sherpa900: #0C3B41; - --color-white: #FFFFFF; + --color-sherpa700: #0c646d; + --color-sherpa800: #004f59; + --color-sherpa900: #0c3b41; + --color-white: #ffffff; --color-black: #000000; - --color-yellow: #F1B828; + --color-yellow: #f1b828; --color-yellow-hover: #e0a71f; --color-yellow-active: #c99319; --color-red: #bf6366; @@ -24,12 +24,14 @@ display: flex; flex-direction: column; /* Desktop background (default) */ - background-image: - linear-gradient(180deg, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0.00) 15.58%), - radial-gradient(68.05% 68.05% at 50.79% 4.4%, rgba(12, 59, 65, 0.30) 0%, #0C3B41 100%), + background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0) 15.58%), + radial-gradient(68.05% 68.05% at 50.79% 4.4%, rgba(12, 59, 65, 0.3) 0%, #0c3b41 100%), url('/background-image-desktop.jpg'); background-position: center, center, top; - background-size: 100% 100%, 100% 100%, cover; + background-size: + 100% 100%, + 100% 100%, + cover; background-repeat: no-repeat; background-attachment: fixed; } @@ -175,7 +177,7 @@ /* Headings */ h3 { color: var(--color-white); - font-family: "Exo 2", sans-serif; + font-family: 'Exo 2', sans-serif; font-size: 28px; font-weight: 600; line-height: 32px; @@ -213,9 +215,8 @@ h3 { /* Tablet layout (600px - 1023px) */ @media (min-width: 600px) and (max-width: 1023px) { .App { - background-image: - linear-gradient(180deg, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0.00) 15.58%), - radial-gradient(68.05% 68.05% at 50.79% 4.4%, rgba(12, 59, 65, 0.30) 0%, #0C3B41 100%), + background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0) 15.58%), + radial-gradient(68.05% 68.05% at 50.79% 4.4%, rgba(12, 59, 65, 0.3) 0%, #0c3b41 100%), url('/background-image-tablet.jpg'); } @@ -236,10 +237,8 @@ h3 { /* Mobile layout (up to 599px) */ @media (max-width: 599px) { .App { - background-image: - linear-gradient(180deg, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.00) 30%), - radial-gradient(90% 90% at 50% 10%, rgba(12, 59, 65, 0.50) 0%, #0C3B41 100%), - url('/background-image-mobile.jpg'); + background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 30%), + radial-gradient(90% 90% at 50% 10%, rgba(12, 59, 65, 0.5) 0%, #0c3b41 100%), url('/background-image-mobile.jpg'); } .content-container { @@ -261,5 +260,4 @@ h3 { .documentation-link { font-size: 14px; } - -} \ No newline at end of file +} diff --git a/ui/src/components/Footer.css b/ui/src/components/Footer.css index 4e29a31..13487ec 100644 --- a/ui/src/components/Footer.css +++ b/ui/src/components/Footer.css @@ -1,6 +1,6 @@ .footer-container { width: 100%; - background: #00282D; + background: #00282d; padding: 64px 0; margin-top: auto; border-top: 1px solid var(--color-sherpa600); @@ -138,4 +138,4 @@ font-size: 14px; line-height: 20px; } -} \ No newline at end of file +} diff --git a/ui/src/components/Footer.jsx b/ui/src/components/Footer.jsx index b5e301f..06a1081 100644 --- a/ui/src/components/Footer.jsx +++ b/ui/src/components/Footer.jsx @@ -6,17 +6,8 @@ const Footer = () => {
{/* First Row - Logo and Contact */}
- EUMETNET Logo - + EUMETNET Logo +

Contact information

Opens in new tab
@@ -26,12 +17,8 @@ const Footer = () => {

- If you need technical guidance or encounter issues, see the Support Section {' '} - + If you need technical guidance or encounter issues, see the Support Section{' '} + MeteoGate

@@ -44,9 +31,9 @@ const Footer = () => { {/* Third Row - Copyright and Legal Links */}

Copyright EUMETNET SNC ©{new Date().getFullYear()}

- @@ -59,4 +46,4 @@ const Footer = () => { ); }; -export default Footer; \ No newline at end of file +export default Footer; diff --git a/ui/src/components/Header.css b/ui/src/components/Header.css index 5b9acef..d34933d 100644 --- a/ui/src/components/Header.css +++ b/ui/src/components/Header.css @@ -35,7 +35,7 @@ .header-content h1 { color: var(--color-white); - font-family: "Exo 2", sans-serif; + font-family: 'Exo 2', sans-serif; font-size: 48px; font-weight: 600; line-height: 48px; @@ -45,7 +45,7 @@ .header-content .subtitle { color: var(--color-white); - font-family: "Exo 2", sans-serif; + font-family: 'Exo 2', sans-serif; font-size: 36px; font-weight: 600; line-height: 36px; @@ -125,4 +125,4 @@ font-size: 18px; line-height: 24px; } -} \ No newline at end of file +} diff --git a/ui/src/components/Header.jsx b/ui/src/components/Header.jsx index 0a55c4d..4201f4d 100644 --- a/ui/src/components/Header.jsx +++ b/ui/src/components/Header.jsx @@ -14,7 +14,8 @@ const Header = () => {

Developer Portal

- Register and manage your API keys and view available routes + Register and manage your API keys and{' '} + view available routes

diff --git a/ui/src/components/InfoPanelCard.css b/ui/src/components/InfoPanelCard.css index f5b022e..722a49a 100644 --- a/ui/src/components/InfoPanelCard.css +++ b/ui/src/components/InfoPanelCard.css @@ -64,7 +64,7 @@ padding: 16px !important; } -.p-datatable .p-datatable-thead>tr>th { +.p-datatable .p-datatable-thead > tr > th { background: var(--color-sherpa700) !important; border: 1px solid var(--color-sherpa600) !important; color: var(--color-white) !important; @@ -75,12 +75,12 @@ box-sizing: border-box !important; } -.p-datatable .p-datatable-tbody>tr { +.p-datatable .p-datatable-tbody > tr { background: var(--color-sherpa800) !important; color: var(--color-white) !important; } -.p-datatable .p-datatable-tbody>tr>td { +.p-datatable .p-datatable-tbody > tr > td { border: 1px solid var(--color-sherpa600) !important; padding: 16px !important; font-family: 'Heebo', sans-serif !important; @@ -90,24 +90,24 @@ box-sizing: border-box !important; } -.p-datatable .p-datatable-tbody>tr:hover { +.p-datatable .p-datatable-tbody > tr:hover { background: rgba(255, 255, 255, 0.05) !important; } /* Empty message in DataTable */ -.p-datatable .p-datatable-emptymessage>td { +.p-datatable .p-datatable-emptymessage > td { color: var(--color-sherpa400) !important; } /* DataTable Column Widths */ -.p-datatable .p-datatable-thead>tr>th:nth-child(1), -.p-datatable .p-datatable-tbody>tr>td:nth-child(1), +.p-datatable .p-datatable-thead > tr > th:nth-child(1), +.p-datatable .p-datatable-tbody > tr > td:nth-child(1), .p-datatable .route-column { width: 60% !important; } -.p-datatable .p-datatable-thead>tr>th:nth-child(2), -.p-datatable .p-datatable-tbody>tr>td:nth-child(2), +.p-datatable .p-datatable-thead > tr > th:nth-child(2), +.p-datatable .p-datatable-tbody > tr > td:nth-child(2), .p-datatable .limits-column { width: 40% !important; } @@ -136,7 +136,7 @@ .footer-title { color: var(--color-sherpa400); font-size: 20px; - font-family: "Exo 2", sans-serif; + font-family: 'Exo 2', sans-serif; font-weight: 600; margin-bottom: 16px; margin-top: 0; @@ -208,14 +208,14 @@ padding: 24px !important; } - .p-datatable .p-datatable-thead>tr>th:nth-child(1), - .p-datatable .p-datatable-tbody>tr>td:nth-child(1), + .p-datatable .p-datatable-thead > tr > th:nth-child(1), + .p-datatable .p-datatable-tbody > tr > td:nth-child(1), .p-datatable .route-column { width: 55% !important; } - .p-datatable .p-datatable-thead>tr>th:nth-child(2), - .p-datatable .p-datatable-tbody>tr>td:nth-child(2), + .p-datatable .p-datatable-thead > tr > th:nth-child(2), + .p-datatable .p-datatable-tbody > tr > td:nth-child(2), .p-datatable .limits-column { width: 45% !important; } @@ -248,14 +248,14 @@ padding: 20px !important; } - .p-datatable .p-datatable-thead>tr>th:nth-child(1), - .p-datatable .p-datatable-tbody>tr>td:nth-child(1), + .p-datatable .p-datatable-thead > tr > th:nth-child(1), + .p-datatable .p-datatable-tbody > tr > td:nth-child(1), .p-datatable .route-column { width: 50% !important; } - .p-datatable .p-datatable-thead>tr>th:nth-child(2), - .p-datatable .p-datatable-tbody>tr>td:nth-child(2), + .p-datatable .p-datatable-thead > tr > th:nth-child(2), + .p-datatable .p-datatable-tbody > tr > td:nth-child(2), .p-datatable .limits-column { width: 50% !important; } @@ -296,4 +296,4 @@ .footer-docs-link { font-size: 13px; } -} \ No newline at end of file +} diff --git a/ui/src/components/InfoPanelCard.jsx b/ui/src/components/InfoPanelCard.jsx index 4e12645..d8dcf6d 100644 --- a/ui/src/components/InfoPanelCard.jsx +++ b/ui/src/components/InfoPanelCard.jsx @@ -12,41 +12,27 @@ const InfoPanelCard = ({ children }) => {

Delete API Key

-

- Revoke your current API key if it has been compromised or is no longer needed. -

+

Revoke your current API key if it has been compromised or is no longer needed.

Show Routes

-

- View available API routes and your rate limits based on your group membership. -

+

View available API routes and your rate limits based on your group membership.

Using Your API Key

-

- Include your API key in requests as a header or URL parameter. -

+

Include your API key in requests as a header or URL parameter.

In header: -
-          {`curl -H "apikey: " https://api.meteogate.eu/route`}
-        
+
{`curl -H "apikey: " https://api.meteogate.eu/route`}
In URL parameter: -
-          {`curl "https://api.meteogate.eu/route?apikey="`}
-        
+
{`curl "https://api.meteogate.eu/route?apikey="`}

For complete documentation, see{' '} - + MeteoGate Docs

@@ -55,11 +41,9 @@ const InfoPanelCard = ({ children }) => { return ( -
- {children || 'Click a button above to get started'} -
+
{children || 'Click a button above to get started'}
); }; -export default InfoPanelCard; \ No newline at end of file +export default InfoPanelCard; diff --git a/ui/src/index.css b/ui/src/index.css index 2693d73..f504da0 100644 --- a/ui/src/index.css +++ b/ui/src/index.css @@ -32,8 +32,19 @@ body { margin: 0; - font-family: 'Heebo', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', - 'Droid Sans', 'Helvetica Neue', sans-serif; + font-family: + 'Heebo', + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + 'Roboto', + 'Oxygen', + 'Ubuntu', + 'Cantarell', + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } From b38d50dc7473040d74325dd7c19d7dd28096edcb Mon Sep 17 00:00:00 2001 From: Kristian Harju Date: Fri, 27 Feb 2026 14:54:24 +0200 Subject: [PATCH 4/7] Lint and format --- .github/workflows/frontend_ci_cd.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/frontend_ci_cd.yml b/.github/workflows/frontend_ci_cd.yml index e49c01c..e28fe43 100644 --- a/.github/workflows/frontend_ci_cd.yml +++ b/.github/workflows/frontend_ci_cd.yml @@ -12,9 +12,36 @@ on: - ui/** jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: 'ui/.nvmrc' + cache: 'npm' + cache-dependency-path: 'ui/package-lock.json' + + - name: Install dependencies + run: npm ci + working-directory: ./ui + + - name: Run Prettier format check + run: npm run format:check + working-directory: ./ui + + - name: Run ESLint + run: npm run lint + working-directory: ./ui + # Currently there are no tests to run before build build: + needs: lint runs-on: ubuntu-latest # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. From 105cb0a7dd0e4ae890263c8a2d24633c1fa71e1d Mon Sep 17 00:00:00 2001 From: Kristian Harju Date: Fri, 27 Feb 2026 14:57:34 +0200 Subject: [PATCH 5/7] Lint UI on pull requests --- .github/workflows/on-pull-request.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/on-pull-request.yaml b/.github/workflows/on-pull-request.yaml index 8af7d49..80c2e81 100644 --- a/.github/workflows/on-pull-request.yaml +++ b/.github/workflows/on-pull-request.yaml @@ -49,6 +49,32 @@ jobs: run: poetry run test working-directory: ./backend + lint-frontend: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: 'ui/.nvmrc' + cache: 'npm' + cache-dependency-path: 'ui/package-lock.json' + + - name: Install dependencies + run: npm ci + working-directory: ./ui + + - name: Run Prettier format check + run: npm run format:check + working-directory: ./ui + + - name: Run ESLint + run: npm run lint + working-directory: ./ui + lint-helm: runs-on: ubuntu-latest steps: From 67b843d8fd8fb35ef1f87babf8ec072f69c2cb94 Mon Sep 17 00:00:00 2001 From: Kristian Harju Date: Mon, 2 Mar 2026 08:28:36 +0200 Subject: [PATCH 6/7] Removed inline styles --- ui/src/App.css | 42 ++++++++++++++++++++++++++++++++++++++++++ ui/src/App.jsx | 19 ++++--------------- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/ui/src/App.css b/ui/src/App.css index feca811..5417976 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -212,6 +212,27 @@ h3 { text-decoration: underline; } +/* Login */ +.login-screen { + text-align: center; + padding: 60px 20px; +} + +.login-screen h3 { + margin-bottom: 24px; +} + +.login-screen-text { + color: var(--color-sherpa200); + margin-bottom: 32px; + font-size: 18px; + line-height: 24px; +} + +.login-screen-docs { + margin-top: 24px; +} + /* Tablet layout (600px - 1023px) */ @media (min-width: 600px) and (max-width: 1023px) { .App { @@ -232,6 +253,14 @@ h3 { .btn--uniform { min-width: 160px !important; } + + .login-screen { + padding: 48px 20px; + } + + .login-screen-text { + font-size: 16px; + } } /* Mobile layout (up to 599px) */ @@ -260,4 +289,17 @@ h3 { .documentation-link { font-size: 14px; } + + .login-screen { + padding: 40px 16px; + } + + .login-screen-text { + font-size: 16px; + margin-bottom: 24px; + } + + .login-screen-docs { + margin-top: 20px; + } } diff --git a/ui/src/App.jsx b/ui/src/App.jsx index 201ee14..0d593b9 100644 --- a/ui/src/App.jsx +++ b/ui/src/App.jsx @@ -152,25 +152,14 @@ function App() {
) : (
-
-

Welcome to Developer Portal

-

+

+

Welcome to Developer Portal

+

Please log in to access your API keys and manage routes

+
+ + ); } else { showToaster(data?.message ?? 'Undefined error message'); } @@ -154,9 +182,7 @@ function App() {

Welcome to Developer Portal

-

- Please log in to access your API keys and manage routes -

+

Please log in to access your API keys and manage routes