-
Notifications
You must be signed in to change notification settings - Fork 14
feat: add guides list to toolbar v2 w/ eligibility status indicators #846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5a6aa56
f2a6527
5121e19
bd02b99
bb961c8
2fe6b99
0d93024
355b45d
7122e8e
9e9d8c1
5822240
93306dc
4b23853
a4d0d6d
62c2d99
d39f1b1
615d0ce
445daf1
b126aa7
c51c88e
bc87d33
3aa0a9e
6f66518
35fcbe6
4a41c9b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import * as HoverCard from "@radix-ui/react-hover-card"; | ||
| import { Box, Stack } from "@telegraph/layout"; | ||
| import * as React from "react"; | ||
|
|
||
| import { | ||
| AnnotatedGuide, | ||
| UnknownGuide, | ||
| isUnknownGuide, | ||
| } from "./useInspectGuideClientStore"; | ||
|
|
||
| type Props = { | ||
| guide: AnnotatedGuide | UnknownGuide; | ||
| }; | ||
|
|
||
| export const GuideHoverCard = ({ | ||
| children, | ||
| guide, | ||
| }: React.PropsWithChildren<Props>) => { | ||
| if (isUnknownGuide(guide)) { | ||
| return <Stack align="center">{children}</Stack>; | ||
| } | ||
|
|
||
| // Prune out internal or legacy fields. | ||
| const { | ||
| annotation: _annotation, | ||
| activation_location_rules: _activation_location_rules, | ||
| priority: _priority, | ||
| ...rest | ||
| } = guide; | ||
|
|
||
| return ( | ||
| <HoverCard.Root> | ||
| <HoverCard.Trigger> | ||
| <Stack align="center">{children}</Stack> | ||
| </HoverCard.Trigger> | ||
| <HoverCard.Portal> | ||
| <HoverCard.Content sideOffset={44} side="left"> | ||
| <Box | ||
| px="2" | ||
| shadow="2" | ||
| rounded="3" | ||
| border="px" | ||
| overflow="auto" | ||
| backgroundColor="surface-2" | ||
| style={{ | ||
| width: "450px", | ||
| maxHeight: "600px", | ||
| }} | ||
| > | ||
| <pre | ||
| style={{ | ||
| fontSize: "11px", | ||
| }} | ||
| > | ||
| <code>{JSON.stringify(rest, null, 2)}</code> | ||
| </pre> | ||
| </Box> | ||
| <HoverCard.Arrow /> | ||
| </HoverCard.Content> | ||
cursor[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </HoverCard.Portal> | ||
| </HoverCard.Root> | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| import { Button } from "@telegraph/button"; | ||
| import { Stack } from "@telegraph/layout"; | ||
| import { Tag } from "@telegraph/tag"; | ||
| import { Tooltip } from "@telegraph/tooltip"; | ||
| import { Text } from "@telegraph/typography"; | ||
| import { CheckCircle2, CircleDashed, Eye, UserCircle2 } from "lucide-react"; | ||
| import * as React from "react"; | ||
|
|
||
| import { GuideHoverCard } from "./GuideHoverCard"; | ||
| import { | ||
| AnnotatedGuide, | ||
| UnknownGuide, | ||
| isUnknownGuide, | ||
| } from "./useInspectGuideClientStore"; | ||
|
|
||
| const Row = ({ children }: React.PropsWithChildren) => ( | ||
| <Stack h="7" px="2" borderTop="px" justify="space-between" align="center"> | ||
| {children} | ||
| </Stack> | ||
| ); | ||
|
|
||
| type Props = { | ||
| guide: UnknownGuide | AnnotatedGuide; | ||
| orderIndex: number; | ||
| }; | ||
|
|
||
| export const GuideRow = ({ guide, orderIndex }: Props) => { | ||
| return ( | ||
| <Row> | ||
| <Stack h="6" justify="flex-start" align="center" gap="2"> | ||
| <Tag | ||
| size="0" | ||
| variant="soft" | ||
| color={guide.bypass_global_group_limit ? "blue" : "default"} | ||
| > | ||
| {orderIndex + 1} | ||
| </Tag> | ||
| <GuideHoverCard guide={guide}> | ||
| <Text as="code" size="1" color={guide.active ? "black" : "disabled"}> | ||
| {guide.key} | ||
| </Text> | ||
| </GuideHoverCard> | ||
| </Stack> | ||
|
|
||
| <Stack justify="flex-end"> | ||
| <Stack gap="1"> | ||
| {!isUnknownGuide(guide) && ( | ||
| <> | ||
| <Tooltip | ||
| label={ | ||
| guide.annotation.targetable.status | ||
| ? "This user is being targeted" | ||
| : guide.annotation.targetable.message | ||
| } | ||
| > | ||
| <Button | ||
| px="1" | ||
| size="1" | ||
| variant="soft" | ||
| color={guide.annotation.targetable.status ? "green" : "red"} | ||
| leadingIcon={{ icon: UserCircle2, alt: "Target" }} | ||
| /> | ||
| </Tooltip> | ||
| <Tooltip | ||
| label={ | ||
| guide.annotation.archived.status | ||
| ? "User has already dismissed this guide" | ||
| : "User has not dismissed this guide" | ||
| } | ||
| > | ||
| <Button | ||
| px="1" | ||
| size="1" | ||
| variant="soft" | ||
| color={guide.annotation.archived.status ? "red" : "green"} | ||
| leadingIcon={{ icon: Eye, alt: "Not archived" }} | ||
| /> | ||
| </Tooltip> | ||
| </> | ||
| )} | ||
| <Tooltip | ||
| label={ | ||
| isUnknownGuide(guide) | ||
| ? "This guide has never been committed and published yet" | ||
| : !guide.active | ||
| ? "This guide is not active" | ||
| : "This guide is active" | ||
| } | ||
| > | ||
| <Button | ||
| px="1" | ||
| size="1" | ||
| variant="soft" | ||
| color={guide.active ? "green" : "red"} | ||
| leadingIcon={ | ||
| guide.active | ||
| ? { icon: CheckCircle2, alt: "Active" } | ||
| : { icon: CircleDashed, alt: "Inactive" } | ||
| } | ||
| /> | ||
| </Tooltip> | ||
| </Stack> | ||
| </Stack> | ||
| </Row> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { Select } from "@telegraph/select"; | ||
|
|
||
| import { TOOLBAR_Z_INDEX } from "../shared"; | ||
|
|
||
| export type DisplayOption = "current-page" | "all-eligible" | "all-guides"; | ||
|
|
||
| type Props = { | ||
| value: DisplayOption; | ||
| onChange: (option: DisplayOption) => void; | ||
| }; | ||
|
|
||
| export const GuidesListDisplaySelect = ({ value, onChange }: Props) => { | ||
| return ( | ||
| <Select.Root | ||
| size="1" | ||
| value={value} | ||
| onValueChange={(value) => { | ||
| if (!value) return; | ||
| onChange(value as DisplayOption); | ||
| }} | ||
| contentProps={{ | ||
| style: { zIndex: TOOLBAR_Z_INDEX }, | ||
| }} | ||
| > | ||
| {/* NOTE: Commented out until we can show relevant indicators for this opt | ||
| <Select.Option size="1" value="current-page"> | ||
| Displayable on current page | ||
| </Select.Option> | ||
| */} | ||
| <Select.Option size="1" value="all-eligible"> | ||
| All eligible guides for user | ||
| </Select.Option> | ||
| <Select.Option size="1" value="all-guides"> | ||
| All existing guides | ||
| </Select.Option> | ||
| </Select.Root> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,36 +1,46 @@ | ||
| import { useGuideContext, useStore } from "@knocklabs/react-core"; | ||
| import { useGuideContext } from "@knocklabs/react-core"; | ||
| import { Button } from "@telegraph/button"; | ||
| import { Box, Stack } from "@telegraph/layout"; | ||
| import { Text } from "@telegraph/typography"; | ||
| import { Minimize2, Undo2 } from "lucide-react"; | ||
| import React from "react"; | ||
|
|
||
| import { KnockButton } from "../KnockButton"; | ||
| import { TOOLBAR_Z_INDEX } from "../shared"; | ||
| import "../styles.css"; | ||
|
|
||
| import { GuideRow } from "./GuideRow"; | ||
| import { | ||
| DisplayOption, | ||
| GuidesListDisplaySelect, | ||
| } from "./GuidesListDisplaySelect"; | ||
| import { detectToolbarParam } from "./helpers"; | ||
| import { | ||
| InspectionResult, | ||
| useInspectGuideClientStore, | ||
| } from "./useInspectGuideClientStore"; | ||
|
|
||
| const useInspectGuideClientStore = () => { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to its own file, as it is getting more complex. |
||
| const { client } = useGuideContext(); | ||
| const GuidesList = ({ | ||
| guides, | ||
| displayOption, | ||
| }: { | ||
| guides: InspectionResult["guides"]; | ||
| displayOption: DisplayOption; | ||
| }) => { | ||
| return guides.map((guide, idx) => { | ||
| if (displayOption === "all-eligible" && !guide.annotation.isEligible) { | ||
| return null; | ||
| } | ||
|
|
||
| const snapshot = useStore(client.store, (state) => { | ||
| return { | ||
| debug: state.debug, | ||
| }; | ||
| return <GuideRow key={guide.key} guide={guide} orderIndex={idx} />; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Filtered guide list shows non-sequential row numberingLow Severity In |
||
| }); | ||
|
|
||
| if (!snapshot.debug?.debugging) { | ||
| return; | ||
| } | ||
|
|
||
| // TODO: Transform the raw client state into more useful data for debugging. | ||
| return {}; | ||
| }; | ||
|
|
||
| export const V2 = () => { | ||
| const { client } = useGuideContext(); | ||
|
|
||
| const [guidesListDisplayOption, setGuidesListDisplayOption] = | ||
| React.useState<DisplayOption>("all-eligible"); | ||
|
|
||
| const [isVisible, setIsVisible] = React.useState(detectToolbarParam()); | ||
| const [isCollapsed, setIsCollapsed] = React.useState(true); | ||
|
|
||
|
|
@@ -73,9 +83,10 @@ export const V2 = () => { | |
| style={{ boxSizing: "border-box" }} | ||
| > | ||
| <Box style={{ width: "220px" }}> | ||
| <Text as="div" size="1" weight="medium" w="full" maxWidth="40"> | ||
| Toolbar v2 placeholder | ||
| </Text> | ||
| <GuidesListDisplaySelect | ||
| value={guidesListDisplayOption} | ||
| onChange={(opt) => setGuidesListDisplayOption(opt)} | ||
| /> | ||
| </Box> | ||
|
|
||
| <Stack gap="2"> | ||
|
|
@@ -95,6 +106,14 @@ export const V2 = () => { | |
| /> | ||
| </Stack> | ||
| </Stack> | ||
|
|
||
| <Box w="full"> | ||
| {result.error && <Box>{result.error}</Box>} | ||
| <GuidesList | ||
| guides={result.guides} | ||
| displayOption={guidesListDisplayOption} | ||
| /> | ||
| </Box> | ||
| </Stack> | ||
| )} | ||
| </Box> | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will see if we want to keep this dep. I pulled it in for the time being but we will need to work out the final design with Krisna. I do think it's helpful to show the guide data from the client store state.