From 2078dc5924242d86b3f1287256827ae260e03b01 Mon Sep 17 00:00:00 2001 From: hodanoori <107242553+hodanoori@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:19:51 +0200 Subject: [PATCH] feat(heureka): switches to TopNavigationItem (#344) * chore(heureka): fix linting issues * feat(heureka): uses TopNavigationItem instead of TabNavigationItem * Create hot-dolphins-know.md * Revert "chore(heureka): fix linting issues" This reverts commit b4ecc09e19c1a505161aa145bdbd2380cc714771. * feat(heureka): renames all tab names into navEntry * Create little-onions-obey.md * Delete .changeset/hot-dolphins-know.md --- .changeset/little-onions-obey.md | 5 ++ apps/heureka/src/App.js | 4 +- ...onentsTab.jsx => ComponentsTopNavItem.jsx} | 0 ...chesTab.jsx => IssueMatchesTopNavItem.jsx} | 0 .../TabPanel.jsx => navEntries/NavEntry.jsx} | 10 +-- .../components/navEntries/NavEntryContext.jsx | 73 +++++++++++++++++++ ...ServicesTab.jsx => ServicesTopNavItem.jsx} | 0 .../src/components/shared/ListController.jsx | 6 +- .../src/components/tabs/TabContext.jsx | 68 ----------------- apps/heureka/src/hooks/useAppStore.js | 5 +- apps/heureka/src/hooks/useUrlState.js | 16 ++-- .../src/lib/slices/createGlobalsSlice.js | 14 ++-- 12 files changed, 106 insertions(+), 95 deletions(-) create mode 100644 .changeset/little-onions-obey.md rename apps/heureka/src/components/components/{ComponentsTab.jsx => ComponentsTopNavItem.jsx} (100%) rename apps/heureka/src/components/issueMatches/{IssueMatchesTab.jsx => IssueMatchesTopNavItem.jsx} (100%) rename apps/heureka/src/components/{tabs/TabPanel.jsx => navEntries/NavEntry.jsx} (55%) create mode 100644 apps/heureka/src/components/navEntries/NavEntryContext.jsx rename apps/heureka/src/components/services/{ServicesTab.jsx => ServicesTopNavItem.jsx} (100%) delete mode 100644 apps/heureka/src/components/tabs/TabContext.jsx diff --git a/.changeset/little-onions-obey.md b/.changeset/little-onions-obey.md new file mode 100644 index 000000000..50f37ac55 --- /dev/null +++ b/.changeset/little-onions-obey.md @@ -0,0 +1,5 @@ +--- +"@fake-scope/fake-pkg": minor +--- + +feat(heureka): switches to TopNavigationItem diff --git a/apps/heureka/src/App.js b/apps/heureka/src/App.js index 372e144ab..5dcf4aa1f 100644 --- a/apps/heureka/src/App.js +++ b/apps/heureka/src/App.js @@ -9,7 +9,7 @@ import { AppShell, AppShellProvider, CodeBlock } from "@cloudoperators/juno-ui-c import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { MessagesProvider } from "@cloudoperators/juno-messages-provider" import AsyncWorker from "./components/AsyncWorker" -import TabContext from "./components/tabs/TabContext" +import NavEntryContext from "./components/navEntries/NavEntryContext" import { ErrorBoundary } from "react-error-boundary" import { useGlobalsActions, StoreProvider } from "./hooks/useAppStore" import PanelManager from "./components/shared/PanelManager" @@ -57,7 +57,7 @@ function App(props = {}) { - + diff --git a/apps/heureka/src/components/components/ComponentsTab.jsx b/apps/heureka/src/components/components/ComponentsTopNavItem.jsx similarity index 100% rename from apps/heureka/src/components/components/ComponentsTab.jsx rename to apps/heureka/src/components/components/ComponentsTopNavItem.jsx diff --git a/apps/heureka/src/components/issueMatches/IssueMatchesTab.jsx b/apps/heureka/src/components/issueMatches/IssueMatchesTopNavItem.jsx similarity index 100% rename from apps/heureka/src/components/issueMatches/IssueMatchesTab.jsx rename to apps/heureka/src/components/issueMatches/IssueMatchesTopNavItem.jsx diff --git a/apps/heureka/src/components/tabs/TabPanel.jsx b/apps/heureka/src/components/navEntries/NavEntry.jsx similarity index 55% rename from apps/heureka/src/components/tabs/TabPanel.jsx rename to apps/heureka/src/components/navEntries/NavEntry.jsx index 5d6e4b8a0..8c3201b6b 100644 --- a/apps/heureka/src/components/tabs/TabPanel.jsx +++ b/apps/heureka/src/components/navEntries/NavEntry.jsx @@ -4,15 +4,15 @@ */ import React, { useMemo } from "react" -import { useGlobalsActiveTab } from "../../hooks/useAppStore" +import { useGlobalsActiveNavEntry } from "../../hooks/useAppStore" -const TabPanel = ({ value, children }) => { - const activeTab = useGlobalsActiveTab() +const NavEntry = ({ value, children }) => { + const activeNavEntry = useGlobalsActiveNavEntry() // ATENTION!! compare with == since tabindex is int and value is string - const displayChildren = useMemo(() => activeTab == value, [activeTab, value]) + const displayChildren = useMemo(() => activeNavEntry == value, [activeNavEntry, value]) return
{children}
} -export default TabPanel +export default NavEntry diff --git a/apps/heureka/src/components/navEntries/NavEntryContext.jsx b/apps/heureka/src/components/navEntries/NavEntryContext.jsx new file mode 100644 index 000000000..876a416d9 --- /dev/null +++ b/apps/heureka/src/components/navEntries/NavEntryContext.jsx @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useMemo } from "react" +import { Container, TopNavigation, TopNavigationItem } from "@cloudoperators/juno-ui-components" +import NavEntry from "./NavEntry" +import { useGlobalsActions, useGlobalsActiveNavEntry } from "../../hooks/useAppStore" + +import ServicesNav from "../services/ServicesTopNavItem" +import IssueMatchesNav from "../issueMatches/IssueMatchesTopNavItem" +import ComponentsNav from "../components/ComponentsTopNavItem" + +const NAV_CONFIG = [ + { + label: "Services", + value: "Services", + icon: "dns", + component: ServicesNav, + }, + { + label: "IssueMatches", + value: "IssueMatches", + icon: "autoAwesomeMotion", + component: IssueMatchesNav, + }, + { + label: "Components", + value: "Components", + icon: "autoAwesomeMotion", + component: ComponentsNav, + }, +] + +const NavEntryContext = () => { + const { setActiveNavEntry } = useGlobalsActions() + const activeNavEntry = useGlobalsActiveNavEntry() + + // Memorized top navigation items + const memorizedNavItems = useMemo( + () => + NAV_CONFIG.map((nav) => ( + setActiveNavEntry(nav.value)} // Trigger tab change + /> + )), + [activeNavEntry, setActiveNavEntry] + ) + + // Memorized tab panels + const memorizedNavItemContents = useMemo( + () => + NAV_CONFIG.map((nav) => ( + + + + )), + [] + ) + + return ( + <> + {}}>{memorizedNavItems} + {memorizedNavItemContents} + + ) +} + +export default NavEntryContext diff --git a/apps/heureka/src/components/services/ServicesTab.jsx b/apps/heureka/src/components/services/ServicesTopNavItem.jsx similarity index 100% rename from apps/heureka/src/components/services/ServicesTab.jsx rename to apps/heureka/src/components/services/ServicesTopNavItem.jsx diff --git a/apps/heureka/src/components/shared/ListController.jsx b/apps/heureka/src/components/shared/ListController.jsx index 3d1d491ea..bee82db91 100644 --- a/apps/heureka/src/components/shared/ListController.jsx +++ b/apps/heureka/src/components/shared/ListController.jsx @@ -11,7 +11,7 @@ import { useGlobalsActions, useActiveFilters, usePredefinedFilters, - useGlobalsActiveTab, + useGlobalsActiveNavEntry, useSearchTerm, } from "../../hooks/useAppStore" import { Pagination, Container, Stack } from "@cloudoperators/juno-ui-components" @@ -23,7 +23,7 @@ const ListController = ({ queryKey, entityName, ListComponent }) => { const queryOptions = useGlobalsQueryOptions(queryKey) const { setQueryOptions } = useGlobalsActions() const { addMessage, resetMessages } = messageActions() - const activeTab = useGlobalsActiveTab() + const activeNavEntry = useGlobalsActiveNavEntry() const activeFilters = useActiveFilters(entityName) const predefinedFilters = usePredefinedFilters(entityName) const searchTerm = useSearchTerm(entityName) @@ -43,7 +43,7 @@ const ListController = ({ queryKey, entityName, ListComponent }) => { }, }, ], - enabled: !!queryClientFnReady && queryKey === activeTab, + enabled: !!queryClientFnReady && queryKey === activeNavEntry, }) const [currentPage, setCurrentPage] = useState(1) diff --git a/apps/heureka/src/components/tabs/TabContext.jsx b/apps/heureka/src/components/tabs/TabContext.jsx deleted file mode 100644 index bb58a90e1..000000000 --- a/apps/heureka/src/components/tabs/TabContext.jsx +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useMemo } from "react" -import { Container, TabNavigation, TabNavigationItem } from "@cloudoperators/juno-ui-components" -import TabPanel from "./TabPanel" -import { useGlobalsActions, useGlobalsActiveTab } from "../../hooks/useAppStore" - -import ServicesTab from "../services/ServicesTab" -import IssueMatchesTab from "../issueMatches/IssueMatchesTab" -import ComponentsTab from "../components/ComponentsTab" - -const TAB_CONFIG = [ - { - label: "Services", - value: "Services", - icon: "dns", - component: ServicesTab, - }, - { - label: "IssueMatches", - value: "IssueMatches", - icon: "autoAwesomeMotion", - component: IssueMatchesTab, - }, - { - label: "Components", - value: "Components", - icon: "autoAwesomeMotion", - component: ComponentsTab, - }, -] - -const TabContext = () => { - const { setActiveTab } = useGlobalsActions() - const activeTab = useGlobalsActiveTab() - - const memoizedTabs = useMemo( - () => - TAB_CONFIG.map((tab) => ( - - )), - [] - ) - - const memoizedTabPanels = useMemo( - () => - TAB_CONFIG.map((tab) => ( - - - - )), - [] - ) - - return ( - <> - setActiveTab(value)}> - {memoizedTabs} - - {memoizedTabPanels} - - ) -} - -export default TabContext diff --git a/apps/heureka/src/hooks/useAppStore.js b/apps/heureka/src/hooks/useAppStore.js index a0830da17..375b2518d 100644 --- a/apps/heureka/src/hooks/useAppStore.js +++ b/apps/heureka/src/hooks/useAppStore.js @@ -36,8 +36,9 @@ const useAppStore = (selector) => useStore(useContext(StoreContext), selector) // Globals exports export const useGlobalsEmbedded = () => useAppStore((state) => state.globals.embedded) export const useGlobalsQueryClientFnReady = () => useAppStore((state) => state.globals.queryClientFnReady) -export const useGlobalsActiveTab = () => useAppStore((state) => state.globals.activeTab) -export const useGlobalsQueryOptions = (tab) => useAppStore((state) => state.globals.tabs[tab].queryOptions) +export const useGlobalsActiveNavEntry = () => useAppStore((state) => state.globals.activeNavEntry) +export const useGlobalsQueryOptions = (navEntry) => + useAppStore((state) => state.globals.navEntries[navEntry].queryOptions) export const useGlobalsApiEndpoint = () => useAppStore((state) => state.globals.apiEndpoint) export const useGlobalsShowPanel = () => useAppStore((state) => state.globals.showPanel) export const useGlobalsShowServiceDetail = () => useAppStore((state) => state.globals.showServiceDetail) diff --git a/apps/heureka/src/hooks/useUrlState.js b/apps/heureka/src/hooks/useUrlState.js index 2724b0dc8..f383b414c 100644 --- a/apps/heureka/src/hooks/useUrlState.js +++ b/apps/heureka/src/hooks/useUrlState.js @@ -5,10 +5,10 @@ import { useState, useEffect } from "react" import { registerConsumer } from "@cloudoperators/juno-url-state-provider-v1" -import { useGlobalsActions, useGlobalsActiveTab } from "./useAppStore" +import { useGlobalsActions, useGlobalsActiveNavEntry } from "./useAppStore" const DEFAULT_KEY = "heureka" -const ACTIVE_TAB = "t" +const ACTIVE_NAV = "t" const useUrlState = (key) => { const [isURLRead, setIsURLRead] = useState(false) @@ -16,17 +16,17 @@ const useUrlState = (key) => { // int his case the key should be different per app const urlStateManager = registerConsumer(key || DEFAULT_KEY) - const { setActiveTab } = useGlobalsActions() - const activeTab = useGlobalsActiveTab() + const { setActiveNavEntry } = useGlobalsActions() + const activeNavEntry = useGlobalsActiveNavEntry() // Set initial state from URL (on login) useEffect(() => { if (isURLRead) return // READ the url state and set the state - const newTabIndex = urlStateManager.currentState()?.[ACTIVE_TAB] + const newNavIndex = urlStateManager.currentState()?.[ACTIVE_NAV] // SAVE the state - if (newTabIndex) setActiveTab(newTabIndex) + if (newNavIndex) setActiveNavEntry(newNavIndex) setIsURLRead(true) }, [isURLRead]) @@ -34,9 +34,9 @@ const useUrlState = (key) => { useEffect(() => { if (!isURLRead) return urlStateManager.push({ - [ACTIVE_TAB]: activeTab, + [ACTIVE_NAV]: activeNavEntry, }) - }, [isURLRead, activeTab]) + }, [isURLRead, activeNavEntry]) } export default useUrlState diff --git a/apps/heureka/src/lib/slices/createGlobalsSlice.js b/apps/heureka/src/lib/slices/createGlobalsSlice.js index 75f446092..a12bfb193 100644 --- a/apps/heureka/src/lib/slices/createGlobalsSlice.js +++ b/apps/heureka/src/lib/slices/createGlobalsSlice.js @@ -12,12 +12,12 @@ const createGlobalsSlice = (set, get, options) => ({ apiEndpoint: options?.apiEndpoint, //The API endpoint to use for fetching data. isUrlStateSetup: false, //Set to true when the URL state has been set up. queryClientFnReady: false, //Set to true when the queryClient function is ready to be used. - activeTab: "Services", //Set to the active tab. + activeNavEntry: "Services", //Set to the active navEntry. showPanel: constants.PANEL_NONE, //Set to the which panel should be shown (e.g service details panel, issue matches details panel and so on), if any. showServiceDetail: null, showIssueDetail: null, - tabs: { + navEntries: { Services: { queryOptions: { first: 20, @@ -45,10 +45,10 @@ const createGlobalsSlice = (set, get, options) => ({ "globals/setQueryClientFnReady" ), - setQueryOptions: (tab, options) => + setQueryOptions: (navEntry, options) => set( produce((state) => { - state.globals.tabs[tab].queryOptions = options + state.globals.navEntries[navEntry].queryOptions = options }), false, "globals/setQueryOptions" @@ -63,13 +63,13 @@ const createGlobalsSlice = (set, get, options) => ({ false, "globals/setApiEndpoint" ), - setActiveTab: (activeTab) => + setActiveNavEntry: (activeNavEntry) => set( (state) => ({ - globals: { ...state.globals, activeTab: activeTab }, + globals: { ...state.globals, activeNavEntry: activeNavEntry }, }), false, - "globals/setActiveTab" + "globals/setActiveNavEntry" ), setShowPanel: (panel) => set(