diff --git a/src/components/shared/Entity/Details/Logs/Status/SectionFormatter.tsx b/src/components/shared/Entity/Details/Logs/Status/SectionFormatter.tsx new file mode 100644 index 000000000..a9ef28926 --- /dev/null +++ b/src/components/shared/Entity/Details/Logs/Status/SectionFormatter.tsx @@ -0,0 +1,42 @@ +import { Box, ToggleButtonGroup } from '@mui/material'; +import OutlinedToggleButton from 'components/shared/buttons/OutlinedToggleButton'; +import { outlinedToggleButtonGroupStyling } from 'context/Theme'; +import { useIntl } from 'react-intl'; +import { useEntityStatusStore } from 'stores/EntityStatus/Store'; + +export default function SectionFormatter() { + const intl = useIntl(); + + const format = useEntityStatusStore((state) => state.format); + const setFormat = useEntityStatusStore((state) => state.setFormat); + + return ( + + + setFormat(value, 'code')} + > + {intl.formatMessage({ + id: 'details.ops.status.cta.formatted', + })} + + + setFormat(value, 'dashboard')} + > + {intl.formatMessage({ id: 'details.ops.status.cta.raw' })} + + + + ); +} diff --git a/src/components/shared/Entity/Details/Logs/Status/SectionViews.tsx b/src/components/shared/Entity/Details/Logs/Status/SectionViews.tsx new file mode 100644 index 000000000..25b4ecc5e --- /dev/null +++ b/src/components/shared/Entity/Details/Logs/Status/SectionViews.tsx @@ -0,0 +1,34 @@ +import { Divider, Typography } from '@mui/material'; +import ControllerStatusHistoryTable from 'components/tables/ControllerStatusHistory'; +import { useIntl } from 'react-intl'; +import { useEntityStatusStore } from 'stores/EntityStatus/Store'; +import Overview from './Overview'; +import StatusResponseViewer from './StatusResponseViewer'; + +export default function SectionViews() { + const intl = useIntl(); + + const format = useEntityStatusStore((state) => state.format); + + if (format === 'dashboard') { + return ( + <> + + + + + + {intl.formatMessage({ + id: 'details.ops.status.table.header', + })} + + + + + ); + } else { + return ; + } +} diff --git a/src/components/shared/Entity/Details/Logs/Status/StatusResponseViewer.tsx b/src/components/shared/Entity/Details/Logs/Status/StatusResponseViewer.tsx new file mode 100644 index 000000000..cdffcb3c3 --- /dev/null +++ b/src/components/shared/Entity/Details/Logs/Status/StatusResponseViewer.tsx @@ -0,0 +1,64 @@ +import { Editor } from '@monaco-editor/react'; +import { Box, Divider, Paper, useTheme } from '@mui/material'; +import { MonacoEditorSkeleton } from 'components/editor/MonacoEditor/EditorSkeletons'; +import { editorToolBarSx } from 'context/Theme'; +import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api'; +import { useRef } from 'react'; +import { logRocketConsole } from 'services/shared'; +import { stringifyJSON } from 'services/stringify'; +import { useEntityStatusStore } from 'stores/EntityStatus/Store'; +import { DEFAULT_TOOLBAR_HEIGHT } from 'utils/editor-utils'; +import { hasLength } from 'utils/misc-utils'; + +const EDITOR_HEIGHT = 400; + +export default function StatusResponseViewer() { + const theme = useTheme(); + const editorRef = useRef( + null + ); + + const response = useEntityStatusStore((state) => state.response); + + if (response) { + return ( + + + + + + { + logRocketConsole('handlers:mount'); + editorRef.current = editor; + }} + options={{ + readOnly: true, + minimap: { + enabled: false, + }, + }} + path={ + hasLength(response.catalog_name) + ? response.catalog_name + : 'preset_status_path' + } + saveViewState={false} + theme={theme.palette.mode === 'light' ? 'vs' : 'vs-dark'} + value={stringifyJSON(response)} + /> + + ); + } else { + return ; + } +} diff --git a/src/components/shared/Entity/Details/Logs/Status/index.tsx b/src/components/shared/Entity/Details/Logs/Status/index.tsx index 6f3e9f344..261e78eb8 100644 --- a/src/components/shared/Entity/Details/Logs/Status/index.tsx +++ b/src/components/shared/Entity/Details/Logs/Status/index.tsx @@ -1,13 +1,12 @@ -import { Box, Button, Divider, Stack, Typography } from '@mui/material'; -import ControllerStatusHistoryTable from 'components/tables/ControllerStatusHistory'; +import { Box, Button, Stack, Typography } from '@mui/material'; import useEntityStatus from 'hooks/entityStatus/useEntityStatus'; import useGlobalSearchParams, { GlobalSearchParams, } from 'hooks/searchParams/useGlobalSearchParams'; import { Refresh } from 'iconoir-react'; import { useIntl } from 'react-intl'; -import { isEntityControllerStatus } from 'utils/entityStatus-utils'; -import Overview from './Overview'; +import SectionFormatter from './SectionFormatter'; +import SectionViews from './SectionViews'; export default function Status() { const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME); @@ -18,55 +17,44 @@ export default function Status() { return ( - - - - {intl.formatMessage({ - id: 'details.ops.status.header', - })} - - - - - - - This is a placeholder description for this section that is - used to mock the Account Access tab of the Admin page. - - - - - - + + {intl.formatMessage({ + id: 'details.ops.status.header', + })} + + + + + + + This is a placeholder description for this section that + is used to mock the Account Access tab of the Admin + page. + + - - {intl.formatMessage({ - id: 'details.ops.status.table.header', - })} - + + - + ); } diff --git a/src/components/tables/ControllerStatusHistory/index.tsx b/src/components/tables/ControllerStatusHistory/index.tsx index e05c00b26..2fbf4ca8c 100644 --- a/src/components/tables/ControllerStatusHistory/index.tsx +++ b/src/components/tables/ControllerStatusHistory/index.tsx @@ -2,10 +2,13 @@ import { Box, Table, TableContainer } from '@mui/material'; import EntityTableBody from 'components/tables/EntityTable/TableBody'; import EntityTableHeader from 'components/tables/EntityTable/TableHeader'; import { useDisplayTableColumns } from 'context/TableSettings'; +import { PublicationInfo } from 'deps/control-plane/types'; import { useEffect, useMemo, useState } from 'react'; import { useIntl } from 'react-intl'; +import { useEntityStatusStore } from 'stores/EntityStatus/Store'; import { TablePrefixes } from 'stores/Tables/hooks'; import { SortDirection, TableColumns, TableState, TableStatuses } from 'types'; +import { isEntityControllerStatus } from 'utils/entityStatus-utils'; import Rows from './Rows'; import { TableProps } from './types'; @@ -41,11 +44,18 @@ const evaluateColumnsToShow = (columnsToHide: string[]) => ); export default function ControllerStatusHistoryTable({ - history, serverErrorExists, }: TableProps) { const intl = useIntl(); + const history: PublicationInfo[] | null | undefined = useEntityStatusStore( + (state) => + state.response?.controller_status && + isEntityControllerStatus(state.response.controller_status) + ? state.response.controller_status.publications?.history + : [] + ); + const [tableState, setTableState] = useState({ status: TableStatuses.LOADING, }); @@ -66,9 +76,9 @@ export default function ControllerStatusHistoryTable({ }; useEffect(() => { - if (history === null) { + if (!history) { setTableState({ status: TableStatuses.LOADING }); - } else if (history && history.length > 0) { + } else if (history.length > 0) { setTableState({ status: TableStatuses.DATA_FETCHED, }); diff --git a/src/components/tables/ControllerStatusHistory/types.ts b/src/components/tables/ControllerStatusHistory/types.ts index 5e99a0401..b038536df 100644 --- a/src/components/tables/ControllerStatusHistory/types.ts +++ b/src/components/tables/ControllerStatusHistory/types.ts @@ -12,6 +12,5 @@ export interface RowsProps { } export interface TableProps { - history: PublicationInfo[] | null | undefined; serverErrorExists: boolean; } diff --git a/src/lang/en-US/Details.ts b/src/lang/en-US/Details.ts index f30db2420..7c92d0ffd 100644 --- a/src/lang/en-US/Details.ts +++ b/src/lang/en-US/Details.ts @@ -10,6 +10,8 @@ export const Details: Record = { 'details.history.noPublications': `No publications were found.`, 'details.ops.status.header': `Status`, + 'details.ops.status.cta.formatted': `Dashboard`, + 'details.ops.status.cta.raw': `Code`, 'details.ops.status.overview.autoDiscovery.header': `Auto Discovery`, 'details.ops.status.overview.autoDiscovery.subheaderFirstFailure': `First Failed`, 'details.ops.status.overview.autoDiscovery.subheaderLastSuccess': `Last Success`, diff --git a/src/stores/EntityStatus/Store.ts b/src/stores/EntityStatus/Store.ts index ad129318c..083371ee3 100644 --- a/src/stores/EntityStatus/Store.ts +++ b/src/stores/EntityStatus/Store.ts @@ -4,7 +4,11 @@ import { create, StoreApi } from 'zustand'; import { devtools, NamedSet } from 'zustand/middleware'; import { EntityStatusState } from './types'; -const getInitialStateData = (): Pick => ({ +const getInitialStateData = (): Pick< + EntityStatusState, + 'format' | 'response' +> => ({ + format: 'dashboard', response: null, }); @@ -14,6 +18,16 @@ const getInitialState = ( ): EntityStatusState => ({ ...getInitialStateData(), + setFormat: (value, invertedValue) => { + set( + produce((state: EntityStatusState) => { + state.format = state.format === value ? invertedValue : value; + }), + false, + 'Format set' + ); + }, + setResponse: (value) => { set( produce((state: EntityStatusState) => { diff --git a/src/stores/EntityStatus/types.ts b/src/stores/EntityStatus/types.ts index 95c27cdd6..b9992083c 100644 --- a/src/stores/EntityStatus/types.ts +++ b/src/stores/EntityStatus/types.ts @@ -3,4 +3,10 @@ import { EntityStatusResponse } from 'deps/control-plane/types'; export interface EntityStatusState { response: EntityStatusResponse | null; setResponse: (value: EntityStatusResponse) => void; + + format: 'code' | 'dashboard'; + setFormat: ( + value: EntityStatusState['format'], + invertedValue: EntityStatusState['format'] + ) => void; }