Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit e1c5a04

Browse files
feat: added filters and outward linking from tables
1 parent 6cad9c1 commit e1c5a04

23 files changed

+682
-51
lines changed

src/renderer/App.tsx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ import './styles/app.css';
2020
// OTHER
2121
import client from './graphql/client';
2222
import Layout from './components/Layout';
23+
import Filters from './components/Filters/Filters';
2324
import { UserProvider } from './components/UserContext';
2425
import { ThemeProvider } from './components/ThemeContext';
26+
import { FiltersProvider } from './components/FiltersContext';
2527

2628
export default function App() {
2729
return (
@@ -31,21 +33,26 @@ export default function App() {
3133
<ThemeProvider>
3234
<Router>
3335
<Layout>
34-
<Routes>
35-
<Route path="/" element={<Home />} />
36-
<Route path="/my-snippets" element={<MySnippets />} />
37-
<Route
38-
path="/favorite-snippets"
39-
element={<FavoriteSnippets />}
40-
/>
41-
<Route path="/my-cookbooks" element={<MyCookbooks />} />
42-
<Route
43-
path="/favorite-cookbooks"
44-
element={<FavoriteCookbooks />}
45-
/>
46-
<Route path="/team-snippets" element={<TeamSnippets />} />
47-
<Route path="/team-cookbooks" element={<TeamCookbooks />} />
48-
</Routes>
36+
<FiltersProvider>
37+
<Filters />
38+
39+
<Routes>
40+
<Route path="/" element={<Home />} />
41+
42+
<Route path="/my-snippets" element={<MySnippets />} />
43+
<Route
44+
path="/favorite-snippets"
45+
element={<FavoriteSnippets />}
46+
/>
47+
<Route path="/my-cookbooks" element={<MyCookbooks />} />
48+
<Route
49+
path="/favorite-cookbooks"
50+
element={<FavoriteCookbooks />}
51+
/>
52+
<Route path="/team-snippets" element={<TeamSnippets />} />
53+
<Route path="/team-cookbooks" element={<TeamCookbooks />} />
54+
</Routes>
55+
</FiltersProvider>
4956
</Layout>
5057
</Router>
5158
</ThemeProvider>

src/renderer/components/CookbookTable/CookbookTable.tsx

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@ import {
88
Tbody,
99
Td as ChakraTd,
1010
TableCellProps,
11+
Link,
1112
} from '@chakra-ui/react';
1213
import {
1314
LockIcon,
1415
Avatar,
1516
UsersIcon,
1617
CodeIcon,
1718
} from '@codiga/codiga-components';
18-
import { AssistantCookbook } from 'renderer/types/assistantTypes';
19+
20+
import { getCookbookUrl, getGroupUrl } from 'renderer/utils/urlUtils';
1921
import { getAvatarUrl } from 'renderer/utils/userUtils';
22+
import { AssistantCookbook } from 'renderer/types/assistantTypes';
23+
import { PageTypes } from 'renderer/types/pageTypes';
2024
import FavoriteCookbook from 'renderer/components/Favorite/FavoriteCookbook';
25+
import UserLink from 'renderer/components/UserLink';
2126

2227
const Td = (props: TableCellProps) => (
2328
<ChakraTd
@@ -31,9 +36,10 @@ const Td = (props: TableCellProps) => (
3136

3237
type CookbookTableProps = {
3338
cookbooks: AssistantCookbook[];
39+
page: PageTypes;
3440
};
3541

36-
export default function CookbookTable({ cookbooks }: CookbookTableProps) {
42+
export default function CookbookTable({ cookbooks, page }: CookbookTableProps) {
3743
return (
3844
<Box w="full" overflow="auto">
3945
<TableContainer>
@@ -55,23 +61,46 @@ export default function CookbookTable({ cookbooks }: CookbookTableProps) {
5561
>
5662
<Td>
5763
<Flex alignItems="center" gap="space_8">
58-
<Text size="sm" noOfLines={1}>
59-
{cookbook.name}
64+
<Text
65+
size="sm"
66+
noOfLines={1}
67+
maxWidth="300px"
68+
display="inline-block"
69+
>
70+
<Link
71+
isExternal
72+
variant="subtle"
73+
href={getCookbookUrl(
74+
page,
75+
cookbook.id,
76+
cookbook.groups?.length
77+
? cookbook.groups[0].id
78+
: undefined
79+
)}
80+
>
81+
{cookbook.name}
82+
</Link>
6083
</Text>
61-
{!cookbook.groups && (
62-
<FavoriteCookbook
63-
isSubscribed={!!cookbook.isSubscribed}
64-
cookbookId={cookbook.id}
65-
/>
66-
)}
84+
<FavoriteCookbook
85+
isSubscribed={!!cookbook.isSubscribed}
86+
cookbookId={cookbook.id}
87+
/>
6788
</Flex>
6889
</Td>
6990
{cookbook.groups && cookbook.groups.length > 0 && (
7091
<Td>
7192
<Flex alignItems="center" gap="space_8">
7293
<UsersIcon />
7394
<Text size="xs" noOfLines={1}>
74-
{cookbook?.groups[0]?.name}
95+
<Link
96+
isExternal
97+
variant="subtle"
98+
href={`${getGroupUrl(
99+
cookbook.groups[0].id!
100+
)}/cookbooks`}
101+
>
102+
{cookbook.groups[0].name}
103+
</Link>
75104
</Text>
76105
</Flex>
77106
</Td>
@@ -95,7 +124,7 @@ export default function CookbookTable({ cookbooks }: CookbookTableProps) {
95124
src={getAvatarUrl({ id: cookbook.owner?.id })}
96125
/>
97126
<Text size="xs" noOfLines={1}>
98-
{cookbook.owner?.displayName || 'Anonymous'}
127+
<UserLink owner={cookbook.owner} />
99128
</Text>
100129
</Flex>
101130
</Td>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Button, Flex, Link } from '@chakra-ui/react';
2+
import { EmptyState } from '@codiga/codiga-components';
3+
import { APP_URL } from 'renderer/lib/config';
4+
import { useFilters } from '../FiltersContext';
5+
6+
export default function CookbookTableEmptyFiltereed() {
7+
const { resetAllFilters } = useFilters();
8+
9+
return (
10+
<EmptyState
11+
title="No cookbooks match that criteria"
12+
description="You don't have any cookbooks that match your filter criteria."
13+
illustration="empty"
14+
py="space_64"
15+
>
16+
<Flex gridGap="space_16">
17+
<Button variant="secondary" size="sm" onClick={resetAllFilters}>
18+
Clear Filters
19+
</Button>
20+
<Link
21+
isExternal
22+
href={`${APP_URL}/assistant/cookbook/create`}
23+
variant="primary"
24+
size="sm"
25+
>
26+
Create Cookbook
27+
</Link>
28+
</Flex>
29+
</EmptyState>
30+
);
31+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import {
2+
IconButton,
3+
Box,
4+
Collapse,
5+
useDisclosure,
6+
Tooltip,
7+
HStack,
8+
Input,
9+
Radio,
10+
Checkbox,
11+
Text,
12+
Flex,
13+
} from '@chakra-ui/react';
14+
import {
15+
ChevronDownIcon,
16+
ChevronUpIcon,
17+
LanguageSelector,
18+
LibrarySelector,
19+
} from '@codiga/codiga-components';
20+
import { useFilters } from 'renderer/components/FiltersContext';
21+
import { ALL_LANGUAGES } from 'renderer/lib/constants';
22+
import {
23+
LanguageEnumeration,
24+
LibraryEnumeration,
25+
} from 'renderer/types/assistantTypes';
26+
27+
export default function Filters() {
28+
const { isOpen, onToggle } = useDisclosure();
29+
const {
30+
searchTerm,
31+
setSearchTerm,
32+
language,
33+
setLanguage,
34+
library,
35+
setLibrary,
36+
privacy,
37+
setPrivacy,
38+
isSubscribed,
39+
setIsSubscribed,
40+
tags,
41+
setTags,
42+
} = useFilters();
43+
44+
return (
45+
<Box bg="neutral.25" _dark={{ bg: 'base.dark' }}>
46+
<HStack w="full" spacing="space_16" py="space_16" pr="space_16">
47+
<Input
48+
flex={1}
49+
minWidth="200px"
50+
maxWidth="400px"
51+
placeholder="Search"
52+
value={searchTerm}
53+
onChange={(e) => setSearchTerm(e.target.value)}
54+
/>
55+
<LanguageSelector
56+
minW="150px"
57+
value={language || ''}
58+
options={['', ...ALL_LANGUAGES]}
59+
emptyLabel="All Languages"
60+
onChange={(newLanguage) => {
61+
setLanguage(newLanguage as LanguageEnumeration);
62+
setLibrary('' as LibraryEnumeration);
63+
}}
64+
labelProps={{ hidden: true, children: 'Filter by language' }}
65+
/>
66+
<LibrarySelector
67+
minW="150px"
68+
isCreatable
69+
value={library || ''}
70+
language={language || ''}
71+
onChange={(newLibrary) =>
72+
setLibrary(newLibrary as LibraryEnumeration)
73+
}
74+
emptyLabel="No library"
75+
isDisabled={!language}
76+
labelProps={{
77+
fontSize: 'md',
78+
fontWeight: 'bold',
79+
hidden: true,
80+
}}
81+
/>
82+
<Tooltip label="More Filters" isDisabled={isOpen}>
83+
<IconButton
84+
size="xs"
85+
variant="unstyled"
86+
aria-label="Open more filter options"
87+
icon={isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
88+
onClick={onToggle}
89+
/>
90+
</Tooltip>
91+
</HStack>
92+
93+
<Collapse in={isOpen}>
94+
<Flex gridGap="space_16" mb="space_16" flexWrap="wrap" pr="space_16">
95+
<Input
96+
flex={1}
97+
minWidth="200px"
98+
maxWidth="400px"
99+
placeholder="Search by tags"
100+
value={tags}
101+
onChange={(e) => setTags(e.target.value)}
102+
/>
103+
<Flex flexWrap="nowrap" gridRowGap="0" gridColumnGap="space_16">
104+
<Radio
105+
isChecked={privacy === 'all'}
106+
onChange={() => setPrivacy('all')}
107+
mb={0}
108+
>
109+
<Text as="span" size="sm" fontFamily="body">
110+
All
111+
</Text>
112+
</Radio>
113+
<Radio
114+
isChecked={privacy === 'public'}
115+
onChange={() => setPrivacy('public')}
116+
mb={0}
117+
>
118+
<Text as="span" size="sm" fontFamily="body">
119+
Public
120+
</Text>
121+
</Radio>
122+
<Radio
123+
isChecked={privacy === 'private'}
124+
onChange={() => setPrivacy('private')}
125+
mb={0}
126+
>
127+
<Text as="span" size="sm" fontFamily="body">
128+
Private
129+
</Text>
130+
</Radio>
131+
<Checkbox
132+
checked={isSubscribed}
133+
onChange={(e) => setIsSubscribed(e.target.checked)}
134+
mb={0}
135+
>
136+
<Text as="span" size="sm" fontFamily="body">
137+
Favorites only
138+
</Text>
139+
</Checkbox>
140+
</Flex>
141+
</Flex>
142+
</Collapse>
143+
</Box>
144+
);
145+
}

0 commit comments

Comments
 (0)