• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

apowers313 / aiforge / 20962792399

13 Jan 2026 03:39PM UTC coverage: 84.707%. First build
20962792399

push

github

apowers313
feat: initial commit

787 of 905 branches covered (86.96%)

Branch coverage included in aggregate %.

4248 of 5039 new or added lines in 70 files covered. (84.3%)

4248 of 5039 relevant lines covered (84.3%)

13.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.24
/src/client/components/shells/ShellItem.tsx
1
import { useState } from 'react';
1✔
2
import { Group, Text, UnstyledButton, ActionIcon, Menu, Badge, Modal, TextInput, Button, Stack } from '@mantine/core';
1✔
3
import { IconTerminal2, IconDots, IconTrash, IconPencil, IconRefresh } from '@tabler/icons-react';
1✔
4
import type { Shell } from '@shared/types';
5
import { useDeleteShell, useUpdateShell, useRestartShell, useActiveShellId } from '@client/hooks/useShells';
1✔
6

7
interface ShellItemProps {
8
  shell: Shell;
9
  projectId: string;
10
}
11

12
export function ShellItem({ shell, projectId }: ShellItemProps): React.ReactElement {
1✔
13
  const { activeShellId, setActiveShell } = useActiveShellId();
31✔
14
  const deleteShellMutation = useDeleteShell();
31✔
15
  const updateShellMutation = useUpdateShell();
31✔
16
  const restartShellMutation = useRestartShell();
31✔
17
  const [renameModalOpen, setRenameModalOpen] = useState(false);
31✔
18
  const [newName, setNewName] = useState(shell.name);
31✔
19

20
  const isActive = activeShellId === shell.id;
31✔
21

22
  const handleClick = (): void => {
31✔
23
    setActiveShell(shell.id);
1✔
24
  };
1✔
25

26
  const handleDelete = (): void => {
31✔
27
    deleteShellMutation.mutate({ shellId: shell.id, projectId });
1✔
28
  };
1✔
29

30
  const handleRenameClick = (): void => {
31✔
31
    setNewName(shell.name);
1✔
32
    setRenameModalOpen(true);
1✔
33
  };
1✔
34

35
  const handleRenameSubmit = (): void => {
31✔
36
    if (!newName.trim() || newName === shell.name) {
1!
NEW
37
      setRenameModalOpen(false);
×
NEW
38
      return;
×
NEW
39
    }
×
40
    updateShellMutation.mutate(
1✔
41
      { shellId: shell.id, updates: { name: newName.trim() } },
1✔
42
      {
1✔
43
        onSuccess: () => {
1✔
44
          setRenameModalOpen(false);
1✔
45
        },
1✔
46
      },
1✔
47
    );
1✔
48
  };
1✔
49

50
  const handleRestart = (): void => {
31✔
51
    restartShellMutation.mutate(shell.id);
1✔
52
  };
1✔
53

54
  const statusColor = shell.status === 'active' ? 'green' : shell.status === 'error' ? 'red' : 'gray';
31!
55

56
  return (
31✔
57
    <>
31✔
58
      <Group gap={0} wrap="nowrap">
31✔
59
        <UnstyledButton
31✔
60
          onClick={handleClick}
31✔
61
          style={{
31✔
62
            flex: 1,
31✔
63
            padding: '6px 10px',
31✔
64
            borderRadius: 'var(--mantine-radius-sm)',
31✔
65
            backgroundColor: isActive ? 'var(--mantine-color-dark-5)' : 'transparent',
31✔
66
            display: 'flex',
31✔
67
            alignItems: 'center',
31✔
68
            gap: 8,
31✔
69
          }}
31✔
70
          className="shell-item"
31✔
71
          data-testid="shell-item"
31✔
72
        >
73
          <IconTerminal2 size={14} style={{ flexShrink: 0, color: 'var(--mantine-color-green-4)' }} />
31✔
74
          <Text size="xs" truncate style={{ flex: 1 }}>
31✔
75
            {shell.name}
31✔
76
          </Text>
31✔
77
          <Badge size="xs" variant="dot" color={statusColor}>
31✔
78
            {shell.status}
31✔
79
          </Badge>
31✔
80
        </UnstyledButton>
31✔
81

82
        <Menu position="bottom-end" withinPortal>
31✔
83
          <Menu.Target>
31✔
84
            <ActionIcon
31✔
85
              variant="subtle"
31✔
86
              size="xs"
31✔
87
              onClick={(e) => { e.stopPropagation(); }}
31✔
88
            >
89
              <IconDots size={12} />
31✔
90
            </ActionIcon>
31✔
91
          </Menu.Target>
31✔
92
          <Menu.Dropdown>
31✔
93
            <Menu.Item
31✔
94
              leftSection={<IconPencil size={14} />}
31✔
95
              onClick={handleRenameClick}
31✔
96
            >
31✔
97
              Rename
98
            </Menu.Item>
31✔
99
            <Menu.Item
31✔
100
              leftSection={<IconRefresh size={14} />}
31✔
101
              onClick={handleRestart}
31✔
102
            >
31✔
103
              Restart
104
            </Menu.Item>
31✔
105
            <Menu.Divider />
31✔
106
            <Menu.Item
31✔
107
              color="red"
31✔
108
              leftSection={<IconTrash size={14} />}
31✔
109
              onClick={handleDelete}
31✔
110
            >
31✔
111
              Close Shell
112
            </Menu.Item>
31✔
113
          </Menu.Dropdown>
31✔
114
        </Menu>
31✔
115
      </Group>
31✔
116

117
      <Modal
31✔
118
        opened={renameModalOpen}
31✔
119
        onClose={() => { setRenameModalOpen(false); }}
31✔
120
        title="Rename Shell"
31✔
121
        size="sm"
31✔
122
      >
123
        <Stack>
31✔
124
          <TextInput
31✔
125
            label="Shell name"
31✔
126
            value={newName}
31✔
127
            onChange={(e) => { setNewName(e.currentTarget.value); }}
31✔
128
            placeholder="Enter shell name"
31✔
129
            autoFocus
31✔
130
            onKeyDown={(e) => {
31✔
131
              if (e.key === 'Enter') {
8!
NEW
132
                handleRenameSubmit();
×
NEW
133
              }
×
134
            }}
8✔
135
          />
31✔
136
          <Group justify="flex-end">
31✔
137
            <Button variant="subtle" onClick={() => { setRenameModalOpen(false); }}>
31✔
138
              Cancel
139
            </Button>
31✔
140
            <Button onClick={handleRenameSubmit} loading={updateShellMutation.isPending}>
31✔
141
              Rename
142
            </Button>
31✔
143
          </Group>
31✔
144
        </Stack>
31✔
145
      </Modal>
31✔
146
    </>
31✔
147
  );
148
}
31✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc