diff --git a/frontend/console/e2e/deployment.spec.ts b/frontend/console/e2e/deployment.spec.ts
deleted file mode 100644
index f9d07575a0..0000000000
--- a/frontend/console/e2e/deployment.spec.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { expect, ftlTest } from './ftl-test'
-
-ftlTest('shows verbs for deployment', async ({ page }) => {
- const deploymentsNavItem = page.getByRole('link', { name: 'Deployments' })
- await deploymentsNavItem.click()
-
- const deploymentEcho = page.getByText('dpl-echo')
- await deploymentEcho.click()
-
- await expect(page).toHaveURL(/\/deployments\/dpl-echo-.*/)
-
- await expect(page.getByText('echo', { exact: true })).toBeVisible()
- await expect(page.getByText('exported', { exact: true })).toBeVisible()
-})
diff --git a/frontend/console/e2e/deployments.spec.ts b/frontend/console/e2e/deployments.spec.ts
deleted file mode 100644
index dbe1ba67fa..0000000000
--- a/frontend/console/e2e/deployments.spec.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { expect, ftlTest } from './ftl-test'
-
-ftlTest('shows active deployments', async ({ page }) => {
- const deploymentsNavItem = page.getByRole('link', { name: 'Deployments' })
- await deploymentsNavItem.click()
- await expect(page).toHaveURL(/\/deployments$/)
-
- await expect(page.getByText('dpl-time')).toBeVisible()
- await expect(page.getByText('dpl-echo')).toBeVisible()
-})
diff --git a/frontend/console/e2e/module.spec.ts b/frontend/console/e2e/module.spec.ts
new file mode 100644
index 0000000000..16a71ddad9
--- /dev/null
+++ b/frontend/console/e2e/module.spec.ts
@@ -0,0 +1,15 @@
+import { expect, ftlTest } from './ftl-test'
+
+ftlTest('shows verbs for deployment', async ({ page }) => {
+ const modulesNavItem = page.getByRole('link', { name: 'Modules' })
+ await modulesNavItem.click()
+
+ const moduleEchoRow = page.getByRole('button', { name: 'echo' })
+ const moduleEcho = moduleEchoRow.locator('svg').nth(1)
+ await moduleEcho.click()
+
+ await expect(page).toHaveURL(/\/modules\/echo/)
+
+ await expect(page.getByText('Deployment', { exact: true })).toBeVisible()
+ await expect(page.getByText('Deployed dpl-echo')).toBeVisible()
+})
diff --git a/frontend/console/e2e/modules.spec.ts b/frontend/console/e2e/modules.spec.ts
new file mode 100644
index 0000000000..97a3d06045
--- /dev/null
+++ b/frontend/console/e2e/modules.spec.ts
@@ -0,0 +1,10 @@
+import { expect, ftlTest } from './ftl-test'
+
+ftlTest('shows active modules', async ({ page }) => {
+ const modulesNavItem = page.getByRole('link', { name: 'Modules' })
+ await modulesNavItem.click()
+ await expect(page).toHaveURL(/\/modules$/)
+
+ await expect(page.getByText('dpl-time')).toBeVisible()
+ await expect(page.getByText('dpl-echo')).toBeVisible()
+})
diff --git a/frontend/console/e2e/verb.spec.ts b/frontend/console/e2e/verb.spec.ts
index bc71c272db..6a857fce42 100644
--- a/frontend/console/e2e/verb.spec.ts
+++ b/frontend/console/e2e/verb.spec.ts
@@ -1,16 +1,16 @@
import { expect, ftlTest } from './ftl-test'
ftlTest.beforeEach(async ({ page }) => {
- const deploymentsNavItem = page.getByRole('link', { name: 'Deployments' })
- await deploymentsNavItem.click()
+ const modulesNavItem = page.getByRole('link', { name: 'Modules' })
+ await modulesNavItem.click()
- const deploymentEcho = page.getByText('dpl-echo')
- await deploymentEcho.click()
+ const moduleEcho = page.getByRole('button', { name: 'echo' })
+ await moduleEcho.click()
- const verbEcho = page.getByText('echo', { exact: true })
+ const verbEcho = page.getByRole('button', { name: 'echo Exported' })
await verbEcho.click()
- await expect(page).toHaveURL(/\/deployments\/dpl-echo-[^/]+\/verbs\/echo/)
+ await expect(page).toHaveURL(/\/modules\/echo\/verb\/echo/)
})
ftlTest('shows verb form', async ({ page }) => {
diff --git a/frontend/console/playwright-report/index.html b/frontend/console/playwright-report/index.html
new file mode 100644
index 0000000000..6f946aec02
--- /dev/null
+++ b/frontend/console/playwright-report/index.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+ Playwright Test Report
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/console/src/features/deployments/DeploymentCard.tsx b/frontend/console/src/features/deployments/DeploymentCard.tsx
index 6379a0a614..e4d5dae2e6 100644
--- a/frontend/console/src/features/deployments/DeploymentCard.tsx
+++ b/frontend/console/src/features/deployments/DeploymentCard.tsx
@@ -20,7 +20,7 @@ export const DeploymentCard = ({ deploymentKey, className }: { deploymentKey: st
}, [modules.data])
return (
- navigate(`/deployments/${deploymentKey}`)}>
+ navigate(`/modules/${module?.name}`)}>
{deploymentKey}
diff --git a/frontend/console/src/features/deployments/DeploymentPage.tsx b/frontend/console/src/features/deployments/DeploymentPage.tsx
index f898bde547..23dc8c7ec5 100644
--- a/frontend/console/src/features/deployments/DeploymentPage.tsx
+++ b/frontend/console/src/features/deployments/DeploymentPage.tsx
@@ -1,26 +1,20 @@
-import { RocketLaunchIcon } from '@heroicons/react/24/outline'
-import { useContext, useEffect, useMemo, useState } from 'react'
-import { useNavigate, useParams } from 'react-router-dom'
+import { useEffect, useMemo, useState } from 'react'
+import { useNavigate } from 'react-router-dom'
import { useModules } from '../../api/modules/use-modules'
import { modulesFilter } from '../../api/timeline'
import { Badge } from '../../components/Badge'
import { Card } from '../../components/Card'
import { Page } from '../../layout'
import type { Module, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb'
-import { NotificationType, NotificationsContext } from '../../providers/notifications-provider'
import { SidePanelProvider } from '../../providers/side-panel-provider'
-import { deploymentKeyModuleName } from '../modules/module.utils'
import { Timeline } from '../timeline/Timeline'
import { isCron, isExported, isHttpIngress } from '../verbs/verb.utils'
const timeSettings = { isTailing: true, isPaused: false }
-export const DeploymentPage = () => {
- const navigate = useNavigate()
- const { deploymentKey } = useParams()
+export const DeploymentPage = ({ moduleName }: { moduleName: string }) => {
const modules = useModules()
- const notification = useContext(NotificationsContext)
- const navgation = useNavigate()
+ const navigate = useNavigate()
const [module, setModule] = useState
()
const filters = useMemo(() => {
@@ -30,41 +24,21 @@ export const DeploymentPage = () => {
}, [module?.deploymentKey])
useEffect(() => {
- if (modules.isSuccess && modules.data.modules.length > 0 && deploymentKey) {
- let module = modules.data.modules.find((module) => module.deploymentKey === deploymentKey)
- if (!module) {
- const moduleName = deploymentKeyModuleName(deploymentKey)
- if (moduleName) {
- module = modules.data.modules.find((module) => module.name === moduleName)
- navgation(`/deployments/${module?.deploymentKey}`)
- notification.showNotification({
- title: 'Showing latest deployment',
- message: `The previous deployment of ${module?.deploymentKey} was not found. Showing the latest deployment of ${module?.name} instead.`,
- type: NotificationType.Info,
- })
- setModule(module)
- }
- } else {
- setModule(module)
- }
+ if (modules.isSuccess && modules.data.modules.length > 0) {
+ const module = modules.data.modules.find((module) => module.name === moduleName)
+ setModule(module)
}
- }, [modules.data, deploymentKey])
+ }, [modules.data, moduleName])
return (
- } title={module?.deploymentKey || 'Loading...'} breadcrumbs={[{ label: 'Deployments', link: '/deployments' }]} />
-
{module?.verbs.map((verb) => (
-
navigate(`/deployments/${module.deploymentKey}/verbs/${verb.verb?.name}`)}
- >
+ navigate(`/modules/${module.name}/verb/${verb.verb?.name}`)}>
{verb.verb?.name}
{badges(verb).length > 0 && (
diff --git a/frontend/console/src/features/deployments/DeploymentsPage.tsx b/frontend/console/src/features/deployments/DeploymentsPage.tsx
index e0456efe3e..cbde32f835 100644
--- a/frontend/console/src/features/deployments/DeploymentsPage.tsx
+++ b/frontend/console/src/features/deployments/DeploymentsPage.tsx
@@ -1,4 +1,3 @@
-import { RocketLaunchIcon } from '@heroicons/react/24/outline'
import { useModules } from '../../api/modules/use-modules'
import { Page } from '../../layout'
import { DeploymentCard } from './DeploymentCard'
@@ -12,7 +11,6 @@ export const DeploymentsPage = () => {
return (
- } title='Deployments' />
{modules.isLoading && Loading...
}
{modules.isSuccess && (
diff --git a/frontend/console/src/features/modules/ModulePanel.tsx b/frontend/console/src/features/modules/ModulePanel.tsx
index 3b9e30bc5d..7b378b8bba 100644
--- a/frontend/console/src/features/modules/ModulePanel.tsx
+++ b/frontend/console/src/features/modules/ModulePanel.tsx
@@ -1,11 +1,8 @@
import { useParams } from 'react-router-dom'
+import { DeploymentPage } from '../deployments/DeploymentPage'
export const ModulePanel = () => {
const { moduleName } = useParams()
- return (
-
- )
+ return
}
diff --git a/frontend/console/src/features/modules/ModulesPage.tsx b/frontend/console/src/features/modules/ModulesPage.tsx
index 41a3abdcb5..07eebd6358 100644
--- a/frontend/console/src/features/modules/ModulesPage.tsx
+++ b/frontend/console/src/features/modules/ModulesPage.tsx
@@ -2,17 +2,14 @@ import type React from 'react'
import { useMemo, useState } from 'react'
import { useSchema } from '../../api/schema/use-schema'
import { ResizableHorizontalPanels } from '../../components/ResizableHorizontalPanels'
+import { DeploymentsPage } from '../deployments/DeploymentsPage'
import { ModulesTree } from './ModulesTree'
import { moduleTreeFromSchema } from './module.utils'
const treeWidthStorageKey = 'tree_w'
export const ModulesPanel = () => {
- return (
-
- )
+ return
}
export const ModulesPage = ({ body }: { body: React.ReactNode }) => {
diff --git a/frontend/console/src/features/modules/ModulesTree.tsx b/frontend/console/src/features/modules/ModulesTree.tsx
index e2a9c048e0..3a838567f4 100644
--- a/frontend/console/src/features/modules/ModulesTree.tsx
+++ b/frontend/console/src/features/modules/ModulesTree.tsx
@@ -92,7 +92,6 @@ const ModuleSection = ({ module, isExpanded, toggleExpansion }: { module: Module
{module.name}
{
e.preventDefault()
diff --git a/frontend/console/src/features/modules/decls/DeclPanel.tsx b/frontend/console/src/features/modules/decls/DeclPanel.tsx
index 6403f37eb2..864efc5eda 100644
--- a/frontend/console/src/features/modules/decls/DeclPanel.tsx
+++ b/frontend/console/src/features/modules/decls/DeclPanel.tsx
@@ -1,9 +1,9 @@
import { useMemo } from 'react'
import { useParams } from 'react-router-dom'
import { useSchema } from '../../../api/schema/use-schema'
+import { VerbPage } from '../../verbs/VerbPage'
import { declFromSchema } from '../module.utils'
import { DataPanel } from './DataPanel'
-import { VerbPanel } from './VerbPanel'
export const DeclPanel = () => {
const { moduleName, declCase, declName } = useParams()
@@ -23,7 +23,7 @@ export const DeclPanel = () => {
case 'data':
return
case 'verb':
- return
+ return
}
return (
diff --git a/frontend/console/src/features/verbs/VerbPage.tsx b/frontend/console/src/features/verbs/VerbPage.tsx
index 59fdfc3157..c91339184d 100644
--- a/frontend/console/src/features/verbs/VerbPage.tsx
+++ b/frontend/console/src/features/verbs/VerbPage.tsx
@@ -1,6 +1,6 @@
-import { BoltIcon, Square3Stack3DIcon } from '@heroicons/react/24/outline'
+import { BoltIcon } from '@heroicons/react/24/outline'
import { useContext, useEffect, useState } from 'react'
-import { useNavigate, useParams } from 'react-router-dom'
+import { useNavigate } from 'react-router-dom'
import { useModules } from '../../api/modules/use-modules'
import { useStreamVerbCalls } from '../../api/timeline/stream-verb-calls'
import { Loader } from '../../components/Loader'
@@ -10,12 +10,10 @@ import type { CallEvent, Module, Verb } from '../../protos/xyz/block/ftl/v1/cons
import { NotificationType, NotificationsContext } from '../../providers/notifications-provider'
import { SidePanelProvider } from '../../providers/side-panel-provider'
import { CallList } from '../calls/CallList'
-import { deploymentKeyModuleName } from '../modules/module.utils'
import { VerbRequestForm } from './VerbRequestForm'
import { verbPanels } from './VerbRightPanel'
-export const VerbPage = () => {
- const { deploymentKey, verbName } = useParams()
+export const VerbPage = ({ moduleName, declName }: { moduleName: string; declName: string }) => {
const notification = useContext(NotificationsContext)
const navgation = useNavigate()
const modules = useModules()
@@ -24,25 +22,22 @@ export const VerbPage = () => {
useEffect(() => {
if (!modules.isSuccess) return
- if (modules.data.modules.length === 0 || !deploymentKey || !verbName) return
+ if (modules.data.modules.length === 0 || !moduleName || !declName) return
- let module = modules.data.modules.find((module) => module.deploymentKey === deploymentKey)
- if (!module) {
- const moduleName = deploymentKeyModuleName(deploymentKey)
- if (moduleName) {
- module = modules.data.modules.find((module) => module.name === moduleName)
- navgation(`/deployments/${module?.deploymentKey}/verbs/${verbName}`)
- notification.showNotification({
- title: 'Showing latest deployment',
- message: `The previous deployment of ${module?.deploymentKey} was not found. Showing the latest deployment of ${module?.name}.${verbName} instead.`,
- type: NotificationType.Info,
- })
- }
+ let module = modules.data.modules.find((module) => module.name === moduleName)
+ if (!module && moduleName) {
+ module = modules.data.modules.find((module) => module.name === moduleName)
+ navgation(`/modules/${module?.name}/verb/${declName}`)
+ notification.showNotification({
+ title: 'Showing latest deployment',
+ message: `The previous deployment of ${module?.name} was not found. Showing the latest deployment of ${module?.name}.${declName} instead.`,
+ type: NotificationType.Info,
+ })
}
setModule(module)
- const verb = module?.verbs.find((verb) => verb.verb?.name.toLocaleLowerCase() === verbName?.toLocaleLowerCase())
+ const verb = module?.verbs.find((verb) => verb.verb?.name.toLocaleLowerCase() === declName?.toLocaleLowerCase())
setVerb(verb)
- }, [modules.data, deploymentKey])
+ }, [modules.data, moduleName])
const callEvents = useStreamVerbCalls(module?.name, verb?.verb?.name)
const calls: CallEvent[] = callEvents.data || []
@@ -65,14 +60,6 @@ export const VerbPage = () => {
return (
- }
- title={verb?.verb?.name || ''}
- breadcrumbs={[
- { label: 'Deployments', link: '/deployments' },
- { label: module?.deploymentKey || '', link: `/deployments/${module?.deploymentKey}` },
- ]}
- />
}
diff --git a/frontend/console/src/layout/navigation/Navigation.tsx b/frontend/console/src/layout/navigation/Navigation.tsx
index 8c4121f13a..1d2df860f8 100644
--- a/frontend/console/src/layout/navigation/Navigation.tsx
+++ b/frontend/console/src/layout/navigation/Navigation.tsx
@@ -6,7 +6,6 @@ import { Version } from './Version'
const navigation = [
{ name: 'Events', href: '/events', icon: ListBulletIcon },
- { name: 'Deployments', href: '/deployments', icon: Square3Stack3DIcon },
{ name: 'Modules', href: '/modules', icon: Square3Stack3DIcon },
{ name: 'Graph', href: '/graph', icon: CubeTransparentIcon },
{ name: 'Infrastructure', href: '/infrastructure', icon: ServerStackIcon },
diff --git a/frontend/console/src/providers/routing-provider.tsx b/frontend/console/src/providers/routing-provider.tsx
index 0eb55bfc44..86dfaeefcc 100644
--- a/frontend/console/src/providers/routing-provider.tsx
+++ b/frontend/console/src/providers/routing-provider.tsx
@@ -1,13 +1,10 @@
import { Navigate, Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'
import { ConsolePage } from '../features/console/ConsolePage'
-import { DeploymentPage } from '../features/deployments/DeploymentPage'
-import { DeploymentsPage } from '../features/deployments/DeploymentsPage'
import { InfrastructurePage } from '../features/infrastructure/InfrastructurePage'
import { ModulePanel } from '../features/modules/ModulePanel'
import { ModulesPage, ModulesPanel } from '../features/modules/ModulesPage'
import { DeclPanel } from '../features/modules/decls/DeclPanel'
import { TimelinePage } from '../features/timeline/TimelinePage'
-import { VerbPage } from '../features/verbs/VerbPage'
import { Layout } from '../layout/Layout'
import { NotFoundPage } from '../layout/NotFoundPage'
@@ -20,9 +17,6 @@ const router = createBrowserRouter(
} />} />
} />} />
} />} />
- } />
- } />
- } />
} />
} />
diff --git a/frontend/console/test-results/.last-run.json b/frontend/console/test-results/.last-run.json
new file mode 100644
index 0000000000..cbcc1fbac1
--- /dev/null
+++ b/frontend/console/test-results/.last-run.json
@@ -0,0 +1,4 @@
+{
+ "status": "passed",
+ "failedTests": []
+}
\ No newline at end of file