diff --git a/src/features/workspace/components/workspace-activate-button.tsx b/src/features/workspace/components/workspace-activate-button.tsx
new file mode 100644
index 00000000..2531cd00
--- /dev/null
+++ b/src/features/workspace/components/workspace-activate-button.tsx
@@ -0,0 +1,77 @@
+import { useMutationActivateWorkspace } from '@/hooks/use-mutation-activate-workspace'
+import { useQueryActiveWorkspaceName } from '@/hooks/use-query-active-workspace-name'
+import {
+ Button,
+ Tooltip,
+ TooltipInfoButton,
+ TooltipTrigger,
+} from '@stacklok/ui-kit'
+import { Check } from '@untitled-ui/icons-react'
+
+function getTooltipText({
+ isActivated,
+ isArchived,
+}: {
+ isArchived: boolean
+ isActivated: boolean
+}) {
+ if (isArchived) {
+ return 'Cannot activate an archived workspace'
+ }
+
+ if (isActivated) {
+ return 'Workspace already active'
+ }
+
+ return null
+}
+
+function TooltipActivateBtn({
+ isActivated,
+ isArchived,
+}: {
+ isActivated: boolean
+ isArchived: boolean
+}) {
+ const text = getTooltipText({ isActivated, isArchived })
+
+ if (!text) return null
+ return (
+
+
+ {text}
+
+ )
+}
+
+export function WorkspaceActivateButton({
+ workspaceName,
+ isArchived,
+}: {
+ workspaceName: string
+ isArchived: boolean | undefined
+}) {
+ const { data: activeWorkspaceName, isPending: isPendingWsName } =
+ useQueryActiveWorkspaceName()
+ const { mutateAsync: activateWorkspace, isPending: isPendingMutation } =
+ useMutationActivateWorkspace()
+ const isActivated = activeWorkspaceName === workspaceName
+ const isPending = isPendingWsName || isPendingMutation
+
+ return (
+
+
+
+
+ )
+}
diff --git a/src/routes/__tests__/route-workspace.test.tsx b/src/routes/__tests__/route-workspace.test.tsx
index 4ecf1b7a..b451dc1b 100644
--- a/src/routes/__tests__/route-workspace.test.tsx
+++ b/src/routes/__tests__/route-workspace.test.tsx
@@ -3,6 +3,9 @@ import { test, expect, vi } from 'vitest'
import userEvent from '@testing-library/user-event'
import { RouteWorkspace } from '../route-workspace'
import { useParams } from 'react-router-dom'
+import { server } from '@/mocks/msw/node'
+import { http, HttpResponse } from 'msw'
+import { mswEndpoint } from '@/test/msw-endpoint'
const mockNavigate = vi.fn()
@@ -148,3 +151,61 @@ test('revert changes button', async () => {
})
).toHaveValue('foo')
})
+
+test('disable activate workspace button', async () => {
+ server.use(
+ http.get(mswEndpoint('/api/v1/workspaces/active'), async () => {
+ return HttpResponse.json({
+ workspaces: [
+ {
+ name: 'foo',
+ is_active: true,
+ last_updated: new Date(Date.now()).toISOString(),
+ },
+ ],
+ })
+ })
+ )
+
+ const { getByTestId } = renderComponent()
+ const activateSection = getByTestId(/workspace-activate/i)
+ await waitFor(() => {
+ expect(
+ within(activateSection).getByRole('button', { name: /activate/i })
+ ).toBeDisabled()
+ })
+
+ expect(
+ within(activateSection).getByRole('button', {
+ name: /context active button/i,
+ })
+ ).toBeVisible()
+})
+
+test('activate workspace', async () => {
+ server.use(
+ http.get(mswEndpoint('/api/v1/workspaces/active'), async () => {
+ return HttpResponse.json({
+ workspaces: [
+ {
+ name: 'bar',
+ is_active: true,
+ last_updated: new Date(Date.now()).toISOString(),
+ },
+ ],
+ })
+ })
+ )
+ const { getByTestId, getByText } = renderComponent()
+ const activateSection = getByTestId(/workspace-activate/i)
+ const activateButton = await within(activateSection).findByRole('button', {
+ name: /activate/i,
+ })
+ expect(activateButton).not.toBeDisabled()
+
+ await userEvent.click(activateButton)
+
+ await waitFor(() => {
+ expect(getByText(/Activated "foo" workspace/i)).toBeVisible()
+ })
+})
diff --git a/src/routes/route-workspace.tsx b/src/routes/route-workspace.tsx
index 3de4e14f..d5df90ed 100644
--- a/src/routes/route-workspace.tsx
+++ b/src/routes/route-workspace.tsx
@@ -1,14 +1,15 @@
import { BreadcrumbHome } from '@/components/BreadcrumbHome'
import { ArchiveWorkspace } from '@/features/workspace/components/archive-workspace'
-import { PageHeading } from "@/components/heading";
-import { WorkspaceName } from "@/features/workspace/components/workspace-name";
-import { Alert, Breadcrumb, Breadcrumbs } from "@stacklok/ui-kit";
-import { useParams } from "react-router-dom";
-import { useArchivedWorkspaces } from "@/features/workspace/hooks/use-archived-workspaces";
-import { useRestoreWorkspaceButton } from "@/features/workspace/hooks/use-restore-workspace-button";
-import { WorkspaceCustomInstructions } from "@/features/workspace/components/workspace-custom-instructions";
-import { WorkspaceMuxingModel } from "@/features/workspace/components/workspace-muxing-model";
-import { PageContainer } from "@/components/page-container";
+import { PageHeading } from '@/components/heading'
+import { WorkspaceName } from '@/features/workspace/components/workspace-name'
+import { Alert, Breadcrumb, Breadcrumbs } from '@stacklok/ui-kit'
+import { useParams } from 'react-router-dom'
+import { useArchivedWorkspaces } from '@/features/workspace/hooks/use-archived-workspaces'
+import { useRestoreWorkspaceButton } from '@/features/workspace/hooks/use-restore-workspace-button'
+import { WorkspaceCustomInstructions } from '@/features/workspace/components/workspace-custom-instructions'
+import { WorkspaceMuxingModel } from '@/features/workspace/components/workspace-muxing-model'
+import { PageContainer } from '@/components/page-container'
+import { WorkspaceActivateButton } from '@/features/workspace/components/workspace-activate-button'
function WorkspaceArchivedBanner({ name }: { name: string }) {
const restoreButtonProps = useRestoreWorkspaceButton({ workspaceName: name })
@@ -44,7 +45,9 @@ export function RouteWorkspace() {
Workspace Settings
-
+
+
+
{isArchived ? : null}