diff --git a/frontend/src/component/application/Application.tsx b/frontend/src/component/application/Application.tsx new file mode 100644 index 0000000000..70066f326f --- /dev/null +++ b/frontend/src/component/application/Application.tsx @@ -0,0 +1,238 @@ +/* eslint react/no-multi-comp:off */ +import React, { useContext, useState } from 'react'; +import { + Box, + Avatar, + Icon, + IconButton, + LinearProgress, + Link, + Tab, + Tabs, + Typography, + styled, +} from '@mui/material'; +import { Link as LinkIcon } from '@mui/icons-material'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { UPDATE_APPLICATION } from 'component/providers/AccessProvider/permissions'; +import { ConnectedInstances } from './ConnectedInstances/ConnectedInstances'; +import { Dialogue } from 'component/common/Dialogue/Dialogue'; +import { PageContent } from 'component/common/PageContent/PageContent'; +import { PageHeader } from 'component/common/PageHeader/PageHeader'; +import AccessContext from 'contexts/AccessContext'; +import useApplicationsApi from 'hooks/api/actions/useApplicationsApi/useApplicationsApi'; +import useApplication from 'hooks/api/getters/useApplication/useApplication'; +import { Route, Routes, useLocation, useNavigate } from 'react-router-dom'; +import { useLocationSettings } from 'hooks/useLocationSettings'; +import useToast from 'hooks/useToast'; +import PermissionButton from 'component/common/PermissionButton/PermissionButton'; +import { formatDateYMD } from 'utils/formatDate'; +import { formatUnknownError } from 'utils/formatUnknownError'; +import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; +import { useUiFlag } from 'hooks/useUiFlag'; +import { ApplicationEdit } from './ApplicationEdit/ApplicationEdit'; + +type Tab = { + title: string; + path: string; + name: string; +}; + +const StyledHeader = styled('div')(({ theme }) => ({ + backgroundColor: theme.palette.background.paper, + borderRadius: theme.shape.borderRadiusLarge, + marginBottom: theme.spacing(3), +})); + +const TabContainer = styled('div')(({ theme }) => ({ + padding: theme.spacing(0, 4), +})); + +const Separator = styled('div')(({ theme }) => ({ + width: '100%', + backgroundColor: theme.palette.divider, + height: '1px', +})); + +const StyledTab = styled(Tab)(({ theme }) => ({ + textTransform: 'none', + fontSize: theme.fontSizes.bodySize, + flexGrow: 1, + flexBasis: 0, + [theme.breakpoints.down('md')]: { + paddingLeft: theme.spacing(1), + paddingRight: theme.spacing(1), + }, + [theme.breakpoints.up('md')]: { + minWidth: 160, + }, +})); + +export const Application = () => { + const useOldApplicationScreen = !useUiFlag('sdkReporting'); + const navigate = useNavigate(); + const name = useRequiredPathParam('name'); + const { application, loading } = useApplication(name); + const { appName, url, description, icon = 'apps', createdAt } = application; + const { hasAccess } = useContext(AccessContext); + const { deleteApplication } = useApplicationsApi(); + const { locationSettings } = useLocationSettings(); + const { setToastData, setToastApiError } = useToast(); + const { pathname } = useLocation(); + + if (useOldApplicationScreen) { + return ; + } + + const basePath = `/applications/${name}`; + + const [showDialog, setShowDialog] = useState(false); + + const toggleModal = () => { + setShowDialog(!showDialog); + }; + + const formatDate = (v: string) => formatDateYMD(v, locationSettings.locale); + + const onDeleteApplication = async (evt: React.SyntheticEvent) => { + evt.preventDefault(); + try { + await deleteApplication(appName); + setToastData({ + title: 'Deleted Successfully', + text: 'Application deleted successfully', + type: 'success', + }); + navigate('/applications'); + } catch (error: unknown) { + setToastApiError(formatUnknownError(error)); + } + }; + + const renderModal = () => ( + + ); + + if (loading) { + return ( +
+

Loading...

+ +
+ ); + } else if (!application) { + return

Application ({appName}) not found

; + } + + const tabs: Tab[] = [ + { + title: 'Overview', + path: basePath, + name: 'overview', + }, + { + title: 'Connected instances', + path: `${basePath}/instances`, + name: 'instances', + }, + ]; + + const newActiveTab = tabs.find((tab) => tab.path === pathname); + + return ( + <> + + + + + {icon || 'apps'} + + {appName} + + } + title={appName} + actions={ + <> + + + + } + /> + + + Delete + + + } + /> + + ({ marginTop: theme.spacing(1) })}> + + {description || ''} + + + Created: {formatDate(createdAt)} + + + + + + + {tabs.map((tab) => { + return ( + navigate(tab.path)} + data-testid={`TAB_${tab.title}`} + /> + ); + })} + + + + + {renderModal()}} + /> + + } /> + This is a placeholder

} /> +
+
+ + ); +}; diff --git a/frontend/src/component/application/ApplicationEdit/ApplicationEdit.tsx b/frontend/src/component/application/ApplicationEdit/ApplicationEdit.tsx index aea2b3924e..7abc3e4a64 100644 --- a/frontend/src/component/application/ApplicationEdit/ApplicationEdit.tsx +++ b/frontend/src/component/application/ApplicationEdit/ApplicationEdit.tsx @@ -31,10 +31,8 @@ import { formatDateYMD } from 'utils/formatDate'; import { formatUnknownError } from 'utils/formatUnknownError'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { TabPanel } from 'component/common/TabNav/TabPanel/TabPanel'; -import { useUiFlag } from 'hooks/useUiFlag'; export const ApplicationEdit = () => { - const showAdvancedApplicationMetrics = useUiFlag('sdkReporting'); const navigate = useNavigate(); const name = useRequiredPathParam('name'); const { application, loading } = useApplication(name); @@ -87,13 +85,6 @@ export const ApplicationEdit = () => { }, ]; - if (showAdvancedApplicationMetrics) { - tabData.push({ - label: 'Connected instances', - component: , - }); - } - if (loading) { return (
diff --git a/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap index 434e846304..206cceae83 100644 --- a/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap +++ b/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap @@ -144,7 +144,7 @@ exports[`returns all baseRoutes 1`] = ` "component": [Function], "menu": {}, "parent": "/applications", - "path": "/applications/:name", + "path": "/applications/:name/*", "title": ":name", "type": "protected", }, diff --git a/frontend/src/component/menu/routes.ts b/frontend/src/component/menu/routes.ts index 2b4a6e2792..3bd675e294 100644 --- a/frontend/src/component/menu/routes.ts +++ b/frontend/src/component/menu/routes.ts @@ -17,7 +17,6 @@ import EditTagType from 'component/tags/EditTagType/EditTagType'; import CreateTagType from 'component/tags/CreateTagType/CreateTagType'; import CreateFeature from 'component/feature/CreateFeature/CreateFeature'; import EditFeature from 'component/feature/EditFeature/EditFeature'; -import { ApplicationEdit } from 'component/application/ApplicationEdit/ApplicationEdit'; import ContextList from 'component/context/ContextList/ContextList/ContextList'; import RedirectFeatureView from 'component/feature/RedirectFeatureView/RedirectFeatureView'; import { CreateIntegration } from 'component/integrations/CreateIntegration/CreateIntegration'; @@ -47,6 +46,7 @@ import { ApplicationList } from '../application/ApplicationList/ApplicationList' import { AddonRedirect } from 'component/integrations/AddonRedirect/AddonRedirect'; import { ExecutiveDashboard } from 'component/executiveDashboard/ExecutiveDashboard'; import { FeedbackList } from '../feedbackNew/FeedbackList'; +import { Application } from 'component/application/Application'; export const routes: IRoute[] = [ // Splash @@ -163,10 +163,10 @@ export const routes: IRoute[] = [ // Applications { - path: '/applications/:name', + path: '/applications/:name/*', title: ':name', parent: '/applications', - component: ApplicationEdit, + component: Application, type: 'protected', menu: {}, },