diff --git a/web/package-lock.json b/web/package-lock.json index 2ac625b8d..bbdea1cdb 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -733,6 +733,7 @@ }, "node_modules/@clack/prompts/node_modules/is-unicode-supported": { "version": "1.3.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { diff --git a/web/package.json b/web/package.json index 40c057666..c164ba70c 100644 --- a/web/package.json +++ b/web/package.json @@ -17,7 +17,7 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", - "@faker-js/faker": "^9.3.0", + "@faker-js/faker": "^9.4.0", "@fluentui/react-context-selector": "^9.1.71", "@manufac/echarts-simple-transform": "^2.0.11", "@million/lint": "^1.0.14", @@ -25,11 +25,11 @@ "@supabase/auth-helpers-nextjs": "^0.10.0", "@supabase/auth-helpers-react": "^0.5.0", "@supabase/ssr": "^0.5.2", - "@supabase/supabase-js": "^2.47.10", - "@tanstack/react-query": "^5.62.16", + "@supabase/supabase-js": "^2.47.14", + "@tanstack/react-query": "^5.64.1", "@vercel/speed-insights": "^1.1.0", "ahooks": "^3.8.4", - "antd": "^5.23.0", + "antd": "^5.23.1", "antd-style": "^3.7.1", "axios": "^1.7.9", "canvas-confetti": "^1.9.3", @@ -56,7 +56,7 @@ "echarts-stat": "^1.2.0", "email-validator": "^2.0.4", "font-color-contrast": "^11.1.0", - "framer-motion": "^11.16.0", + "framer-motion": "^11.18.0", "html2canvas": "^1.4.1", "immer": "^10.1.1", "js-cookie": "^3.0.5", @@ -70,12 +70,12 @@ "next": "14.2.22", "next-themes": "^0.4.4", "next-transpile-modules": "^10.0.1", - "papaparse": "^5.4.1", + "papaparse": "^5.5.1", "patternomaly": "^1.3.2", "pluralize": "^8.0.0", - "posthog-js": "^1.204.0", + "posthog-js": "^1.206.1", "prettier": "^3.4.2", - "prettier-plugin-tailwindcss": "^0.6.9", + "prettier-plugin-tailwindcss": "^0.6.10", "rc-virtual-list": "^3.17.0", "react": "^18", "react-chartjs-2": "^5.3.0", @@ -99,7 +99,7 @@ "sql-language-server": "^1.7.1", "tailwind-merge": "^2.6.0", "utility-types": "^3.11.0", - "uuid": "^11.0.4" + "uuid": "^11.0.5" }, "devDependencies": { "@types/canvas-confetti": "^1.9.0", @@ -119,10 +119,10 @@ "eslint": "^8", "eslint-config-next": "14.2.3", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-prettier": "^5.2.2", "monaco-editor-webpack-plugin": "^7.1.0", "postcss": "~8", - "sass": "^1.83.1", + "sass": "^1.83.4", "tailwindcss": "^3.4.17", "typescript": "^5" }, diff --git a/web/src/app/app/_controllers/AppSidebar/AppSidebarSettings.tsx b/web/src/app/app/_controllers/AppSidebar/AppSidebarSettings.tsx index 1e5332280..8fd165bf1 100644 --- a/web/src/app/app/_controllers/AppSidebar/AppSidebarSettings.tsx +++ b/web/src/app/app/_controllers/AppSidebar/AppSidebarSettings.tsx @@ -7,7 +7,7 @@ import { BusterRoutes, createBusterRoute } from '@/routes'; import { Menu, MenuProps } from 'antd'; import { createStyles } from 'antd-style'; import Link from 'next/link'; -import React, { useContext } from 'react'; +import React, { useContext, useMemo } from 'react'; import { Text } from '@/components'; import { SignOutButton } from './SignOutButton'; import { useMemoizedFn } from 'ahooks'; @@ -164,6 +164,64 @@ const accountItems: MenuItem[] = [ } ]; +const permissionsAndSecurityItems: MenuItem[] = [ + { + key: BusterRoutes.APP_SETTINGS_USERS, + label: ( + + Users + + ) + }, + { + key: BusterRoutes.APP_SETTINGS_DATASETS, + label: ( + + Datasets + + ) + }, + { + key: BusterRoutes.APP_SETTINGS_DATASET_GROUPS, + label: ( + + Dataset Groups + + ) + }, + { + key: BusterRoutes.APP_SETTINGS_ATTRIBUTES, + label: ( + + Attributes + + ) + }, + { + key: BusterRoutes.APP_SETTINGS_SECURITY, + label: ( + + Security + + ) + } +]; + const useStyles = createStyles(({ token, css }) => { return { menuHeader: css` @@ -181,63 +239,75 @@ const useStyles = createStyles(({ token, css }) => { export const AppSidebarSettings: React.FC<{ className?: string; signOut: () => void; -}> = ({ signOut }) => { +}> = React.memo(({ signOut }) => { + const { styles, cx } = useStyles(); const { openInfoMessage } = useBusterNotifications(); const currentRoute = useAppLayoutContextSelector((s) => s.currentRoute); - const { styles, cx } = useStyles(); const userTeams = useUserConfigContextSelector((state) => state.userTeams); const onAddTeam = useMemoizedFn(() => { openInfoMessage('Adding team is not currently supported'); }); - const teamsList: MenuItem[] = [ - ...userTeams.map((team) => ({ - key: createBusterRoute({ - route: BusterRoutes.SETTINGS_TEAM_ID, - teamId: team.id - }), - label: ( - - {team.name} - - ) - })), - { - key: 'addteam', - label: ( -
- - Add team -
- ) - } - ]; + const teamsList: MenuItem[] = useMemo( + () => [ + ...userTeams.map((team) => ({ + key: createBusterRoute({ + route: BusterRoutes.SETTINGS_TEAM_ID, + teamId: team.id + }), + label: ( + + {team.name} + + ) + })), + { + key: 'addteam', + label: ( +
+ + Add team +
+ ) + } + ], + [userTeams, onAddTeam, styles.addButton, cx] + ); - const menus = [ - { - key: 'workspace', - label: 'Workspace', - icon: , - children: workSpaceItems - }, - { - key: 'myaccount', - label: 'My Account', - icon: , - children: accountItems - }, - { - key: 'teams', - label: 'Teams', - icon: , - children: teamsList - } - ]; + const menus = useMemo( + () => [ + { + key: 'myaccount', + label: 'Account', + icon: , + children: accountItems + }, + { + key: 'workspace', + label: 'Workspace', + icon: , + children: workSpaceItems + }, + { + key: 'permissionsandsecurity', + label: 'Permissions & Security', + icon: , + children: permissionsAndSecurityItems + } + // { + // key: 'teams', + // label: 'Teams', + // icon: , + // children: teamsList + // } + ], + [workSpaceItems, permissionsAndSecurityItems, accountItems, teamsList] + ); const allKeys = menus.map((menu) => menu.key); @@ -264,4 +334,5 @@ export const AppSidebarSettings: React.FC<{ ); -}; +}); +AppSidebarSettings.displayName = 'AppSidebarSettings'; diff --git a/web/src/routes/busterRoutes/busterAppRoutes.ts b/web/src/routes/busterRoutes/busterAppRoutes.ts index d0c0ebf03..b2987170b 100644 --- a/web/src/routes/busterRoutes/busterAppRoutes.ts +++ b/web/src/routes/busterRoutes/busterAppRoutes.ts @@ -9,7 +9,6 @@ export enum BusterAppRoutes { APP_DASHBOARD_ID = '/app/dashboards/:dashboardId', APP_DASHBOARD_THREADS = '/app/dashboards/:dashboardId/metrics', APP_DASHBOARD_THREADS_ID = '/app/dashboards/:dashboardId/metrics/:threadId', - APP_LOGS = '/app/logs', APP_DATASETS = '/app/datasets', APP_DATASETS_ID = '/app/datasets/:datasetId', @@ -35,6 +34,14 @@ export enum BusterAppRoutes { SETTINGS_PREFERENCES = '/app/settings/preferences', SETTINGS_NOTIFICATIONS = '/app/settings/notifications', SETTINGS_TEAM_ID = '/app/settings/team/:teamId', + APP_SETTINGS_USERS = '/app/settings/users', + APP_SETTINGS_USERS_ID = '/app/settings/users/:userId', + APP_SETTINGS_DATASETS = '/app/settings/datasets', + APP_SETTINGS_DATASETS_ID = '/app/settings/datasets/:datasetId', + APP_SETTINGS_DATASET_GROUPS = '/app/settings/dataset-groups', + APP_SETTINGS_DATASET_GROUPS_ID = '/app/settings/dataset-groups/:datasetGroupId', + APP_SETTINGS_ATTRIBUTES = '/app/settings/attributes', + APP_SETTINGS_SECURITY = '/app/settings/security', NEW_USER = '/app/new-user' } @@ -106,4 +113,23 @@ export type BusterAppRoutesWithArgs = { threadId: string; }; [BusterAppRoutes.NEW_USER]: { route: BusterAppRoutes.NEW_USER }; + [BusterAppRoutes.APP_SETTINGS_USERS]: { route: BusterAppRoutes.APP_SETTINGS_USERS }; + [BusterAppRoutes.APP_SETTINGS_USERS_ID]: { + route: BusterAppRoutes.APP_SETTINGS_USERS_ID; + userId: string; + }; + [BusterAppRoutes.APP_SETTINGS_DATASETS]: { route: BusterAppRoutes.APP_SETTINGS_DATASETS }; + [BusterAppRoutes.APP_SETTINGS_DATASETS_ID]: { + route: BusterAppRoutes.APP_SETTINGS_DATASETS_ID; + datasetId: string; + }; + [BusterAppRoutes.APP_SETTINGS_DATASET_GROUPS]: { + route: BusterAppRoutes.APP_SETTINGS_DATASET_GROUPS; + }; + [BusterAppRoutes.APP_SETTINGS_DATASET_GROUPS_ID]: { + route: BusterAppRoutes.APP_SETTINGS_DATASET_GROUPS_ID; + datasetGroupId: string; + }; + [BusterAppRoutes.APP_SETTINGS_ATTRIBUTES]: { route: BusterAppRoutes.APP_SETTINGS_ATTRIBUTES }; + [BusterAppRoutes.APP_SETTINGS_SECURITY]: { route: BusterAppRoutes.APP_SETTINGS_SECURITY }; };