From 286ba1da7029367be508645bc43ae89f65f29c55 Mon Sep 17 00:00:00 2001 From: Ambient Code Bot Date: Thu, 23 Apr 2026 16:42:54 -0400 Subject: [PATCH] feat(frontend): rename Sharing to Pair Prompting and improve grant dialog UX Rename the "Sharing" workspace section to "Pair Prompting" across sidebar nav, card title, and all tests. Remove the duplicate "Grant First Permission" button from the empty state. Add placeholder examples and a help tooltip to the name input in the Grant Permission dialog. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../__tests__/sessions-sidebar.test.tsx | 2 +- .../components/sessions-sidebar.tsx | 2 +- .../__tests__/sharing-section.test.tsx | 5 ++- .../workspace-sections/sharing-section.tsx | 45 ++++++++++++------- e2e/cypress/e2e/screenshots.cy.ts | 2 +- e2e/cypress/e2e/sessions.cy.ts | 14 +++--- 6 files changed, 41 insertions(+), 29 deletions(-) diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/__tests__/sessions-sidebar.test.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/__tests__/sessions-sidebar.test.tsx index 1528564ec..09097c5a6 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/__tests__/sessions-sidebar.test.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/__tests__/sessions-sidebar.test.tsx @@ -103,7 +103,7 @@ describe('SessionsSidebar', () => { render(); expect(screen.getByText('Sessions')).toBeDefined(); expect(screen.getByText('Schedules')).toBeDefined(); - expect(screen.getByText('Sharing')).toBeDefined(); + expect(screen.getByText('Pair Prompting')).toBeDefined(); expect(screen.getByText('Access Keys')).toBeDefined(); expect(screen.getByText('Workspace Settings')).toBeDefined(); }); diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx index ba40b4020..3d2dc2615 100644 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx @@ -130,7 +130,7 @@ export function SessionsSidebar({ href: `/projects/${projectName}/scheduled-sessions`, }, { - label: "Sharing", + label: "Pair Prompting", icon: Share2, href: `/projects/${projectName}/permissions`, }, diff --git a/components/frontend/src/components/workspace-sections/__tests__/sharing-section.test.tsx b/components/frontend/src/components/workspace-sections/__tests__/sharing-section.test.tsx index 439bb52ec..71258d106 100644 --- a/components/frontend/src/components/workspace-sections/__tests__/sharing-section.test.tsx +++ b/components/frontend/src/components/workspace-sections/__tests__/sharing-section.test.tsx @@ -60,7 +60,7 @@ describe('SharingSection', () => { it('renders permissions table with data', () => { render(); - expect(screen.getByText('Sharing')).toBeDefined(); + expect(screen.getByText('Pair Prompting')).toBeDefined(); expect(screen.getByText('developers')).toBeDefined(); expect(screen.getByText('alice')).toBeDefined(); }); @@ -87,7 +87,7 @@ describe('SharingSection', () => { render(); fireEvent.click(screen.getByText('Grant Permission')); - const nameInput = screen.getByPlaceholderText('Enter group name'); + const nameInput = screen.getByPlaceholderText('e.g., platform-team'); fireEvent.change(nameInput, { target: { value: 'new-team' } }); // Click the Grant Permission button in the dialog footer @@ -150,5 +150,6 @@ describe('SharingSection', () => { render(); expect(screen.getByText('No users or groups have access yet')).toBeDefined(); + expect(screen.queryByText('Grant First Permission')).toBeNull(); }); }); diff --git a/components/frontend/src/components/workspace-sections/sharing-section.tsx b/components/frontend/src/components/workspace-sections/sharing-section.tsx index 642e73d61..4f7e4a997 100644 --- a/components/frontend/src/components/workspace-sections/sharing-section.tsx +++ b/components/frontend/src/components/workspace-sections/sharing-section.tsx @@ -1,7 +1,7 @@ 'use client'; import { useCallback, useMemo, useState } from 'react'; -import { Users, User as UserIcon, Plus, Loader2, Trash2, Info } from 'lucide-react'; +import { Users, User as UserIcon, Plus, Loader2, Trash2, Info, HelpCircle } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; @@ -12,6 +12,7 @@ import { Label } from '@/components/ui/label'; import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { DestructiveConfirmationDialog } from '@/components/confirmation-dialog'; import { useProjectPermissions, useAddProjectPermission, useRemoveProjectPermission } from '@/services/queries'; @@ -50,6 +51,8 @@ export function SharingSection({ projectName }: SharingSectionProps) { const isAdmin = userRole === 'admin' || userRole === undefined; + const subjectPlaceholder = grantForm.subjectType === 'group' ? 'e.g., platform-team' : 'e.g., jdoe@example.com'; + const handleGrant = useCallback(() => { if (!grantForm.subjectName.trim()) { setGrantError(`${grantForm.subjectType === 'group' ? 'Group' : 'User'} name is required`); @@ -113,16 +116,10 @@ export function SharingSection({ projectName }: SharingSectionProps) { () => (
-

No users or groups have access yet

- {isAdmin && ( - - )} +

No users or groups have access yet

), - [isAdmin] + [] ); return ( @@ -143,7 +140,7 @@ export function SharingSection({ projectName }: SharingSectionProps) {
- Sharing + Pair Prompting Users and groups with access to this workspace and their roles
@@ -227,9 +224,9 @@ export function SharingSection({ projectName }: SharingSectionProps) { - {/* Grant Permission Dialog */} + Grant Permission Add a user or group to this workspace with a role @@ -251,14 +248,28 @@ export function SharingSection({ projectName }: SharingSectionProps) {
- +
+ + + + + + + {grantForm.subjectType === 'group' ? ( +

Enter the LDAP or identity provider group name, e.g. platform-team, ai-engineering

+ ) : ( +

Enter the username or email, e.g. jdoe, jdoe@example.com

+ )} +
+
+
{ldapEnabled ? ( setGrantForm((prev) => ({ ...prev, subjectName: val }))} disabled={addPermissionMutation.isPending} @@ -266,7 +277,7 @@ export function SharingSection({ projectName }: SharingSectionProps) { ) : ( setGrantForm((prev) => ({ ...prev, subjectName: e.target.value }))} disabled={addPermissionMutation.isPending} @@ -327,10 +338,10 @@ export function SharingSection({ projectName }: SharingSectionProps) { )} + - {/* Revoke Permission Dialog */} { it('should visit each workspace page via direct routes', () => { // Each workspace section now has its own route (no more ?section= params) - // Sharing page — covers sharing-section.tsx + // Pair Prompting page — covers sharing-section.tsx cy.visit(`/projects/${workspaceSlug}/permissions`) - cy.get('body', { timeout: 10000 }).should('contain.text', 'Sharing') + cy.get('body', { timeout: 10000 }).should('contain.text', 'Pair Prompting') cy.wait(500) // Access Keys page — covers keys page @@ -484,7 +484,7 @@ describe('Ambient Session Management Tests', () => { it('should interact with sharing tab', () => { cy.visit(`/projects/${workspaceSlug}/permissions`) - cy.get('body', { timeout: 15000 }).should('contain.text', 'Sharing') + cy.get('body', { timeout: 15000 }).should('contain.text', 'Pair Prompting') // Look for "Grant Permission" button cy.get('body').then(($body) => { @@ -1339,11 +1339,11 @@ describe('Ambient Session Management Tests', () => { it('should interact with sharing tab Grant Permission dialog', () => { cy.visit(`/projects/${workspaceSlug}/permissions`) - cy.get('body', { timeout: 15000 }).should('contain.text', 'Sharing') + cy.get('body', { timeout: 15000 }).should('contain.text', 'Pair Prompting') - // Look for "Grant Permission" or "Grant First Permission" button + // Look for "Grant Permission" button cy.get('body').then(($body) => { - const grantBtn = $body.find('button:contains("Grant Permission"), button:contains("Grant First Permission")') + const grantBtn = $body.find('button:contains("Grant Permission")') if (grantBtn.length) { cy.wrap(grantBtn.first()).click({ force: true }) cy.wait(500) @@ -1654,7 +1654,7 @@ describe('Ambient Session Management Tests', () => { it('should click Refresh button on sharing tab', () => { cy.visit(`/projects/${workspaceSlug}/permissions`) - cy.get('body', { timeout: 15000 }).should('contain.text', 'Sharing') + cy.get('body', { timeout: 15000 }).should('contain.text', 'Pair Prompting') cy.get('body').then(($body) => { if ($body.find('button:contains("Refresh")').length) {