Skip to content

Commit d11440d

Browse files
committed
added files
1 parent 8ec180f commit d11440d

2 files changed

Lines changed: 248 additions & 0 deletions

File tree

src/components/HashIcon.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Flex } from "@radix-ui/themes";
2+
3+
interface HashIconProps {
4+
size?: number | string;
5+
width?: number | string;
6+
height?: number | string;
7+
color?: string;
8+
}
9+
10+
export default function HashIcon({
11+
size,
12+
width,
13+
height,
14+
color = 'currentColor'
15+
}: HashIconProps) {
16+
17+
const w = width || size || 16;
18+
const h = height || size || 16;
19+
20+
const numericHeight = typeof h === 'number'
21+
? h
22+
: parseInt(h, 10) || 16;
23+
24+
const calculatedFontSize = Math.max(10, Math.floor(numericHeight * 1.0));
25+
26+
return (
27+
<Flex
28+
align="center"
29+
justify="center"
30+
style={{
31+
width: typeof w === 'number' ? `${w}px` : w,
32+
height: typeof h === 'number' ? `${h}px` : h,
33+
color: color,
34+
fontSize: `${calculatedFontSize}px`,
35+
fontWeight: 'bold',
36+
fontFamily: 'monospace',
37+
userSelect: 'none',
38+
lineHeight: 1,
39+
}}
40+
title="Integer"
41+
>
42+
#
43+
</Flex>
44+
);
45+
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import { useCallback, useEffect, useMemo, useState } from 'react';
2+
import { Flex, Text, Card, Box, IconButton, Tooltip, TextField } from '@radix-ui/themes';
3+
import { UpdateIcon, DividerHorizontalIcon, Cross2Icon, QuoteIcon, CubeIcon, TokensIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons';
4+
import { useActiveWorkspaceId, useWebSocket } from '../../hooks';
5+
import type { Enum } from '../../types';
6+
import { errStr } from '../../utils';
7+
import HashIcon from '../HashIcon';
8+
// import EnumModal from './EnumModal';
9+
10+
interface EnumsPanelProps {
11+
scope: string;
12+
}
13+
14+
export default function EnumsPanel({ scope }: EnumsPanelProps) {
15+
const { emit } = useWebSocket();
16+
const activeId = useActiveWorkspaceId();
17+
const [enums, setEnums] = useState<Enum[]>([]);
18+
const [isLoading, setIsLoading] = useState(false);
19+
const [fetchError, setFetchError] = useState<string | null>(null);
20+
const [searchQuery, setSearchQuery] = useState('');
21+
const [viewEnum, setViewEnum] = useState<Enum | null>(null);
22+
23+
const fetchEnums = useCallback(async () => {
24+
setIsLoading(true);
25+
setFetchError(null);
26+
try {
27+
const response = await emit('FETCH_ENUMS', { id: activeId, scope }) as Enum[];
28+
setEnums(response || []);
29+
} catch (err: unknown) {
30+
console.error("Failed to fetch enums:", err);
31+
setFetchError(errStr(err, "Failed to fetch enums."));
32+
} finally {
33+
setIsLoading(false);
34+
}
35+
}, [activeId, emit, scope]);
36+
37+
useEffect(() => {
38+
queueMicrotask(fetchEnums);
39+
}, [fetchEnums]);
40+
41+
const filtered = useMemo(() => {
42+
const cleanedQuery = searchQuery.trim().toLowerCase();
43+
if (!cleanedQuery) {
44+
return enums;
45+
}
46+
47+
return enums.filter((enu) => {
48+
const nameMatch = enu.name?.toLowerCase().includes(cleanedQuery);
49+
50+
return nameMatch;
51+
});
52+
}, [enums, searchQuery]);
53+
54+
return (
55+
<Flex direction="column" gap="3">
56+
<Flex justify="between" align="center" mt="2">
57+
<Text size="1" color="gray" weight="bold" mt="2">
58+
ENUMS ({isLoading ? '...' : filtered.length})
59+
</Text>
60+
<Tooltip content="Refresh enums list">
61+
<IconButton
62+
size="1"
63+
variant="soft"
64+
color="gray"
65+
disabled={isLoading}
66+
onClick={fetchEnums}
67+
style={{ cursor: isLoading ? 'not-allowed' : 'pointer' }}
68+
>
69+
<UpdateIcon width="13" height="13" className={isLoading ? 'animate-spin' : ''} />
70+
</IconButton>
71+
</Tooltip>
72+
</Flex>
73+
74+
{(enums.length > 0 || searchQuery) && (
75+
<TextField.Root
76+
placeholder="Search name..."
77+
value={searchQuery}
78+
onChange={(e) => setSearchQuery(e.target.value)}
79+
size="1"
80+
>
81+
<TextField.Slot>
82+
<MagnifyingGlassIcon height="14" width="14" />
83+
</TextField.Slot>
84+
{searchQuery && (
85+
<TextField.Slot style={{ paddingRight: '4px' }}>
86+
<IconButton
87+
size="1"
88+
variant="ghost"
89+
color="gray"
90+
onClick={() => setSearchQuery('')}
91+
style={{ cursor: 'pointer', height: '16px', width: '16px' }}
92+
>
93+
<Cross2Icon height="12" width="12" />
94+
</IconButton>
95+
</TextField.Slot>
96+
)}
97+
</TextField.Root>
98+
)}
99+
100+
{fetchError && enums.length === 0 && !isLoading && (
101+
<Box
102+
py="3"
103+
px="2"
104+
style={{
105+
backgroundColor: 'var(--red-2)',
106+
borderRadius: 'var(--radius-2)',
107+
border: '1px dashed var(--red-4)',
108+
textAlign: 'center',
109+
}}
110+
>
111+
<Text size="1" color="red">{fetchError}</Text>
112+
</Box>
113+
)}
114+
115+
{!fetchError && enums.length === 0 && !isLoading && (
116+
<Box
117+
py="3"
118+
px="2"
119+
style={{
120+
textAlign: 'center',
121+
border: '1px dashed var(--gray-5)',
122+
borderRadius: 'var(--radius-2)'
123+
}}
124+
>
125+
<Text size="1" color="gray">No enums found in this scope.</Text>
126+
</Box>
127+
)}
128+
129+
{!fetchError && enums.length > 0 && filtered.length === 0 && (
130+
<Box
131+
py="3"
132+
px="2"
133+
style={{
134+
textAlign: 'center',
135+
border: '1px dashed var(--gray-5)',
136+
borderRadius: 'var(--radius-2)'
137+
}}
138+
>
139+
<Text size="1" color="gray" >No matching enums match your query.</Text>
140+
</Box>
141+
)}
142+
143+
{!fetchError && isLoading && enums.length === 0 && (
144+
<Flex justify="center" py="2">
145+
<Text size="1" color="gray" className="animate-pulse">Loading enums...</Text>
146+
</Flex>
147+
)}
148+
149+
<Flex direction="column" gap="2">
150+
{filtered.map((enu) => {
151+
152+
return (
153+
<Card
154+
key={enu.name}
155+
size="1"
156+
style={{
157+
padding: '6px 8px',
158+
backgroundColor: 'var(--gray-2)',
159+
borderColor: 'var(--gray-4)',
160+
cursor: 'pointer',
161+
}}
162+
onClick={() => setViewEnum(enu)}
163+
>
164+
<Flex direction="column" gap="2">
165+
<Flex align="center" justify="between" gap="2">
166+
<Tooltip content={enu.name}>
167+
<Text
168+
size="1"
169+
weight="bold"
170+
truncate
171+
style={{
172+
fontFamily: 'monospace',
173+
color: 'var(--gray-12)',
174+
minWidth: 0,
175+
flexGrow: 1
176+
}}
177+
>
178+
{enu.name}
179+
</Text>
180+
</Tooltip>
181+
182+
{enu.type === 'str' && <QuoteIcon color='var(--iris-5)' width="14" height="14" />}
183+
{enu.type === 'int' && <HashIcon color='var(--iris-5)' width="14" height="14" />}
184+
{enu.type === 'float' && <DividerHorizontalIcon color='var(--iris-5)' width="14" height="14" />}
185+
{enu.type === 'bytes' && <TokensIcon color='var(--iris-5)' width="14" height="14" />}
186+
{enu.type === 'thing' && <CubeIcon color='var(--iris-5)' width="14" height="14" />}
187+
</Flex>
188+
</Flex>
189+
</Card>
190+
);
191+
})}
192+
</Flex>
193+
{viewEnum && <>{null}</>}
194+
{/* {viewEnum && (
195+
<EnumModal
196+
onClose={() => setViewEnum(null)}
197+
scope={scope}
198+
enum={viewEnum}
199+
/>
200+
)} */}
201+
</Flex>
202+
);
203+
}

0 commit comments

Comments
 (0)