Skip to content

Commit

Permalink
feat(COS-6902): Implement sub-routes for agent view (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kasia9090 authored Feb 18, 2025
1 parent da0ea71 commit 24d21fd
Show file tree
Hide file tree
Showing 72 changed files with 4,062 additions and 400 deletions.
35 changes: 35 additions & 0 deletions src/domain/usecases/agents/toggle-agent-active.usecase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { computed } from 'mobx';
import { Tracer } from '@infra/tracer';
import { RootStore } from '@store/root';
import { AgentService } from '@domain/services/agent/agent.service';

export class ToggleAgentActiveUsecase {
private service = new AgentService();
private root = RootStore.getInstance();

constructor(private id: string) {
this.toggleActive = this.toggleActive.bind(this);
}

@computed
get agent() {
return this.root.agents.getById(this.id);
}

toggleActive() {
const span = Tracer.span('ToggleAgentActiveUsecase.toggleActive');

if (!this.agent) {
console.error(
'ToggleAgentActiveUsecase.toggleActive: Agent not found. Aborting',
);

return;
}

this.agent.toggleStatus();
this.service.saveAgent(this.agent);

span.end();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useMemo } from 'react';
import { useParams } from 'react-router-dom';

import { observer } from 'mobx-react-lite';
import { AddTagToCompanyUsecase } from '@domain/usecases/agents/capabilities/add-tag-to-company.usecase';
import { AddTagToCompanyUsecase } from '@domain/usecases/agents/capabilities/add-tag-to-company.usecase.ts';

import { cn } from '@ui/utils/cn.ts';
import { Icon } from '@ui/media/Icon';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ApplyTag.tsx';
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ import { useRef, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';

import { observer } from 'mobx-react-lite';
import { DetectSupportWebVistUsecase } from '@domain/usecases/agents/capabilities/detect-support-web-vist';
import { DetectSupportWebVistUsecase } from '@domain/usecases/agents/capabilities/detect-support-web-vist.ts';

import { Icon } from '@ui/media/Icon';
import { Input } from '@ui/form/Input';
import { Button } from '@ui/form/Button/Button';
import { IconButton } from '@ui/form/IconButton';
import { useStore } from '@shared/hooks/useStore';
import {
AgentType,
CapabilityType,
} from '@shared/types/__generated__/graphql.types';
import { Button } from '@ui/form/Button/Button.tsx';
import { AgentType, CapabilityType } from '@graphql/types';
import {
AlertDialog,
AlertDialogBody,
Expand All @@ -21,7 +18,7 @@ import {
AlertDialogContent,
AlertDialogOverlay,
AlertDialogCloseIconButton,
} from '@ui/overlay/AlertDialog/AlertDialog';
} from '@ui/overlay/AlertDialog/AlertDialog.tsx';
export const DetectSupportWebVisit = observer(() => {
const store = useStore();
const navigate = useNavigate();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DetectSupportWebVisit.tsx';
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,31 @@ import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';

import { observer } from 'mobx-react-lite';
import { EditIcpDomainsUsecase } from '@domain/usecases/agents/capabilities/edit-icp-domains.usecase';
import { EditIcpQualificationCriteriaUsecase } from '@domain/usecases/agents/capabilities/edit-icp-qualification-criteria.usecase';
import { EditIcpDisqualificationCriteriaUsecase } from '@domain/usecases/agents/capabilities/edit-icp-disqualification-criteria.usecase';
import { EditIcpDomainsUsecase } from '@domain/usecases/agents/capabilities/edit-icp-domains.usecase.ts';
import { EditIcpQualificationCriteriaUsecase } from '@domain/usecases/agents/capabilities/edit-icp-qualification-criteria.usecase.ts';
import { EditIcpDisqualificationCriteriaUsecase } from '@domain/usecases/agents/capabilities/edit-icp-disqualification-criteria.usecase.ts';

import { Icon } from '@ui/media/Icon';
import { Button } from '@ui/form/Button/Button';
import { CapabilityType } from '@graphql/types';
import { IconButton } from '@ui/form/IconButton';
import { useStore } from '@shared/hooks/useStore';
import { Textarea } from '@ui/form/Textarea/Textarea';
import { Button } from '@ui/form/Button/Button.tsx';
import { Textarea } from '@ui/form/Textarea/Textarea.tsx';
import { getFormattedLink } from '@utils/getExternalLink.ts';
import { Menu, MenuItem, MenuList, MenuButton } from '@ui/overlay/Menu/Menu';
import {
Menu,
MenuItem,
MenuList,
MenuButton,
} from '@ui/overlay/Menu/Menu.tsx';
import {
ScrollAreaRoot,
ScrollAreaThumb,
ScrollAreaViewport,
ScrollAreaScrollbar,
} from '@ui/utils/ScrollArea';

import { IdealCustomersModal } from './IdealCustomersModal';
import { IdealCustomersModal } from './IdealCustomersModal.tsx';
const disqualificationCriteriaUsecase =
new EditIcpDisqualificationCriteriaUsecase();
const qualificationCriteriaUsecase = new EditIcpQualificationCriteriaUsecase();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import { useRef } from 'react';

import { useKey } from 'rooks';
import { observer } from 'mobx-react-lite';
import { EditIcpDomainsUsecase } from '@domain/usecases/agents/capabilities/edit-icp-domains.usecase';
import { EditIcpDomainsUsecase } from '@domain/usecases/agents/capabilities/edit-icp-domains.usecase.ts';

import { cn } from '@ui/utils/cn';
import { cn } from '@ui/utils/cn.ts';
import { Avatar } from '@ui/media/Avatar';
import { Check } from '@ui/media/icons/Check';
import { Spinner } from '@ui/feedback/Spinner';
import { User03 } from '@ui/media/icons/User03';
import { Check } from '@ui/media/icons/Check.tsx';
import { User03 } from '@ui/media/icons/User03.tsx';
import { useModKey } from '@shared/hooks/useModKey';
import { PlusCircle } from '@ui/media/icons/PlusCircle';
import { getFormattedLink } from '@utils/getExternalLink';
import { useOutsideClick } from '@ui/utils/hooks/useOutsideClick';
import { PlusCircle } from '@ui/media/icons/PlusCircle.tsx';
import { getFormattedLink } from '@utils/getExternalLink.ts';
import { useOutsideClick } from '@ui/utils/hooks/useOutsideClick.ts';
import {
Modal,
ModalBody,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { EvaluateCompanyIcpFit } from './EvaluateCompanyICPFit.tsx';
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import {
import { Icon } from '@ui/media/Icon';
import { Switch } from '@ui/form/Switch';
import { Combobox } from '@ui/form/Combobox';
import { Slack } from '@ui/media/logos/Slack';
import { Button } from '@ui/form/Button/Button';
import { CapabilityType } from '@graphql/types';
import { Slack } from '@ui/media/logos/Slack.tsx';
import { useStore } from '@shared/hooks/useStore';
import { Button } from '@ui/form/Button/Button.tsx';
import { Tag, TagLabel } from '@ui/presentation/Tag';
import { Popover, PopoverTrigger, PopoverContent } from '@ui/overlay/Popover';

import { DisconnectSlackMenu } from './DisconnectSlackMenu';
import { DisconnectSlackMenu } from './DisconnectSlackMenu.tsx';

export const SendSlackNotificationCapability = observer(() => {
const store = useStore();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './SendSlackNotificationCapability.tsx';
206 changes: 206 additions & 0 deletions src/routes/agent/components/AgentConfig/ConfigPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { useMemo, useEffect } from 'react';
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';

import { useKeys } from 'rooks';
import { observer } from 'mobx-react-lite';
import { AgentViewUsecase } from '@domain/usecases/agents/agent-view.usecase';

import { cn } from '@ui/utils/cn';
import { Icon } from '@ui/media/Icon';
import { useStore } from '@shared/hooks/useStore';
import { useModKey } from '@shared/hooks/useModKey';

import { Scope } from './Scope';
import { goals, configs } from './config.tsx';

export const ConfigPage = observer(() => {
const store = useStore();

const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const [queryParams, setQueryParams] = useSearchParams();

const agent = id ? store.agents.getById(id) : null;

const usecase = useMemo(
() => new AgentViewUsecase(id ?? '', queryParams.get('cid')),
[id],
);

const ActiveConfig = useMemo(
() =>
usecase.activeConfig ? configs[usecase.activeConfig.type] : () => null,
[usecase?.activeConfig?.type],
);

useEffect(() => {
if (!queryParams.get('cid')) {
setQueryParams(
(params) => {
if (!usecase.activeConfig?.id) return params;
params.set('cid', usecase.activeConfig.id);

return params;
},
{ replace: true },
);
}
}, []);

useEffect(() => {
if (id) {
store.ui.commandMenu.setContext({
...store.ui.commandMenu.context,
ids: [id],
});
store.ui.commandMenu.setType('AgentCommands');
}
}, [id]);

useKeys(['Shift', 'S'], (e) => {
e.stopPropagation();
e.preventDefault();
usecase.toggleActive();
});

useKeys(['Shift', 'R'], (e) => {
e.stopPropagation();
e.preventDefault();
store.ui.commandMenu.setType('RenameAgent');
store.ui.commandMenu.setOpen(true);
});

useModKey('Backspace', () => {
store.ui.commandMenu.setType('ArchiveAgent');
store.ui.commandMenu.setOpen(true);
});

if (!id) {
throw new Error('No id provided');
}

if (!agent) {
return null;
}

return (
<div>
<div className='flex h-screen'>
<div className='w-[448px] border-r border-r-grayModern-200 px-4 py-3'>
<div className='mb-2'>
<div className='mb-1 flex items-center justify-between'>
<h2 className='font-medium text-sm'>About this agent</h2>
{agent?.value.scope && <Scope scope={agent.value.scope} />}
</div>
<p className='pb-2 text-sm'>{agent?.value.goal ?? 'Unknown'}</p>
</div>

<h2 className='mb-2 font-medium text-sm'>It's goal is to</h2>
<ul className='space-y-1 mb-4'>
{agent &&
goals[agent?.value.type]?.map((goal) => (
<div
key={goal}
className='flex items-center px-2 py-1 justify-between rounded-lg select-none'
>
<div className='flex items-center gap-2'>
<Icon
stroke='none'
name='dot-single'
className={'text-grayModern-500'}
/>
<p className='text-sm'>{goal}</p>
</div>
</div>
))}
</ul>

<h2 className='mb-2 font-medium text-sm'>It listens for</h2>
<ul className='space-y-1 mb-4'>
{agent?.value.listeners.map((listener) => (
<div
key={listener.id}
onClick={() => {
if (listener.config.length) {
usecase.setActiveConfig(listener);
navigate(`?lid=${listener.id}`, { replace: true });
}
}}
className={cn(
'flex items-center px-2 py-1 justify-between rounded-lg select-none',
listener.config.length &&
'hover:bg-grayModern-200 cursor-pointer',
listener.id === usecase?.activeConfig?.id &&
'bg-grayModern-100 hover:bg-grayModern-100 font-medium',
)}
>
<div className='flex items-center gap-2'>
<Icon
stroke={listener.errors ? 'currentColor' : 'none'}
name={listener.errors ? 'radio-dot' : 'dot-single'}
className={
listener.errors ? 'text-error-500' : 'text-grayModern-500'
}
/>
<p className='text-sm'>{listener.name ?? 'Unknown'}</p>
</div>

{listener.config.length > 0 && (
<Icon name='settings-02' className='text-grayModern-500' />
)}
</div>
))}
</ul>

<h2 className='mb-2 font-medium text-sm'>
It can perform these actions
</h2>

<ul className='space-y-1'>
{agent?.value.capabilities.map((capability) => (
<div
key={capability.id}
onClick={() => {
if (capability.config.length) {
usecase.setActiveConfig(capability);
navigate(`?cid=${capability.id}`, { replace: true });
}
}}
className={cn(
'flex items-center px-2 py-1 justify-between rounded-lg select-none',
capability.config.length &&
'hover:bg-grayModern-200 cursor-pointer',
capability.id === usecase?.activeConfig?.id &&
'bg-grayModern-100 hover:bg-grayModern-100 font-medium',
)}
>
<div className='flex items-center gap-2'>
<Icon
stroke={capability.errors ? 'currentColor' : 'none'}
name={capability.errors ? 'radio-dot' : 'dot-single'}
className={
capability.errors
? 'text-error-500'
: 'text-grayModern-500'
}
/>
<p className='text-sm'>{capability.name ?? 'Unknown'}</p>
</div>

{capability.config.length > 0 && (
<Icon name='settings-02' className='text-grayModern-500' />
)}
</div>
))}
</ul>
</div>

{usecase.activeConfig && ActiveConfig && (
<div className='w-[418px] border-r border-r-grayModern-200 px-4 py-3'>
<ActiveConfig />
</div>
)}
</div>
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ import { useEffect } from 'react';
import { useParams } from 'react-router-dom';

import { observer } from 'mobx-react-lite';
import { NewMeetingRecordingUsecase } from '@domain/usecases/agents/listeners/new-meeting-recording.usecase';
import { NewMeetingRecordingUsecase } from '@domain/usecases/agents/listeners/new-meeting-recording.usecase.ts';

import { cn } from '@ui/utils/cn';
import { cn } from '@ui/utils/cn.ts';
import { Icon } from '@ui/media/Icon';
import { Combobox } from '@ui/form/Combobox';
import { Image } from '@ui/media/Image/Image';
import { Spinner } from '@ui/feedback/Spinner';
import { Logo, LogoName } from '@ui/media/Logo';
import { IconButton } from '@ui/form/IconButton';
import { Image } from '@ui/media/Image/Image.tsx';
import { useStore } from '@shared/hooks/useStore';
import { AgentListenerEvent } from '@graphql/types';
import { getOptionClassNames } from '@ui/form/Select';
import logoCustomerOs from '@shared/assets/customer-os-small.png';
import { Popover, PopoverContent, PopoverTrigger } from '@ui/overlay/Popover';
import { AgentListenerEvent } from '@shared/types/__generated__/graphql.types';

const usecase = new NewMeetingRecordingUsecase();

Expand Down
Loading

0 comments on commit 24d21fd

Please sign in to comment.