Skip to content

Commit 9311871

Browse files
committed
add guides list w/ targeting and archived indicators
1 parent 1b10cb1 commit 9311871

8 files changed

Lines changed: 518 additions & 24 deletions

File tree

packages/client/src/clients/guide/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ export { KnockGuideClient, DEBUG_QUERY_PARAMS } from "./client";
22
export type {
33
KnockGuide,
44
KnockGuideStep,
5+
GuideIneligibilityMarker as KnockGuideIneligibilityMarker,
56
TargetParams as KnockGuideTargetParams,
67
SelectFilterParams as KnockGuideFilterParams,
78
SelectGuideOpts as KnockSelectGuideOpts,
89
SelectGuidesOpts as KnockSelectGuidesOpts,
10+
StoreState as KnockGuideClientStoreState,
911
} from "./types";

packages/react/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,12 @@
7676
"@knocklabs/react-core": "workspace:^",
7777
"@popperjs/core": "^2.11.8",
7878
"@radix-ui/react-dialog": "^1.1.15",
79+
"@radix-ui/react-hover-card": "^1.1.15",
7980
"@telegraph/combobox": "^0.1.16",
8081
"@telegraph/icon": "^0.2.7",
8182
"@telegraph/layout": "^0.2.3",
8283
"@telegraph/tokens": "^0.1.2",
84+
"@telegraph/tooltip": "0.0.61",
8385
"@telegraph/typography": "^0.1.25",
8486
"clsx": "^2.1.1",
8587
"lodash.debounce": "^4.0.8"
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import * as HoverCard from "@radix-ui/react-hover-card";
2+
import { Box, Stack } from "@telegraph/layout";
3+
import * as React from "react";
4+
5+
import { InspectedGuide, MissingGuide } from "./useInspectGuideClientStore";
6+
7+
type Props = {
8+
guide: InspectedGuide | MissingGuide;
9+
};
10+
11+
export const GuideHoverCard = ({
12+
children,
13+
guide,
14+
}: React.PropsWithChildren<Props>) => {
15+
return (
16+
<HoverCard.Root>
17+
<HoverCard.Trigger>
18+
<Stack align="center">{children}</Stack>
19+
</HoverCard.Trigger>
20+
<HoverCard.Portal>
21+
<HoverCard.Content sideOffset={44} side="left">
22+
<Box
23+
px="2"
24+
shadow="2"
25+
rounded="3"
26+
border="px"
27+
overflow="auto"
28+
style={{
29+
width: "450px",
30+
maxHeight: "600px",
31+
}}
32+
>
33+
<pre
34+
style={{
35+
fontSize: "12px",
36+
}}
37+
>
38+
{/* TODO: Prune some details */}
39+
<code>{JSON.stringify(guide, null, 2)}</code>
40+
</pre>
41+
</Box>
42+
<HoverCard.Arrow />
43+
</HoverCard.Content>
44+
</HoverCard.Portal>
45+
</HoverCard.Root>
46+
);
47+
};
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { Button } from "@telegraph/button";
2+
import { Stack } from "@telegraph/layout";
3+
import { Tag } from "@telegraph/tag";
4+
import { Tooltip } from "@telegraph/tooltip";
5+
import { Text } from "@telegraph/typography";
6+
import { CheckCircle2, CircleDashed, Eye, UserCircle2 } from "lucide-react";
7+
import * as React from "react";
8+
9+
import { GuideHoverCard } from "./GuideHoverCard";
10+
import { InspectedGuide, MissingGuide } from "./useInspectGuideClientStore";
11+
12+
const Row = ({ children }: React.PropsWithChildren) => (
13+
<Stack h="7" px="2" borderTop="px" justify="space-between" align="center">
14+
{children}
15+
</Stack>
16+
);
17+
18+
type Props = {
19+
guide: MissingGuide | InspectedGuide;
20+
orderIndex: number;
21+
};
22+
23+
export const GuideRow = ({ guide, orderIndex }: Props) => {
24+
return (
25+
<Row>
26+
<Stack h="6" justify="flex-start" align="center" gap="2">
27+
<Tag
28+
size="0"
29+
variant="soft"
30+
color={guide.bypass_global_group_limit ? "blue" : "default"}
31+
>
32+
{orderIndex + 1}
33+
</Tag>
34+
<GuideHoverCard guide={guide}>
35+
<Text as="code" size="1" color={guide.active ? "black" : "disabled"}>
36+
{guide.key}
37+
</Text>
38+
</GuideHoverCard>
39+
</Stack>
40+
41+
<Stack gap="1" justify="flex-end">
42+
{guide.__typename === "Guide" && (
43+
<>
44+
<Tooltip
45+
label={
46+
!guide.inspection.targetable.status &&
47+
guide.inspection.targetable.message
48+
}
49+
enabled={!guide.inspection.targetable.status}
50+
>
51+
<Button
52+
px="1"
53+
size="1"
54+
variant="soft"
55+
color={guide.inspection.targetable.status ? "green" : "red"}
56+
leadingIcon={{ icon: UserCircle2, alt: "Target" }}
57+
/>
58+
</Tooltip>
59+
<Tooltip
60+
label="User has already archived this guide"
61+
enabled={guide.inspection.archived.status}
62+
>
63+
<Button
64+
px="1"
65+
size="1"
66+
variant="soft"
67+
color={guide.inspection.archived.status ? "red" : "green"}
68+
leadingIcon={{ icon: Eye, alt: "Not archived" }}
69+
/>
70+
</Tooltip>
71+
</>
72+
)}
73+
<Tooltip
74+
label={
75+
guide.__typename === "MissingGuide"
76+
? "This guide has never been committed and published yet"
77+
: "This guide is not active"
78+
}
79+
enabled={!guide.active}
80+
>
81+
<Button
82+
px="1"
83+
size="1"
84+
variant="soft"
85+
color={guide.active ? "green" : "red"}
86+
leadingIcon={
87+
guide.active
88+
? { icon: CheckCircle2, alt: "Active" }
89+
: { icon: CircleDashed, alt: "Inactive" }
90+
}
91+
/>
92+
</Tooltip>
93+
</Stack>
94+
</Row>
95+
);
96+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Select } from "@telegraph/select";
2+
3+
import { MAX_Z_INDEX } from "../shared";
4+
5+
export type DisplayOption = "current-page" | "all-eligible" | "all-guides";
6+
7+
type Props = {
8+
value: DisplayOption;
9+
onChange: (option: DisplayOption) => void;
10+
};
11+
12+
export const GuidesListDisplaySelect = ({ value, onChange }: Props) => {
13+
return (
14+
<Select.Root
15+
size="1"
16+
value={value}
17+
onValueChange={(value) => {
18+
if (!value) return;
19+
onChange(value as DisplayOption);
20+
}}
21+
contentProps={{
22+
style: { zIndex: MAX_Z_INDEX },
23+
}}
24+
>
25+
{/*
26+
<Select.Option size="1" value="current-page">
27+
Present and activated on current page
28+
</Select.Option>
29+
*/}
30+
<Select.Option size="1" value="all-eligible">
31+
All eligible guides for user
32+
</Select.Option>
33+
<Select.Option size="1" value="all-guides">
34+
All existing guides
35+
</Select.Option>
36+
</Select.Root>
37+
);
38+
};

packages/react/src/modules/guide/components/Toolbar/V2/V2.tsx

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,30 @@
1-
import { useGuideContext, useStore } from "@knocklabs/react-core";
1+
import { useGuideContext } from "@knocklabs/react-core";
22
import { Button } from "@telegraph/button";
33
import { Box, Stack } from "@telegraph/layout";
4-
import { Text } from "@telegraph/typography";
54
import { Minimize2, Undo2 } from "lucide-react";
65
import React from "react";
76

87
import { KnockButton } from "../KnockButton";
9-
import { MAX_Z_INDEX } from "../shared";
8+
// import { MAX_Z_INDEX } from "../shared";
109
import "../styles.css";
1110

11+
import { GuideRow } from "./GuideRow";
12+
import {
13+
DisplayOption,
14+
GuidesListDisplaySelect,
15+
} from "./GuidesListDisplaySelect";
1216
import { detectToolbarParam } from "./helpers";
13-
14-
const useInspectGuideClientStore = () => {
15-
const { client } = useGuideContext();
16-
17-
const snapshot = useStore(client.store, (state) => {
18-
return {
19-
debug: state.debug,
20-
};
21-
});
22-
23-
if (!snapshot.debug?.debugging) {
24-
return;
25-
}
26-
27-
// TODO: Transform the raw client state into more useful data for debugging.
28-
return {};
29-
};
17+
import {
18+
checkEligible,
19+
useInspectGuideClientStore,
20+
} from "./useInspectGuideClientStore";
3021

3122
export const V2 = () => {
3223
const { client } = useGuideContext();
3324

25+
const [guidesListDisplayed, setGuidesListDisplayed] =
26+
React.useState<DisplayOption>("all-eligible");
27+
3428
const [isVisible, setIsVisible] = React.useState(detectToolbarParam());
3529
const [isCollapsed, setIsCollapsed] = React.useState(true);
3630

@@ -53,11 +47,14 @@ export const V2 = () => {
5347

5448
return (
5549
<Box
50+
id="knock-guide-toolbar-v2"
5651
position="fixed"
5752
top="4"
5853
right="4"
5954
style={{
60-
zIndex: MAX_Z_INDEX,
55+
// zIndex: MAX_Z_INDEX
56+
// Match the hardcoded z-index value in tooltip
57+
zIndex: 1800,
6158
}}
6259
>
6360
{isCollapsed ? (
@@ -80,9 +77,10 @@ export const V2 = () => {
8077
style={{ boxSizing: "border-box" }}
8178
>
8279
<Box style={{ width: "220px" }}>
83-
<Text as="div" size="1" weight="medium" w="full" maxWidth="40">
84-
Toolbar v2 placeholder
85-
</Text>
80+
<GuidesListDisplaySelect
81+
value={guidesListDisplayed}
82+
onChange={(selected) => setGuidesListDisplayed(selected)}
83+
/>
8684
</Box>
8785

8886
<Stack gap="2">
@@ -102,6 +100,22 @@ export const V2 = () => {
102100
/>
103101
</Stack>
104102
</Stack>
103+
104+
<Box w="full">
105+
{data.error && <Box>{data.error}</Box>}
106+
{data.guides.map((guide, idx) => {
107+
if (
108+
guidesListDisplayed === "all-eligible" &&
109+
!checkEligible(guide)
110+
) {
111+
return null;
112+
}
113+
114+
return (
115+
<GuideRow key={guide.key} guide={guide} orderIndex={idx} />
116+
);
117+
})}
118+
</Box>
105119
</Stack>
106120
)}
107121
</Box>

0 commit comments

Comments
 (0)