diff --git a/playwright/editing-dashboard.spec.ts b/playwright/editing-dashboard.spec.ts index 1b04171..9f83510 100644 --- a/playwright/editing-dashboard.spec.ts +++ b/playwright/editing-dashboard.spec.ts @@ -11,7 +11,7 @@ const navigateToDashboardHub = async (page: Page) => { const navigateToGenericDashboard = async (page: Page, dashboardName: string) => { await navigateToDashboardHub(page); - await page.getByRole('link', { name: dashboardName }).click(); + await page.getByRole('link', { name: dashboardName, exact: true }).click(); await page.getByRole('button', { name: 'Add widgets' }).waitFor({ state: 'visible', timeout: 30000 }); }; @@ -123,6 +123,7 @@ test.describe('Set Dashboard as Homepage from Generic Page', () => { await page.getByText(`'${nonDefaultName}' has been set as homepage`).waitFor({ state: 'visible', timeout: 10000 }); await navigateToDashboardHub(page); + await page.getByRole('link', { name: nonDefaultName, exact: true }).waitFor({ state: 'visible', timeout: 10000 }); expect(await hasHomeIcon(page, nonDefaultName)).toBe(true); expect(await hasHomeIcon(page, defaultName)).toBe(false); diff --git a/playwright/widget-layout.spec.ts b/playwright/widget-layout.spec.ts index b594936..7b0f577 100644 --- a/playwright/widget-layout.spec.ts +++ b/playwright/widget-layout.spec.ts @@ -124,4 +124,50 @@ test.describe('Widget Layout - Add Widget from Drawer', () => { const resetButton = page.getByRole('button', { name: 'Reset to default' }); await expect(resetButton).toBeVisible(); }); + + test('should not show the widget drawer by default on page load', async ({ page }) => { + await page.locator('#widget-layout-container .pf-v6-widget-grid-tile__title') + .first() + .waitFor({ state: 'visible', timeout: 10000 }); + + const drawerText = page.getByText('Add new and previously removed widgets'); + await expect(drawerText).not.toBeVisible(); + }); +}); + +test.describe('Widget Layout - Empty Dashboard', () => { + test('should auto-open the widget drawer when dashboard has no widgets', async ({ page }) => { + await disableCookiePrompt(page); + await page.addInitScript(() => { + const originalFetch = window.fetch; + window.fetch = async (...args) => { + const url = typeof args[0] === 'string' ? args[0] : args[0] instanceof Request ? args[0].url : ''; + if ( + (url.includes('/api/widget-layout/v1/') && url.includes('dashboardType=')) || + (url.includes('/api/chrome-service/v1/dashboard-templates') && url.includes('dashboard=')) + ) { + return new Response(JSON.stringify({ + data: [{ + id: 1, + default: true, + templateBase: { name: 'landing-landingPage', displayName: 'Landing Page' }, + templateConfig: { sm: [], md: [], lg: [], xl: [] }, + dashboardName: 'Test Dashboard', + createdAt: '2024-01-01T00:00:00Z', + updatedAt: '2024-01-01T00:00:00Z', + deletedAt: null, + userId: 'test-user', + }], + }), { status: 200, headers: { 'Content-Type': 'application/json' } }); + } + return originalFetch(...args); + }; + }); + + await page.goto('/'); + await page.getByRole('button', { name: 'Add widgets' }).waitFor({ state: 'visible', timeout: 10000 }); + + const drawerText = page.getByText('Add new and previously removed widgets'); + await expect(drawerText).toBeVisible({ timeout: 10000 }); + }); }); diff --git a/src/Components/DnDLayout/GridLayout.tsx b/src/Components/DnDLayout/GridLayout.tsx index d77a87c..aca7762 100644 --- a/src/Components/DnDLayout/GridLayout.tsx +++ b/src/Components/DnDLayout/GridLayout.tsx @@ -22,29 +22,21 @@ const sidebarBreakpoints = { xl: 1250, lg: 1100, md: 800, sm: 500 }; const documentationLink = 'https://docs.redhat.com/en/documentation/red_hat_hybrid_cloud_console/1-latest/html-single/getting_started_with_the_red_hat_hybrid_cloud_console/index#customizing-main-page_navigating-the-console'; -const LayoutEmptyState = () => { - const setDrawerExpanded = useSetAtom(drawerExpandedAtom); - - useEffect(() => { - setDrawerExpanded(true); - }, []); - - return ( - - - - You don't have any widgets on your dashboard. To populate your dashboard, drag items from the blue widget bank to - this dashboard body here. - - - - - - - ); -}; +const LayoutEmptyState = () => ( + + + + You don't have any widgets on your dashboard. To populate your dashboard, drag items from the blue widget bank to + this dashboard body here. + + + + + + +); const getResizeHandle = (resizeHandleAxis: string, ref: React.Ref) => (
@@ -95,6 +87,10 @@ const GridLayout = ({ template, saveTemplate, isLoaded, isLayoutLocked = false, const activeLayout = newTemplate[layoutVariant] || []; setCurrentlyUsedWidgets(activeLayout.map((item) => item.widgetType)); + if (activeLayout.length === 0) { + setDrawerExpanded(true); + } + await saveTemplate(newTemplate as LocalExtendedTemplateConfig); }; @@ -108,6 +104,12 @@ const GridLayout = ({ template, saveTemplate, isLoaded, isLayoutLocked = false, const activeLayout = patternFlyTemplate[layoutVariant] || []; + useEffect(() => { + if (isLoaded && activeLayout.length === 0) { + setDrawerExpanded(true); + } + }, [isLoaded]); + return (
{activeLayout.length === 0 && isLoaded && } diff --git a/src/Modules/GenericDashboardPage.tsx b/src/Modules/GenericDashboardPage.tsx index 03d30e5..0b517ec 100644 --- a/src/Modules/GenericDashboardPage.tsx +++ b/src/Modules/GenericDashboardPage.tsx @@ -1,7 +1,7 @@ import { Breadcrumb, BreadcrumbItem, PageSection } from '@patternfly/react-core'; import React, { useEffect, useRef } from 'react'; import GridLayout from '../Components/DnDLayout/GridLayout'; -import { useAtomValue, useSetAtom } from 'jotai'; +import { Provider, useAtomValue, useSetAtom } from 'jotai'; import { lockedLayoutAtom } from '../state/lockedLayoutAtom'; import { Link, useParams } from 'react-router-dom'; import useDashboardTemplate from '../hooks/useDashboardTemplate'; @@ -11,8 +11,10 @@ import useChrome from '@redhat-cloud-services/frontend-components/useChrome'; import { resolvedWidgetMappingAtom } from '../state/widgetMappingAtom'; import { notificationsAtom, useRemoveNotification } from '../state/notificationsAtom'; import Portal from '@redhat-cloud-services/frontend-components-notifications/Portal'; +import { backendFlagAtom, store } from '../state/store'; +import { useFlag } from '@unleash/proxy-client-react'; -const GenericDashboardPage = () => { +const GenericDashboardPageInner = () => { const { id } = useParams<{ id: string }>(); const isLayoutLocked = useAtomValue(lockedLayoutAtom); const { template, saveTemplate, renameDashboard, isLoaded, dashboard } = useDashboardTemplate(Number(id)); @@ -23,6 +25,13 @@ const GenericDashboardPage = () => { const notifications = useAtomValue(notificationsAtom); const removeNotification = useRemoveNotification(); + const setBackendFlag = useSetAtom(backendFlagAtom); + const isNewBackend = useFlag('platform.widget-layout.new-backend'); + + useEffect(() => { + setBackendFlag(isNewBackend); + }, [isNewBackend]); + useEffect(() => { if (visibilityFunctions) { resolveWidgetMapping(visibilityFunctions); @@ -53,4 +62,10 @@ const GenericDashboardPage = () => { ); }; +const GenericDashboardPage = () => ( + + + +); + export default GenericDashboardPage; diff --git a/src/api/dashboard-templates-new.ts b/src/api/dashboard-templates-new.ts index e3c4771..06e7660 100644 --- a/src/api/dashboard-templates-new.ts +++ b/src/api/dashboard-templates-new.ts @@ -264,7 +264,7 @@ export const renameDashboardTemplate = async (templateId: DashboardTemplate['id' }); handleErrors(resp); const json = await resp.json(); - return json.data; + return json; }; // POST /api/widget-layout/v1/{id}/copy diff --git a/src/hooks/useDashboardConfig.ts b/src/hooks/useDashboardConfig.ts index f4e2721..f265d02 100644 --- a/src/hooks/useDashboardConfig.ts +++ b/src/hooks/useDashboardConfig.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useAtom } from 'jotai'; +import { useAtom, useSetAtom } from 'jotai'; import DebouncePromise from 'awesome-debounce-promise'; import { templateAtom, templateIdAtom } from '../state/templateAtom'; import { layoutVariantAtom } from '../state/layoutAtom'; @@ -14,6 +14,7 @@ import { import useCurrentUser from './useCurrentUser'; import { useAddNotification } from '../state/notificationsAtom'; import { useApi } from './useApi'; +import { drawerExpandedAtom } from '../state/drawerExpandedAtom'; import { useFlag } from '@unleash/proxy-client-react'; const sidebarBreakpoints = { xl: 1250, lg: 1100, md: 800, sm: 500 }; @@ -30,12 +31,20 @@ const useDashboardConfig = (layoutType: LayoutTypes = 'landing-landingPage') => const layoutRef = useRef(null); const api = useApi(); const debouncedPatchDashboardTemplate = useMemo(() => DebouncePromise(api.patchDashboardTemplate, 1500, { onlyResolvesLast: true }), [api]); + const setDrawerExpanded = useSetAtom(drawerExpandedAtom); useEffect(() => { - if (!currentUser || templateId >= 0) { + if (!currentUser) { return; } + if (templateId >= 0) { + setIsLoaded(true); + return; + } + + setDrawerExpanded(false); + api .getDashboardTemplates(mappedLayoutType) .then((templates) => { diff --git a/src/hooks/useDashboardTemplate.ts b/src/hooks/useDashboardTemplate.ts index 20c528f..358b233 100644 --- a/src/hooks/useDashboardTemplate.ts +++ b/src/hooks/useDashboardTemplate.ts @@ -14,6 +14,7 @@ import { useAtomValue, useSetAtom } from 'jotai'; import { renameDashboardAtom } from '../state/dashboardsAtom'; import { templateIdAtom } from '../state/templateAtom'; import { backendFlagAtom } from '../state/store'; +import { drawerExpandedAtom } from '../state/drawerExpandedAtom'; import { widgetKeyMap } from '../consts'; const remapShortKeys = (config: ExtendedTemplateConfig): ExtendedTemplateConfig => { @@ -68,8 +69,10 @@ const useDashboardTemplate = (id: number) => { const debouncedPatchDashboardTemplate = useMemo(() => DebouncePromise(api.patchDashboardTemplateHub, 1500, { onlyResolvesLast: true }), [api]); const renameDashboardInList = useSetAtom(renameDashboardAtom); const invalidateStartPage = useSetAtom(templateIdAtom); + const setDrawerExpanded = useSetAtom(drawerExpandedAtom); useEffect(() => { + setDrawerExpanded(false); const fetchTemplate = async () => { setIsLoaded(false); setError(null);