diff --git a/package-lock.json b/package-lock.json index f7947d146ce3d1646a9b15a06291d1fbd110e698..4777807dea6121e33df24cc195e3bf359e74e3e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "@ahooksjs/use-url-state": "^3.5.0", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@ess-ics/ce-ui-common": "^6.3.1", + "@ess-ics/ce-ui-common": "^6.4.1", "@fontsource/roboto": "^4.1.0", "@mui/icons-material": "^5.14.1", "@mui/material": "^5.14.1", @@ -3072,9 +3072,9 @@ } }, "node_modules/@ess-ics/ce-ui-common": { - "version": "6.3.1", - "resolved": "https://artifactory.esss.lu.se/artifactory/api/npm/ics-npm/@ess-ics/ce-ui-common/-/ce-ui-common-6.3.1.tgz", - "integrity": "sha512-UU0p7E8eO3q6kuC3jhIrjXXbHfoNcURGdZw9YawdnwEyUDTs0QC8H+dgWvYoyUsfzCMa2PXBmltTwmBVUFyWiw==", + "version": "6.4.1", + "resolved": "https://artifactory.esss.lu.se/artifactory/api/npm/ics-npm/@ess-ics/ce-ui-common/-/ce-ui-common-6.4.1.tgz", + "integrity": "sha512-4mj9tuLVdj6dXqL9LV+ls7V5Jsz2S/JeBs2EP/bE+ekisk/dfFxvZa2sAaXDYqCEQH8E+Q2tK0bQ7mlAiEl5gA==", "dependencies": { "@fontsource/titillium-web": "^4.5.9", "@mui/x-data-grid-pro": "^6.5.0", @@ -3083,6 +3083,7 @@ "ajv-formats": "^2.1.1", "json-source-map": "^0.6.1", "moment": "^2.29.4", + "nanoid": "^5.0.7", "prop-types": "^15.8.1", "react-ace": "^10.1.0", "react-error-boundary": "^3.1.4", @@ -3098,6 +3099,24 @@ "react-dom": "^18.2.0" } }, + "node_modules/@ess-ics/ce-ui-common/node_modules/nanoid": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", + "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/@fal-works/esbuild-plugin-global-externals": { "version": "2.1.2", "dev": true, @@ -34273,9 +34292,9 @@ "dev": true }, "@ess-ics/ce-ui-common": { - "version": "6.3.1", - "resolved": "https://artifactory.esss.lu.se/artifactory/api/npm/ics-npm/@ess-ics/ce-ui-common/-/ce-ui-common-6.3.1.tgz", - "integrity": "sha512-UU0p7E8eO3q6kuC3jhIrjXXbHfoNcURGdZw9YawdnwEyUDTs0QC8H+dgWvYoyUsfzCMa2PXBmltTwmBVUFyWiw==", + "version": "6.4.1", + "resolved": "https://artifactory.esss.lu.se/artifactory/api/npm/ics-npm/@ess-ics/ce-ui-common/-/ce-ui-common-6.4.1.tgz", + "integrity": "sha512-4mj9tuLVdj6dXqL9LV+ls7V5Jsz2S/JeBs2EP/bE+ekisk/dfFxvZa2sAaXDYqCEQH8E+Q2tK0bQ7mlAiEl5gA==", "requires": { "@fontsource/titillium-web": "^4.5.9", "@mui/x-data-grid-pro": "^6.5.0", @@ -34284,11 +34303,19 @@ "ajv-formats": "^2.1.1", "json-source-map": "^0.6.1", "moment": "^2.29.4", + "nanoid": "^5.0.7", "prop-types": "^15.8.1", "react-ace": "^10.1.0", "react-error-boundary": "^3.1.4", "react-router-dom": "^6.4.1", "swagger-client": "^3.18.5" + }, + "dependencies": { + "nanoid": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", + "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==" + } } }, "@fal-works/esbuild-plugin-global-externals": { diff --git a/package.json b/package.json index 8aadf280143d76bf5ad86e5fccad163f45f73f92..9b6aaf3833819b0fd44ab299438aa8d5f7dc8378 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "@ahooksjs/use-url-state": "^3.5.0", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@ess-ics/ce-ui-common": "^6.3.1", + "@ess-ics/ce-ui-common": "^6.4.1", "@fontsource/roboto": "^4.1.0", "@mui/icons-material": "^5.14.1", "@mui/material": "^5.14.1", diff --git a/src/components/IOC/CreateIOC/RepositoryName.js b/src/components/IOC/CreateIOC/RepositoryName.js index fb7eedf200fc3d86d5504ebb92298c1dab1c6c8c..7bfaabaccb7070652ecbed038d9b3cc2108ef821 100644 --- a/src/components/IOC/CreateIOC/RepositoryName.js +++ b/src/components/IOC/CreateIOC/RepositoryName.js @@ -11,7 +11,7 @@ const propTypes = { // starts with an alpha numeric character (a-Z 0-9) // followed by 0 or more combinations of alphanumeric characters or - or _ // ends with an alpha numeric character (a-Z 0-9) -const REPO_NAME_REGEX = "^[a-z0-9]+([a-z0-9_-]+)*[a-z0-9]$"; +const REPO_NAME_REGEX = "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$"; export const RepositoryName = ({ repoName, onRepoNameChange }) => { const [valid, setValid] = useState(repoName || repoName.length === 0); diff --git a/src/components/common/Loki/LokiPanel.js b/src/components/common/Loki/LokiPanel.js index 87845f66facc82732170f2f4e590dc3b169e3e7c..a9a65617f235b0afe962abac9ca73371d7b1aa6d 100644 --- a/src/components/common/Loki/LokiPanel.js +++ b/src/components/common/Loki/LokiPanel.js @@ -290,7 +290,7 @@ export function LokiPanel({ hostName, iocName, isSyslog, isDeployed }) { } function formatLogLine(logLine) { - var convert = new Convert(); + const convert = new Convert(); return ( "<span><span class=logdate>" + diff --git a/src/components/common/SearchBoxFilter/SearchBoxFilter.js b/src/components/common/SearchBoxFilter/SearchBoxFilter.js index f90746a4a39d6c87c3878b7ff53a4f2ff4d1d0e1..8c0618e7d01bc3e7e22575410fec822dfe2b112f 100644 --- a/src/components/common/SearchBoxFilter/SearchBoxFilter.js +++ b/src/components/common/SearchBoxFilter/SearchBoxFilter.js @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import { styled } from "@mui/material/styles"; import { Container, List, ListItem, Paper, TextField } from "@mui/material"; import { useTypingTimer } from "./TypingTimer"; +import { useUniqueKeys } from "@ess-ics/ce-ui-common"; const PREFIX = "SearchBoxFilter"; @@ -44,6 +45,22 @@ export function SearchBoxFilter({ items, filter, render }) { ); } +const MyList = ({ items }) => { + const itemsKeys = useUniqueKeys(items); + return ( + <List> + {items && + items.map((item, i) => { + return ( + <Paper key={itemsKeys[i]}> + <ListItem>{item}</ListItem> + </Paper> + ); + })} + </List> + ); +}; + export function SearchBoxFilterDemo() { const items = ["Big Dog", "Big Cat", "Small Dog", "Small Cat"]; @@ -53,21 +70,6 @@ export function SearchBoxFilterDemo() { }; }; - function MyList({ items }) { - return ( - <List> - {items && - items.map((item) => { - return ( - <Paper key={item}> - <ListItem button>{item}</ListItem> - </Paper> - ); - })} - </List> - ); - } - const renderFilteredItems = (items) => { return <MyList items={items} />; }; diff --git a/src/components/common/Status/StatusPopoverContent.js b/src/components/common/Status/StatusPopoverContent.js index 6dadd92a809dfb676f293ad87ed23763cd7187e7..fe0f8a970ede4e81f3b576b69fdf1af22e412a6a 100644 --- a/src/components/common/Status/StatusPopoverContent.js +++ b/src/components/common/Status/StatusPopoverContent.js @@ -1,7 +1,7 @@ import { string, arrayOf, object } from "prop-types"; import { SEVERITY } from "./StatusData"; import { Typography, Stack } from "@mui/material"; -import { AlertBanner } from "@ess-ics/ce-ui-common"; +import { AlertBanner, useUniqueKeys } from "@ess-ics/ce-ui-common"; const propsTypes = { title: string, @@ -20,6 +20,7 @@ export const StatusPopoverContent = ({ title, alerts }) => { type: alert?.type?.toLowerCase(), link: undefined })); + const alertsKeys = useUniqueKeys(sanitizedAlerts); return ( <Stack @@ -34,10 +35,10 @@ export const StatusPopoverContent = ({ title, alerts }) => { {title} </Typography> {sanitizedAlerts.length > 0 - ? sanitizedAlerts.map((alert, index) => ( + ? sanitizedAlerts.map((alert, i) => ( <AlertBanner {...alert} - key={index} + key={alertsKeys[i]} /> )) : null} diff --git a/src/components/navigation/NavigationMenu/NavigationMenu.js b/src/components/navigation/NavigationMenu/NavigationMenu.js index 3472cbdc624557671ecfdcc9dad8343f2f30d46e..a85664370f9dc9290f4f2b9b4e3f817fbcd04265 100644 --- a/src/components/navigation/NavigationMenu/NavigationMenu.js +++ b/src/components/navigation/NavigationMenu/NavigationMenu.js @@ -3,7 +3,8 @@ import { GlobalAppBar, IconMenuButton, EssIconLogo, - BodyBox + BodyBox, + useUniqueKeys } from "@ess-ics/ce-ui-common"; import { Assignment, @@ -56,10 +57,11 @@ function MenuListItem({ url, icon, text, tooltip }) { } function MenuListItems({ menuItems, drawerOpen }) { + const menuItemsKeys = useUniqueKeys(menuItems); return ( <Box sx={{ paddingTop: 3 }}> - {menuItems.map(({ text, url, icon }, index) => ( - <Fragment key={index}> + {menuItems.map(({ text, url, icon }, i) => ( + <Fragment key={menuItemsKeys[i]}> {typeof (text && url && icon) === "undefined" ? ( <Divider sx={{ marginTop: 5 }} /> ) : ( diff --git a/src/mocks/UserImpersonator.js b/src/mocks/UserImpersonator.js index 000b43892843350cc06580f6c1cead8751148046..d1ec252f23c79513a16d839315089699ec2a6a3e 100644 --- a/src/mocks/UserImpersonator.js +++ b/src/mocks/UserImpersonator.js @@ -1,4 +1,4 @@ -import { useCallback, useContext, useEffect, useState } from "react"; +import { useCallback, useContext, useEffect, useMemo, useState } from "react"; import testUser from "./fixtures/User.json"; import { userContext } from "@ess-ics/ce-ui-common"; @@ -24,19 +24,34 @@ const TestAuthContextProvider = ({ children }) => { setLoginError(defaultLoginError); }, [setLoginError]); - const value = { - user, - setUser, - userRoles, - setUserRoles, - login, - setLogin, - loginError, - setLoginError, - logout, - setLogout, - resetLoginError - }; + const value = useMemo( + () => ({ + user, + setUser, + userRoles, + setUserRoles, + login, + setLogin, + loginError, + setLoginError, + logout, + setLogout, + resetLoginError + }), + [ + user, + setUser, + userRoles, + setUserRoles, + login, + setLogin, + loginError, + setLoginError, + logout, + setLogout, + resetLoginError + ] + ); return ( <testAuthContext.Provider value={value}>