diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f04b2e95 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,53 @@ +# Contributing to This Project + +Thank you for your interest in contributing to our project! We appreciate all contributions, big and small. Below are some guidelines to help you get started. + +## How to Contribute + +### 1. Opening an Issue + +- **Discuss Before Implementing:** Before making a pull request (PR), especially for non-trivial changes, please [open an issue](https://github.com/DIRACGrid/diracx-web/issues) to discuss your idea. This ensures that everyone is aligned on the proposed change. +- **Check for Existing Issues:** Before opening a new issue, please check if a similar issue already exists. If a similar issue exists, consider contributing to the discussion there instead. + +### 2. Making Changes + +- **Code Documentation:** Ensure that any code you write is well-documented. This includes: + - Inline comments where necessary to explain complex logic. + - Updating or creating Storybook documentation if you are contributing to the `diracx-web-components` library. +- **Writing/Updating Tests:** When you change or add new code, make sure to write or update tests accordingly. This helps maintain the reliability and stability of the codebase. +- **Helping with Existing Issues:** If you want to start contributing right away, check out the issues labeled with ["good first issue"](https://github.com/DIRACGrid/diracx-web/labels/good%20first%20issue). These are issues that are well-suited for newcomers to the project. + +### 3. Commit Messages + +- **Conventional Commits:** All commits must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. This ensures that commit messages are structured and consistent, which is important for automation and versioning. + - **Examples:** + - `feat(ui): add new button component` + - `fix(api): handle null values in response` + - `docs(readme): update contributing guidelines` + - **Why?** If your commit messages do not follow this convention, the Continuous Integration (CI) process will fail, and your PR will not be merged. Please ensure your commit messages are properly formatted before pushing. + +### 4. How to Make a Pull Request (PR) + +- **Fork the Repository:** Start by forking the repository and creating a new branch for your work. Use a descriptive name for your branch that reflects the work you're doing. +- **Make Your Changes:** Commit your changes with clear and concise commit messages following the Conventional Commits format. +- **Update Documentation and Tests:** As mentioned, ensure all relevant documentation and tests are updated to reflect your changes. +- **Submit Your PR:** When you’re ready, submit your pull request. Please include a clear description of what your PR does and reference the issue number it addresses (if applicable). +- **Review Process:** Your PR will be reviewed by project maintainers. Please be patient and responsive to any feedback you receive. + +### 5. Updating Storybook Stories + +If your changes affect the `diracx-web-components` library, you may need to update or add new Storybook stories to ensure components are well-documented and tested visually. + +- **Add New Stories:** If you’ve created a new component, add a corresponding Storybook story in the appropriate directory. This story should be placed inside a `*.stories.tsx` file alongside your new component. +- **Update Existing Stories:** If your changes modify the behavior or appearance of an existing component, make sure to update its Storybook story accordingly. +- **Run Storybook Locally:** Before submitting your PR, run Storybook locally to ensure that your changes are reflected correctly. You can do this by running `npm run storybook` in the `packages/diracx-web-components` directory. + +You can check the existing stories and the [Storybook documentation](https://storybook.js.org/docs) for more details on how to use Storybook. + +### 6. Additional Notes + +- **Trivial Changes:** For minor changes like fixing typos, feel free to skip the issue creation step and go straight to making a PR. +- **Stay Up-to-Date:** Make sure your branch is up-to-date with the latest changes in the main branch before submitting your PR. Use `git rebase` if necessary. +- **Project Setup:** See the README for instructions on how to set up the project and run tests locally. + +Thank you again for your contributions! We look forward to working with you. diff --git a/README.md b/README.md index 3324f45f..eadac92b 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ diracx-charts/run_demo.sh ./diracx-web - Want to discuss about UX/UI design? Share your [Design idea](https://github.com/DIRACGrid/diracx-web/discussions/categories/design-ideas). +See the [Contributing guidelines](/CONTRIBUTING.md) + ## Testing Unit tests can be started with: diff --git a/packages/diracx-web-components/.storybook/main.ts b/packages/diracx-web-components/.storybook/main.ts index e9ca7530..83611293 100644 --- a/packages/diracx-web-components/.storybook/main.ts +++ b/packages/diracx-web-components/.storybook/main.ts @@ -10,7 +10,7 @@ function getAbsolutePath(value: string): any { return dirname(require.resolve(join(value, "package.json"))); } const config: StorybookConfig = { - stories: ["../**/*.mdx", "../**/*.stories.@(js|jsx|mjs|ts|tsx)"], + stories: ["./*.mdx", "../**/*.mdx", "../**/*.stories.@(js|jsx|mjs|ts|tsx)"], addons: [ getAbsolutePath("@storybook/addon-links"), getAbsolutePath("@storybook/addon-essentials"), diff --git a/packages/diracx-web-components/.storybook/preview.tsx b/packages/diracx-web-components/.storybook/preview.tsx index 04b10592..51dcf29d 100644 --- a/packages/diracx-web-components/.storybook/preview.tsx +++ b/packages/diracx-web-components/.storybook/preview.tsx @@ -15,7 +15,7 @@ const preview: Preview = { decorators: [ (Story) => ( -
+
diff --git a/packages/diracx-web-components/components/DashboardLayout/ApplicationDialog.tsx b/packages/diracx-web-components/components/DashboardLayout/ApplicationDialog.tsx index 21e2df4d..232a2314 100644 --- a/packages/diracx-web-components/components/DashboardLayout/ApplicationDialog.tsx +++ b/packages/diracx-web-components/components/DashboardLayout/ApplicationDialog.tsx @@ -1,4 +1,4 @@ -import React, { ComponentType } from "react"; +import React from "react"; import { Dialog, DialogTitle, @@ -9,7 +9,7 @@ import { Icon, IconButton, } from "@mui/material"; -import { Close } from "@mui/icons-material"; +import { Close, SvgIconComponent } from "@mui/icons-material"; import { ApplicationsContext } from "@/contexts/ApplicationsProvider"; /** @@ -28,7 +28,7 @@ export default function AppDialog({ /** Function to set the open state of the dialog. */ setAppDialogOpen: React.Dispatch>; /** Function to handle the creation of a new application. */ - handleCreateApp: (name: string, icon: ComponentType) => void; + handleCreateApp: (name: string, icon: SvgIconComponent) => void; }) { const [appType, setAppType] = React.useState(""); const applicationList = React.useContext(ApplicationsContext)[2]; @@ -50,7 +50,7 @@ export default function AppDialog({ return; } - handleCreateApp(appType, icon as React.ComponentType); + handleCreateApp(appType, icon); setAppDialogOpen(false); }, diff --git a/packages/diracx-web-components/components/DashboardLayout/Dashboard.stories.tsx b/packages/diracx-web-components/components/DashboardLayout/Dashboard.stories.tsx index 6c5f32a9..594ba7c4 100644 --- a/packages/diracx-web-components/components/DashboardLayout/Dashboard.stories.tsx +++ b/packages/diracx-web-components/components/DashboardLayout/Dashboard.stories.tsx @@ -75,7 +75,7 @@ export const Default: Story = { children:
, logoURL: process.env.STORYBOOK_DEV ? undefined - : "/diracx-web/DIRAC-logo.png", + : "/diracx-web/DIRAC-logo.png", // we need to add "/diracx-web" at the start of the url in production because of the repo name in the github pages url }, render: (props) => { useOidc.mockReturnValue({ diff --git a/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.stories.tsx b/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.stories.tsx index 05050c1e..0703d84a 100644 --- a/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.stories.tsx +++ b/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.stories.tsx @@ -72,6 +72,6 @@ export const Default: Story = { width: 240, logoURL: process.env.STORYBOOK_DEV ? undefined - : "/diracx-web/DIRAC-logo.png", + : "/diracx-web/DIRAC-logo.png", // we need to add "/diracx-web" at the start of the url in production because of the repo name in the github pages url }, }; diff --git a/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.tsx b/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.tsx index 48733344..0b68f5ff 100644 --- a/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.tsx +++ b/packages/diracx-web-components/components/DashboardLayout/DashboardDrawer.tsx @@ -13,9 +13,8 @@ import { TextField, Toolbar, } from "@mui/material"; -import { MenuBook, Add } from "@mui/icons-material"; +import { MenuBook, Add, SvgIconComponent } from "@mui/icons-material"; import React, { - ComponentType, ReactEventHandler, useContext, useEffect, @@ -206,7 +205,7 @@ export default function DashboardDrawer(props: DashboardDrawerProps) { * @param appType - The type of the app to be created. * @param icon - The icon component for the app. */ - const handleAppCreation = (appType: string, icon: ComponentType) => { + const handleAppCreation = (appType: string, icon: SvgIconComponent) => { let group = userSections[userSections.length - 1]; const empty = !group; if (empty) { diff --git a/packages/diracx-web-components/components/Login/LoginForm.stories.tsx b/packages/diracx-web-components/components/Login/LoginForm.stories.tsx index d1c0a0e8..5ceb9ad0 100644 --- a/packages/diracx-web-components/components/Login/LoginForm.stories.tsx +++ b/packages/diracx-web-components/components/Login/LoginForm.stories.tsx @@ -37,7 +37,7 @@ const meta = { args: { logoURL: process.env.STORYBOOK_DEV ? undefined - : "/diracx-web/DIRAC-logo-minimal.png", + : "/diracx-web/DIRAC-logo-minimal.png", // we need to add "/diracx-web" at the start of the url in production because of the repo name in the github pages url }, } satisfies Meta; diff --git a/packages/diracx-web-components/hooks/theme.tsx b/packages/diracx-web-components/hooks/theme.tsx index 55dc859d..925b93ae 100644 --- a/packages/diracx-web-components/hooks/theme.tsx +++ b/packages/diracx-web-components/hooks/theme.tsx @@ -36,6 +36,9 @@ export const useMUITheme = () => { }, }); + const primary = lightGreen[700]; + const secondary = cyan[500]; + const scrollbarBackground = theme === "dark" ? "#333" : "#f1f1f1"; const scrollbarThumbBackground = theme === "dark" ? "#888" : "#ccc"; const scrollbarThumbHoverBackground = theme === "dark" ? "#555" : "#999"; @@ -70,27 +73,27 @@ export const useMUITheme = () => { contained: { // Target the 'contained' variant color: "white", - backgroundColor: lightGreen[700], + backgroundColor: primary, "&:hover": { color: "white", - backgroundColor: cyan[500], + backgroundColor: secondary, }, }, outlined: { // Target the 'outlined' variant - color: lightGreen[700], - borderColor: lightGreen[700], + color: primary, + borderColor: primary, "&:hover": { - color: cyan[500], - borderColor: cyan[500], + color: secondary, + borderColor: secondary, backgroundColor: "transparent", }, }, text: { // Target the 'text' variant - color: lightGreen[700], + color: primary, "&:hover": { - color: cyan[500], + color: secondary, backgroundColor: "transparent", //underline in cyan textDecoration: "underline", @@ -168,10 +171,10 @@ export const useMUITheme = () => { styleOverrides: { root: { "&.Mui-checked": { - color: lightGreen[700], + color: primary, }, "&.MuiCheckbox-indeterminate": { - color: cyan[500], + color: secondary, }, }, }, diff --git a/packages/diracx-web-components/mocks/JobDataService.mock.ts b/packages/diracx-web-components/mocks/JobDataService.mock.ts index 77148e4f..770b92bc 100644 --- a/packages/diracx-web-components/mocks/JobDataService.mock.ts +++ b/packages/diracx-web-components/mocks/JobDataService.mock.ts @@ -1,4 +1,5 @@ import { fn } from "@storybook/test"; +// @ts-ignore: Cannot find module '@actual/components/JobMonitor/JobDataService' import * as actual from "@actual/components/JobMonitor/JobDataService"; export const useJobs = fn(actual.useJobs); diff --git a/packages/diracx-web-components/mocks/metadata.mock.ts b/packages/diracx-web-components/mocks/metadata.mock.ts index 16fd8f37..a80aaef2 100644 --- a/packages/diracx-web-components/mocks/metadata.mock.ts +++ b/packages/diracx-web-components/mocks/metadata.mock.ts @@ -1,4 +1,5 @@ import { fn } from "@storybook/test"; +// @ts-ignore: Cannot find module '@actual/hooks/metadata' import * as actual from "@actual/hooks/metadata"; export const useMetadata = fn(actual.useMetadata); diff --git a/packages/diracx-web-components/mocks/react-oidc.mock.ts b/packages/diracx-web-components/mocks/react-oidc.mock.ts index 9c10e918..6fb5a582 100644 --- a/packages/diracx-web-components/mocks/react-oidc.mock.ts +++ b/packages/diracx-web-components/mocks/react-oidc.mock.ts @@ -1,4 +1,5 @@ import { fn } from "@storybook/test"; +// @ts-ignore: Cannot find module '@actual/react-oidc' import * as actual from "@actual/react-oidc"; export const useOidc = fn(actual.useOidc); diff --git a/packages/diracx-web-components/test/tsconfig.json b/packages/diracx-web-components/test/tsconfig.json index dbf8147c..5315ee96 100644 --- a/packages/diracx-web-components/test/tsconfig.json +++ b/packages/diracx-web-components/test/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "module": "esnext", "lib": ["dom", "dom.iterable", "esnext"], "declaration": true, diff --git a/packages/diracx-web-components/tsconfig.json b/packages/diracx-web-components/tsconfig.json index a6bdfc3f..6921613a 100644 --- a/packages/diracx-web-components/tsconfig.json +++ b/packages/diracx-web-components/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "module": "esnext", "lib": ["dom", "dom.iterable", "esnext"], "declaration": true, diff --git a/packages/diracx-web-components/tsup.config.ts b/packages/diracx-web-components/tsup.config.ts index f37073b9..96efba1a 100644 --- a/packages/diracx-web-components/tsup.config.ts +++ b/packages/diracx-web-components/tsup.config.ts @@ -11,9 +11,9 @@ export default defineConfig([ "contexts/!(index|*.stories).ts?(x)", "types/!(index|*.stories).ts?(x)", ], - format: ["esm", "cjs"], + format: ["esm"], experimentalDts: true, // Seems to work fine, lower memory usage and faster than dts - target: "es5", + target: "es6", bundle: true, sourcemap: true, async onSuccess() { diff --git a/packages/diracx-web-components/types/UserSection.ts b/packages/diracx-web-components/types/UserSection.ts index a5ac13be..900d6377 100644 --- a/packages/diracx-web-components/types/UserSection.ts +++ b/packages/diracx-web-components/types/UserSection.ts @@ -1,3 +1,5 @@ +import { SvgIconComponent } from "@mui/icons-material"; + // Define the type for the userSections state export type UserSection = { title: string; @@ -6,7 +8,7 @@ export type UserSection = { title: string; type: string; id: string; - icon: React.ComponentType; + icon: SvgIconComponent; data?: any; }[]; }; diff --git a/packages/diracx-web/tsconfig.json b/packages/diracx-web/tsconfig.json index be05ba1f..5bdf703c 100644 --- a/packages/diracx-web/tsconfig.json +++ b/packages/diracx-web/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es6", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/packages/extensions/README.md b/packages/extensions/README.md index 4abfb022..f63d5762 100644 --- a/packages/extensions/README.md +++ b/packages/extensions/README.md @@ -1,5 +1,7 @@ # Creating a Next.js DiracX Web Extension +![Extension Logo](public/robot.png) + This project aims to provide an example for creating a basic Next.js web extension for DiracX. It includes the necessary configuration and setup to get you started quickly. ## Prerequisites @@ -10,6 +12,12 @@ Before starting, ensure you have the following installed: - [Node.js](https://nodejs.org/) - [Git](https://git-scm.com/) +And ensure you have basic knowledge of: + +- [React](https://react.dev/) +- [Next.js](https://nextjs.org/) +- [MUI](https://mui.com/) + ## Getting Started You can either create a new repository or fork this repository to build your DiracX extension. Follow one of the methods below: @@ -25,6 +33,8 @@ You can either create a new repository or fork this repository to build your Dir npm install ``` +3. **Modify the app pages** to use components from the `diracx-components` library (e.g., providers, apps). + ### Method 2: Create a New Next.js Project 1. **Create a new Next.js project** using the following command: @@ -74,13 +84,34 @@ You can either create a new repository or fork this repository to build your Dir See the [OIDC library documentation](https://github.com/AxaFrance/oidc-client/tree/main/packages/react-oidc#getting-started) for more information. -4. **Modify the app pages** to use components from the `diracx-components` library (e.g., providers, apps). +4. **Edit the Next.js config** with these options: + + ```js + output: "export", + images: { + unoptimized: true, + }, + ``` + + The output is set to `export` to have a static application. + Images are left unoptimized because it's not well-supported with a static export. + +5. **Add the nginx config** located in the [`config/nginx`](config/nginx/) directory. + This adjustment ensures that Nginx can correctly handle requests for .html files and fall back appropriately, preventing the `404: Not Found` errors encountered when accessing routes like `/auth`. (see [#57](https://github.com/DIRACGrid/diracx-web/pull/57)) + +6. **Organize your pages** in the `src/app` app directory. + The `` context is needed by most of the components of `diracx-web-components`, so you should include it in the layouts of your application. Use `` to require authentication on a route. You can also override some default values of certain contexts like `` for the application list. + Finally, some components have some personalization options (i.e. the logo URL for the dashboard), check the [Storybook documentation](https://diracgrid.github.io/diracx-web/) to see the props of each component. + Check [the app directory](src/app/) in this example to have a reference. ### Architecture We strongly recommend following the directory structure below to keep your project organized: -- `/src/app`: Contains the main application logic and Next.js setup. This directory houses the core of the application built using Next.js, where each page.tsx file represents a page in the application with [folder-based routing](https://nextjs.org/docs/app/building-your-application/routing). [Next.js Official Documentation](https://nextjs.org/docs) +- `/src/app`: Contains the main application logic and Next.js setup. This directory houses the core of the application built using Next.js, where each page.tsx file represents a page in the application with [folder-based routing](https://nextjs.org/docs/app/building-your-application/routing). [Next.js Official Documentation](https://nextjs.org/docs). + The page.tsx files contain the UI for a route and layout.tsx files handles the shared UI for a segment and its children. + In this example the `(Dashboard)` folder manages the main interface where users interact with the app's primary functions. Names in parentheses are ignored for the route, so it is the root URL. + The `auth` folder handles the authentication of users, and the route is `/auth`. - `/src/`: This directory includes the source code related to your extension. You can create custom components, hooks, ... in this directory. - `/src//components`: Contains custom React components. This folder includes reusable UI components built using React. Components in React are independent, reusable pieces of UI that can manage their own state. [React Components](https://reactjs.org/docs/components-and-props.html) @@ -116,7 +147,7 @@ Having a directory dedicated to your extension components will help you keep you To add new apps to your extension, you can create new components in your extension directory. -[`testApp`](src/gubbins/components/TestApp/testApp.tsx) provides an example of a basic app component. +[`testApp`](src/gubbins/components/TestApp/testApp.tsx) provides an example of a basic app component and the [Storybook documentation](https://diracgrid.github.io/diracx-web/) showcases all the components you can use from the library in an interactive interface. It is then pretty easy to add them to DiracX Web by extending the `applicationList` (the list of apps available in DiracX-Web) from `diracx-web-components/components`. diff --git a/packages/extensions/package.json b/packages/extensions/package.json index 7e3e0e61..81b3c732 100644 --- a/packages/extensions/package.json +++ b/packages/extensions/package.json @@ -11,6 +11,7 @@ "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public" }, "dependencies": { + "@axa-fr/react-oidc": "^7.22.6", "@dirac-grid/diracx-web-components": "0.1.0-a1", "autoprefixer": "10.4.19", "next": "14.2.3", diff --git a/packages/extensions/public/DIRAC-logo-minimal.png b/packages/extensions/public/DIRAC-logo-minimal.png deleted file mode 100644 index 606fefde..00000000 Binary files a/packages/extensions/public/DIRAC-logo-minimal.png and /dev/null differ diff --git a/packages/extensions/public/DIRAC-logo.png b/packages/extensions/public/DIRAC-logo.png deleted file mode 100644 index 931b84b4..00000000 Binary files a/packages/extensions/public/DIRAC-logo.png and /dev/null differ diff --git a/packages/extensions/public/robot.png b/packages/extensions/public/robot.png new file mode 100644 index 00000000..e044d811 Binary files /dev/null and b/packages/extensions/public/robot.png differ diff --git a/packages/extensions/src/app/(dashboard)/layout.tsx b/packages/extensions/src/app/(dashboard)/layout.tsx index 419d0f41..c2e6e450 100644 --- a/packages/extensions/src/app/(dashboard)/layout.tsx +++ b/packages/extensions/src/app/(dashboard)/layout.tsx @@ -25,8 +25,7 @@ export default function DashboardLayout({ const searchParams = useSearchParams(); // A custom logo URL can be used for the dashboard - const customLogoURL = - "https://mattermost.web.cern.ch/files/oktn8gxjobrb9gwkznx3hx3z7w/public?h=VpJiHpv03q76Pv6KqX90y-dkGxOResdO9xFOa4JsMr4"; + const customLogoURL = "/robot.png"; return ( // DiracXWebProviders is the main provider for the DiracX Web components, you need to give it the pathname, router and search params pathname} setPath={router.push} getSearchParams={() => searchParams} > {children} - + ); } diff --git a/packages/extensions/src/app/auth/page.tsx b/packages/extensions/src/app/auth/page.tsx index 21a1fdfd..3f90f211 100644 --- a/packages/extensions/src/app/auth/page.tsx +++ b/packages/extensions/src/app/auth/page.tsx @@ -3,5 +3,6 @@ import { LoginForm } from "@dirac-grid/diracx-web-components/components"; // Login form page export default function Page() { - return ; + const logoURL = "/robot.png"; + return ; } diff --git a/packages/extensions/tsconfig.json b/packages/extensions/tsconfig.json index 7b921a4e..9a23d943 100644 --- a/packages/extensions/tsconfig.json +++ b/packages/extensions/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES5", + "target": "es6", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true,