diff --git a/.github/workflows/gubbins-test.yml b/.github/workflows/gubbins-test.yml index cb15ad76..aaaa8382 100644 --- a/.github/workflows/gubbins-test.yml +++ b/.github/workflows/gubbins-test.yml @@ -330,3 +330,10 @@ jobs: browser: chrome config: baseUrl=${{ env.DIRACX_URL }} project: /tmp/gubbins-web + + - name: Upload Cypress screenshots + if: failure() + uses: actions/upload-artifact@v4 + with: + name: cypress-screenshots + path: /tmp/gubbins-web/cypress/screenshots \ No newline at end of file diff --git a/docs/developer/create_application.md b/docs/developer/create_application.md index 8964e4b1..52b552b6 100644 --- a/docs/developer/create_application.md +++ b/docs/developer/create_application.md @@ -6,7 +6,7 @@ The applicatins created here will be available for DiracX-Web and for all the ex ### Declare the application -In the file `packages/diracx-web-components/src/components/ApplicationList.ts` you can extend the `applicationList` with your new app. +In the file `packages/diracx-web-components/src/components/applicationList.ts` you can extend the `applicationList` with your new app. You must provide: - A clear and explicit name diff --git a/packages/diracx-web-components/src/components/ApplicationList.ts b/packages/diracx-web-components/src/components/applicationList.ts similarity index 100% rename from packages/diracx-web-components/src/components/ApplicationList.ts rename to packages/diracx-web-components/src/components/applicationList.ts diff --git a/packages/diracx-web-components/src/components/defaultDashboard.ts b/packages/diracx-web-components/src/components/defaultDashboard.ts new file mode 100644 index 00000000..b04b6f10 --- /dev/null +++ b/packages/diracx-web-components/src/components/defaultDashboard.ts @@ -0,0 +1,15 @@ +import { DashboardGroup } from "../types/DashboardGroup"; + +export const defaultDashboard: DashboardGroup[] = [ + { + title: "My dashboard", + extended: true, + items: [ + { + title: "My Jobs", + type: "Job Monitor", + id: "JobMonitor0", + }, + ], + }, +]; diff --git a/packages/diracx-web-components/src/components/index.ts b/packages/diracx-web-components/src/components/index.ts index a093c1e5..f5da5865 100644 --- a/packages/diracx-web-components/src/components/index.ts +++ b/packages/diracx-web-components/src/components/index.ts @@ -1,5 +1,5 @@ // Application list -export { applicationList } from "./ApplicationList"; +export { applicationList } from "./applicationList"; // Dashboard Layout export * from "./DashboardLayout"; diff --git a/packages/diracx-web-components/src/contexts/ApplicationsProvider.tsx b/packages/diracx-web-components/src/contexts/ApplicationsProvider.tsx index af97ee87..c0996263 100644 --- a/packages/diracx-web-components/src/contexts/ApplicationsProvider.tsx +++ b/packages/diracx-web-components/src/contexts/ApplicationsProvider.tsx @@ -1,7 +1,8 @@ "use client"; import React, { createContext, useEffect, useState } from "react"; -import { applicationList } from "../components/ApplicationList"; +import { applicationList } from "../components/applicationList"; +import { defaultDashboard } from "../components/defaultDashboard"; import { DashboardGroup } from "../types/DashboardGroup"; import ApplicationMetadata from "../types/ApplicationMetadata"; @@ -33,7 +34,7 @@ interface ApplicationsProviderProps { export const ApplicationsProvider = ({ children, appList = applicationList, - defaultUserDashboard, + defaultUserDashboard = defaultDashboard, }: ApplicationsProviderProps) => { const loadedDashboard = sessionStorage.getItem("savedDashboard"); const parsedDashboard: DashboardGroup[] = loadedDashboard @@ -51,21 +52,7 @@ export const ApplicationsProvider = ({ useEffect(() => { if (userDashboard.length !== 0) return; - setUserDashboard( - defaultUserDashboard || [ - { - title: "My dashboard", - extended: true, - items: [ - { - title: "My Jobs", - type: "Job Monitor", - id: "JobMonitor0", - }, - ], - }, - ], - ); + setUserDashboard(defaultUserDashboard); }, [appList, defaultUserDashboard]); // Save the dashboard in session storage diff --git a/packages/diracx-web-components/src/contexts/DiracXWebProviders.tsx b/packages/diracx-web-components/src/contexts/DiracXWebProviders.tsx index 323b3502..856a7e2c 100644 --- a/packages/diracx-web-components/src/contexts/DiracXWebProviders.tsx +++ b/packages/diracx-web-components/src/contexts/DiracXWebProviders.tsx @@ -1,5 +1,8 @@ "use client"; +import type { ApplicationMetadata, DashboardGroup } from "../types"; + +import { OIDCSecure } from "../components"; import { OIDCConfigurationProvider, ThemeProvider, @@ -12,6 +15,8 @@ interface DiracXWebProvidersProps { getPath: () => string; setPath: (path: string) => void; getSearchParams: () => URLSearchParams; + appList?: ApplicationMetadata[]; + defaultUserDashboard?: DashboardGroup[]; } export function DiracXWebProviders({ @@ -19,6 +24,8 @@ export function DiracXWebProviders({ getPath, setPath, getSearchParams, + appList, + defaultUserDashboard, }: DiracXWebProvidersProps) { return ( @@ -27,8 +34,13 @@ export function DiracXWebProviders({ setPath={setPath} getSearchParams={getSearchParams} > - - {children} + + + {children} + diff --git a/packages/diracx-web-components/stories/Dashboard.stories.tsx b/packages/diracx-web-components/stories/Dashboard.stories.tsx index be3d3e3f..1a05227c 100644 --- a/packages/diracx-web-components/stories/Dashboard.stories.tsx +++ b/packages/diracx-web-components/stories/Dashboard.stories.tsx @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Box } from "@mui/material"; import { ApplicationsContext } from "../src/contexts/ApplicationsProvider"; import { NavigationProvider } from "../src/contexts/NavigationProvider"; -import { applicationList } from "../src/components/ApplicationList"; +import { applicationList } from "../src/components/applicationList"; import { DashboardGroup } from "../src/types/DashboardGroup"; import Dashboard from "../src/components/DashboardLayout/Dashboard"; import { ThemeProvider } from "../src/contexts/ThemeProvider"; diff --git a/packages/diracx-web/src/app/(dashboard)/layout.tsx b/packages/diracx-web/src/app/(dashboard)/layout.tsx index 3e2f29e2..0222f171 100644 --- a/packages/diracx-web/src/app/(dashboard)/layout.tsx +++ b/packages/diracx-web/src/app/(dashboard)/layout.tsx @@ -2,10 +2,7 @@ import React from "react"; import { Box } from "@mui/material"; import { DiracXWebProviders } from "@dirac-grid/diracx-web-components/contexts"; -import { - OIDCSecure, - Dashboard, -} from "@dirac-grid/diracx-web-components/components"; +import { Dashboard } from "@dirac-grid/diracx-web-components/components"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; export default function DashboardLayout({ @@ -25,22 +22,20 @@ export default function DashboardLayout({ }} getSearchParams={() => searchParams} > - - - - {children} - - - + + + {children} + + ); diff --git a/packages/extensions/src/app/(dashboard)/layout.tsx b/packages/extensions/src/app/(dashboard)/layout.tsx index b15d764d..1f464574 100644 --- a/packages/extensions/src/app/(dashboard)/layout.tsx +++ b/packages/extensions/src/app/(dashboard)/layout.tsx @@ -1,16 +1,10 @@ "use client"; import React from "react"; import { Box } from "@mui/material"; -import { - OIDCSecure, - Dashboard, -} from "@dirac-grid/diracx-web-components/components"; -import { - ApplicationsProvider, - DiracXWebProviders, -} from "@dirac-grid/diracx-web-components/contexts"; +import { Dashboard } from "@dirac-grid/diracx-web-components/components"; +import { DiracXWebProviders } from "@dirac-grid/diracx-web-components/contexts"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; -import { applicationList } from "@/gubbins/ApplicationList"; +import { applicationList } from "@/gubbins/applicationList"; import { defaultSections } from "@/gubbins/DefaultUserDashboard"; // Layout for the dashboard: setup the providers and the dashboard for the applications @@ -32,32 +26,25 @@ export default function DashboardLayout({ getPath={() => pathname} setPath={router.push} getSearchParams={() => searchParams} + // You can optionally pass a list of applications and a default user dashboard + appList={applicationList} + defaultUserDashboard={defaultSections} > - {/* ApplicationsProvider is the provider for the applications, you can give it customized application list or default user dashboard to override them. - No need to use it if you don't want to customize the applications */} - - {/* OIDCSecure is used to make sure the user is authenticated before accessing the dashboard */} - - {/* Dashboard is the main layout for the applications, you can optionally give it a custom logo URL and a drawer width */} - - - {children} - - - - + {/* Dashboard is the main layout for the applications, you can optionally give it a custom logo URL and a drawer width */} + + + {children} + + ); } diff --git a/packages/extensions/src/app/auth/layout.tsx b/packages/extensions/src/app/auth/layout.tsx index 7e563ffc..1a573ab0 100644 --- a/packages/extensions/src/app/auth/layout.tsx +++ b/packages/extensions/src/app/auth/layout.tsx @@ -2,6 +2,8 @@ import React from "react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { DiracXWebProviders } from "@dirac-grid/diracx-web-components/contexts"; +import { applicationList } from "@/gubbins/applicationList"; +import { defaultSections } from "@/gubbins/DefaultUserDashboard"; // Layout for the authentication page: setup the navigation provider export default function AuthLayout({ @@ -19,6 +21,9 @@ export default function AuthLayout({ getPath={() => pathname} setPath={router.push} getSearchParams={() => searchParams} + // You can optionally pass a list of applications and a default user dashboard + appList={applicationList} + defaultUserDashboard={defaultSections} > {children} diff --git a/packages/extensions/src/gubbins/ApplicationList.ts b/packages/extensions/src/gubbins/applicationList.ts similarity index 100% rename from packages/extensions/src/gubbins/ApplicationList.ts rename to packages/extensions/src/gubbins/applicationList.ts diff --git a/packages/extensions/src/gubbins/components/OwnerMonitor/OwnerMonitor.tsx b/packages/extensions/src/gubbins/components/OwnerMonitor/OwnerMonitor.tsx index 6dc9c552..ef49e8e0 100644 --- a/packages/extensions/src/gubbins/components/OwnerMonitor/OwnerMonitor.tsx +++ b/packages/extensions/src/gubbins/components/OwnerMonitor/OwnerMonitor.tsx @@ -1,5 +1,5 @@ "use client"; -import React, { useMemo, useState } from "react"; +import React, { useMemo, useState, useEffect, useCallback } from "react"; import { useOidcAccessToken } from "@axa-fr/react-oidc"; import { fetcher, @@ -34,7 +34,7 @@ export default function OwnerMonitor() { }); // Fetch the list of owners - const fetchOwners = async () => { + const fetchOwners = useCallback(async () => { try { setIsLoading(true); const response = await fetcher([ @@ -53,7 +53,7 @@ export default function OwnerMonitor() { } finally { setIsLoading(false); } - }; + }, [accessToken]); // Handle adding a new owner const handleAddOwner = async () => { @@ -91,6 +91,10 @@ export default function OwnerMonitor() { onPaginationChange: setPagination, }); + useEffect(() => { + fetchOwners(); + }, [fetchOwners]); + return ( { // so we must tell it to visit our website with the `cy.visit()` command. // Since we want to visit the same URL at the start of all our tests, // we include it in our beforeEach function so that it runs before each test - cy.visit("/"); + cy.visit("/auth"); }); it("login", () => { @@ -43,7 +43,9 @@ describe("Login and Logout", () => { // From now on the user is logged in // The login buttton should not be present anymore cy.get('[data-testid="button-login"]').should("not.exist"); - cy.contains("Hello admin").should("exist"); + + cy.visit("/"); + cy.contains("Owners").should("exist"); // Click on the user avatar cy.get(".MuiAvatar-root").click(); diff --git a/packages/extensions/test/e2e/ownerMonitor.cy.ts b/packages/extensions/test/e2e/ownerMonitor.cy.ts index ff81c400..cad7dd61 100644 --- a/packages/extensions/test/e2e/ownerMonitor.cy.ts +++ b/packages/extensions/test/e2e/ownerMonitor.cy.ts @@ -1,9 +1,9 @@ /// -describe("Job Monitor", () => { +describe("Owner Monitor", () => { beforeEach(() => { cy.session("login", () => { - cy.visit("/"); + cy.visit("/auth"); //login cy.get('[data-testid="button-login"]').click(); cy.get("#login").type("admin@example.com"); @@ -17,9 +17,14 @@ describe("Job Monitor", () => { }); // Visit the page where the Job Monitor is rendered - cy.visit( - "/?appId=OwnerMonitor1&dashboard=%5B3Gubbins+Apps%27~extended%21true~items%21%5B-020.04~data%21%5B%5D%29%2C3Job2Job.Job4%29%5D%29%5D*Monitor-%28%27title%21%27.*1%27~type%21%270Owner2s%27~id%21%273-My+4+*%27%014320.-*_", - ); + cy.window().then((win) => { + win.sessionStorage.setItem( + "savedDashboard", + '[{"title":"Group 2","extended":true,"items":[{"title":"Owner Monitor","id":"JOwner Monitor0","type":"Owner Monitor"},{"title":"Owner Monitor 2","id":"Owner Monitor 21","type":"Owner Monitor"}]}]', + ); + }); + + cy.visit("/"); }); it("should render the drawer", () => { @@ -47,7 +52,6 @@ describe("Job Monitor", () => { }); /** Column interactions */ - it("should hide/show columns", () => { // Click on the visibility icon cy.get('[data-testid="VisibilityIcon"] > path').click();