From e22ac0445949d8b7f092a291d983727e29194c18 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 12 Apr 2023 12:29:38 +0200 Subject: [PATCH] [WIFI-12492] Entity and venue page rework Signed-off-by: Charles --- .prettierignore | 4 + package-lock.json | 4 +- package.json | 2 +- src/components/Card/CardHeader.tsx | 13 +- .../LocationPickerCreator/index.jsx | 2 +- .../VenueTable/CreateVenueModal/index.jsx | 66 ++-- src/hooks/Network/Analytics.ts | 296 ++------------- src/hooks/Network/Entity.ts | 22 +- src/hooks/Network/Resources.ts | 2 +- src/hooks/Network/Venues.ts | 23 +- src/index.css | 3 +- src/layout/Containers/PanelContainer.tsx | 18 - src/layout/Containers/PanelContent.tsx | 18 - src/layout/MainPanel.tsx | 23 -- src/layout/Navbar/index.tsx | 243 ++++++------- src/layout/PageContainer/index.tsx | 48 +++ src/layout/Sidebar/CreateLinks.tsx | 21 -- src/layout/Sidebar/EntityNavButton.tsx | 18 +- src/layout/Sidebar/EntityPopover.tsx | 24 +- src/layout/Sidebar/NavLinkButton.tsx | 98 ++--- src/layout/Sidebar/index.tsx | 105 +++--- src/layout/index.tsx | 90 +++-- src/models/Analytics.ts | 238 ++++++++++++ src/models/Entity.ts | 13 + src/models/Routes.ts | 5 +- src/models/Venue.ts | 17 +- src/pages/ConfigurationPage/index.jsx | 9 +- .../EntityPage/CreateEntityModal/Form.jsx | 3 +- .../EntityPage/CreateEntityModal/index.jsx | 56 ++- ...ityPopover.jsx => DeleteEntityPopover.tsx} | 35 +- src/pages/EntityPage/EntityCard/Form.jsx | 160 -------- src/pages/EntityPage/EntityCard/index.jsx | 67 ---- .../EntityChildrenTableWrapper/Actions.jsx | 34 -- .../EntityChildrenTableWrapper/index.jsx | 27 -- .../Actions.tsx | 38 -- .../index.jsx | 52 --- .../EntityContactTableWrapper /index.jsx | 57 --- .../EntityLocationTableWrapper /index.jsx | 57 --- .../EntityResourcesTableWrapper/index.jsx | 60 --- .../EntityVenueTableWrapper/Actions.jsx | 34 -- .../EntityVenueTableWrapper/index.jsx | 39 -- .../EntityPage/EntityChildrenCard/index.tsx | 92 ----- src/pages/EntityPage/EntityDropdown.tsx | 77 ++++ src/pages/EntityPage/EntityHeader.tsx | 40 ++ .../EntityConfigurations.tsx | 58 +++ .../ConfigurationCard/EntityResources.tsx | 67 ++++ .../ConfigurationCard/ResourceActions.tsx} | 27 +- .../Layout/ConfigurationCard/index.tsx | 56 +++ .../EntityPage/Layout/EntityChildren.tsx | 38 ++ .../Layout/EntityChildrenActions.tsx} | 15 +- src/pages/EntityPage/Layout/EntityDetails.tsx | 161 ++++++++ .../ContactActions.tsx} | 38 +- .../EntityContacts.tsx | 60 +++ .../EntityLocations.tsx | 60 +++ .../LocationActions.tsx} | 38 +- .../EntityLocationContactsCard/index.tsx | 56 +++ src/pages/EntityPage/Layout/EntityNotes.tsx | 172 +++++++++ .../Layout/InventoryCard}/Actions.tsx | 25 +- .../InventoryCard}/index.tsx | 81 +++-- src/pages/EntityPage/Layout/index.tsx | 31 ++ src/pages/EntityPage/VenueDropdown.tsx | 81 +++++ src/pages/EntityPage/index.tsx | 23 +- src/pages/InventoryPage/index.tsx | 12 +- src/pages/MapPage/index.jsx | 12 +- src/pages/NotFound/index.tsx | 8 +- src/pages/Notifications/index.tsx | 136 ++++--- src/pages/OperatorPage/index.tsx | 19 +- src/pages/OperatorsPage/index.tsx | 12 +- src/pages/Profile/index.tsx | 18 +- src/pages/SubscriberPage/index.tsx | 19 +- src/pages/SystemPage/index.tsx | 96 +++-- src/pages/UsersPage/index.jsx | 12 +- .../VenuePage/{VenueCard => }/Actions.tsx | 0 .../{VenueCard => }/DeleteVenuePopover.jsx | 0 .../Layout/AnalyticsCard/DatePickers.tsx | 194 ++++++++++ .../AssociationCirclePack.tsx} | 38 +- .../CircleComponent/DeviceCirclePack.tsx} | 43 ++- .../CircleComponent/RadioCirclePack.tsx} | 40 +- .../CircleComponent/SsidCirclePack.tsx} | 38 +- .../CircleComponent/VenueCirclePack.tsx} | 38 +- .../CirclePack/CircleComponent/index.tsx | 110 ++++++ .../LiveView/CirclePack/CircleLabel.tsx | 23 ++ .../LiveView/CirclePack/Slider.tsx} | 20 +- .../LiveView/CirclePack/index.tsx | 89 +++++ .../LiveView/CirclePack/useCirclePackTheme.ts | 101 +++++ .../LiveView/CirclePack/utils.ts | 259 +++++++++++++ .../LiveView/FullScreenLiveViewButton.tsx | 33 ++ .../AnalyticsCard/LiveView/InfoButton.tsx | 49 +++ .../AnalyticsCard/LiveView/LiveViewLayout.tsx | 60 +++ .../Layout/AnalyticsCard/LiveView/index.tsx | 64 ++++ .../AnalyticsCard/LiveView/useLiveView.ts | 42 +++ .../AnalyticsCard/StartAnalyticsModal.tsx | 186 ++++++++++ .../AnalyticsCard/StopMonitoringButton.tsx | 114 ++++++ .../VenueClientLifecycle/MacSearchBar.tsx | 13 +- .../VenueClientLifecycle/Table.tsx | 42 +-- .../VenueClientLifecycle/index.tsx | 86 +++++ .../VenueDashboard/Header/DeviceTypeStat.jsx | 1 - .../VenueDashboard/Header/FirmwareStat.jsx | 1 - .../VenueDashboard/Header/HealthStat.jsx | 1 - .../VenueDashboard/Header/MemoryStat.jsx | 1 - .../VenueDashboard/Header/index.jsx | 7 +- .../VenueDashboard/TableModal.jsx | 14 +- .../AnalyticsCard}/VenueDashboard/index.jsx | 77 ++-- .../ViewAnalyticsSettingsModal.tsx | 196 ++++++++++ .../VenuePage/Layout/AnalyticsCard/index.tsx | 172 +++++++++ .../ConfigurationCard/ResourceActions.tsx} | 27 +- .../ConfigurationCard/VenueConfigurations.tsx | 58 +++ .../ConfigurationCard/VenueResources.tsx | 67 ++++ .../Layout/ConfigurationCard/index.tsx | 56 +++ src/pages/VenuePage/Layout/ContactActions.tsx | 118 ++++++ .../Layout/InventoryCard}/Actions.tsx | 20 +- .../InventoryCard}/index.tsx | 82 +++-- .../UseContactExistingModal}/Actions.tsx | 12 +- .../UseContactExistingModal}/index.tsx | 11 +- src/pages/VenuePage/Layout/VenueContacts.tsx | 72 ++++ src/pages/VenuePage/Layout/VenueDetails.tsx | 177 +++++++++ src/pages/VenuePage/Layout/VenueNotes.tsx | 175 +++++++++ src/pages/VenuePage/Layout/index.tsx | 38 ++ src/pages/VenuePage/VenueCard/Form.jsx | 344 ------------------ .../VenueCard/VenueAnalytics/index.jsx | 18 - src/pages/VenuePage/VenueCard/index.tsx | 74 ---- .../VenueChildrenTableWrapper/Actions.jsx | 34 -- .../VenueChildrenTableWrapper/index.jsx | 32 -- .../VenueClientLifecycle/index.tsx | 49 --- .../VenueConfigurationsTableWrapper/index.jsx | 55 --- .../VenueContactTableWrapper/Actions.tsx | 101 ----- .../VenueContactTableWrapper/index.tsx | 78 ---- .../CirclePack/CircleComponent/index.jsx | 34 -- .../VenueLiveView/CirclePack/CircleLabel.jsx | 36 -- .../VenueLiveView/CirclePack/InfoButton.jsx | 54 --- .../VenueLiveView/CirclePack/index.jsx | 329 ----------------- .../VenueLiveView/ExpandButton.jsx | 38 -- .../VenueLiveView/TimePickers.jsx | 37 -- .../VenueChildrenCard/VenueLiveView/index.jsx | 91 ----- .../VenueResourcesTableWrapper/index.jsx | 56 --- .../VenuePage/VenueChildrenCard/index.tsx | 133 ------- src/pages/VenuePage/VenueDropdown.tsx | 79 ++++ .../VenueFirmwareUpgradeModal.tsx | 0 src/pages/VenuePage/VenueHeader.tsx | 40 ++ src/pages/VenuePage/index.tsx | 23 +- src/router/index.tsx | 2 +- src/router/routes.tsx | 10 +- src/theme/additions/layout/MainPanel.ts | 27 -- src/theme/additions/layout/PanelContainer.ts | 12 - src/theme/additions/layout/PanelContent.ts | 14 - src/theme/components/alert.ts | 2 +- src/theme/theme.ts | 8 +- src/utils/colors.ts | 35 +- 148 files changed, 4884 insertions(+), 3810 deletions(-) delete mode 100644 src/layout/Containers/PanelContainer.tsx delete mode 100644 src/layout/Containers/PanelContent.tsx delete mode 100644 src/layout/MainPanel.tsx create mode 100644 src/layout/PageContainer/index.tsx delete mode 100644 src/layout/Sidebar/CreateLinks.tsx create mode 100644 src/models/Analytics.ts rename src/pages/EntityPage/{EntityCard/DeleteEntityPopover.jsx => DeleteEntityPopover.tsx} (82%) delete mode 100644 src/pages/EntityPage/EntityCard/Form.jsx delete mode 100644 src/pages/EntityPage/EntityCard/index.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityChildrenTableWrapper/Actions.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityChildrenTableWrapper/index.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityConfigurationsTableWrapper/Actions.tsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityConfigurationsTableWrapper/index.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityContactTableWrapper /index.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityLocationTableWrapper /index.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityResourcesTableWrapper/index.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityVenueTableWrapper/Actions.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/EntityVenueTableWrapper/index.jsx delete mode 100644 src/pages/EntityPage/EntityChildrenCard/index.tsx create mode 100644 src/pages/EntityPage/EntityDropdown.tsx create mode 100644 src/pages/EntityPage/EntityHeader.tsx create mode 100644 src/pages/EntityPage/Layout/ConfigurationCard/EntityConfigurations.tsx create mode 100644 src/pages/EntityPage/Layout/ConfigurationCard/EntityResources.tsx rename src/pages/EntityPage/{EntityChildrenCard/EntityResourcesTableWrapper/Actions.jsx => Layout/ConfigurationCard/ResourceActions.tsx} (82%) create mode 100644 src/pages/EntityPage/Layout/ConfigurationCard/index.tsx create mode 100644 src/pages/EntityPage/Layout/EntityChildren.tsx rename src/pages/{VenuePage/VenueChildrenCard/VenueConfigurationsTableWrapper/Actions.tsx => EntityPage/Layout/EntityChildrenActions.tsx} (60%) create mode 100644 src/pages/EntityPage/Layout/EntityDetails.tsx rename src/pages/EntityPage/{EntityChildrenCard/EntityContactTableWrapper /Actions.jsx => Layout/EntityLocationContactsCard/ContactActions.tsx} (75%) create mode 100644 src/pages/EntityPage/Layout/EntityLocationContactsCard/EntityContacts.tsx create mode 100644 src/pages/EntityPage/Layout/EntityLocationContactsCard/EntityLocations.tsx rename src/pages/EntityPage/{EntityChildrenCard/EntityLocationTableWrapper /Actions.jsx => Layout/EntityLocationContactsCard/LocationActions.tsx} (75%) create mode 100644 src/pages/EntityPage/Layout/EntityLocationContactsCard/index.tsx create mode 100644 src/pages/EntityPage/Layout/EntityNotes.tsx rename src/pages/{VenuePage/VenueChildrenCard/VenueDeviceTableWrapper => EntityPage/Layout/InventoryCard}/Actions.tsx (92%) rename src/pages/EntityPage/{EntityChildrenCard/EntityDeviceTableWrapper => Layout/InventoryCard}/index.tsx (60%) create mode 100644 src/pages/EntityPage/Layout/index.tsx create mode 100644 src/pages/EntityPage/VenueDropdown.tsx rename src/pages/VenuePage/{VenueCard => }/Actions.tsx (100%) rename src/pages/VenuePage/{VenueCard => }/DeleteVenuePopover.jsx (100%) create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/DatePickers.tsx rename src/pages/VenuePage/{VenueChildrenCard/VenueLiveView/CirclePack/CircleComponent/AssociationCircle.jsx => Layout/AnalyticsCard/LiveView/CirclePack/CircleComponent/AssociationCirclePack.tsx} (83%) rename src/pages/VenuePage/{VenueChildrenCard/VenueLiveView/CirclePack/CircleComponent/DeviceCircle.jsx => Layout/AnalyticsCard/LiveView/CirclePack/CircleComponent/DeviceCirclePack.tsx} (83%) rename src/pages/VenuePage/{VenueChildrenCard/VenueLiveView/CirclePack/CircleComponent/RadioCircle.jsx => Layout/AnalyticsCard/LiveView/CirclePack/CircleComponent/RadioCirclePack.tsx} (79%) rename src/pages/VenuePage/{VenueChildrenCard/VenueLiveView/CirclePack/CircleComponent/SsidCircle.jsx => Layout/AnalyticsCard/LiveView/CirclePack/CircleComponent/SsidCirclePack.tsx} (85%) rename src/pages/VenuePage/{VenueChildrenCard/VenueLiveView/CirclePack/CircleComponent/VenueCircle.jsx => Layout/AnalyticsCard/LiveView/CirclePack/CircleComponent/VenueCirclePack.tsx} (71%) create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/CirclePack/CircleComponent/index.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/CirclePack/CircleLabel.tsx rename src/pages/VenuePage/{VenueChildrenCard/VenueLiveView/CirclePack/Slider.jsx => Layout/AnalyticsCard/LiveView/CirclePack/Slider.tsx} (70%) create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/CirclePack/index.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/CirclePack/useCirclePackTheme.ts create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/CirclePack/utils.ts create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/FullScreenLiveViewButton.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/InfoButton.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/LiveViewLayout.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/index.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/LiveView/useLiveView.ts create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/StartAnalyticsModal.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/StopMonitoringButton.tsx rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueClientLifecycle/MacSearchBar.tsx (92%) rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueClientLifecycle/Table.tsx (94%) create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/VenueClientLifecycle/index.tsx rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueDashboard/Header/DeviceTypeStat.jsx (99%) rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueDashboard/Header/FirmwareStat.jsx (99%) rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueDashboard/Header/HealthStat.jsx (99%) rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueDashboard/Header/MemoryStat.jsx (99%) rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueDashboard/Header/index.jsx (98%) rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueDashboard/TableModal.jsx (96%) rename src/pages/VenuePage/{VenueChildrenCard => Layout/AnalyticsCard}/VenueDashboard/index.jsx (76%) create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/ViewAnalyticsSettingsModal.tsx create mode 100644 src/pages/VenuePage/Layout/AnalyticsCard/index.tsx rename src/pages/VenuePage/{VenueChildrenCard/VenueResourcesTableWrapper/Actions.jsx => Layout/ConfigurationCard/ResourceActions.tsx} (82%) create mode 100644 src/pages/VenuePage/Layout/ConfigurationCard/VenueConfigurations.tsx create mode 100644 src/pages/VenuePage/Layout/ConfigurationCard/VenueResources.tsx create mode 100644 src/pages/VenuePage/Layout/ConfigurationCard/index.tsx create mode 100644 src/pages/VenuePage/Layout/ContactActions.tsx rename src/pages/{EntityPage/EntityChildrenCard/EntityDeviceTableWrapper => VenuePage/Layout/InventoryCard}/Actions.tsx (94%) rename src/pages/VenuePage/{VenueChildrenCard/VenueDeviceTableWrapper => Layout/InventoryCard}/index.tsx (63%) rename src/pages/VenuePage/{VenueChildrenCard/VenueContactTableWrapper/UseExistingModal => Layout/UseContactExistingModal}/Actions.tsx (81%) rename src/pages/VenuePage/{VenueChildrenCard/VenueContactTableWrapper/UseExistingModal => Layout/UseContactExistingModal}/index.tsx (87%) create mode 100644 src/pages/VenuePage/Layout/VenueContacts.tsx create mode 100644 src/pages/VenuePage/Layout/VenueDetails.tsx create mode 100644 src/pages/VenuePage/Layout/VenueNotes.tsx create mode 100644 src/pages/VenuePage/Layout/index.tsx delete mode 100644 src/pages/VenuePage/VenueCard/Form.jsx delete mode 100644 src/pages/VenuePage/VenueCard/VenueAnalytics/index.jsx delete mode 100644 src/pages/VenuePage/VenueCard/index.tsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueChildrenTableWrapper/Actions.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueChildrenTableWrapper/index.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueClientLifecycle/index.tsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueConfigurationsTableWrapper/index.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueContactTableWrapper/Actions.tsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueContactTableWrapper/index.tsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueLiveView/CirclePack/CircleComponent/index.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueLiveView/CirclePack/CircleLabel.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueLiveView/CirclePack/InfoButton.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueLiveView/CirclePack/index.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueLiveView/ExpandButton.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueLiveView/TimePickers.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueLiveView/index.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/VenueResourcesTableWrapper/index.jsx delete mode 100644 src/pages/VenuePage/VenueChildrenCard/index.tsx create mode 100644 src/pages/VenuePage/VenueDropdown.tsx rename src/pages/VenuePage/{VenueCard => }/VenueFirmwareUpgradeModal.tsx (100%) create mode 100644 src/pages/VenuePage/VenueHeader.tsx delete mode 100644 src/theme/additions/layout/MainPanel.ts delete mode 100644 src/theme/additions/layout/PanelContainer.ts delete mode 100644 src/theme/additions/layout/PanelContent.ts diff --git a/.prettierignore b/.prettierignore index 9020bbc..305ef68 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,7 @@ build dist node_modules .github +docker-entrypoint.d +helm +.dockerignore +Dockerfile diff --git a/package-lock.json b/package-lock.json index 5eb048c..cb56ba9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wlan-cloud-owprov-ui", - "version": "2.9.0(18)", + "version": "2.10.0(2)", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wlan-cloud-owprov-ui", - "version": "2.9.0(18)", + "version": "2.10.0(2)", "license": "ISC", "dependencies": { "@chakra-ui/icons": "^2.0.11", diff --git a/package.json b/package.json index f71331a..804df2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wlan-cloud-owprov-ui", - "version": "2.9.0(18)", + "version": "2.10.0(2)", "description": "", "main": "index.tsx", "scripts": { diff --git a/src/components/Card/CardHeader.tsx b/src/components/Card/CardHeader.tsx index 3d7f8f2..26deecb 100644 --- a/src/components/Card/CardHeader.tsx +++ b/src/components/Card/CardHeader.tsx @@ -1,8 +1,7 @@ import React from 'react'; -import { Box, useStyleConfig } from '@chakra-ui/react'; -import { ThemeProps } from 'models/Theme'; +import { Box, LayoutProps, SpaceProps, useStyleConfig } from '@chakra-ui/react'; -interface Props extends ThemeProps { +interface Props extends LayoutProps, SpaceProps { variant?: string; children: React.ReactNode; } @@ -11,13 +10,7 @@ const defaultProps = { variant: undefined, }; -const CardHeader = ( - { - variant, - children, - ...rest - }: Props -) => { +const CardHeader = ({ variant, children, ...rest }: Props) => { // @ts-ignore const styles = useStyleConfig('CardHeader', { variant }); // Pass the computed styles into the `__css` prop diff --git a/src/components/CreateObjectsForms/LocationPickerCreator/index.jsx b/src/components/CreateObjectsForms/LocationPickerCreator/index.jsx index 99c649b..3e1af69 100644 --- a/src/components/CreateObjectsForms/LocationPickerCreator/index.jsx +++ b/src/components/CreateObjectsForms/LocationPickerCreator/index.jsx @@ -97,7 +97,7 @@ const LocationPickerCreator = ({ locationName, createLocationName, editing, isMo { value: 'CREATE_NEW', label: getCreateLabel() }, ...getOptions(), ]} - w={256} + w="unset" /> {location === 'CREATE_NEW' && newLocation && !isModal &&
} {location === 'CREATE_NEW' && isModal && ( diff --git a/src/components/Tables/VenueTable/CreateVenueModal/index.jsx b/src/components/Tables/VenueTable/CreateVenueModal/index.jsx index 9b2b33c..e2f4cba 100644 --- a/src/components/Tables/VenueTable/CreateVenueModal/index.jsx +++ b/src/components/Tables/VenueTable/CreateVenueModal/index.jsx @@ -4,27 +4,25 @@ import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import CreateVenueForm from './Form'; import CloseButton from 'components/Buttons/CloseButton'; -import CreateButton from 'components/Buttons/CreateButton'; import SaveButton from 'components/Buttons/SaveButton'; import ConfirmCloseAlert from 'components/Modals/Actions/ConfirmCloseAlert'; import ModalHeader from 'components/Modals/ModalHeader'; import useFormRef from 'hooks/useFormRef'; const propTypes = { - isDisabled: PropTypes.bool, parentId: PropTypes.string, entityId: PropTypes.string, + isOpen: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, }; const defaultProps = { - isDisabled: false, parentId: '', entityId: '', }; -const CreateVenueModal = ({ parentId, entityId, isDisabled }) => { +const CreateVenueModal = ({ isOpen, onClose, parentId, entityId }) => { const { t } = useTranslation(); - const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen: showConfirm, onOpen: openConfirm, onClose: closeConfirm } = useDisclosure(); const { form, formRef } = useFormRef(); @@ -36,37 +34,35 @@ const CreateVenueModal = ({ parentId, entityId, isDisabled }) => { }; return ( - <> - - - - - - - - - } + + + + + + + + } + /> + + - - - - - - - + + + + ); }; diff --git a/src/hooks/Network/Analytics.ts b/src/hooks/Network/Analytics.ts index 5d0ca0c..a3800f6 100644 --- a/src/hooks/Network/Analytics.ts +++ b/src/hooks/Network/Analytics.ts @@ -1,248 +1,16 @@ import { useToast } from '@chakra-ui/react'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; +import { + AnalyticsBoardApiResponse, + AnalyticsBoardDevicesApiResponse, + AnalyticsClientLifecycleApiResponse, + AnalyticsTimePointsApiResponse, +} from 'models/Analytics'; import { AxiosError } from 'models/Axios'; -import { Note } from 'models/Note'; import { PageInfo, SortInfo } from 'models/Table'; import { axiosAnalytics } from 'utils/axiosInstances'; -export type AnalyticsBoardDevice = { - associations_2g: number; - associations_5g: number; - associations_6g: number; - boardId: string; - connected: boolean; - connectionIp: string; - deviceType: string; - health: number; - lastConnection: number; - lastContact: number; - lastDisconnection: number; - lastFirmware: string; - lastFirmwareUpdate: number; - lastHealth: number; - lastPing: number; - lastState: number; - locale: string; - memory: number; - pings: number; - serialNumber: string; - states: number; - type: string; - uptime: number; -}; - -export type AnalyticsBoardDevicesApiResponse = { - devices: AnalyticsBoardDevice[]; -}; - -export type AnalyticsBoardApiResponse = { - created: number; - description: string; - id: string; - modified: number; - name: string; - notes: Note[]; - tags: string[]; - venueList: { - description: string; - id: string; - interval: number; - monitorSubVenues: boolean; - name: string; - retention: number; - }; -}; - -export type AnalyticsClientLifecycleApiResponse = { - ack_signal: number; - ack_signal_avg: number; - active_ms: number; - bssid: string; - busy_ms: number; - channel: number; - channel_width: number; - connected: number; - inactive: number; - ipv4: string; - ipv6: string; - mode: string; - noise: number; - receive_ms: number; - rssi: number; - rx_bitrate: number; - rx_bytes: number; - rx_chwidth: number; - rx_duration: number; - rx_mcs: number; - rx_nss: number; - rx_packets: number; - rx_vht: boolean; - ssid: string; - station_id: string; - timestamp: number; - tx_bitrate: number; - tx_bytes: number; - tx_chwidth: number; - tx_duration: number; - tx_mcs: number; - tx_nss: number; - tx_packets: number; - tx_power: number; - tx_retries: number; - tx_vht: boolean; - venue_id: string; -}; - -export type AnalyticsApData = { - collisions: number; - multicast: number; - rx_bytes: number; - rx_bytes_bw: number; - rx_bytes_delta: number; - rx_dropped: number; - rx_dropped_delta: number; - rx_dropped_pct: number; - rx_errors: number; - rx_errors_delta: number; - rx_errors_pct: number; - rx_packets: number; - rx_packets_bw: number; - rx_packets_delta: number; - tx_bytes: number; - tx_bytes_bw: number; - tx_bytes_delta: number; - tx_dropped: number; - tx_dropped_delta: number; - tx_dropped_pct: number; - tx_errors: number; - tx_errors_delta: number; - tx_errors_pct: number; - tx_packets: number; - tx_packets_bw: number; - tx_packets_delta: number; -}; - -export type AnalyticsRadioData = { - active_ms: number; - active_pct: number; - band: number; - busy_ms: number; - busy_pct: number; - channel: number; - channel_width: number; - noise: number; - receive_ms: number; - receive_pct: number; - temperature: number; - transmit_ms: number; - transmit_pct: number; - tx_power: number; -}; - -export type AnalyticsAssociationData = { - connected: number; - inactive: number; - rssi: number; - rx_bytes: number; - rx_bytes_bw: number; - rx_bytes_delta: number; - rx_packets: number; - rx_packets_bw: number; - rx_packets_delta: number; - rx_rate: { - bitrate: number; - chwidth: number; - ht: boolean; - mcs: number; - nss: number; - sgi: boolean; - }; - station: string; - tx_bytes: number; - tx_bytes_bw: number; - tx_bytes_delta: number; - tx_duration: number; - tx_duration_delta: number; - tx_duration_pct: number; - tx_failed: number; - tx_failed_delta: number; - tx_failed_pct: number; - tx_packets: number; - tx_packets_bw: number; - tx_packets_delta: number; - tx_rate: { - bitrate: number; - chwidth: number; - ht: boolean; - mcs: number; - nss: number; - sgi: boolean; - }; - tx_retries: number; - tx_retries_delta: number; - tx_retries_pct: number; -}; - -export type AnalyticsSsidData = { - associations: AnalyticsAssociationData[]; - band: 2; - bssid: string; - channel: number; - mode: string; - rx_bytes_bw: { - avg: number; - max: number; - min: number; - }; - rx_packets_bw: { - avg: number; - max: number; - min: number; - }; - ssid: string; - tx_bytes_bw: { - avg: number; - max: number; - min: number; - }; - tx_duration_pct: { - avg: number; - max: number; - min: number; - }; - tx_failed_pct: { - avg: number; - max: number; - min: number; - }; - tx_packets_bw: { - avg: number; - max: number; - min: number; - }; - tx_retries_pct: { - avg: number; - max: number; - min: number; - }; -}; - -export type AnalyticsTimePointApiResponse = { - ap_data: AnalyticsApData; - boardId: string; - device_info: AnalyticsBoardDevice; - id: string; - radio_data: AnalyticsRadioData[]; - serialNumber: string; - ssid_data: AnalyticsSsidData[]; - timestamp: number; -}; - -export type AnalyticsTimePointsApiResponse = { - points: AnalyticsTimePointApiResponse[][]; -}; - export const useGetAnalyticsBoard = ({ id }: { id?: string }) => { const { t } = useTranslation(); const toast = useToast(); @@ -344,26 +112,6 @@ export const useGetClientLifecycleTableSpecs = () => }, ); -const getPartialClients = async (venueId: string, offset: number) => - axiosAnalytics - .get(`wifiClientHistory?macsOnly=true&venue=${venueId}&limit=500&offset=${offset}`) - .then(({ data }) => data.entries as string[]); - -export const getAllClients = async (venueId: string) => { - const allClients: string[] = []; - let continueFirmware = true; - let offset = 0; - while (continueFirmware) { - // eslint-disable-next-line no-await-in-loop - const newClients = await getPartialClients(venueId, offset); - if (newClients === null || newClients.length === 0 || newClients.length < 500 || offset >= 50000) - continueFirmware = false; - allClients.push(...newClients); - offset += 500; - } - return allClients; -}; - export const useGetClientLifecycleCount = ({ venueId, mac, @@ -497,9 +245,31 @@ export const useGetAnalyticsBoardTimepoints = ({ ); }; -export const useCreateAnalyticsBoard = () => useMutation((newBoard) => axiosAnalytics.post('board/0', newBoard)); +export const useCreateAnalyticsBoard = () => + useMutation((newBoard: unknown) => axiosAnalytics.post('board/0', newBoard)); -export const useUpdateAnalyticsBoard = () => - useMutation((newBoard: { id: string }) => axiosAnalytics.put(`board/${newBoard.id}`, newBoard)); +export const useUpdateAnalyticsBoard = ({ id }: { id: string }) => { + const queryClient = useQueryClient(); -export const useDeleteAnalyticsBoard = () => useMutation((id) => axiosAnalytics.delete(`board/${id}`, {})); + return useMutation( + (newBoard: { + name: string; + venueList: [ + { + id: string; + name: string; + retention: number; + interval: number; + monitorSubVenues: boolean; + }, + ]; + }) => axiosAnalytics.put(`board/${id}`, newBoard), + { + onSuccess: () => { + queryClient.invalidateQueries(['get-board', id]); + }, + }, + ); +}; + +export const useDeleteAnalyticsBoard = () => useMutation((id: string) => axiosAnalytics.delete(`board/${id}`, {})); diff --git a/src/hooks/Network/Entity.ts b/src/hooks/Network/Entity.ts index 338b18e..8d2a779 100644 --- a/src/hooks/Network/Entity.ts +++ b/src/hooks/Network/Entity.ts @@ -1,9 +1,9 @@ import { useToast } from '@chakra-ui/react'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; -import useDefaultPage from 'hooks/useDefaultPage'; +import { Entity } from '../../models/Entity'; +import useDefaultPage from '../useDefaultPage'; import { AxiosError } from 'models/Axios'; -import { Entity } from 'models/Entity'; import { axiosProv, axiosSec } from 'utils/axiosInstances'; export const useGetEntityTree = () => { @@ -151,7 +151,19 @@ export const useCreateEntity = (isRoot = false) => axiosProv.post(`entity/${isRoot ? '0000-0000-0000' : 0}`, newEnt).then(({ data }) => data as Entity), ); -export const useUpdateEntity = ({ id }: { id: string }) => - useMutation((newEnt) => axiosProv.put(`entity/${id}`, newEnt).then(({ data }) => data as Entity)); +export const useUpdateEntity = ({ id }: { id: string }) => { + const queryClient = useQueryClient(); + + return useMutation( + (newEnt: Partial) => axiosProv.put(`entity/${id}`, newEnt).then(({ data }) => data as Entity), + { + onSuccess: (data) => { + queryClient.invalidateQueries(['get-entity-tree']); + queryClient.invalidateQueries(['get-entities']); + queryClient.setQueryData(['get-entity', id], data); + }, + }, + ); +}; export const useDeleteEntity = () => useMutation((id: string) => axiosProv.delete(`entity/${id}`)); diff --git a/src/hooks/Network/Resources.ts b/src/hooks/Network/Resources.ts index 7659dc7..4910182 100644 --- a/src/hooks/Network/Resources.ts +++ b/src/hooks/Network/Resources.ts @@ -177,4 +177,4 @@ export const useGetResource = ({ id, enabled }: { id: string; enabled: boolean } export const useCreateResource = () => useMutation((newResource: unknown) => axiosProv.post('variable/0', newResource)); export const useUpdateResource = (id: string) => useMutation((resource: unknown) => axiosProv.put(`variable/${id}`, resource)); -export const useDeleteResource = () => useMutation((id) => axiosProv.delete(`variable/${id}`, {})); +export const useDeleteResource = () => useMutation((id: string) => axiosProv.delete(`variable/${id}`, {})); diff --git a/src/hooks/Network/Venues.ts b/src/hooks/Network/Venues.ts index 7592c12..edfe927 100644 --- a/src/hooks/Network/Venues.ts +++ b/src/hooks/Network/Venues.ts @@ -4,30 +4,9 @@ import { useTranslation } from 'react-i18next'; import { v4 as uuid } from 'uuid'; import useDefaultPage from '../useDefaultPage'; import { AxiosError } from 'models/Axios'; -import { DeviceRules } from 'models/Basic'; -import { Note } from 'models/Note'; +import { VenueApiResponse } from 'models/Venue'; import { axiosProv } from 'utils/axiosInstances'; -export interface VenueApiResponse { - id: string; - name: string; - description: string; - parent: string; - devices: string[]; - children: string[]; - contacts: string[]; - entity: string; - boards: string[]; - created: number; - modified: number; - configurations: string[]; - notes: Note[]; - variables: string[]; - location: string; - sourceIP: string[]; - deviceRules: DeviceRules; -} - const getVenuesBatch = async (limit: number, offset: number) => axiosProv .get(`venue?withExtendedInfo=true&offset=${offset}&limit=${limit}`) diff --git a/src/index.css b/src/index.css index 8647090..d9f1f2c 100644 --- a/src/index.css +++ b/src/index.css @@ -2,7 +2,8 @@ display: -webkit-box; display: -ms-flexbox; display: flex; - margin-left: -30px; + margin-left: -20px; + margin-bottom: -20px; width: auto; } .my-masonry-grid_column { diff --git a/src/layout/Containers/PanelContainer.tsx b/src/layout/Containers/PanelContainer.tsx deleted file mode 100644 index a8b985f..0000000 --- a/src/layout/Containers/PanelContainer.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React, { ReactNode } from 'react'; -import { Box, useStyleConfig } from '@chakra-ui/react'; - -interface Props { - children: ReactNode; -} - -const PanelContainer = ( - { - children - }: Props -) => { - const styles = useStyleConfig('PanelContainer'); - // Pass the computed styles into the `__css` prop - return {children}; -}; - -export default PanelContainer; diff --git a/src/layout/Containers/PanelContent.tsx b/src/layout/Containers/PanelContent.tsx deleted file mode 100644 index 302fdb1..0000000 --- a/src/layout/Containers/PanelContent.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React, { ReactNode } from 'react'; -import { Box, useStyleConfig } from '@chakra-ui/react'; - -interface Props { - children: ReactNode; -} - -const PanelContent = ( - { - children - }: Props -) => { - const styles = useStyleConfig('PanelContent'); - - return {children}; -}; - -export default PanelContent; diff --git a/src/layout/MainPanel.tsx b/src/layout/MainPanel.tsx deleted file mode 100644 index cf245c7..0000000 --- a/src/layout/MainPanel.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { Box, LayoutProps, useStyleConfig } from '@chakra-ui/react'; - -interface Props extends LayoutProps { - children: React.ReactNode; -} - -const MainPanel = ( - { - children, - ...props - }: Props -) => { - const styles = useStyleConfig('MainPanel'); - - return ( - - {children} - - ); -}; - -export default MainPanel; diff --git a/src/layout/Navbar/index.tsx b/src/layout/Navbar/index.tsx index 56242f2..fb75119 100644 --- a/src/layout/Navbar/index.tsx +++ b/src/layout/Navbar/index.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { ChevronDownIcon, HamburgerIcon, MoonIcon, SunIcon } from '@chakra-ui/icons'; +import { HamburgerIcon, MoonIcon, SunIcon } from '@chakra-ui/icons'; import { Box, Flex, @@ -12,73 +12,55 @@ import { MenuList, Heading, HStack, - VStack, Text, IconButton, Tooltip, + useBreakpoint, + Portal, } from '@chakra-ui/react'; import { ArrowCircleLeft, MapTrifold } from 'phosphor-react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; -import LanguageSwitcher from 'components/LanguageSwitcher'; +import { useNavigate } from 'react-router-dom'; import { useAuth } from 'contexts/AuthProvider'; -import routes from 'router/routes'; -import { uppercaseFirstLetter } from 'utils/stringHelper'; -interface Props { - secondary: boolean; - isSidebarOpen: boolean; +export type NavbarProps = { toggleSidebar: () => void; -} + activeRoute?: string; + languageSwitcher?: React.ReactNode; +}; -const Navbar = ({ secondary, toggleSidebar, isSidebarOpen }: Props) => { +export const Navbar = ({ toggleSidebar, activeRoute, languageSwitcher }: NavbarProps) => { const { t } = useTranslation(); - const location = useLocation(); const navigate = useNavigate(); const [scrolled, setScrolled] = useState(false); + const breakpoint = useBreakpoint(); const { colorMode, toggleColorMode } = useColorMode(); const { logout, user, avatar } = useAuth(); - const getActiveRoute = () => { - const route = routes.find( - (r) => r.path === location.pathname || location.pathname.split('/')[1] === r.path.split('/')[1], - ); - if (route) return route.navName ?? route.name; + const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md'; - return ''; - }; - - // Style variables - let navbarPosition: 'absolute' | 'fixed' = 'absolute'; - let navbarFilter = 'none'; - let navbarBackdrop = 'blur(21px)'; - let navbarShadow = 'none'; - let navbarBg = 'none'; - let navbarBorder = 'transparent'; - let secondaryMargin = '0px'; - - // Values if scrolled - const scrolledNavbarShadow = useColorModeValue('0px 7px 23px rgba(0, 0, 0, 0.05)', 'none'); - const scrolledNavbarBg = useColorModeValue( + const boxShadow = useColorModeValue('0px 7px 23px rgba(0, 0, 0, 0.05)', 'none'); + const bg = useColorModeValue( 'linear-gradient(112.83deg, rgba(255, 255, 255, 0.82) 0%, rgba(255, 255, 255, 0.8) 110.84%)', 'linear-gradient(112.83deg, rgba(255, 255, 255, 0.21) 0%, rgba(255, 255, 255, 0) 110.84%)', ); - const scrolledNavbarBorder = useColorModeValue('#FFFFFF', 'rgba(255, 255, 255, 0.31)'); - const scrolledNavbarFilter = useColorModeValue('none', 'drop-shadow(0px 7px 23px rgba(0, 0, 0, 0.05))'); - - if (scrolled === true) { - navbarPosition = 'fixed'; - navbarShadow = scrolledNavbarShadow; - navbarBg = scrolledNavbarBg; - navbarBorder = scrolledNavbarBorder; - navbarFilter = scrolledNavbarFilter; - } - - if (secondary) { - navbarBackdrop = 'none'; - navbarPosition = 'absolute'; - secondaryMargin = '22px'; - } + const borderColor = useColorModeValue('#FFFFFF', 'rgba(255, 255, 255, 0.31)'); + const filter = useColorModeValue('none', 'drop-shadow(0px 7px 23px rgba(0, 0, 0, 0.05))'); + const scrollDependentStyles = scrolled + ? ({ + position: 'fixed', + boxShadow, + bg, + borderColor, + filter, + } as const) + : ({ + position: 'absolute', + filter: 'none', + boxShadow: 'none', + bg: 'none', + borderColor: 'transparent', + } as const); const goBack = () => navigate(-1); @@ -96,103 +78,86 @@ const Navbar = ({ secondary, toggleSidebar, isSidebarOpen }: Props) => { window.addEventListener('scroll', changeNavbar); return ( - - - - {t(getActiveRoute())} - - } - /> - - - - - } - onClick={goToMap} - /> - - - : } - onClick={toggleColorMode} - /> - - - - + + + + {isCompact && } + {activeRoute} + + } + /> + + + + + } + onClick={goToMap} + /> + + + : } + onClick={toggleColorMode} + /> + + {languageSwitcher} + - - {user?.name} - {`${uppercaseFirstLetter(user?.userRole)}`} - - - - - + {!isCompact && {user?.name}} + - - - {t('account.title')} - - {t('common.logout')} - + + + + {t('account.title')} + + {t('common.logout')} + + - - - - + + + + - + ); }; - -export default Navbar; diff --git a/src/layout/PageContainer/index.tsx b/src/layout/PageContainer/index.tsx new file mode 100644 index 0000000..485bd61 --- /dev/null +++ b/src/layout/PageContainer/index.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; +import { Box, Center, Flex, Spinner, useBreakpoint } from '@chakra-ui/react'; +import { useAuth } from 'contexts/AuthProvider'; + +export type PageContainerProps = { + waitForUser: boolean; + children: React.ReactNode; +}; + +export const PageContainer = ({ waitForUser, children }: PageContainerProps) => { + const { isUserLoaded } = useAuth(); + const breakpoint = useBreakpoint('xl'); + const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md'; + + return ( + + + + + + + } + > + {waitForUser && !isUserLoaded ? ( +
+ +
+ ) : ( + children + )} +
+
+
+
+ ); +}; diff --git a/src/layout/Sidebar/CreateLinks.tsx b/src/layout/Sidebar/CreateLinks.tsx deleted file mode 100644 index 2295380..0000000 --- a/src/layout/Sidebar/CreateLinks.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { v4 as uuid } from 'uuid'; -import EntityNavButton from './EntityNavButton'; -import NavLinkButton from './NavLinkButton'; -import { Route } from 'models/Routes'; - -const createLinks = ( - routes: Route[], - activeRoute: (path: string, otherRoute: string | undefined) => string, - role: string, - toggleSidebar = () => {}, -) => - routes.map((route) => - route.isEntity ? ( - - ) : ( - - ), - ); - -export default createLinks; diff --git a/src/layout/Sidebar/EntityNavButton.tsx b/src/layout/Sidebar/EntityNavButton.tsx index 319f3a8..e4e24d1 100644 --- a/src/layout/Sidebar/EntityNavButton.tsx +++ b/src/layout/Sidebar/EntityNavButton.tsx @@ -9,20 +9,12 @@ import { Route } from 'models/Routes'; const variantChange = '0.2s linear'; interface Props { - activeRoute: (path: string, otherRoute: string | undefined) => string; + isActive: boolean; route: Route; - role: string; toggleSidebar: () => void; } -const EntityNavButton = ( - { - activeRoute, - route, - role, - toggleSidebar - }: Props -) => { +const EntityNavButton = ({ isActive, route, toggleSidebar }: Props) => { const { t } = useTranslation(); const { isOpen, onOpen, onClose } = useDisclosure(); const activeArrowColor = useColorModeValue('var(--chakra-colors-gray-700)', 'white'); @@ -33,17 +25,15 @@ const EntityNavButton = ( return ( - {activeRoute(route.path, '/venue/:id') === 'active' ? ( + {isActive ? ( ) : (