From c3b2521fd550e87e05b8329f39cbd4cc787f61dd Mon Sep 17 00:00:00 2001 From: Jeremy Foster Date: Thu, 18 Jan 2024 09:35:17 -0800 Subject: [PATCH] Connect chart links --- .../AllocationTable.module.scss | 6 +- .../allocationTable/AllocationTable.tsx | 19 +- .../charts/allocationTable/ITableRowData.ts | 3 +- .../charts/allocationTable/TableRow.tsx | 15 +- .../charts/allocationTable/defaultData.ts | 3 +- .../hooks/useAllocationByOS.ts | 5 +- .../allocationByOS/AllocationByOS.module.scss | 5 + .../bar/allocationByOS/AllocationByOS.tsx | 16 +- .../charts/bar/allocationByOS/defaultData.ts | 3 +- .../bar/allocationByOS/utils/groupByOS.ts | 7 +- .../AllocationByStorageVolume.module.scss | 276 +++++++++--------- .../AllocationByStorageVolume.tsx | 4 +- .../allocationByStorageVolume/BarChart.tsx | 19 +- .../components/charts/bar/smallBar/BarRow.tsx | 2 +- .../charts/bar/smallBar/IBarChartRowData.ts | 3 +- .../charts/bar/smallBar/SmallBarChart.tsx | 4 +- .../src/components/dashboard/Dashboard.tsx | 13 + .../src/components/dashboard/index.ts | 1 + .../dashboard/useDashboardFilter.ts | 118 ++++++++ .../src/components/filter/Filter.tsx | 33 +-- 20 files changed, 360 insertions(+), 195 deletions(-) create mode 100644 src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.module.scss create mode 100644 src/dashboard/src/components/dashboard/useDashboardFilter.ts diff --git a/src/dashboard/src/components/charts/allocationTable/AllocationTable.module.scss b/src/dashboard/src/components/charts/allocationTable/AllocationTable.module.scss index 991cf02b..77ef8eec 100644 --- a/src/dashboard/src/components/charts/allocationTable/AllocationTable.module.scss +++ b/src/dashboard/src/components/charts/allocationTable/AllocationTable.module.scss @@ -214,4 +214,8 @@ } } } -} \ No newline at end of file +} + +.link { + cursor: pointer; +} diff --git a/src/dashboard/src/components/charts/allocationTable/AllocationTable.tsx b/src/dashboard/src/components/charts/allocationTable/AllocationTable.tsx index ca570e57..651e2f15 100644 --- a/src/dashboard/src/components/charts/allocationTable/AllocationTable.tsx +++ b/src/dashboard/src/components/charts/allocationTable/AllocationTable.tsx @@ -18,19 +18,21 @@ export interface IAllocationTableProps { operatingSystem?: string; serverItems: IServerItemModel[]; loading?: boolean; + onClick?: (serverItem?: IServerItemModel) => void; } export const AllocationTable = ({ operatingSystem, serverItems, loading, + onClick, }: IAllocationTableProps) => { const getServerItems = useAllocationByOS(operatingSystem); const [keyword, setKeyword] = React.useState(''); const [filter, setFilter] = React.useState(keyword); const [sort, setSort] = React.useState('server:asc'); - const [rows, setRows] = React.useState([]); + const [rows, setRows] = React.useState[]>([]); React.useEffect(() => { const sorting = sort.split(':'); @@ -43,7 +45,7 @@ export const AllocationTable = ({ : '[NO NAME]'.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) || (!!si.operatingSystemItem && si.operatingSystemItem.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())), - sorting[0] as keyof ITableRowData, + sorting[0] as keyof ITableRowData, sorting[1] as any, ); setRows(rows); @@ -90,15 +92,16 @@ export const AllocationTable = ({

Total

- {rows.map((data, index) => ( + {rows.map((row, index) => ( onClick?.(row.data)} /> ))}
diff --git a/src/dashboard/src/components/charts/allocationTable/ITableRowData.ts b/src/dashboard/src/components/charts/allocationTable/ITableRowData.ts index 063deff6..6fac68b3 100644 --- a/src/dashboard/src/components/charts/allocationTable/ITableRowData.ts +++ b/src/dashboard/src/components/charts/allocationTable/ITableRowData.ts @@ -1,7 +1,8 @@ -export interface ITableRowData { +export interface ITableRowData { server: string; tenant: string; os: string; capacity: number; available: number; + data?: T; } diff --git a/src/dashboard/src/components/charts/allocationTable/TableRow.tsx b/src/dashboard/src/components/charts/allocationTable/TableRow.tsx index 82ebcb84..f35aeb7d 100644 --- a/src/dashboard/src/components/charts/allocationTable/TableRow.tsx +++ b/src/dashboard/src/components/charts/allocationTable/TableRow.tsx @@ -1,4 +1,3 @@ -import Link from 'next/link'; import React from 'react'; import { convertToStorageSize } from './../../../utils/convertToStorageSize'; import styles from './AllocationTable.module.scss'; @@ -10,6 +9,7 @@ interface TableRowProps { capacity: number; available: number; showTenant?: boolean; + onClick?: (e: React.MouseEvent) => void; } export const TableRow: React.FC = ({ @@ -19,6 +19,7 @@ export const TableRow: React.FC = ({ capacity, available, showTenant, + onClick, }) => { const percentageUsed = capacity ? Math.round(((capacity - available) / capacity) * 100) : 0; const capacityValue = convertToStorageSize(capacity, 'MB', 'TB'); @@ -27,9 +28,15 @@ export const TableRow: React.FC = ({ return (
- - {server} - +

+ {onClick ? ( + + ) : ( + + )} +

{showTenant ?

{tenant}

: ''}

{os}

{capacityValue}

diff --git a/src/dashboard/src/components/charts/allocationTable/defaultData.ts b/src/dashboard/src/components/charts/allocationTable/defaultData.ts index 90742d2d..25c57cee 100644 --- a/src/dashboard/src/components/charts/allocationTable/defaultData.ts +++ b/src/dashboard/src/components/charts/allocationTable/defaultData.ts @@ -1,6 +1,7 @@ +import { IServerItemModel } from '@/hooks'; import { ITableRowData } from './ITableRowData'; -export const tableRowData: ITableRowData[] = [ +export const tableRowData: ITableRowData[] = [ { server: 'Server Alpha', tenant: '', diff --git a/src/dashboard/src/components/charts/allocationTable/hooks/useAllocationByOS.ts b/src/dashboard/src/components/charts/allocationTable/hooks/useAllocationByOS.ts index 249bc2e1..75597dab 100644 --- a/src/dashboard/src/components/charts/allocationTable/hooks/useAllocationByOS.ts +++ b/src/dashboard/src/components/charts/allocationTable/hooks/useAllocationByOS.ts @@ -16,7 +16,7 @@ export const useAllocationByOS = (operatingSystem?: string) => { ( serverItems: IServerItemModel[], filter: (serverItem: IServerItemModel) => boolean = () => true, - sort: keyof ITableRowData = 'server', + sort: keyof ITableRowData = 'server', direction: 'asc' | 'desc' = 'asc', ) => { const data = serverItems @@ -29,13 +29,14 @@ export const useAllocationByOS = (operatingSystem?: string) => { const className = si.operatingSystemItem?.rawData.u_class; return (!operatingSystem || className === operatingSystem) && filter(si); }) - .map((si) => { + .map>((si) => { return { server: si.name.length ? si.name : '[NO NAME]', os: si.operatingSystemItem?.name ?? '', tenant: si.tenant?.name ?? '', capacity: si.capacity ?? 0, available: si.availableSpace ?? 0, + data: si, }; }) .sort((a, b) => { diff --git a/src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.module.scss b/src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.module.scss new file mode 100644 index 00000000..1ab35003 --- /dev/null +++ b/src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.module.scss @@ -0,0 +1,5 @@ +@import '@/styles/utils.scss'; + +.link { + cursor: pointer; +} \ No newline at end of file diff --git a/src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.tsx b/src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.tsx index 40d071a8..d28af3d4 100644 --- a/src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.tsx +++ b/src/dashboard/src/components/charts/bar/allocationByOS/AllocationByOS.tsx @@ -1,8 +1,8 @@ 'use client'; import { IOperatingSystemItemModel, IServerItemModel } from '@/hooks'; -import Link from 'next/link'; import { BarRow, SmallBarChart } from '../smallBar'; +import styles from './AllocationByOS.module.scss'; import defaultData from './defaultData'; import { groupByOS } from './utils'; @@ -10,12 +10,14 @@ export interface IAllocationByOSProps { serverItems: IServerItemModel[]; operatingSystemItems: IOperatingSystemItemModel[]; loading?: boolean; + onClick?: (operatingSystemItem?: IOperatingSystemItemModel) => void; } export const AllocationByOS = ({ serverItems, operatingSystemItems, loading, + onClick, }: IAllocationByOSProps) => { return ( ( {os.label}} + label={ +

+ {onClick && os.data ? ( + + ) : ( +

{os.label}

+ )} +

+ } capacity={os.capacity} available={os.available} /> diff --git a/src/dashboard/src/components/charts/bar/allocationByOS/defaultData.ts b/src/dashboard/src/components/charts/bar/allocationByOS/defaultData.ts index 41e89c9e..0a673865 100644 --- a/src/dashboard/src/components/charts/bar/allocationByOS/defaultData.ts +++ b/src/dashboard/src/components/charts/bar/allocationByOS/defaultData.ts @@ -1,7 +1,8 @@ +import { IOperatingSystemItemModel } from '@/hooks'; import { IBarChartData } from '../smallBar/IBarChartData'; import { IBarChartRowData } from '../smallBar/IBarChartRowData'; -const defaultData: IBarChartData = { +const defaultData: IBarChartData> = { labels: ['Operating System', 'Allocated', 'Used', 'Unused', 'Percentage Used'], datasets: [ { diff --git a/src/dashboard/src/components/charts/bar/allocationByOS/utils/groupByOS.ts b/src/dashboard/src/components/charts/bar/allocationByOS/utils/groupByOS.ts index e056580a..5f4f75a6 100644 --- a/src/dashboard/src/components/charts/bar/allocationByOS/utils/groupByOS.ts +++ b/src/dashboard/src/components/charts/bar/allocationByOS/utils/groupByOS.ts @@ -6,7 +6,7 @@ export const groupByOS = ( serverItems: IServerItemModel[], operatingSystemItems: IOperatingSystemItemModel[], ) => { - const groups = groupBy( + const groups = groupBy( serverItems, (item) => `${item.operatingSystemItemId ?? 'NA'}`, (item) => { @@ -20,14 +20,15 @@ export const groupByOS = ( ); const result = Object.keys(groups) - .map((key) => { + .map>((key) => { const items = groups[key]; const capacity = items.reduce((result, item) => result + item.capacity, 0); const available = items.reduce((result, item) => result + item.available, 0); const label = key === 'NA' ? 'NA' : operatingSystemItems.find((os) => os.id === +key)?.name ?? 'NA'; + const os = operatingSystemItems.find((os) => os.id == +key); - return { key, label, capacity, available }; + return { key, label, capacity, available, data: os }; }) .sort((a, b) => (a.label < b.label ? -1 : a.label > b.label ? 1 : 0)); diff --git a/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.module.scss b/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.module.scss index 1e0081d2..3a88aa66 100644 --- a/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.module.scss +++ b/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.module.scss @@ -1,181 +1,185 @@ @import '@/styles/utils.scss'; .panel { - @include panel-style(560px, 560px, unset, 1310px); + @include panel-style(560px, 560px, unset, 1310px); - >button { - @include export-btn; - } + >button { + @include export-btn; + } } .sort { - display: flex; - align-items: center; - margin: 15px 0; + display: flex; + align-items: center; + margin: 15px 0; - select { - min-width: 233px; - } + select { + min-width: 233px; + } - input { - margin-left: 18px; - } + input { + margin-left: 18px; + } } .chartContainer { - max-height: 345px; - overflow-y: scroll; - padding-right: 8px; - scrollbar-width: thin; - scrollbar-color: $chart-gray $light-gray; + max-height: 345px; + overflow-y: scroll; + padding-right: 8px; + scrollbar-width: thin; + scrollbar-color: $chart-gray $light-gray; - @include scrollBar; + @include scrollBar; } .barChart { - position: relative; - padding: 5px 0 12px; + position: relative; + padding: 5px 0 12px; - &:hover { - background-color: $light-gray; - } + &:hover { + background-color: $light-gray; + } - a { - color: $bc-black; - font-weight: bold; - text-decoration: underline; - margin-left: 5px; + a { + color: $bc-black; + font-weight: bold; + text-decoration: underline; + margin-left: 5px; - &:hover { - opacity: 0.8; - } + &:hover { + opacity: 0.8; } + } - p { - position: absolute; - right: 8px; - top: 10px; - font-size: $font-size-12; - color: $info-gray; - } + p { + position: absolute; + right: 8px; + top: 10px; + font-size: $font-size-12; + color: $info-gray; + } } .barLine { - height: 18px; - width: 100%; - background-color: $chart-gray; - border-radius: 10px; - margin-top: 12px; - - &:hover { - background-color: $dark-gray; - transition: background-color, .4s; - - .percentage { - background-color: $bc-blue; - transition: background-color, .4s; - - .tooltip { - opacity: .85; - transition: opacity, .4s; - } - } + height: 18px; + width: 100%; + background-color: $chart-gray; + border-radius: 10px; + margin-top: 12px; + + &:hover { + background-color: $dark-gray; + transition: background-color, .4s; + + .percentage { + background-color: $bc-blue; + transition: background-color, .4s; + + .tooltip { + opacity: .85; + transition: opacity, .4s; + } } + } } .percentage { - height: 100%; - width: 50%; - background-color: $chart-blue; - border-radius: 10px; - position: relative; + height: 100%; + width: 50%; + background-color: $chart-blue; + border-radius: 10px; + position: relative; } .tooltip { - opacity: 0; - background-color: $bc-black; - height: 25px; - width: 100px; + opacity: 0; + background-color: $bc-black; + height: 25px; + width: 100px; + position: absolute; + top: -30px; + right: 0; + border-radius: 6px; + display: flex; + justify-content: center; + align-items: center; + z-index: 1; + + &::after { + content: ""; + height: 8px; + width: 8px; + display: inline-block; + background-color: #313132; + transform: rotate(135deg); position: absolute; - top: -30px; - right: 0; - border-radius: 6px; - display: flex; - justify-content: center; - align-items: center; - z-index: 1; - - &::after { - content: ""; - height: 8px; - width: 8px; - display: inline-block; - background-color: #313132; - transform: rotate(135deg); - position: absolute; - bottom: -4px; - } + bottom: -4px; + } - p { - color: $white; - position: unset; - } + p { + color: $white; + position: unset; + } } .footer { + display: flex; + position: absolute; + bottom: 28px; + left: 0; + padding-left: 22px; + background-color: $white; + width: 100%; + + p { display: flex; - position: absolute; - bottom: 28px; - left: 0; - padding-left: 22px; - background-color: $white; - width: 100%; - - p { - display: flex; - margin-right: 35px; - - &::before { - content: ''; - display: inline-block; - height: 22px; - width: 22px; - background-color: $chart-blue; - border-radius: 50%; - margin-right: 15px; - } - - &:last-child::before { - background-color: $chart-gray; - } + margin-right: 35px; + + &::before { + content: ''; + display: inline-block; + height: 22px; + width: 22px; + background-color: $chart-blue; + border-radius: 50%; + margin-right: 15px; + } + + &:last-child::before { + background-color: $chart-gray; } + } } .linesContainer { - height: 100%; - max-height: 380px; - position: absolute; - width: 100%; - max-width: calc(100% - 57px); + height: 100%; + max-height: 380px; + position: absolute; + width: 100%; + max-width: calc(100% - 57px); } .percentageLine { + position: absolute; + bottom: 0; + height: 100%; + + .line { + width: 1px; + height: 92%; + background-color: $light-gray; + } + + .label { position: absolute; - bottom: 0; - height: 100%; - - .line { - width: 1px; - height: 92%; - background-color: $light-gray; - } - - .label { - position: absolute; - bottom: 5px; - left: 5px; - transform: translateX(-50%); - font-size: $font-size-small; - color: $info-gray; - } - } \ No newline at end of file + bottom: 5px; + left: 5px; + transform: translateX(-50%); + font-size: $font-size-small; + color: $info-gray; + } +} + +.link { + cursor: pointer; +} diff --git a/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.tsx b/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.tsx index b94a60ca..7fefa195 100644 --- a/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.tsx +++ b/src/dashboard/src/components/charts/bar/allocationByStorageVolume/AllocationByStorageVolume.tsx @@ -16,12 +16,14 @@ export interface IAllocationByStorageVolumeProps { organizations: IOrganizationModel[]; serverItems: IServerItemModel[]; loading?: boolean; + onClick?: (organization: IOrganizationModel) => void; } export const AllocationByStorageVolume = ({ organizations, serverItems, loading, + onClick, }: IAllocationByStorageVolumeProps) => { const [sortOption, setSortOption] = React.useState(0); const [search, setSearch] = React.useState(''); @@ -87,10 +89,10 @@ export const AllocationByStorageVolume = ({ return ( onClick?.(org)} /> ); })} diff --git a/src/dashboard/src/components/charts/bar/allocationByStorageVolume/BarChart.tsx b/src/dashboard/src/components/charts/bar/allocationByStorageVolume/BarChart.tsx index f5277355..d10ae36b 100644 --- a/src/dashboard/src/components/charts/bar/allocationByStorageVolume/BarChart.tsx +++ b/src/dashboard/src/components/charts/bar/allocationByStorageVolume/BarChart.tsx @@ -7,9 +7,16 @@ export interface IBarChartProps { to?: string; availableSpace: number; totalStorage: number; + onClick?: (e: React.MouseEvent) => void; } -export const BarChart: React.FC = ({ label, to, availableSpace, totalStorage }) => { +export const BarChart: React.FC = ({ + label, + to = '', + availableSpace, + totalStorage, + onClick, +}) => { var validPercentage = totalStorage ? Math.min(100, Math.max(0, Math.round(((totalStorage - availableSpace) / totalStorage) * 100))) : 0; @@ -23,7 +30,15 @@ export const BarChart: React.FC = ({ label, to, availableSpace, return (
- {to ? {label} : } + {to ? ( + {label} + ) : onClick ? ( + + ) : ( + + )}
{ +interface IBarRowProps extends Omit, 'label'> { label: React.ReactNode; } diff --git a/src/dashboard/src/components/charts/bar/smallBar/IBarChartRowData.ts b/src/dashboard/src/components/charts/bar/smallBar/IBarChartRowData.ts index ed6bbe40..29cf0586 100644 --- a/src/dashboard/src/components/charts/bar/smallBar/IBarChartRowData.ts +++ b/src/dashboard/src/components/charts/bar/smallBar/IBarChartRowData.ts @@ -1,6 +1,7 @@ -export interface IBarChartRowData { +export interface IBarChartRowData { key: string; label: string; capacity: number; available: number; + data?: T; } diff --git a/src/dashboard/src/components/charts/bar/smallBar/SmallBarChart.tsx b/src/dashboard/src/components/charts/bar/smallBar/SmallBarChart.tsx index b96c524e..d72be89a 100644 --- a/src/dashboard/src/components/charts/bar/smallBar/SmallBarChart.tsx +++ b/src/dashboard/src/components/charts/bar/smallBar/SmallBarChart.tsx @@ -4,7 +4,7 @@ import { IBarChartData } from './IBarChartData'; import { IBarChartRowData } from './IBarChartRowData'; import styles from './SmallBarChart.module.scss'; -export interface ISmallBarChartProps { +export interface ISmallBarChartProps> { /** Title header of the component */ title?: string; /** Data to be displayed in the bar chart */ @@ -17,7 +17,7 @@ export interface ISmallBarChartProps { children?: React.ReactNode | ((data: IBarChartData) => React.ReactNode); } -export const SmallBarChart = ({ +export const SmallBarChart = >({ title, data, children, diff --git a/src/dashboard/src/components/dashboard/Dashboard.tsx b/src/dashboard/src/components/dashboard/Dashboard.tsx index 5b0c3817..5c4856a1 100644 --- a/src/dashboard/src/components/dashboard/Dashboard.tsx +++ b/src/dashboard/src/components/dashboard/Dashboard.tsx @@ -17,6 +17,7 @@ import { } from '@/hooks/dashboard'; import { useOperatingSystemItems, useOrganizations, useServerItems } from '@/hooks/data'; import { useFilteredFileSystemItems } from '@/hooks/filter'; +import { useDashboardFilter } from '.'; /** * Dashboard component displays different charts depending on what data has been stored in the dashboard state. @@ -33,6 +34,8 @@ export const Dashboard = () => { const { serverItems: dashboardServerItems } = useDashboardServerItems(); const { fileSystemItems } = useFilteredFileSystemItems(); + const updateDashboard = useDashboardFilter(); + const selectedOrganizations = dashboardOrganizations.length ? dashboardOrganizations : organizations; @@ -69,6 +72,9 @@ export const Dashboard = () => { operatingSystemItems={selectedOperatingSystemItems} serverItems={selectedServerItems} loading={!isReadyOperatingSystemItems || !isReadyServerItems} + onClick={async (operatingSystemItem) => { + await updateDashboard({ operatingSystemItem }); + }} /> )} {/* One Server Selected */} @@ -95,6 +101,9 @@ export const Dashboard = () => { organizations={selectedOrganizations} serverItems={selectedServerItems} loading={!isReadyOrganizations || !isReadyServerItems} + onClick={async (organization) => { + await updateDashboard({ organization }); + }} /> )} {showAllocationTable && ( @@ -102,6 +111,10 @@ export const Dashboard = () => { operatingSystem={selectedServerItems[0].className} serverItems={selectedServerItems} loading={!isReadyServerItems || !isReadyOperatingSystemItems} + onClick={async (serverItem) => { + console.debug(serverItem); + await updateDashboard({ serverItem }); + }} /> )} {showSegmentedBarChart && ( diff --git a/src/dashboard/src/components/dashboard/index.ts b/src/dashboard/src/components/dashboard/index.ts index 19bd377d..80148538 100644 --- a/src/dashboard/src/components/dashboard/index.ts +++ b/src/dashboard/src/components/dashboard/index.ts @@ -1 +1,2 @@ export * from './Dashboard'; +export * from './useDashboardFilter'; diff --git a/src/dashboard/src/components/dashboard/useDashboardFilter.ts b/src/dashboard/src/components/dashboard/useDashboardFilter.ts new file mode 100644 index 00000000..83e78ba0 --- /dev/null +++ b/src/dashboard/src/components/dashboard/useDashboardFilter.ts @@ -0,0 +1,118 @@ +'use client'; + +import { + IOperatingSystemItemModel, + IOrganizationModel, + IServerItemModel, + ITenantModel, +} from '@/hooks'; +import { useDashboardServerHistoryItems } from '@/hooks/dashboard'; +import { + useFilteredFileSystemItems, + useFilteredOperatingSystemItems, + useFilteredOrganizations, + useFilteredTenants, +} from '@/hooks/filter'; +import { useDashboard, useFiltered } from '@/store'; +import React from 'react'; + +export interface IDashboardFilterProps { + tenant?: ITenantModel; + organization?: IOrganizationModel; + operatingSystemItem?: IOperatingSystemItemModel; + serverItem?: IServerItemModel; +} + +/** + * Hook provides a function to update dashboard state. + * The function will apply the current filter to the dashboard, or will update the filter based on the passed in selected values. + * @returns Function to update dashboard state. + */ +export const useDashboardFilter = () => { + const setDashboardTenants = useDashboard((state) => state.setTenants); + const setDashboardOrganizations = useDashboard((state) => state.setOrganizations); + const setDashboardOperatingSystemItems = useDashboard((state) => state.setOperatingSystemItems); + const setDashboardServerItems = useDashboard((state) => state.setServerItems); + const setDashboardDateRange = useDashboard((state) => state.setDateRange); + const { findFileSystemItems } = useFilteredFileSystemItems(); + const { findServerHistoryItems } = useDashboardServerHistoryItems(); + + const filteredTenant = useFiltered((state) => state.tenant); + const setFilteredTenant = useFiltered((state) => state.setTenant); + const { tenants: filteredTenants } = useFilteredTenants(); + const filteredOrganization = useFiltered((state) => state.organization); + const setFilteredOrganization = useFiltered((state) => state.setOrganization); + const { organizations: filteredOrganizations } = useFilteredOrganizations(); + const filteredOperatingSystemItem = useFiltered((state) => state.operatingSystemItem); + const setFilteredOperatingSystemItem = useFiltered((state) => state.setOperatingSystemItem); + const { operatingSystemItems: filteredOperatingSystemItems } = useFilteredOperatingSystemItems(); + const filteredServerItem = useFiltered((state) => state.serverItem); + const setFilteredServerItem = useFiltered((state) => state.setServerItem); + const filteredServerItems = useFiltered((state) => state.serverItems); + const filteredDateRange = useFiltered((state) => state.dateRange); + + return React.useCallback( + async (filter?: IDashboardFilterProps) => { + const selectedTenant = filter?.tenant ?? filteredTenant; + const selectedOrganization = filter?.organization ?? filteredOrganization; + const selectedOperatingSystemItem = + filter?.operatingSystemItem ?? filteredOperatingSystemItem; + const selectedServerItem = filter?.serverItem ?? filteredServerItem; + + if (filter?.tenant) setFilteredTenant(filter?.tenant); + if (selectedTenant) setDashboardTenants([selectedTenant]); + else setDashboardTenants(filteredTenants); + + if (filter?.organization) setFilteredOrganization(filter?.organization); + if (selectedOrganization) setDashboardOrganizations([selectedOrganization]); + else setDashboardOrganizations(filteredOrganizations); + + if (filter?.operatingSystemItem) setFilteredOperatingSystemItem(filter?.operatingSystemItem); + if (selectedOperatingSystemItem) + setDashboardOperatingSystemItems([selectedOperatingSystemItem]); + else setDashboardOperatingSystemItems(filteredOperatingSystemItems); + + if (filter?.serverItem) setFilteredServerItem(filter?.serverItem); + if (selectedServerItem) setDashboardServerItems([selectedServerItem]); + else setDashboardServerItems(filteredServerItems); + + setDashboardDateRange(filteredDateRange); + + if (filteredServerItem) + await findFileSystemItems({ + serverItemServiceNowKey: filteredServerItem.serviceNowKey, + }); + + await findServerHistoryItems({ + startDate: filteredDateRange[0] ? filteredDateRange[0] : undefined, + endDate: filteredDateRange[1] ? filteredDateRange[1] : undefined, + tenantId: filteredTenant?.id, + organizationId: filteredOrganization?.id, + operatingSystemItemId: filteredOperatingSystemItem?.id, + serviceNowKey: filteredServerItem?.serviceNowKey, + }); + }, + [ + filteredDateRange, + filteredOperatingSystemItem, + filteredOperatingSystemItems, + filteredOrganization, + filteredOrganizations, + filteredServerItem, + filteredServerItems, + filteredTenant, + filteredTenants, + findFileSystemItems, + findServerHistoryItems, + setDashboardDateRange, + setDashboardOperatingSystemItems, + setDashboardOrganizations, + setDashboardServerItems, + setDashboardTenants, + setFilteredOperatingSystemItem, + setFilteredOrganization, + setFilteredServerItem, + setFilteredTenant, + ], + ); +}; diff --git a/src/dashboard/src/components/filter/Filter.tsx b/src/dashboard/src/components/filter/Filter.tsx index 7ffb37c4..d08183aa 100644 --- a/src/dashboard/src/components/filter/Filter.tsx +++ b/src/dashboard/src/components/filter/Filter.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Button, DateRangePicker, Select } from '@/components'; +import { Button, DateRangePicker, Select, useDashboardFilter } from '@/components'; import { IOperatingSystemItemModel, IOrganizationModel, ITenantModel, useAuth } from '@/hooks'; import { useDashboardServerHistoryItems } from '@/hooks/dashboard'; import { @@ -69,6 +69,8 @@ export const Filter: React.FC = () => { useDashboardServerHistoryItems(); const { findFileSystemItems } = useFilteredFileSystemItems(); + const updateDashboard = useDashboardFilter(); + const enableTenants = isHSB || tenants.length > 1; const enableOrganizations = isHSB || organizations.length > 1; @@ -250,34 +252,7 @@ export const Filter: React.FC = () => { } loading={!serverHistoryItemsReady} onClick={async () => { - if (filteredTenant) setDashboardTenants([filteredTenant]); - else setDashboardTenants(filteredTenants); - - if (filteredOrganization) setDashboardOrganizations([filteredOrganization]); - else setDashboardOrganizations(filteredOrganizations); - - if (filteredOperatingSystemItem) - setDashboardOperatingSystemItems([filteredOperatingSystemItem]); - else setDashboardOperatingSystemItems(filteredOperatingSystemItems); - - if (filteredServerItem) setDashboardServerItems([filteredServerItem]); - else setDashboardServerItems(filteredServerItems); - - setDashboardDateRange(filteredDateRange); - - if (filteredServerItem) - await findFileSystemItems({ - serverItemServiceNowKey: filteredServerItem.serviceNowKey, - }); - - await findServerHistoryItems({ - startDate: filteredDateRange[0] ? filteredDateRange[0] : undefined, - endDate: filteredDateRange[1] ? filteredDateRange[1] : undefined, - tenantId: filteredTenant?.id, - organizationId: filteredOrganization?.id, - operatingSystemItemId: filteredOperatingSystemItem?.id, - serviceNowKey: filteredServerItem?.serviceNowKey, - }); + await updateDashboard(); }} > Update