diff --git a/applications/accounts/Dockerfile b/applications/accounts/Dockerfile index 78b20c996..ea9d5529b 100644 --- a/applications/accounts/Dockerfile +++ b/applications/accounts/Dockerfile @@ -15,4 +15,4 @@ COPY themes/custom /opt/keycloak/themes/custom COPY plugins/* /opt/keycloak/providers/ ENTRYPOINT [ "/opt/keycloak/bin/kc-entrypoint.sh" ] -CMD [ "start-dev", "--import-realm", "--health-enabled=true", "--metrics-enabled=true" ] \ No newline at end of file +CMD [ "start-dev", "--import-realm", "--health-enabled=true", "--metrics-enabled=true", "--verbose" ] \ No newline at end of file diff --git a/applications/accounts/deploy/resources/realm.json b/applications/accounts/deploy/resources/realm.json index e7e764ad8..80888301c 100644 --- a/applications/accounts/deploy/resources/realm.json +++ b/applications/accounts/deploy/resources/realm.json @@ -146,7 +146,75 @@ {{- end }} } }, + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account", + "view-groups" + ] + } + ] + }, "clients": [ + { + "id": "18893fbb-8252-4aaa-bc9b-60799ceb9932", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": {{ printf "/realms/%s/account" .Values.namespace | quote }}, + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + {{ printf "/realms/%s/account/*" .Values.namespace | quote }} + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "9a68ec2d-943d-49cb-9fdd-cd821d606210", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "service_account", + "web-origins", + "acr", + "address", + "administrator-scope", + "phone", + "profile", + "roles", + "microprofile-jwt", + "basic", + "email" + ], + "optionalClientScopes": [] + }, { "id": "9a6a2560-c6be-4493-8bd5-3fdc4522d82b", "clientId": {{ .Values.apps.accounts.client.id | quote }}, @@ -319,6 +387,17 @@ "claim.name": "groups", "jsonType.label": "String" } + }, + { + "id": "f99f57ac-a765-4aba-9b45-9425beec0a9f", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } } ] }, diff --git a/applications/backoffice/src/types/workspace.ts b/applications/backoffice/src/types/workspace.ts index 7223d0e8b..3c15051f0 100644 --- a/applications/backoffice/src/types/workspace.ts +++ b/applications/backoffice/src/types/workspace.ts @@ -32,7 +32,7 @@ export interface ResourceType { export const OSBApplications: { [id: string]: OSBApplication } = { nwbexplorer: { name: "NWB Explorer", subdomain: "nwbexplorer" }, netpyne: { name: "NetPyNE", subdomain: "netpyne" }, - jupyter: { name: "JupyterLab", subdomain: "notebooks" }, + jupyter: { name: "JupyterLab", subdomain: "lab" }, } export const SampleResourceTypes = { diff --git a/applications/jupyterhub/src/osb_jupyter/osb_jupyter/osb_jupyterhub.py b/applications/jupyterhub/src/osb_jupyter/osb_jupyter/osb_jupyterhub.py index 0778fdabf..a9ea8b2f6 100644 --- a/applications/jupyterhub/src/osb_jupyter/osb_jupyter/osb_jupyterhub.py +++ b/applications/jupyterhub/src/osb_jupyter/osb_jupyter/osb_jupyterhub.py @@ -38,7 +38,7 @@ class CookieNotFound(Exception): def change_pod_manifest(self: KubeSpawner): """ - Application Hook to change the manifest of the notebook image + Application Hook to change the manifest of the notebook pod before spawning it. Args: diff --git a/applications/netpyne/deploy/values.yaml b/applications/netpyne/deploy/values.yaml index 69f9a87d5..542737608 100644 --- a/applications/netpyne/deploy/values.yaml +++ b/applications/netpyne/deploy/values.yaml @@ -1,5 +1,7 @@ harness: subdomain: netpyne + secured: true + uri_role_mapping: [] service: auto: false port: 80 diff --git a/applications/osb-portal/.babelrc b/applications/osb-portal/.babelrc deleted file mode 100644 index 2b53150f6..000000000 --- a/applications/osb-portal/.babelrc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ], - "env": { - "production":{ - "presets": ["minify"] - } - }, - "plugins": [ - "@babel/transform-regenerator", - "@babel/plugin-proposal-class-properties", - [ - "module-resolver", { - "root": ["./src"] - } - ] - ] -} \ No newline at end of file diff --git a/applications/osb-portal/.eslintignore b/applications/osb-portal/.eslintignore deleted file mode 100644 index 269445acd..000000000 --- a/applications/osb-portal/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -/src/apiclient/ -dist/ -node_modules/ -webpack*.js -public/ \ No newline at end of file diff --git a/applications/osb-portal/.eslintrc.yaml b/applications/osb-portal/.eslintrc.yaml deleted file mode 100644 index 011fa6d78..000000000 --- a/applications/osb-portal/.eslintrc.yaml +++ /dev/null @@ -1,46 +0,0 @@ ---- -root: true -extends: - - eslint:recommended - - plugin:react/recommended -parser: "@babel/eslint-parser" -parserOptions: - ecmaFeatures: - jsx: true -plugins: - - react - - react-hooks -settings: - react: - version: detect -env: - browser: true - es6: true - node: true -rules: - no-console: 0 - func-style: 0 - consistent-return: 2 - prefer-arrow-callback: - - 2 - - allowNamedFunctions: false - allowUnboundThis: false - react/prop-types: 0 - react/forbid-prop-types: 0 - react/no-unused-prop-types: 0 - react-hooks/rules-of-hooks: 2 - react-hooks/exhaustive-deps: 1 - curly: 2 - no-tabs: 2 - arrow-spacing: 2 - no-unneeded-ternary: 2 - object-curly-spacing: - - 2 - - always - indent: - - 2 - - 2 - - SwitchCase: 1 -globals: - __dirname: writable - module: writable diff --git a/applications/osb-portal/deploy/values-local.yaml b/applications/osb-portal/deploy/values-local.yaml index b4bd6f66a..caf5cec6a 100644 --- a/applications/osb-portal/deploy/values-local.yaml +++ b/applications/osb-portal/deploy/values-local.yaml @@ -1,13 +1,13 @@ harness: sentry: false - dependencies: - soft: - - accounts - - accounts-api - - common - - volumemanager - - workspaces - - workflows - - jupyterhub - - jupyterlab - - backoffice \ No newline at end of file + # dependencies: + # soft: + # - accounts + # - accounts-api + # - common + # - volumemanager + # - workspaces + # - workflows + # - jupyterhub + # - jupyterlab + # - backoffice \ No newline at end of file diff --git a/applications/osb-portal/deploy/values.yaml b/applications/osb-portal/deploy/values.yaml index ffd00262a..f2e9b513c 100644 --- a/applications/osb-portal/deploy/values.yaml +++ b/applications/osb-portal/deploy/values.yaml @@ -1,6 +1,6 @@ harness: subdomain: www - secured: false + secured: true deployment: auto: true port: 80 @@ -39,3 +39,11 @@ harness: smoketest: true ignoreRequestErrors: false ignoreConsoleErrors: false + uri_role_mapping: + - roles: [] + uri: /* + white-listed: true + - uri: /login + roles: [] + - uri: /workspaces/open/* + roles: [] \ No newline at end of file diff --git a/applications/osb-portal/eslint.config.js b/applications/osb-portal/eslint.config.js new file mode 100644 index 000000000..7b906a81d --- /dev/null +++ b/applications/osb-portal/eslint.config.js @@ -0,0 +1,62 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + + +export default tseslint.config( + { + ignores: [ + 'dist', + 'node_modules', + '.yalc', + 'src/rest', + 'eslint.config.js' + ] + }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx,js,jsx}'], + languageOptions: { + ecmaVersion: "latest", + globals: globals.browser, + sourceType: "module" + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + // indent: ["warn", 2], + // indent: ["warn", 2, { + // SwitchCase: 1, + // ignoredNodes: ["JSXElement", "JSXElement > *", "JSXAttribute", "JSXIdentifier", "JSXNamespacedName", "JSXMemberExpression", "JSXSpreadAttribute", "JSXExpressionContainer", "JSXOpeningElement", "JSXClosingElement", "JSXText", "JSXEmptyExpression", "JSXSpreadChild"] + // }], + curly: "error", // enforce braces for one-line blocks + "no-tabs": "error", // enforce no tabs + "no-console": ["warn", { + allow: ["warn", "error", "debug"], + }], + "@typescript-eslint/no-unused-vars": "warn", // + "@typescript-eslint/no-explicit-any": "off", // No strict typing (annoying especially with React elements and events callbacks) + "@typescript-eslint/no-empty-object-type": "warn", + "consistent-return": "warn", // https://eslint.org/docs/latest/rules/consistent-return + "prefer-arrow-callback": ["warn"], + "object-curly-spacing": ["warn", "always"], // enforce consistent spacing inside braces + "func-style": "off", // function expressions or arrow functions are equally valid + "no-unneeded-ternary": "warn", // disallow unnecessary ternary expressions + // React rules: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules + "react/prop-types": "off", // PropTypes are not forced + "react/forbid-prop-types": "off", // all PropTypes are allowed + "react-hooks/rules-of-hooks": "error", // https://react.dev/reference/rules/rules-of-hooks + "react-hooks/exhaustive-deps": "warn", // Hooks dependency array, sometimes it's better to ignore + "no-constant-binary-expression": "warn" + }, + } +) \ No newline at end of file diff --git a/applications/osb-portal/index.html b/applications/osb-portal/index.html new file mode 100644 index 000000000..820f69a9b --- /dev/null +++ b/applications/osb-portal/index.html @@ -0,0 +1,32 @@ + + + + + + + Open Source Brain + + + + + + +
+
+
+ + + + diff --git a/applications/osb-portal/package.json b/applications/osb-portal/package.json index a1b10f637..22194749b 100644 --- a/applications/osb-portal/package.json +++ b/applications/osb-portal/package.json @@ -3,20 +3,21 @@ "version": "0.8.0", "description": "", "main": "index.js", + "type": "module", "scripts": { - "start": "webpack serve --progress --config webpack.dev.js --env APP_DOMAIN=http://localhost:8888 --env DOMAIN=https://v2dev.opensourcebrain.org --env WORKSPACES_DOMAIN=http://localhost:5001 --env NAMESPACE=osb2dev --env NODE_OPTIONS='--max-old-space-size=12048'", - "start:dev": "webpack serve --progress --config webpack.dev.js --env DOMAIN=https://v2dev.opensourcebrain.org --env NAMESPACE=osb2dev --env NODE_OPTIONS='--max-old-space-size=12048'", - "start:prod": "webpack serve --progress --config webpack.dev.js --env DOMAIN=https://v2.opensourcebrain.org --env NAMESPACE=osb2 --env NODE_OPTIONS='--max-old-space-size=12048'", - "start:local": "webpack serve --progress --config webpack.dev.js --env DOMAIN=http://osb.local --env NAMESPACE=osblocal --env NODE_OPTIONS='--max-old-space-size=12048'", - "start:local-be": "webpack serve --progress --config webpack.dev.js --env APP_DOMAIN=http://localhost:8888 --env DOMAIN=https://osb.local --env WORKSPACES_DOMAIN=http://localhost:5001 --env NAMESPACE=osblocal --env NODE_OPTIONS='--max-old-space-size=12048'", - "start:dev-be": "webpack serve --progress --config webpack.dev.js --env DOMAIN=https://v2dev.opensourcebrain.org --env ACCOUNTS_API_DOMAIN=localhost:5001 --env WORKSPACES_DOMAIN=http://localhost:5001 --env NAMESPACE=osblocal --env NODE_OPTIONS='--max-old-space-size=12048'", - "start:dev-app": "webpack serve --progress --config webpack.dev.js --env APP_DOMAIN=https://localhost:8888 --env DOMAIN=https://v2.opensourcebrain.org --env NAMESPACE=osblocal --env NODE_OPTIONS='--max-old-space-size=12048'", - "start:local-app": "webpack serve --progress --config webpack.dev.js --env APP_DOMAIN=http://localhost:8888 --env DOMAIN=http://osb.local --env NAMESPACE=osblocal --env NODE_OPTIONS='--max-old-space-size=12048'", - "prebuild": "eslint . --color", - "build": "webpack --mode=production --config webpack.prod.js --devtool source-map", - "prebuild-dev": "eslint . --color --fix", - "build-dev": "webpack --mode=development --devtool eval --config webpack.dev.js", - "build-dev:watch": "webpack --mode=development --devtool source-map --env noTest=true --progress --watch --config webpack.dev.js", + "start": "APP_DOMAIN=http://localhost:8888 DOMAIN=https://v2dev.opensourcebrain.org WORKSPACES_DOMAIN=http://localhost:5001 NAMESPACE=osb2dev vite", + "start:dev": "DOMAIN=https://v2dev.opensourcebrain.org NAMESPACE=osb2dev vite", + "start:prod": "DOMAIN=https://v2.opensourcebrain.org NAMESPACE=osb2 vite", + "start:local": "DOMAIN=https://osb.local NAMESPACE=osblocal vite", + "start:local-be": "APP_DOMAIN=http://localhost:8888 DOMAIN=https://osb.local WORKSPACES_DOMAIN=http://localhost:5001 NAMESPACE=osblocal vite", + "start:dev-be": "DOMAIN=https://v2dev.opensourcebrain.org ACCOUNTS_API_DOMAIN=localhost:5001 WORKSPACES_DOMAIN=http://localhost:5001 NAMESPACE=osblocal vite", + "start:dev-app": "APP_DOMAIN=https://localhost:8888 DOMAIN=https://v2.opensourcebrain.org NAMESPACE=osblocal vite", + "start:local-app": "APP_DOMAIN=http://localhost:8888 DOMAIN=http://osb.local NAMESPACE=osblocal vite", + "prebuild": "eslint src --color", + "build": "vite build", + "prebuild-dev": "eslint src --color --fix", + "build-dev": "vite build --mode development", + "build-dev:watch": "vite build --mode development --watch", "test": "echo \"Error: no test specified\" && exit 1", "format": "prettier --write src/**/*.ts{,x}", "lint": "eslint . --color --fix" @@ -25,30 +26,28 @@ "author": "", "license": "ISC", "dependencies": { - "@emotion/react": "^11.10.5", - "@emotion/styled": "^11.10.5", - "@mui/icons-material": "^5.10.15", - "@mui/lab": "^5.0.0-alpha.109", - "@mui/material": "^5.10.15", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^6.1.2", + "@mui/lab": "^6.0.0-beta.10", + "@mui/material": "^6.1.2", "@mui/styles": "^5.10.15", "@mui/types": "^7.2.2", - "@reduxjs/toolkit": "^1.9.3", + "@reduxjs/toolkit": "^2.8.2", "@sentry/react": "^6.3.5", "assert": "^2.0.0", "axios": "^1.6.5", - "keycloak-js": "^26.0.0", - "less-vars-to-js": "^1.3.0", "lodash": "^4.17.21", "markdown-it": "^12.0.0", "pretty-bytes": "^5.6.0", "qs": "^6.10.1", - "react": "^18.0.0", - "react-dom": "^18.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-dropzone": "^11.0.1", "react-infinite-scroll-component": "^6.1.0", "react-markdown": "^6.0.2", "react-markdown-editor-lite": "^1.2.4", - "react-redux": "^8.0.5", + "react-redux": "^9.2.0", "react-router": "^6.0.0", "react-router-dom": "^6.0.0", "react-show-more-text": "^1.5.0", @@ -60,56 +59,28 @@ "sanitize-html": "^2.7.2" }, "devDependencies": { - "@babel/core": "^7.8.3", - "@babel/eslint-parser": "^7.19.1", - "@babel/plugin-proposal-class-properties": "^7.8.3", - "@babel/preset-env": "^7.8.3", - "@babel/preset-react": "^7.8.3", + "@eslint/js": "^9.9.0", "@types/keycloak-js": "^3.4.1", "@types/lodash": "^4.14.180", "@types/markdown-it": "^10.0.1", + "@types/node": "^24.3.0", "@types/qs": "^6.9.7", - "@types/react": "^17.0.5", - "@types/react-dom": "^17.0.3", + "@types/react": "^18.3.23", + "@types/react-dom": "^18.3.0", "@types/react-redux": "^7.1.16", "@types/react-router": "^5.1.14", "@types/react-router-dom": "^5.1.5", "@types/react-show-more-text": "^1.4.1", "@types/redux-devtools-extension": "^2.13.2", "@types/redux-logger": "^3.0.8", - "@types/webpack-env": "^1.15.2", - "@typescript-eslint/eslint-plugin": "^5.38.1", - "@typescript-eslint/parser": "^5.38.1", - "@webpack-cli/serve": "^1.4.0", - "babel-eslint": "^10.1.0", - "babel-loader": "^8.2.5", - "babel-plugin-module-resolver": "^5.0.0", - "clean-webpack-plugin": "^3.0.0", - "copy-webpack-plugin": "^8.1.1", - "css-loader": "^5.2.4", - "dotenv": "^10.0.0", - "eslint": "^8.24.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-jest": "^27.0.4", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "^7.31.8", - "eslint-plugin-react-hooks": "^4.6.0", - "html-webpack-plugin": "^5.5.0", - "jest": "^29.1.1", - "less-loader": "^6.1.2", - "prettier": "^2.7.1", - "raw-loader": "^4.0.0", + "@vitejs/plugin-react": "^5.0.1", + "eslint": "^9.9.0", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.9", "redux-devtools": "^3.5.0", - "replace-in-file-webpack-plugin": "^1.0.6", - "source-map-loader": "^2.0.0", - "style-loader": "^1.2.1", - "ts-loader": "^9.0.0", - "tslint": "^6.1.2", - "tslint-react": "^5.0.0", - "typescript": "^4.0.0", - "webpack": "^5.61.0", - "webpack-cli": "^4.6.0", - "webpack-dev-server": "^4.5.0", - "webpack-merge": "^5.7.0" + "typescript": "^5.5.3", + "typescript-eslint": "^8.0.1", + "vite": "^7.1.3", + "vite-plugin-eslint": "^1.8.1" } -} +} \ No newline at end of file diff --git a/applications/osb-portal/src/App.tsx b/applications/osb-portal/src/App.tsx index 55969787a..993351a5d 100644 --- a/applications/osb-portal/src/App.tsx +++ b/applications/osb-portal/src/App.tsx @@ -4,7 +4,9 @@ import { Route, Routes, useNavigate, + Navigate, } from "react-router-dom"; +import { useSelector } from "react-redux"; import { ThemeProvider, Theme, @@ -15,7 +17,7 @@ import CssBaseline from "@mui/material/CssBaseline"; import OSBErrorBoundary from "./components/handlers/OSBErrorBoundary"; import theme from "./theme"; import SidebarPageLayout from "./layouts/SidebarLayout"; -import * as UserService from "./service/UserService"; +import { RootState } from "./store/rootReducer"; import { Header, @@ -30,12 +32,12 @@ import { GroupsPage } from "./components"; import Box from "@mui/material/Box"; -import { UserInfo } from "./types/user"; import SampleIframePage from "./pages/SampleIframePage"; import NotFoundPage from "./pages/NotFoundPage"; +import { initApis } from "./service/UserService"; declare module "@mui/styles/defaultTheme" { - // eslint-disable-next-line @typescript-eslint/no-empty-interface + // eslint-disable-next-line @typescript-eslint/no-empty-object-type interface DefaultTheme extends Theme {} } @@ -52,32 +54,17 @@ const styles = { }, }; -const UserActionThenRedirect = ({ userAction, user }) => { - const navigate = useNavigate(); - React.useEffect(() => { - if (user) { - navigate("/"); - } else { - userAction(); - } - }, [navigate, user, userAction]); - return <>; -}; - -interface AppProps { - error: boolean; - user: UserInfo; -} - -export const App = (props: AppProps) => { +export const App = () => { + const error = useSelector((state: RootState) => state.error); + initApis(); return ( - + - {!props.error && ( + {!error && ( @@ -175,21 +162,7 @@ export const App = (props: AppProps) => { /> - } - /> - - } + element={} /> ({ drawerContent: { width: "100%", }, - root: (openDrawer) => (theme) => ({ + root: { display: "flex", flexShrink: 0, whiteSpace: "nowrap", - top: "initial", - - transition: theme.transitions.create("width", { + transition: theme?.transitions?.create ? theme.transitions.create("width", { easing: theme.transitions.easing.sharp, duration: openDrawer ? theme.transitions.duration.enteringScreen : theme.transitions.duration.leavingScreen, - }), + }) : "width 0.2s ease", overflowX: "hidden", width: "100%", - "& .verticalFit": { display: "block", }, - "& .MuiListSubheader-root": { backgroundColor: "transparent", "& .MuiTypography-root": { @@ -88,13 +89,11 @@ const styles = { "& .Mui-selected": { background: selectedMenuItemBg, borderLeft: `2px solid ${primaryColor}`, - "& .MuiListItemIcon-root": { "& .MuiSvgIcon-root": { color: secondaryColor, }, }, - "& .MuiListItemText-root": { "& .MuiTypography-root": { color: secondaryColor, @@ -104,8 +103,7 @@ const styles = { "& .MuiButtonBase-root": { "& .MuiListItemIcon-root": { minWidth: "auto", - marginRight: "0.875rem", - + mr: "0.875rem", "& .MuiSvgIcon-root": { fontSize: "1.143rem", color: drawerText, @@ -126,48 +124,44 @@ const styles = { }, }, }, - }), - menuButton: (theme) => ({ - marginRight: theme.spacing(2), + }, + menuButton: { + mr: 2, display: { md: "none", }, - }), + }, toolbar: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 16px", }, - - drawerPaper: (theme) => ({ + drawerPaper: { position: "static", flex: 1, display: "flex", bottom: 0, - paddingTop: theme.spacing(1), + pt: 1, justifyContent: "space-between", borderRight: `1px solid ${bgRegular}`, backgroundColor: bgDarkest, - }), - createMenu: (theme) => ({ + }, + createMenu: { minWidth: "14.62rem", backgroundColor: "#3C3C3C", borderRadius: "6px", - "& .MuiList-root": { "& .MuiMenuItem-root": { - paddingLeft: theme.spacing(3), + pl: 3, fontSize: "0.857rem", color: drawerText, fontWeight: 500, - "& .MuiSvgIcon-root": { - marginRight: theme.spacing(2), + mr: 2, fontSize: "1rem", color: drawerText, }, - "&:hover": { color: secondaryColor, "& .MuiSvgIcon-root": { @@ -176,22 +170,24 @@ const styles = { }, }, }, - }), -}; + }, +}); export const MainDrawer = (props: { isWorkspacesPage: boolean; - user: UserInfo; isRepositoriesPage: boolean; }) => { const theme = useTheme(); - const isMdUp = useMediaQuery(theme.breakpoints.up("md")); + const dispatch = useDispatch(); + const user = useSelector((state: RootState) => state.user); + const isMdUp = useMediaQuery(theme?.breakpoints?.up("md") || "(min-width:900px)"); const [openDrawer, setOpenDrawer] = React.useState(false); + const styles = getStyles(openDrawer, theme || {}); const [openWorkspaceDialog, setOpenWorkspaceDialog] = React.useState(false); const [openRepoDialog, setOpenRepoDialog] = React.useState(false); const [anchorEl, setAnchorEl] = React.useState(null); const [askLoginOpen, setAskLoginOpen] = React.useState(false); - const {isWorkspacesPage, isRepositoriesPage} = props; + const { isWorkspacesPage, isRepositoriesPage } = props; const openCreatMenu = Boolean(anchorEl); @@ -200,20 +196,24 @@ export const MainDrawer = (props: { const handleOpenDialog = (type) => { setOpenDrawer(false); - if (!props.user) { + if (!user) { setAskLoginOpen(true); } else { - type === "workspace" - ? setOpenWorkspaceDialog(true) - : setOpenRepoDialog(true); + if(type === "workspace") { + setOpenWorkspaceDialog(true); + } else { + setOpenRepoDialog(true); + } setAnchorEl(null); } }; const handleCloseDialog = (type) => { - type === "workspace" - ? setOpenWorkspaceDialog(false) - : setOpenRepoDialog(false); + if(type === "workspace") { + setOpenWorkspaceDialog(false); + } else { + setOpenRepoDialog(false); + } }; const handleClickCreatMenu = (event: React.MouseEvent) => { @@ -227,7 +227,7 @@ export const MainDrawer = (props: { const toggleDrawer = () => setOpenDrawer(!openDrawer); const handleAboutDialogOpen = () => { - props.openDialog(); + dispatch(openDialog()); }; const closeAskLogin = () => setAskLoginOpen(false); @@ -259,7 +259,7 @@ export const MainDrawer = (props: { onClose={toggleDrawer} elevation={0} open={openDrawer} - sx={styles.root(openDrawer)} + sx={styles.root} PaperProps={{ sx: styles.drawerPaper, }} @@ -439,7 +439,6 @@ export const MainDrawer = (props: { handleCloseDialog("repository")} - user={props.user} title="Add repository" /> )} diff --git a/applications/osb-portal/src/components/auth/ProtectedRouter.tsx b/applications/osb-portal/src/components/auth/ProtectedRouter.tsx index 2b3c9fe0f..2a11db5ee 100644 --- a/applications/osb-portal/src/components/auth/ProtectedRouter.tsx +++ b/applications/osb-portal/src/components/auth/ProtectedRouter.tsx @@ -1,9 +1,15 @@ import React from "react"; import { Route } from "react-router-dom"; +import { useSelector, useDispatch } from "react-redux"; +import { RootState } from "../../store/rootReducer"; +import { userLogin } from "../../store/actions/user"; -export const ProtectedRoute = ({ children, user, login}) => { +export const ProtectedRoute = ({ children }) => { + const user = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); + if(!user) { - login(); + dispatch(userLogin()); return <> } return children; diff --git a/applications/osb-portal/src/components/common/CreateWorkspaceDialog.tsx b/applications/osb-portal/src/components/common/CreateWorkspaceDialog.tsx index a3f1a6f7e..5b693fbaa 100644 --- a/applications/osb-portal/src/components/common/CreateWorkspaceDialog.tsx +++ b/applications/osb-portal/src/components/common/CreateWorkspaceDialog.tsx @@ -22,7 +22,7 @@ export default ({ aria-labelledby="alert-dialog-title" aria-describedby="alert-dialog-description" className="createWorkspaceRepo" - sx={{ "& .MuiTypography-h6": {borderBottom: "none !important"} }} + sx={{ "& .MuiTypography-h6": { borderBottom: "none !important" } }} > { /** @@ -42,11 +40,11 @@ export interface NestedMenuItemProps extends Omit { } const TRANSPARENT = 'rgba(0,0,0,0)' -const useMenuItemStyles = makeStyles((theme: Theme) => ({ - root: (props: any) => ({ - backgroundColor: props.open ? theme.palette.action.hover : TRANSPARENT - }) -})) + +// Module-level styles +const getMenuItemStyles = (open: boolean, theme: Theme) => ({ + backgroundColor: open ? theme.palette.action.hover : TRANSPARENT +}) /** * Use as a drop-in replacement for `` when you need to add cascading @@ -55,7 +53,7 @@ const useMenuItemStyles = makeStyles((theme: Theme) => ({ const NestedMenuItem = React.forwardRef< HTMLLIElement | null, NestedMenuItemProps ->(function NestedMenuItem(props, ref) { +>((props, ref) => { const { parentMenuOpen, component = 'div', @@ -69,7 +67,7 @@ const NestedMenuItem = React.forwardRef< ...MenuItemProps } = props - const {ref: containerRefProp, ...ContainerProps} = ContainerPropsProp + const { ref: containerRefProp, ...ContainerProps } = ContainerPropsProp const menuItemRef = useRef(null) useImperativeHandle(ref, () => menuItemRef.current as HTMLLIElement) @@ -145,7 +143,7 @@ const NestedMenuItem = React.forwardRef< } const open = isSubMenuOpen && parentMenuOpen - const menuItemClasses = useMenuItemStyles({open}) + const theme = useTheme() // Root element must have a `tabIndex` attribute for keyboard navigation let tabIndex @@ -165,8 +163,12 @@ const NestedMenuItem = React.forwardRef< > {label} {rightIcon} @@ -174,7 +176,7 @@ const NestedMenuItem = React.forwardRef< -
+
{children}
diff --git a/applications/osb-portal/src/components/common/OSBChipList.tsx b/applications/osb-portal/src/components/common/OSBChipList.tsx index 1cd4dfd6d..db861c1cc 100644 --- a/applications/osb-portal/src/components/common/OSBChipList.tsx +++ b/applications/osb-portal/src/components/common/OSBChipList.tsx @@ -1,6 +1,3 @@ -import * as React from "react"; - -import makeStyles from "@mui/styles/makeStyles"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import Chip from "@mui/material/Chip"; @@ -13,15 +10,15 @@ interface OSBChipListProps { onDeleteChip: (pathOfChipToBeDeleted: string) => void; } -const useStyles = makeStyles((theme) => ({ +const styles = { chipBox: { - paddingTop: theme.spacing(2), + paddingTop: 2, "& h6": { fontWeight: "bold", color: bgInputs, fontSize: "0.8rem", marginBottom: "5px", - marginLeft: theme.spacing(1), + marginLeft: 1, }, }, OSBChipList: { @@ -29,16 +26,15 @@ const useStyles = makeStyles((theme) => ({ flexWrap: "wrap", "& .MuiChip-root": { backgroundColor: bgLight, - marginBottom: theme.spacing(1), + marginBottom: 1, }, }, OSBChipFileExtension: { color: bgInputs, }, -})); +}; -export default (props: OSBChipListProps) => { - const classes = useStyles(); +export const OSBChipList = (props: OSBChipListProps) => { const createChipLabel = (chipItem: RepositoryResourceNode) => { const splitfilename = chipItem.resource.name.split("."); @@ -50,7 +46,7 @@ export default (props: OSBChipListProps) => { return ( <> {filename} - + .{extension} @@ -65,10 +61,10 @@ export default (props: OSBChipListProps) => { }; return ( - + Files selected - + {props.chipItems.map((chipItem) => { return ( { ); }; + +export default OSBChipList; \ No newline at end of file diff --git a/applications/osb-portal/src/components/common/OSBDialog.tsx b/applications/osb-portal/src/components/common/OSBDialog.tsx index cfc907b48..66de97bd4 100644 --- a/applications/osb-portal/src/components/common/OSBDialog.tsx +++ b/applications/osb-portal/src/components/common/OSBDialog.tsx @@ -25,7 +25,8 @@ interface DialogProps { actions?: React.ReactElement; closeAction: () => void; className?: string; - sx?: any + sx?: any, + children?: React.ReactNode; } export const OSBDialog: React.FunctionComponent = ({ @@ -55,7 +56,7 @@ export const OSBDialog: React.FunctionComponent = ({ sx={sx} > - + {title} = ({ - + diff --git a/applications/osb-portal/src/components/common/OSBLoader.tsx b/applications/osb-portal/src/components/common/OSBLoader.tsx index 9a9366280..11f386cd6 100644 --- a/applications/osb-portal/src/components/common/OSBLoader.tsx +++ b/applications/osb-portal/src/components/common/OSBLoader.tsx @@ -1,7 +1,6 @@ // Derived from https://raw.githubusercontent.com/MetaCell/geppetto-meta/master/geppetto.js/geppetto-ui/src/loader/Loader.js -import React, { Component, Fragment } from "react"; -import makeStyles from '@mui/styles/makeStyles'; +import React, { ReactElement, Fragment } from "react"; import Backdrop from "@mui/material/Backdrop"; import CircularProgress from "@mui/material/CircularProgress"; import LinearProgress from "@mui/material/LinearProgress"; @@ -10,33 +9,18 @@ import Grid from "@mui/material/Grid"; import Box from "@mui/material/Box"; import { primaryColor } from "../../theme"; -const useStyles = makeStyles((theme) => ({ - backdrop: { - zIndex: theme.zIndex.drawer + 1, - color: primaryColor, - backgroundColor: "rgba(0, 0, 0, 0.8)", - }, - root: { - position: "absolute", - flex: "0 0 100%", - alignSelf: "stretch", - }, -})); - interface OSBLoaderProps { active: boolean; fullscreen?: boolean; handleClose: () => void; messages: string[]; elapsed?: number; - children?: Component; + children?: ReactElement; className?: string; messagesInterval?: number; } -export default (props: OSBLoaderProps) => { - const classes = useStyles(); - +export const OSBLoader = (props: OSBLoaderProps) => { const { active, fullscreen, @@ -85,7 +69,7 @@ export default (props: OSBLoaderProps) => { ); - const content = children ? ( + const content: ReactElement = children ? ( children ) : ( @@ -98,10 +82,16 @@ export default (props: OSBLoaderProps) => { ); + const backdropStyles = { + zIndex: (theme: any) => theme.zIndex.drawer + 1, + color: primaryColor, + backgroundColor: "rgba(0, 0, 0, 0.8)", + }; + const backdrop = fullscreen ? ( @@ -113,8 +103,12 @@ export default (props: OSBLoaderProps) => { {content} @@ -123,3 +117,5 @@ export default (props: OSBLoaderProps) => { return backdrop; }; + +export default OSBLoader; \ No newline at end of file diff --git a/applications/osb-portal/src/components/common/OSBPagination.tsx b/applications/osb-portal/src/components/common/OSBPagination.tsx index 2396e578c..ec7f93b21 100644 --- a/applications/osb-portal/src/components/common/OSBPagination.tsx +++ b/applications/osb-portal/src/components/common/OSBPagination.tsx @@ -24,7 +24,7 @@ const StyledPagination = styled(Pagination)(() => ({ }, })); -export default (props: OSBPaginationProps) => { +export const OSBPagination = (props: OSBPaginationProps) => { return ( { /> ); }; + +export default OSBPagination; \ No newline at end of file diff --git a/applications/osb-portal/src/components/common/OSBSplitButton.tsx b/applications/osb-portal/src/components/common/OSBSplitButton.tsx index 6b8971128..7b360d054 100644 --- a/applications/osb-portal/src/components/common/OSBSplitButton.tsx +++ b/applications/osb-portal/src/components/common/OSBSplitButton.tsx @@ -38,7 +38,9 @@ export const OSBSplitButton = (props: OSBSplitButtonProps) => { const anchorRef = useRef(null); useEffect(() => { - props.defaultSelected && setSelected(props.defaultSelected); + if (props.defaultSelected) { + setSelected(props.defaultSelected); + } }, [props.defaultSelected]); const options = Object.values(OSBApplications); diff --git a/applications/osb-portal/src/components/common/RepositoriesWorkspacesSearchField.tsx b/applications/osb-portal/src/components/common/RepositoriesWorkspacesSearchField.tsx index a3227f55a..5dcf3348c 100644 --- a/applications/osb-portal/src/components/common/RepositoriesWorkspacesSearchField.tsx +++ b/applications/osb-portal/src/components/common/RepositoriesWorkspacesSearchField.tsx @@ -12,9 +12,9 @@ import { bgRegular, chipTextColor } from "../../theme"; import styled from "@mui/system/styled"; import { debounce } from "lodash"; -const StyledTextField = styled(TextField)(({ theme }) => ({ +const StyledTextField = styled(TextField)({ backgroundColor: bgRegular, - padding: theme.spacing(1), + padding: "0.75rem", marginRight: "0.286rem", "& .MuiSvgIcon-root": { width: "1.25rem", @@ -31,12 +31,12 @@ const StyledTextField = styled(TextField)(({ theme }) => ({ }, }, "& .MuiInputBase-input": { - padding: theme.spacing(0), + padding: 0, fontSize: ".88rem", color: chipTextColor, fontWeight: 500, }, -})); +}); interface RepositoriesSearchProps { filterChanged: (newFilter: string) => void; diff --git a/applications/osb-portal/src/components/common/SearchFilterReposWorkspaces.tsx b/applications/osb-portal/src/components/common/SearchFilterReposWorkspaces.tsx index f9167bf92..bfc35716f 100644 --- a/applications/osb-portal/src/components/common/SearchFilterReposWorkspaces.tsx +++ b/applications/osb-portal/src/components/common/SearchFilterReposWorkspaces.tsx @@ -44,19 +44,19 @@ interface SearchReposWorkspacesProps { setLoading?: (loading: boolean) => void; } -const StyledLabel = styled(Typography)(({ theme }) => ({ +const StyledLabel = styled(Typography)({ color: bgInputs, fontWeight: 700, fontSize: ".88rem", - marginBottom: theme.spacing(1), + marginBottom: "0.75rem", display: "inline-block", -})); +}); -const StyledPopover = styled(Popover)(({ theme }) => ({ +const StyledPopover = styled(Popover)({ "& .MuiPaper-root": { background: chipBg, minWidth: "350px !important", - padding: theme.spacing(3), + padding: 3, boxShadow: "0px 10px 60px rgba(0, 0, 0, 0.5)", "& .MuiSvgIcon-root": { cursor: "pointer", @@ -68,7 +68,7 @@ const StyledPopover = styled(Popover)(({ theme }) => ({ paddingBottom: 0, marginBottom: ".88rem", "& .MuiSvgIcon-root": { - marginLeft: theme.spacing(1), + marginLeft: "0.75rem", color: paragraph, }, "& .MuiInputBase-root": { @@ -86,9 +86,9 @@ const StyledPopover = styled(Popover)(({ theme }) => ({ }, }, }, -})); +}); -const StyledFilterButton = styled(Button)(({ theme }) => ({ +const StyledFilterButton = styled(Button)({ borderRadius: "0px 8px 8px 0px", textTransform: "capitalize", boxShadow: "none", @@ -109,7 +109,7 @@ const StyledFilterButton = styled(Button)(({ theme }) => ({ color: chipTextColor, fontWeight: 500, }, -})); +}); export const SearchFilterReposWorkspaces = ( props: SearchReposWorkspacesProps @@ -138,10 +138,10 @@ export const SearchFilterReposWorkspaces = ( }; const handleInput = (event: React.ChangeEvent) => { - let repositoryTypes = [...props?.searchFilterValues.types]; + let repositoryTypes = [...(props?.searchFilterValues.types ?? [])]; if (event.target.checked) { - repositoryTypes = [...props?.searchFilterValues.types, event.target.name]; + repositoryTypes = [...(props?.searchFilterValues.types ?? []), event.target.name]; } else { repositoryTypes = repositoryTypes.filter( (row) => row !== event.target.name diff --git a/applications/osb-portal/src/components/common/ThumbnailUploadArea.tsx b/applications/osb-portal/src/components/common/ThumbnailUploadArea.tsx index e6920ea2c..f7c3e3b59 100644 --- a/applications/osb-portal/src/components/common/ThumbnailUploadArea.tsx +++ b/applications/osb-portal/src/components/common/ThumbnailUploadArea.tsx @@ -15,179 +15,179 @@ import { alpha } from "@mui/material/styles"; const MAX_ALLOWED_THUMBNAIL_SIZE = 1024 * 1024; // 1MB -export const StyledDropZoneBox = styled(Box)(({ theme }) => ({ - color: bgInputs, - border: `2px dashed ${bgInputs}`, - borderRadius: 5, - padding: 4, - "& .MuiTypography-subtitle2": { - marginTop: theme.spacing(1), - marginBottom: theme.spacing(2), - }, - "& .MuiButton-outlined": { - margin: "0 auto", - display: "flex", - justifyContent: "center", - color: bgInputs, - borderRadius: radius, - border: `2px solid ${bgInputs}`, - }, -})); +export const StyledDropZoneBox = styled(Box)({ + color: bgInputs, + border: `2px dashed ${bgInputs}`, + borderRadius: 5, + padding: "2rem", + "& .MuiTypography-subtitle2": { + marginTop: "0.75rem", + marginBottom: "1rem", + }, + "& .MuiButton-outlined": { + margin: "0 auto", + display: "flex", + justifyContent: "center", + color: bgInputs, + borderRadius: radius, + border: `2px solid ${bgInputs}`, + }, +}); export const StyledImagePreviewSection = styled("section")(() => ({ - display: "flex", - minHeight: "15em", - alignItems: "stretch", - backgroundPosition: "center", - backgroundSize: "cover", - flex: 1, + display: "flex", + minHeight: "15em", + alignItems: "stretch", + backgroundPosition: "center", + backgroundSize: "cover", + flex: 1, })); -export const dropAreaStyle = (error: any) => ({ - flex: 1, - display: "flex", - alignItems: "center", - borderRadius: radius, - padding: gutter, - borderColor: error ? "red" : alpha(bgInputs, 1), +const dropAreaStyle = (error: any) => ({ + flex: 1, + display: "flex", + alignItems: "center", + borderRadius: radius, + padding: gutter, + borderColor: error ? "red" : alpha(bgInputs, 1), }); interface UploadAreaProps { - setThumbnail: any; - thumbnail: any; - thumbnailError: any; - setThumbnailError: any; - workspace: any; + setThumbnail: any; + thumbnail: any; + thumbnailError: any; + setThumbnailError: any; + workspace: any; } export const OSBDialog: React.FunctionComponent = ({ - setThumbnail, - thumbnail, - thumbnailError, - setThumbnailError, - workspace + setThumbnail, + thumbnail, + thumbnailError, + setThumbnailError, + workspace }) => { - const [thumbnailPreview, setThumbnailPreview] = React.useState( - workspace?.thumbnail ? "/proxy/workspaces/" + workspace.thumbnail : null - ); - - - const dropThumbnail = (uploadedThumbnail: any) => { - setThumbnail(uploadedThumbnail); - previewFile(uploadedThumbnail); - }; - - const previewFile = (file: Blob) => { - if (!file) { - setThumbnailError(null); - setThumbnailPreview(null); - return; - } - - if (!file.type.includes("image")) { - setThumbnailError("Not an image file"); - return; - } - if (file.size > MAX_ALLOWED_THUMBNAIL_SIZE) { - setThumbnailError("File exceeds allowed size (1MB)"); - return; - } - - setThumbnailError(null); - - const fileReader: FileReader = new FileReader(); - - fileReader.onload = () => { - setThumbnailPreview(fileReader.result); - }; - - fileReader.readAsDataURL(file); - }; - return ( - - { - dropThumbnail(acceptedFiles[0]); - }} - > - {({ - getRootProps, - getInputProps, - acceptedFiles, - }: { - getRootProps: (p: any) => any; - getInputProps: () => any; - acceptedFiles: any[]; - }) => ( - -
- - - {thumbnail && ( - - {!thumbnail ? ( - "" - ) : ( - { - e.preventDefault(); - dropThumbnail(null); - }} - size="large" - > - - - )} - - )} - - - {!thumbnail ? ( - <> - Drop file here to upload... - - - ) : null} - - {thumbnailError && ( - - {thumbnailError} - - )} - - - -
-
- )} -
-
- - ); + const [thumbnailPreview, setThumbnailPreview] = React.useState( + workspace?.thumbnail ? "/proxy/workspaces/" + workspace.thumbnail : null + ); + + + const dropThumbnail = (uploadedThumbnail: any) => { + setThumbnail(uploadedThumbnail); + previewFile(uploadedThumbnail); + }; + + const previewFile = (file: Blob) => { + if (!file) { + setThumbnailError(null); + setThumbnailPreview(null); + return; + } + + if (!file.type.includes("image")) { + setThumbnailError("Not an image file"); + return; + } + if (file.size > MAX_ALLOWED_THUMBNAIL_SIZE) { + setThumbnailError("File exceeds allowed size (1MB)"); + return; + } + + setThumbnailError(null); + + const fileReader: FileReader = new FileReader(); + + fileReader.onload = () => { + setThumbnailPreview(fileReader.result); + }; + + fileReader.readAsDataURL(file); + }; + return ( + + { + dropThumbnail(acceptedFiles[0]); + }} + > + {({ + getRootProps, + getInputProps, + acceptedFiles, + }: { + getRootProps: (p: any) => any; + getInputProps: () => any; + acceptedFiles: any[]; + }) => ( + +
+ + + {thumbnail && ( + + {!thumbnail ? ( + "" + ) : ( + { + e.preventDefault(); + dropThumbnail(null); + }} + size="large" + > + + + )} + + )} + + + {!thumbnail ? ( + <> + Drop file here to upload... + + + ) : null} + + {thumbnailError && ( + + {thumbnailError} + + )} + + + +
+
+ )} +
+
+ + ); }; export default OSBDialog; diff --git a/applications/osb-portal/src/components/dialogs/AboutDialog.tsx b/applications/osb-portal/src/components/dialogs/AboutDialog.tsx index baa12e5ef..057ace76b 100644 --- a/applications/osb-portal/src/components/dialogs/AboutDialog.tsx +++ b/applications/osb-portal/src/components/dialogs/AboutDialog.tsx @@ -1,9 +1,12 @@ import React from "react"; +import { useSelector, useDispatch } from "react-redux"; import OSBDialog from "../common/OSBDialog"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import Link from "@mui/material/Link"; import { OSBLogo } from "../icons"; +import { RootState } from "../../store/rootReducer"; +import { closeDialog } from "../../store/actions/aboutdialog"; const styles = { paper: { @@ -20,7 +23,7 @@ export const AboutContent = (props: any) => { return ( - + { ); }; -export const AboutDialog = (props: any) => { +export const AboutDialog = () => { + const dispatch = useDispatch(); + const aboutDialog = useSelector((state: RootState) => state.aboutDialog); + + const handleCloseDialog = () => { + dispatch(closeDialog()); + }; + return ( diff --git a/applications/osb-portal/src/components/dialogs/PrimaryDialog.tsx b/applications/osb-portal/src/components/dialogs/PrimaryDialog.tsx index b64c0bd91..f5dd0e20b 100644 --- a/applications/osb-portal/src/components/dialogs/PrimaryDialog.tsx +++ b/applications/osb-portal/src/components/dialogs/PrimaryDialog.tsx @@ -7,36 +7,36 @@ import { Button } from "@mui/material"; const PrimaryDialog = ({ - open, - setOpen, - title, - description, - handleCallback, - actionButtonText, - cancelButtonText, + open, + setOpen, + title, + description, + handleCallback, + actionButtonText, + cancelButtonText, }) => { - return ( - setOpen(false)} - > - {title} - {description} - - - - - - ) + return ( + setOpen(false)} + > + {title} + {description} + + + + + + ) } export default PrimaryDialog; \ No newline at end of file diff --git a/applications/osb-portal/src/components/dialogs/WorkspaceConfirmDialog.tsx b/applications/osb-portal/src/components/dialogs/WorkspaceConfirmDialog.tsx index 9ac9d71df..e60940139 100644 --- a/applications/osb-portal/src/components/dialogs/WorkspaceConfirmDialog.tsx +++ b/applications/osb-portal/src/components/dialogs/WorkspaceConfirmDialog.tsx @@ -8,43 +8,43 @@ import { Button, Link } from "@mui/material"; const WorkspaceConfirmDialog = ({ - createdWorkspaceConfirmationContent, - setChecked, - workspaceLink, - handleCloseConfirmationDialog, + createdWorkspaceConfirmationContent, + setChecked, + workspaceLink, + handleCloseConfirmationDialog, }) => { - const { title, content, isSuccess, } = createdWorkspaceConfirmationContent; + const { title, content, isSuccess, } = createdWorkspaceConfirmationContent; - return ( - handleCloseConfirmationDialog()} - > - {title} - {content} - - - - - - ) + return ( + handleCloseConfirmationDialog()} + > + {title} + {content} + + + + + + ) } export default WorkspaceConfirmDialog; \ No newline at end of file diff --git a/applications/osb-portal/src/components/handlers/OSBErrorBoundary.tsx b/applications/osb-portal/src/components/handlers/OSBErrorBoundary.tsx index 21ff4a5a6..9cca0e849 100644 --- a/applications/osb-portal/src/components/handlers/OSBErrorBoundary.tsx +++ b/applications/osb-portal/src/components/handlers/OSBErrorBoundary.tsx @@ -9,6 +9,7 @@ import Button from "@mui/material/Button"; interface OSBErrorBoundaryProps { error?: any; + children: React.ReactNode; } interface OwnState { diff --git a/applications/osb-portal/src/components/header/Banner.tsx b/applications/osb-portal/src/components/header/Banner.tsx index 7e16a3efc..e3ce9381e 100644 --- a/applications/osb-portal/src/components/header/Banner.tsx +++ b/applications/osb-portal/src/components/header/Banner.tsx @@ -1,49 +1,52 @@ import * as React from "react"; import { useNavigate } from "react-router-dom"; -import makeStyles from '@mui/styles/makeStyles'; -import Typography from "@mui/material/Typography"; +import { useSelector, useDispatch } from "react-redux"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import { UserInfo } from "../../types/user"; +import { RootState } from "../../store/rootReducer"; +import { userLogin } from "../../store/actions/user"; -const useStyles = makeStyles((theme) => ({ - mainFeaturedPost: { - position: "relative", - backgroundImage: "url(images/banner.png)", - backgroundSize: "cover", - backgroundRepeat: "no-repeat", - backgroundPosition: "center", - height: "35vh", - }, - mainFeaturedPostContent: { - position: "absolute", - bottom: 0, - right: 0, - left: 0, - top: 0, - backgroundColor: "rgba(0,0,0,.3)", - display: "flex", - alignItems: "flex-end", - padding: theme.spacing(3), - }, -})); - -export const Banner = (props: any) => { - const classes = useStyles(); +export const Banner = () => { const navigate = useNavigate(); - const user: UserInfo = props.user; + const dispatch = useDispatch(); + const user: UserInfo = useSelector((state: RootState) => state.user); + const handleSignup = () => { - props.register(); + // For now, using userLogin since register action doesn't exist yet + // This should be replaced with proper registration action when implemented + dispatch(userLogin()); }; return ( - - + + - {"" && ( // TODO temporarily disabled - - )} + {// TODO temporarily disabled + + } {user === null ? ( @@ -133,19 +140,18 @@ export const Header = (props: any) => { )); const handleToggleDrawer = (e: any) => { - if (props.drawerEnabled) { - e.preventDefault(); - props.onToggleDrawer(); - } + // Note: drawerEnabled prop would need to be accessed from Redux state if needed + // For now, assuming drawer is always enabled + e.preventDefault(); + dispatch(toggleDrawer()); }; - // @ts-ignore return ( - + - + v2.0 diff --git a/applications/osb-portal/src/components/home/Latest.tsx b/applications/osb-portal/src/components/home/Latest.tsx index d666a6917..c399d8d72 100644 --- a/applications/osb-portal/src/components/home/Latest.tsx +++ b/applications/osb-portal/src/components/home/Latest.tsx @@ -1,22 +1,20 @@ import * as React from "react"; -import makeStyles from '@mui/styles/makeStyles'; import { Typography, Box, Link } from "@mui/material"; -const useStyles = makeStyles((theme) => ({ +const styles = { paper: { - padding: theme.spacing(2), - margin: theme.spacing(1), + p: 2, + m: 1, textAlign: "left", }, partners: { fontSize: "0.9em", marginBottom: "0.5em", }, -})); +}; export const Latest = () => { - const classes = useStyles(); return ( @@ -66,7 +64,7 @@ export const Latest = () => { alignItems="center" textAlign="right" > - Supported by + Supported by Wellcome ({ const dispatchUserProps = { login: userLogin, logout: userLogout, - register: userRegister, }; const dispatchDrawerProps = { @@ -99,57 +99,20 @@ const mapHomePageToProps = (state: RootState) => ({ counter: state.workspaces?.counter, }); -const mapAboutDialogToProps = (state: RootState) => ({ - aboutDialog: state.aboutDialog, -}); - -const dispatchAboutDialogProps = { - closeDialog, -}; -const dispatchMainMenuProps = { - openDialog, -}; - -const mapAboutDialogAndUserToProps = (state: RootState) => ({ - aboutDialog: state.aboutDialog, - user: state.user, -}); - -const dispatchAboutDialogAndUser = { - openDialog, - closeDialog, - ...dispatchUserProps, -}; - export const Workspaces = connect( mapWorkspacesStateToProps, dispatchWorkspaceProps )(workspace); -export const WorkspaceCard = connect( - mapUserStateToProps, - dispatchWorkspaceProps -)(workspaceCard); -export const HomePage = connect( - mapHomePageToProps, - dispatchTagsProps -)(homePage); -export const EditRepoDialog = connect(mapRepositoriesPageToProps, { - ...dispatchTagsProps, - ...dispatchRepositoriesProps, -})(editRepoDialog); +export const WorkspaceCard = workspaceCard; +export const HomePage = homePage; +export const EditRepoDialog = editRepoDialog; export const WorkspaceToolBox = connect( mapUserStateToProps, dispatchWorkspaceProps )(workspacetoolbox); -export const Header = connect(mapUserStateToProps, { - ...dispatchUserProps, - ...dispatchDrawerProps, -})(header); -export const WorkspaceDrawer = connect( - mapSelectedWorkspaceStateToProps, - dispatchDrawerProps -)(workspacedrawer) as any; // any to fix weird type mapping error +export const Header = header; +export const WorkspaceDrawer = workspacedrawer; export const WorkspaceInteractions = connect( mapUserStateToProps, dispatchWorkspaceProps @@ -159,15 +122,9 @@ export const WorkspaceEditor = connect( dispatchTagsProps )(workspaceEditor); -export const App = connect((state: RootState) => ({ - error: state.error, - user: state.user, -}), null)(app); -export const AboutDialog = connect( - mapAboutDialogToProps, - dispatchAboutDialogProps -)(aboutDialog); -export const MainMenu = connect(null, dispatchMainMenuProps)(mainMenu); +export const App = app; +export const AboutDialog = aboutDialog; +export const MainMenu = mainMenu; const genericDispatch = (dispatch: Dispatch) => ({ dispatch: (action: AnyAction) => dispatch(action), }); @@ -175,36 +132,25 @@ export const WorkspaceFrame = connect( mapSelectedWorkspaceStateToProps, genericDispatch )(workspaceFrame); -export const WorkspaceOpenPage = connect( - null, - dispatchWorkspaceProps -)(workspaceOpenPage); +export const WorkspaceOpenPage = workspaceOpenPage; export const WorkspacePage = connect( mapSelectedWorkspaceStateToProps, dispatchWorkspaceProps )(workspacePage); -export const RepositoryPage = connect(mapUserStateToProps)(repositoryPage); -export const UserPage = connect(mapUserStateToProps)(userPage); -export const GroupsPage = connect(mapUserStateToProps)(UserGroupsPage); +export const RepositoryPage = repositoryPage; +export const UserPage = userPage; +export const GroupsPage = UserGroupsPage; export const RepositoriesPage = connect(mapRepositoriesPageToProps, { ...dispatchTagsProps, ...dispatchRepositoriesProps, })(repositoriesPage); -export const NewWorkspaceAskUser = connect( - null, - dispatchUserProps -)(newWorkspaceAskUser); -export const ProtectedRoute = connect( - mapUserStateToProps, - dispatchUserProps -)(protectedRoute); +export const NewWorkspaceAskUser = newWorkspaceAskUser; +export const ProtectedRoute = protectedRoute; -export const PageSider = connect( - mapAboutDialogAndUserToProps, - dispatchAboutDialogAndUser -)(MainDrawer); +// MainDrawer now uses Redux hooks for user and aboutDialog actions +export const PageSider = MainDrawer; -export const WorkspaceActionsMenu = connect( - mapUserStateToProps, - dispatchWorkspaceProps -)(WorkspaceActionsMenuUnbound); +export const WorkspaceActionsMenu = WorkspaceActionsMenuUnbound; + +// Components converted to use Redux hooks instead of connect +export const Banner = banner; diff --git a/applications/osb-portal/src/components/menu/MainMenu.tsx b/applications/osb-portal/src/components/menu/MainMenu.tsx index 9a5901c30..0f3666ee2 100644 --- a/applications/osb-portal/src/components/menu/MainMenu.tsx +++ b/applications/osb-portal/src/components/menu/MainMenu.tsx @@ -1,36 +1,39 @@ import * as React from "react"; -import { useNavigate } from "react-router-dom"; -import makeStyles from '@mui/styles/makeStyles'; +import { useLocation, useNavigate } from "react-router-dom"; +import { useDispatch } from "react-redux"; import Box from "@mui/material/Box"; import { MainMenuItem } from "./MainMenuItem"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import { openDialog } from "../../store/actions/aboutdialog"; -const useStyles = makeStyles(() => ({ - button: { - textTransform: "inherit", - minWidth: "auto", - width: "auto", - marginRight: "3em", - lineHeight: 1, - fontWeight: 400, - }, - firstButton: { - fontWeight: 600, - }, - flipButton: { - fontWeight: 700, - textTransform: "uppercase", - padding: "5px", - fontSize: "0.75rem", - }, -})); +const buttonStyles = { + textTransform: "inherit", + minWidth: "auto", + width: "auto", + marginRight: "3em", + lineHeight: 1, + fontWeight: 400, +}; + +const firstButtonStyles = { + ...buttonStyles, + fontWeight: 600, +}; + +const flipButtonStyles = { + fontWeight: 700, + textTransform: "uppercase", + padding: "5px", + fontSize: "0.75rem", +}; -export const MainMenu = (props: any) => { - const classes = useStyles(); +export const MainMenu = () => { const navigate = useNavigate(); + const location = useLocation(); + const dispatch = useDispatch(); const handleDialogOpen = () => { - props.openDialog(); + dispatch(openDialog()); }; return ( { { /> navigate("/repositories"), - checked: navigate.location.pathname === "/repositories", + checked: location.pathname === "/repositories", }, { label: "Workspaces", callback: () => navigate("/"), - checked: navigate.location.pathname === "/", + checked: location.pathname === "/", }, ]} /> - {navigate.location.pathname === "/" ? ( + {location.pathname === "/" ? ( WORKSPACES } - className={classes.flipButton} + sx={flipButtonStyles} items={[ { label: "Repositories", @@ -96,14 +99,14 @@ export const MainMenu = (props: any) => { ]} popperPlacement="bottom-end" /> - ) : navigate.location.pathname === "/repositories" ? ( + ) : location.pathname === "/repositories" ? ( REPOSITORIES } - className={classes.flipButton} + sx={flipButtonStyles} items={[{ label: "Workspaces", callback: () => navigate("/") }]} popperPlacement="bottom-end" /> diff --git a/applications/osb-portal/src/components/menu/MainMenuItem.tsx b/applications/osb-portal/src/components/menu/MainMenuItem.tsx index 73f037e74..2ab1cc57a 100644 --- a/applications/osb-portal/src/components/menu/MainMenuItem.tsx +++ b/applications/osb-portal/src/components/menu/MainMenuItem.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import makeStyles from '@mui/styles/makeStyles'; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import MenuList from "@mui/material/MenuList"; @@ -10,15 +9,15 @@ import Paper from "@mui/material/Paper"; import Popper from "@mui/material/Popper"; import CheckIcon from "@mui/icons-material/Check"; -const useStyles = makeStyles((theme) => ({ +const styles = { popper: { zIndex: 10000, }, checkIcon: { - paddingRight: theme.spacing(1), + pr: 1, marginLeft: "-1em", }, -})); +}; export interface MenuItem { label: string; @@ -28,13 +27,13 @@ export interface MenuItem { export type MenuItemProps = { title: string | React.ReactNode; - className: string; + className?: string; + sx?: any; items: MenuItem[]; popperPlacement?: any; }; export const MainMenuItem = (props: MenuItemProps) => { - const classes = useStyles(); const [open, setOpen] = React.useState(false); const anchorRef = React.useRef(null); @@ -80,6 +79,7 @@ export const MainMenuItem = (props: MenuItemProps) => { aria-haspopup="true" onClick={handleToggle} className={props.className} + sx={props.sx} > {props.title} @@ -88,7 +88,7 @@ export const MainMenuItem = (props: MenuItemProps) => { anchorEl={anchorRef.current} transition={true} disablePortal={true} - className={classes.popper} + sx={styles.popper} placement={ typeof props.popperPlacement === "undefined" ? "bottom-start" @@ -114,7 +114,7 @@ export const MainMenuItem = (props: MenuItemProps) => { > {item.checked !== undefined && ( )} diff --git a/applications/osb-portal/src/components/repository/EditRepoDialog.tsx b/applications/osb-portal/src/components/repository/EditRepoDialog.tsx index dba9a93f7..473f8cb68 100644 --- a/applications/osb-portal/src/components/repository/EditRepoDialog.tsx +++ b/applications/osb-portal/src/components/repository/EditRepoDialog.tsx @@ -1,4 +1,5 @@ -import React, { useState } from "react"; +import React, { useCallback, useState } from "react"; +import { useSelector, useDispatch } from "react-redux"; import Button from "@mui/material/Button"; import Dialog from "@mui/material/Dialog"; import DialogActions from "@mui/material/DialogActions"; @@ -44,13 +45,15 @@ import { RepositoryInfo, Tag, } from "../../apiclient/workspaces"; -import { UserInfo } from "../../types/user"; +import { RootState } from "../../store/rootReducer"; import { styled } from "@mui/system"; import ButtonGroup from "@mui/material/ButtonGroup"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import RepositoryMarkdownViewer from "./RepositoryMarkdownViewer"; import ThumbnailUploadArea from "../common/ThumbnailUploadArea"; import { readFile } from "../../utils"; +import { ReactNode } from "react-markdown"; +import { refreshRepositories } from "@/store/actions/repositories"; const DEFAULT_CONTEXTS = ["main", "master"]; @@ -60,12 +63,9 @@ interface EditRepoProps { handleClose: (open: boolean) => any; repository?: OSBRepository; title: string; - user?: UserInfo; - tags: Tag[]; - refreshRepositories: () => void; } -const RepoDialog = styled(Dialog)(({ theme }) => ({ +const RepoDialog = styled(Dialog)({ "& .MuiPaper-root": { padding: 0, backgroundColor: bgDarker, @@ -124,24 +124,25 @@ const RepoDialog = styled(Dialog)(({ theme }) => ({ }, }, }, -})); +} +); -const RepoButtonGroup = styled(ButtonGroup)(({ theme }) => ({ +const RepoButtonGroup = styled(ButtonGroup)({ borderRadius: "2px", "& .MuiTextField-root": { "& .MuiInputBase-root.MuiOutlinedInput-root": { borderRadius: "0px 2px 2px 0px", }, }, -})); +}); -const Label = styled(Typography)(({ theme }) => ({ +const Label = styled(Typography)({ fontWeight: 700, fontSize: "0.75rem", color: badgeBgLight, marginBottom: "0.286rem", lineHeight: "1.429rem", -})); +}); const RepoSelect = styled(Select)(({ theme }) => ({ padding: 0, @@ -165,11 +166,11 @@ const RepoSelect = styled(Select)(({ theme }) => ({ }, "& .MuiSvgIcon-root": { - right: theme.spacing(1), + right: 1, }, })); -const RepoAutocomplete = styled(Autocomplete)(({ theme }) => ({ +const RepoAutocomplete = styled(Autocomplete)({ border: 0, padding: 0, "& .MuiButtonBase-root.MuiChip-root": { @@ -180,18 +181,20 @@ const RepoAutocomplete = styled(Autocomplete)(({ theme }) => ({ padding: "7px", }, }, -})); +}); export const EditRepoDialog = ({ dialogOpen, onSubmit, repository = RepositoryService.EMPTY_REPOSITORY, title = "Add repository", - user, - tags: tagOptions, handleClose, - refreshRepositories, }: EditRepoProps) => { + // Redux hooks + const user = useSelector((state: RootState) => state.user); + const tags = useSelector((state: RootState) => state.tags); + const dispatch = useDispatch(); + const [formValues, setFormValues] = useState({ ...repository, userId: user?.id, @@ -210,11 +213,15 @@ export const EditRepoDialog = ({ name: "", }); - const setRepositoryTags = (tags: string[]) => { + const doRefreshRepositories = useCallback(() => { + dispatch(refreshRepositories()); + }, [dispatch]); + + const setRepositoryTags = useCallback((tags: string[]) => { const arrayOfTags: Tag[] = []; tags.forEach((tag) => arrayOfTags.push({ tag })); setFormValues({ ...formValues, tags: arrayOfTags }); - }; + }, [formValues]); React.useEffect(() => { setFormValues({ ...repository, userId: user?.id }); @@ -223,7 +230,7 @@ export const EditRepoDialog = ({ ? repository.tags.map((tagObject) => tagObject.tag) : []; setRepositoryTags(repositoryTags); - }, [repository]); + }, [repository, setRepositoryTags, user?.id]); React.useEffect(() => { if (uri) { @@ -252,7 +259,7 @@ export const EditRepoDialog = ({ } ); } - }, [uri]); + }, [error, formValues, repository, uri]); const handleInput = (event: any, key: any) => { const value = event?.target?.value || event.text; @@ -281,7 +288,7 @@ export const EditRepoDialog = ({ new Blob([fileThumbnail]) ).then( () => { - refreshRepositories(); + doRefreshRepositories(); // Computed fields are not updated: remove so that the repo can be merged by the caller Object.keys(obj).forEach((key) => obj[key] === undefined ? delete obj[key] : {} ); @@ -294,7 +301,7 @@ export const EditRepoDialog = ({ setThumbnail(null); } else { setLoading(true); - refreshRepositories(); + doRefreshRepositories(); } } @@ -590,14 +597,14 @@ export const EditRepoDialog = ({ className="repository-tags-input-element" multiple={true} freeSolo={true} - options={tagOptions.map((t) => t.tag)} + + options={tags.map((t) => t.tag)} onChange={(event, value: string[]) => setRepositoryTags(value)} - placeholder="Select tags" renderTags={(value, getTagProps) => value.map((option, index) => ( diff --git a/applications/osb-portal/src/components/repository/RepositoryPageBanner.tsx b/applications/osb-portal/src/components/repository/RepositoryPageBanner.tsx index 0ac57f72b..2bbfcb9e7 100644 --- a/applications/osb-portal/src/components/repository/RepositoryPageBanner.tsx +++ b/applications/osb-portal/src/components/repository/RepositoryPageBanner.tsx @@ -20,19 +20,19 @@ import CalendarTodayOutlinedIcon from "@mui/icons-material/CalendarTodayOutlined //types import { OSBRepository } from "../../apiclient/workspaces"; -const RepoPageBannerBox = styled(Box)(({ theme }) => ({ +const RepoPageBannerBox = styled(Box)({ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", - padding: theme.spacing(5), + padding: 5, minHeight: "200px", "& .MuiChip-root": { background: chipBg, margin: "0.25rem", }, -})); +}); const RepositoryPageBanner = ({ repository, diff --git a/applications/osb-portal/src/components/repository/RepositoryPageDetails.tsx b/applications/osb-portal/src/components/repository/RepositoryPageDetails.tsx index 9f71fa371..5f197ed0a 100644 --- a/applications/osb-portal/src/components/repository/RepositoryPageDetails.tsx +++ b/applications/osb-portal/src/components/repository/RepositoryPageDetails.tsx @@ -155,9 +155,7 @@ const RepositoryPageDetails = ({ RepositoryResourceNode[] >([repository?.contextResources]); const [filter, setFilter] = React.useState(); - const [checked, setChecked] = React.useState<{ - [id: string]: RepositoryResourceNode; - }>({}); + const [checked, setChecked] = React.useState>({}); const [repositoryEditorOpen, setRepositoryEditorOpen] = React.useState(false); const canEdit = canEditRepository(user, repository); @@ -168,7 +166,7 @@ const RepositoryPageDetails = ({ (e) => !filter || e.resource.name.toLowerCase().includes(filter) ); - let resourcesListObject: {[id: string]: RepositoryResourceNode} = resourcesList?.reduce( + const resourcesListObject: Record = resourcesList?.reduce( (resourcesListObject, item) => { resourcesListObject[item.resource.path] = item.children; return resourcesListObject; @@ -325,11 +323,11 @@ const RepositoryPageDetails = ({ borderBottom={`1px solid ${lineColor}`} > Repository preview - + View on{" "} {Resources[repository?.repositoryType] || repository?.repositoryType} - + @@ -577,7 +575,6 @@ const RepositoryPageDetails = ({ {repositoryEditorOpen && ( ({ +const styles = { textField: { - borderRadius: 4, - marginTop: theme.spacing(2), + borderRadius: 1, + mt: 2, backgroundColor: bgLightestShade, - padding: theme.spacing(2), + p: 2, "& .MuiSvgIcon-root": { width: "1.25rem", borderRadius: 0, @@ -59,7 +58,7 @@ const useStyles = makeStyles((theme) => ({ }, }, "& .MuiInputBase-input": { - padding: theme.spacing(0), + p: 0, fontSize: ".88rem", }, }, @@ -70,7 +69,6 @@ const useStyles = makeStyles((theme) => ({ color: linkColor, }, }, - "& .MuiListItemIcon-root": { minWidth: 1, }, @@ -92,7 +90,6 @@ const useStyles = makeStyles((theme) => ({ fontWeight: "bold", color: bgInputs, }, - "& .MuiAvatar-root": { width: "1.5rem", borderRadius: 0, @@ -103,10 +100,10 @@ const useStyles = makeStyles((theme) => ({ padding: 0, }, "& .MuiListItem-root": { - borderRadius: 4, + borderRadius: 1, padding: 0, - paddingLeft: theme.spacing(2), - paddingRight: theme.spacing(2), + pl: 2, + pr: 2, "&:first-child": { "& .flex-grow-1": { borderTop: 0, @@ -153,9 +150,9 @@ const useStyles = makeStyles((theme) => ({ }, }, }, -})); +}; -export default ({ +export const RepositoryResourceBrowser = ({ repository, checkedChanged, backAction, @@ -174,7 +171,6 @@ export default ({ >([repository.contextResources]); const [filter, setFilter] = React.useState(); const handleToggle = (value: any) => () => ""; - const classes = useStyles(); React.useEffect(() => { setChecked({}); }, [refresh]); @@ -185,8 +181,8 @@ export default ({ (e) => !filter || e.resource.name.toLowerCase().includes(filter) ), [currentPath, filter]); - let resourcesListObject: { - [id: string]: RepositoryResourceNode; + const resourcesListObject: { + [id: string]: RepositoryResourceNode | any; } = React.useMemo(() => resourcesList?.reduce( (resourcesListObject, item) => { resourcesListObject[item.resource.path] = item.children; @@ -230,7 +226,7 @@ export default ({ } aria-label="breadcrumb" - className={classes.breadcrumbs} + sx={styles.breadcrumbs} > {currentPath.map((element, i) => ( setFilter(e.target.value.toLowerCase())} InputProps={{ startAdornment: ( @@ -260,7 +256,7 @@ export default ({ - +
; }; + +export default RepositoryResourceBrowser; \ No newline at end of file diff --git a/applications/osb-portal/src/components/repository/RespositoriesTable.tsx b/applications/osb-portal/src/components/repository/RespositoriesTable.tsx index 5b022b472..52eb2be64 100644 --- a/applications/osb-portal/src/components/repository/RespositoriesTable.tsx +++ b/applications/osb-portal/src/components/repository/RespositoriesTable.tsx @@ -115,7 +115,7 @@ export const RepositoriesList = (props: RepositoriesProps) => { sx={{ "&:last-child td, &:last-child th": { border: 0 } }} > diff --git a/applications/osb-portal/src/components/styled/FormLabel.tsx b/applications/osb-portal/src/components/styled/FormLabel.tsx index 657d1e270..85b29de5e 100644 --- a/applications/osb-portal/src/components/styled/FormLabel.tsx +++ b/applications/osb-portal/src/components/styled/FormLabel.tsx @@ -6,12 +6,12 @@ import Typography from "@mui/material/Typography"; //style import styled from "@mui/system/styled"; -export const StyledLabel = styled((props) => ( +export const StyledLabel = styled((props: any) => ( -))(({ theme }) => ({ +))({ fontWeight: "bold", lineHeight: "2em", fontSize: "0.8rem", -})); +}); export default StyledLabel; diff --git a/applications/osb-portal/src/components/user/UserEditor.tsx b/applications/osb-portal/src/components/user/UserEditor.tsx index 86076bdab..32ad8f848 100644 --- a/applications/osb-portal/src/components/user/UserEditor.tsx +++ b/applications/osb-portal/src/components/user/UserEditor.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import makeStyles from "@mui/styles/makeStyles"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import TextField from "@mui/material/TextField"; @@ -94,7 +93,7 @@ interface UserEditProps { close: () => void; } -export default (props: UserEditProps) => { +export const UserEditor = (props: UserEditProps) => { const [addLinkDialogOpen, setAddLinkDialogOpen] = React.useState(false); const profiles = { @@ -126,7 +125,7 @@ export default (props: UserEditProps) => { setProfileForm({ ...userForm, website: value }); setError({ ...error, website: undefined }); - } catch (_) { + } catch (e) { setError({ ...error, website: "Invalid URL" }); } }; @@ -135,11 +134,11 @@ export default (props: UserEditProps) => { const value = e.target.value; try { if (value) { - const _ = new URL(value); + new URL(value); } setError({ ...error, avatar: undefined }); setProfileForm({ ...userForm, avatar: value }); - } catch (_) { + } catch (e) { setError({ ...error, avatar: "Invalid URL" }); } }; @@ -453,3 +452,5 @@ export default (props: UserEditProps) => { ); }; + +export default UserEditor; diff --git a/applications/osb-portal/src/components/workspace/ExistingWorkspaceSelector.tsx b/applications/osb-portal/src/components/workspace/ExistingWorkspaceSelector.tsx index 90839a63d..fba473cc0 100644 --- a/applications/osb-portal/src/components/workspace/ExistingWorkspaceSelector.tsx +++ b/applications/osb-portal/src/components/workspace/ExistingWorkspaceSelector.tsx @@ -1,7 +1,6 @@ import * as React from "react"; import debounce from "lodash/debounce"; -import makeStyles from "@mui/styles/makeStyles"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import Grid from "@mui/material/Grid"; @@ -16,7 +15,7 @@ import searchFilter from "../../types/searchFilter"; import SearchFilterReposWorkspaces from "../common/SearchFilterReposWorkspaces"; import { Page } from "../../types/model"; -const useStyles = makeStyles((theme) => ({ +const styles = { workspacesBox: { height: "400px", overflow: "auto", @@ -72,7 +71,7 @@ const useStyles = makeStyles((theme) => ({ marginLeft: "0.5rem", marginTop: "0.5rem", }, -})); +}; interface ExistingWorkspaceEditorProps { setWorkspace: (ws: Workspace) => void; @@ -82,7 +81,6 @@ interface ExistingWorkspaceEditorProps { export const ExistingWorkspaceEditor = ( props: ExistingWorkspaceEditorProps ) => { - const classes = useStyles(); const [activeCardClassNames, setActiveCardClassNames] = React.useState< string[] @@ -100,8 +98,8 @@ export const ExistingWorkspaceEditor = ( ...searchFilterValues, text: newTextFilter, tags: newTextFilter - ? [...searchFilterValues?.tags, newTextFilter] - : searchFilterValues?.tags, + ? [...(searchFilterValues?.tags ?? []), newTextFilter] + : searchFilterValues?.tags ?? [], }); }, 500); @@ -120,7 +118,7 @@ export const ExistingWorkspaceEditor = ( ); }; - const getWorkspacesList = (payload?) => { + const getWorkspacesList = React.useCallback((payload?) => { setWorkspaces(null); if (payload?.searchFilterValues) { @@ -132,7 +130,7 @@ export const ExistingWorkspaceEditor = ( .fetchWorkspaces(null, null, 1, 100) .then(setWorkspacesFromPage); } - }; + }, [searchFilterValues]); React.useEffect(() => { if (isSearchFieldsEmpty) { @@ -140,7 +138,7 @@ export const ExistingWorkspaceEditor = ( } else { getWorkspacesList({ searchFilterValues }); } - }, [searchFilterValues]); + }, [getWorkspacesList, isSearchFieldsEmpty, searchFilterValues]); const handleWorkspaceSelection = (index: number) => { const placeHolderArray = Array(workspaces.length).fill("not-active"); @@ -161,7 +159,7 @@ export const ExistingWorkspaceEditor = ( hasTypes={false} /> - + {workspaces ? ( {workspaces && @@ -177,12 +175,14 @@ export const ExistingWorkspaceEditor = ( xl={2} >