Skip to content

Commit 549b534

Browse files
drew-harrisskeptrunedev
authored andcommitted
feat: add ui for new table system
1 parent 0afd3bb commit 549b534

5 files changed

Lines changed: 593 additions & 341 deletions

File tree

clients/trieve-shopify-extension/app/components/analytics/AdvancedTableComponent.tsx

Lines changed: 85 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@ import {
1313
Page,
1414
InlineStack,
1515
} from "@shopify/polaris";
16-
import {
17-
Link
18-
} from "@remix-run/react";
16+
import { Link } from "@remix-run/react";
1917
import { IndexTableHeading } from "@shopify/polaris/build/ts/src/components/IndexTable";
2018
import { NonEmptyArray } from "@shopify/polaris/build/ts/src/types";
2119
import {
2220
ChevronUpIcon,
2321
ChevronDownIcon,
2422
ViewIcon,
25-
} from '@shopify/polaris-icons';
26-
23+
} from "@shopify/polaris-icons";
24+
import { ReactNode } from "react";
25+
import { add } from "date-fns";
2726

2827
export interface Filter {
2928
key: string;
@@ -43,14 +42,14 @@ export interface AdvancedTableComponentProps {
4342
setPage: (page: (page: number) => number) => void;
4443
tabs: string[];
4544
label: string;
46-
tableHeadings: { heading: string, tooltip: string, sortCol?: string }[];
47-
sortOptions: IndexFiltersProps['sortOptions'];
45+
tableHeadings: { heading: string; tooltip: string; sortCol?: string }[];
46+
sortOptions: IndexFiltersProps["sortOptions"];
4847
sortSelected: string[];
4948
setSortSelected: (sortSelected: string[]) => void;
5049
tooltipContent: string;
5150
hasNext: boolean;
5251
loading: boolean;
53-
appliedFilters: IndexFiltersProps['appliedFilters'];
52+
appliedFilters: IndexFiltersProps["appliedFilters"];
5453
filters: Filter[];
5554
query: string;
5655
setQuery: (query: string) => void;
@@ -60,6 +59,7 @@ export interface AdvancedTableComponentProps {
6059
sortableColumns?: boolean[];
6160
onSort?: (index: number, direction: "ascending" | "descending") => void;
6261
disableSearch?: boolean;
62+
additionalControls?: ReactNode;
6363
}
6464

6565
export const AdvancedTableComponent = ({
@@ -85,6 +85,7 @@ export const AdvancedTableComponent = ({
8585
sortSelected,
8686
setSortSelected,
8787
disableSearch,
88+
additionalControls,
8889
}: AdvancedTableComponentProps) => {
8990
const { mode, setMode } = useSetIndexFiltersMode();
9091

@@ -96,37 +97,44 @@ export const AdvancedTableComponent = ({
9697
}));
9798

9899
return (
99-
<Page
100-
title={label}
101-
fullWidth={true}
102-
>
100+
<Page title={label} fullWidth={true}>
103101
<Card>
104102
<Box minHeight="14px">
105-
<IndexFilters
106-
sortOptions={sortOptions}
107-
sortSelected={sortSelected}
108-
onSort={setSortSelected}
109-
mode={mode}
110-
setMode={setMode}
111-
tabs={indexTabs}
112-
filters={filters.map((filter) => ({ ...filter, shortcut: true }))}
113-
queryValue={query}
114-
cancelAction={{
115-
onAction: () => { },
116-
disabled: false,
117-
loading: false,
118-
}}
119-
borderlessQueryField={false}
120-
appliedFilters={appliedFilters}
121-
onQueryChange={setQuery}
122-
onQueryClear={() => setQuery('')}
123-
onClearAll={handleClearAll}
124-
selected={selected}
125-
onSelect={setSelected}
126-
loading={loading}
127-
canCreateNewView={false}
128-
hideQueryField={disableSearch}
129-
/>
103+
<div className="flex justify-end">
104+
<div className="grow border-b border-b-neutral-200 flex items-end pb-1">
105+
{additionalControls}
106+
</div>
107+
<div className="shrink-0">
108+
<IndexFilters
109+
sortOptions={sortOptions}
110+
sortSelected={sortSelected}
111+
onSort={setSortSelected}
112+
mode={mode}
113+
setMode={setMode}
114+
tabs={[]}
115+
filters={filters.map((filter) => ({
116+
...filter,
117+
shortcut: true,
118+
}))}
119+
queryValue={query}
120+
cancelAction={{
121+
onAction: () => {},
122+
disabled: false,
123+
loading: false,
124+
}}
125+
borderlessQueryField={false}
126+
appliedFilters={appliedFilters}
127+
onQueryChange={setQuery}
128+
onQueryClear={() => setQuery("")}
129+
onClearAll={handleClearAll}
130+
selected={selected}
131+
onSelect={setSelected}
132+
loading={loading}
133+
canCreateNewView={false}
134+
hideQueryField={disableSearch}
135+
/>
136+
</div>
137+
</div>
130138
<IndexTable
131139
hasZebraStriping
132140
condensed={useBreakpoints().smDown}
@@ -138,25 +146,34 @@ export const AdvancedTableComponent = ({
138146
tableHeadings.map((heading, index) => {
139147
return {
140148
title: (
141-
<div onClick={() => {
142-
if (heading.sortCol) {
143-
setSortSelected([`${heading.sortCol} ${sortSelected[0].split(" ")[0] === heading.sortCol ? (sortSelected[0].split(" ")[1] === "asc" ? "desc" : "asc") : "asc"}`]);
144-
}
145-
}} className={`${heading.sortCol ? "cursor-pointer" : ""}`}>
149+
<div
150+
onClick={() => {
151+
if (heading.sortCol) {
152+
setSortSelected([
153+
`${heading.sortCol} ${sortSelected[0].split(" ")[0] === heading.sortCol ? (sortSelected[0].split(" ")[1] === "asc" ? "desc" : "asc") : "asc"}`,
154+
]);
155+
}
156+
}}
157+
className={`${heading.sortCol ? "cursor-pointer" : ""}`}
158+
>
146159
<div className="flex flex-row items-center">
147160
<Tooltip content={heading.tooltip} hasUnderline>
148161
<Text as="span" variant="bodyMd" fontWeight="bold">
149162
{heading.heading}
150163
</Text>
151164
</Tooltip>
152165
{heading.sortCol && (
153-
<span className="ml-1">{sortSelected[0].split(" ")[0] === heading.sortCol ? (sortSelected[0].split(" ")[1] === "asc" ? <Icon
154-
source={ChevronUpIcon}
155-
tone="base"
156-
/> : <Icon
157-
source={ChevronDownIcon}
158-
tone="base"
159-
/>) : ""}
166+
<span className="ml-1">
167+
{sortSelected[0].split(" ")[0] ===
168+
heading.sortCol ? (
169+
sortSelected[0].split(" ")[1] === "asc" ? (
170+
<Icon source={ChevronUpIcon} tone="base" />
171+
) : (
172+
<Icon source={ChevronDownIcon} tone="base" />
173+
)
174+
) : (
175+
""
176+
)}
160177
</span>
161178
)}
162179
</div>
@@ -166,36 +183,41 @@ export const AdvancedTableComponent = ({
166183
};
167184
}) as NonEmptyArray<IndexTableHeading>
168185
}
169-
pagination={
170-
{
171-
hasNext, hasPrevious: page > 1, onNext: () => {
172-
setPage((prevPage) => prevPage + 1);
173-
}, onPrevious: () => {
174-
setPage((prevPage) => prevPage - 1);
175-
}
176-
}
177-
}
186+
pagination={{
187+
hasNext,
188+
hasPrevious: page > 1,
189+
onNext: () => {
190+
setPage((prevPage) => prevPage + 1);
191+
},
192+
onPrevious: () => {
193+
setPage((prevPage) => prevPage - 1);
194+
},
195+
}}
178196
>
179197
{data.map((row, index) => {
180198
return (
181-
<IndexTable.Row key={index} id={index.toString()} position={index}>
199+
<IndexTable.Row
200+
key={index}
201+
id={index.toString()}
202+
position={index}
203+
>
182204
{row.map((cell, innerIndex) => (
183205
<IndexTable.Cell
184206
key={innerIndex}
185207
className="max-w-[200px] truncate"
186208
>
187209
{cell.url ? (
188-
<Link
189-
to={cell.url}
190-
>
210+
<Link to={cell.url}>
191211
<InlineStack wrap={false}>
192212
<ViewIcon width={20} />
193213
<Text as="span" variant="bodyMd" truncate={true}>
194214
{cell.content}
195215
</Text>
196216
</InlineStack>
197217
</Link>
198-
) : cell.content}
218+
) : (
219+
cell.content
220+
)}
199221
</IndexTable.Cell>
200222
))}
201223
</IndexTable.Row>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { Select } from "@shopify/polaris";
2+
import { TopicEventFilter } from "trieve-ts-sdk";
3+
import { Dispatch, SetStateAction } from "react";
4+
import { KnownEventNames } from "app/utils/formatting";
5+
6+
interface EventFiltersProps {
7+
eventsFilters: TopicEventFilter;
8+
setEventsFilter: Dispatch<SetStateAction<TopicEventFilter>>;
9+
}
10+
11+
const AVAILABLE_EVENT_TYPES: { label: string; value: KnownEventNames }[] = [
12+
{ label: "Checkout", value: "site-checkout" },
13+
{ label: "Add to Cart", value: "site-add_to_cart" },
14+
];
15+
16+
const eventTypeSelectOptions = [
17+
{ label: "Any Event Type", value: "" },
18+
...AVAILABLE_EVENT_TYPES,
19+
];
20+
21+
const inclusionSelectOptions = [
22+
{ label: "Includes", value: "includes" },
23+
{ label: "Does not include", value: "excludes" },
24+
];
25+
26+
export function EventFilters({
27+
eventsFilters,
28+
setEventsFilter,
29+
}: EventFiltersProps) {
30+
const handleInvertedChange = (selectedValue: string) => {
31+
const isInverted = selectedValue === "excludes";
32+
setEventsFilter((prev) => ({
33+
...prev,
34+
inverted: isInverted,
35+
}));
36+
};
37+
38+
const handleEventTypeChange = (selectedValue: string) => {
39+
setEventsFilter((prev) => ({
40+
...prev,
41+
event_types: selectedValue ? [selectedValue as any] : [],
42+
}));
43+
};
44+
45+
const selectedInclusionValue = eventsFilters.inverted
46+
? "excludes"
47+
: "includes";
48+
49+
const selectedEventTypeValue = eventsFilters.event_types?.[0] || "";
50+
51+
return (
52+
<div className="flex items-center gap-2">
53+
<div>Chat</div>
54+
<Select
55+
labelHidden
56+
label="Includes"
57+
options={inclusionSelectOptions}
58+
onChange={handleInvertedChange}
59+
value={selectedInclusionValue}
60+
/>
61+
<Select
62+
labelHidden
63+
label="Event Type"
64+
options={eventTypeSelectOptions}
65+
onChange={handleEventTypeChange}
66+
value={selectedEventTypeValue}
67+
/>
68+
</div>
69+
);
70+
}

clients/trieve-shopify-extension/app/queries/analytics/chat.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
TopicAnalyticsFilter,
1717
PopularChatsResponse,
1818
FollowupQueriesResponse,
19+
TopicEventFilter,
1920
} from "trieve-ts-sdk";
2021

2122
export const topicsUsageQuery = (
@@ -79,22 +80,35 @@ export const allChatsQuery = (
7980
trieve: TrieveSDK,
8081
filters: RAGAnalyticsFilter,
8182
page: number,
82-
has_clicks?: boolean,
83+
topic_event_filter: TopicEventFilter,
8384
sort_by?: RAGSortBy,
8485
sort_order?: SortOrder,
8586
) => {
8687
return {
87-
queryKey: ["all_chats", filters, page, has_clicks, sort_by, sort_order],
88+
queryKey: [
89+
"all_chats",
90+
filters,
91+
page,
92+
topic_event_filter,
93+
sort_by,
94+
sort_order,
95+
],
8896
queryFn: async () => {
89-
const result = await trieve.getRagAnalytics({
97+
const result = (await trieve.getRagAnalytics({
9098
filter: filters,
9199
type: "topic_queries",
92100
page: page,
93-
has_clicks,
101+
topic_events_filter:
102+
topic_event_filter.event_types.length > 0
103+
? topic_event_filter
104+
: undefined,
94105
sort_by,
95106
sort_order,
96-
});
97-
return { topics: [] } as TopicQueriesResponse;
107+
})) as TopicQueriesResponse;
108+
return {
109+
topics: result.topics,
110+
events: result.events,
111+
} satisfies TopicQueriesResponse;
98112
},
99113
} satisfies QueryOptions;
100114
};

0 commit comments

Comments
 (0)