From b089dca55d81a22f9ccc46593830c59b72e2b744 Mon Sep 17 00:00:00 2001
From: Eamonn Mansour <47121388+eamansour@users.noreply.github.com>
Date: Wed, 6 May 2026 13:58:05 +0100
Subject: [PATCH 1/3] fix: Add side nav for menu navigation on small screens
Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com>
---
.../components/headers/LanguageSelector.tsx | 64 +-
.../src/components/headers/PageHeader.tsx | 43 +-
.../src/components/headers/PageHeaderMenu.tsx | 5 +-
.../src/components/headers/ThemeSelector.tsx | 44 +-
.../src/styles/headers/PageHeader.module.css | 18 +
.../src/styles/headers/Selector.module.css | 51 --
.../tests/__snapshots__/layout.test.tsx.snap | 550 +++++++++++-------
.../components/headers/PageHeader.test.tsx | 11 +-
.../components/headers/ThemeSelector.test.tsx | 8 +-
galasa-ui/src/tests/index.test.tsx | 7 -
10 files changed, 437 insertions(+), 364 deletions(-)
create mode 100644 galasa-ui/src/styles/headers/PageHeader.module.css
diff --git a/galasa-ui/src/components/headers/LanguageSelector.tsx b/galasa-ui/src/components/headers/LanguageSelector.tsx
index b27a2851..06a980ce 100644
--- a/galasa-ui/src/components/headers/LanguageSelector.tsx
+++ b/galasa-ui/src/components/headers/LanguageSelector.tsx
@@ -6,7 +6,7 @@
'use client';
-import React, { useState, useTransition } from 'react';
+import { useState, useTransition } from 'react';
import { OverflowMenu, OverflowMenuItem } from '@carbon/react';
import { setUserLocale } from '@/utils/locale';
import { useLocale, useTranslations } from 'next-intl';
@@ -26,7 +26,7 @@ export default function LanguageSelector() {
languages.find((lang) => lang.value === locale) || languages[0]
);
- const [isPending, startTransition] = useTransition();
+ const [, startTransition] = useTransition();
const router = useRouter();
const translations = useTranslations('LanguageSelector');
@@ -46,36 +46,34 @@ export default function LanguageSelector() {
};
return (
-
- }
- size="lg"
- iconDescription={`${translations('tooltip')}: ${selectedLanguage.text}`}
- aria-label="Filter menu"
- tooltipAlignment="center"
- tooltipPosition="bottom"
- >
- {languages.map((language) => (
-
- {language.text}
- {selectedLanguage.id === language.id && (
-
- )}
-
- }
- onClick={() => handleLanguageChange({ selectedItem: language })}
- />
- ))}
-
-
+ }
+ size="lg"
+ iconDescription={`${translations('tooltip')}: ${selectedLanguage.text}`}
+ aria-label="Filter menu"
+ tooltipAlignment="center"
+ tooltipPosition="bottom"
+ >
+ {languages.map((language) => (
+
+ {language.text}
+ {selectedLanguage.id === language.id && (
+
+ )}
+
+ }
+ onClick={() => handleLanguageChange({ selectedItem: language })}
+ />
+ ))}
+
);
}
diff --git a/galasa-ui/src/components/headers/PageHeader.tsx b/galasa-ui/src/components/headers/PageHeader.tsx
index d43e62a2..3a93175b 100644
--- a/galasa-ui/src/components/headers/PageHeader.tsx
+++ b/galasa-ui/src/components/headers/PageHeader.tsx
@@ -16,25 +16,40 @@ import {
import PageHeaderMenu from './PageHeaderMenu';
import Image from 'next/image';
import galasaLogo from '@/assets/images/galasaLogo.png';
-import Link from 'next/link';
import { useFeatureFlags } from '@/contexts/FeatureFlagContext';
import { FEATURE_FLAGS } from '@/utils/featureFlags';
import { useTranslations } from 'next-intl';
+import { SideNav } from '@carbon/react';
+import { SideNavItems } from '@carbon/react';
+import { HeaderSideNavItems } from '@carbon/react';
+import { HeaderMenuButton } from '@carbon/react';
+import { useState } from 'react';
+import styles from '@/styles/headers/PageHeader.module.css';
export default function PageHeader({ galasaServiceName }: { galasaServiceName: string }) {
const { isFeatureEnabled } = useFeatureFlags();
const translations = useTranslations('PageHeader');
+ const [isSideNavExpanded, setIsSideNavExpanded] = useState(false);
+
+ const onClickSideNavExpand = () => {
+ setIsSideNavExpanded(!isSideNavExpanded);
+ };
+
return (
-
-
-
-
+
- Galasa
+
+ Galasa
+
@@ -44,6 +59,22 @@ export default function PageHeader({ galasaServiceName }: { galasaServiceName: s
)}
+
+
+
+ {translations('users')}
+ {isFeatureEnabled(FEATURE_FLAGS.TEST_RUNS) && (
+ {translations('testRuns')}
+ )}
+
+
+
+
diff --git a/galasa-ui/src/components/headers/PageHeaderMenu.tsx b/galasa-ui/src/components/headers/PageHeaderMenu.tsx
index e633d03d..fb8d6b6b 100644
--- a/galasa-ui/src/components/headers/PageHeaderMenu.tsx
+++ b/galasa-ui/src/components/headers/PageHeaderMenu.tsx
@@ -12,6 +12,7 @@ import { handleDeleteCookieApiOperation } from '@/utils/logout';
import LanguageSelector from './LanguageSelector';
import { useTranslations } from 'next-intl';
import ThemeSelector from './ThemeSelector';
+import styles from '@/styles/headers/PageHeader.module.css';
function PageHeaderMenu({ galasaServiceName }: { galasaServiceName: string }) {
const translations = useTranslations('PageHeaderMenu');
@@ -30,7 +31,9 @@ function PageHeaderMenu({ galasaServiceName }: { galasaServiceName: string }) {
- {galasaServiceName}
+
+ {galasaServiceName}
+
, tooltip: 'Switch to light mode' },
@@ -26,42 +24,26 @@ const themeOptions: { id: ThemeType; label: string; icon: React.ReactNode; toolt
export default function ThemeSelector() {
const { theme, setTheme } = useTheme();
- const [isPending, startTransition] = useTransition();
+ const [, startTransition] = useTransition();
const idx = themeOptions.findIndex((o) => o.id === theme);
const currentTheme = themeOptions[idx] || themeOptions[0];
const next = themeOptions[(idx + 1) % themeOptions.length];
const cycleTheme = () => {
startTransition(() => {
- setTheme(next.id as ThemeType);
+ setTheme(next.id);
});
};
- let current: 'g10' | 'g90';
-
- if (theme === 'light') {
- current = 'g10';
- } else if (theme === 'dark') {
- current = 'g90';
- } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
- current = 'g90';
- } else {
- current = 'g10';
- }
return (
-
-
-
-
-
-
-
+
+ {currentTheme.icon}
+
);
}
diff --git a/galasa-ui/src/styles/headers/PageHeader.module.css b/galasa-ui/src/styles/headers/PageHeader.module.css
new file mode 100644
index 00000000..0de66696
--- /dev/null
+++ b/galasa-ui/src/styles/headers/PageHeader.module.css
@@ -0,0 +1,18 @@
+/*
+ * Copyright contributors to the Galasa project
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+@media (max-width: 768px) {
+ #serviceName {
+ display: none;
+ padding: 0;
+ }
+}
+
+.headerName {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
diff --git a/galasa-ui/src/styles/headers/Selector.module.css b/galasa-ui/src/styles/headers/Selector.module.css
index 0fecb14d..873e02e9 100644
--- a/galasa-ui/src/styles/headers/Selector.module.css
+++ b/galasa-ui/src/styles/headers/Selector.module.css
@@ -3,57 +3,6 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
-.container {
- margin-right: 1rem;
- display: flex; /* Removed the extra comma */
- align-items: center;
-}
-
-.language {
- margin-right: 0.5rem;
- fill: white;
-}
-
-.dropdown {
- background-color: transparent; /* Corrected to background-color */
- color: white;
- width: 120px;
-}
-
-.themeSwitcher {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.25rem 0.5rem;
- width: fit-content;
- background-color: #262626;
-}
-
-.iconButton {
- background: #262626;
- border: none;
- padding: 0.85rem;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- transition:
- background-color 0.2s ease,
- color 0.2s ease;
-}
-
-.iconButton:hover {
- background-color: #474747;
-}
-
-.iconButton:disabled {
- cursor: not-allowed;
- opacity: 0.6;
-}
-
-.active {
- color: var(--cds-icon-on-color);
-}
.overflowMenu {
outline: none !important;
diff --git a/galasa-ui/src/tests/__snapshots__/layout.test.tsx.snap b/galasa-ui/src/tests/__snapshots__/layout.test.tsx.snap
index abe98588..a7eb21b7 100644
--- a/galasa-ui/src/tests/__snapshots__/layout.test.tsx.snap
+++ b/galasa-ui/src/tests/__snapshots__/layout.test.tsx.snap
@@ -19,28 +19,59 @@ exports[`Layout renders the web UI layout 1`] = `
>
Skip to main content
-
+
+
+
+
-
+
-
-
-
-
- Switch to light mode
-
-
-
-
+
+
+
-
+
+
+ Switch to light mode
+
+
+
+
-
+
+
+
+
-
+
-
-
-
-
- Switch to light mode
-
-
-
-
+
+
+
-
+
+
+ Switch to light mode
+
+
+
+