Skip to content

Commit d35d0a8

Browse files
authored
Allow customizing default expansion limit (#925)
* Add Switch component * Add motion * Update settings UI * Add neighbor expansion app wide setting * Update changelog * Add tests for default limit * Update readme
1 parent 8b58e8f commit d35d0a8

25 files changed

+902
-481
lines changed

Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Other changes
66

7+
- **Added** ability to customize default neighbor expansion limit
8+
([#925](https://github.com/aws/graph-explorer/pull/925))
79
- **Improved** Improved connection details by moving the sync button near the
810
last sync timestamp (thanks @enumura1,
911
[#901](https://github.com/aws/graph-explorer/pull/901),

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ out our [roadmap](./ROADMAP.md) and participate in the discussions.
5555

5656
#### General Settings
5757

58+
- **Default Neighbor Expansion Limit:** This setting will allow you to enable or
59+
disable the default limit applied during neighbor expansion. This applies to
60+
both double click expansion and the expand sidebar. This setting can be
61+
overridden by a similar setting on the connection itself.
5862
- **Save Configuration:** This action will export all the configuration data
5963
within the Graph Explorer local database. This will not store any data from
6064
the connected graph databases. However, the export may contain the shape of
@@ -99,6 +103,8 @@ to add a new connection. You can also edit and delete connections.
99103
- **AWS Region:** Specify the AWS region where the Neptune cluster is hosted
100104
(e.g., us-east-1)
101105
- **Fetch Timeout:** Specify the timeout for the fetch request
106+
- **Neighbor Expansion Limit:** Specify the default limit for neighbor
107+
expansion. This will override the app setting for neighbor expansion.
102108

103109
- **Available Connections:** Once a connection is created, this section will
104110
appear as a left-hand pane. When you create more than one connection to a

packages/graph-explorer/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"@radix-ui/react-popover": "^1.1.6",
3030
"@radix-ui/react-select": "^2.1.6",
3131
"@radix-ui/react-slot": "^1.1.2",
32+
"@radix-ui/react-switch": "^1.2.4",
3233
"@radix-ui/react-tabs": "^1.1.3",
3334
"@radix-ui/react-toggle": "^1.1.2",
3435
"@radix-ui/react-tooltip": "^1.1.8",
@@ -65,6 +66,7 @@
6566
"localforage": "^1.10.0",
6667
"lodash": "^4.17.21",
6768
"lucide-react": "^0.460.0",
69+
"motion": "^12.10.5",
6870
"papaparse": "^5.5.2",
6971
"re-resizable": "^6.11.2",
7072
"react": "^18.3.1",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { AnimationProps } from "motion/react";
2+
3+
export const addRemoveAnimationProps: AnimationProps = {
4+
initial: { opacity: 0, scale: 0.95 },
5+
animate: { opacity: 1, scale: 1 },
6+
exit: { opacity: 0, scale: 0.95 },
7+
transition: { duration: 0.2, ease: "easeInOut", when: "beforeChildren" },
8+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { QueryErrorResetBoundary } from "@tanstack/react-query";
2+
import { PropsWithChildren } from "react";
3+
import { ErrorBoundary } from "react-error-boundary";
4+
import PanelError from "./PanelError";
5+
6+
export function DefaultQueryErrorBoundary({ children }: PropsWithChildren) {
7+
return (
8+
<QueryErrorResetBoundary>
9+
{({ reset }) => (
10+
<ErrorBoundary
11+
onReset={reset}
12+
fallbackRender={({ resetErrorBoundary, error }) => (
13+
<PanelError error={error} onRetry={resetErrorBoundary} />
14+
)}
15+
>
16+
{children}
17+
</ErrorBoundary>
18+
)}
19+
</QueryErrorResetBoundary>
20+
);
21+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { cn } from "@/utils";
2+
import {
3+
ComponentProps,
4+
ComponentPropsWithoutRef,
5+
PropsWithChildren,
6+
} from "react";
7+
import { Switch } from "./Switch";
8+
9+
/** Provides a default gap between section elements */
10+
export function SettingsSection({
11+
className,
12+
...props
13+
}: ComponentProps<"section">) {
14+
return (
15+
<section
16+
className={cn("max-w-paragraph space-y-6", className)}
17+
{...props}
18+
/>
19+
);
20+
}
21+
22+
export function SettingsSectionHeader({
23+
className,
24+
...props
25+
}: ComponentProps<"header">) {
26+
return <header className={cn("space-y-1", className)} {...props} />;
27+
}
28+
29+
export function SettingsSectionTitle({
30+
className,
31+
...props
32+
}: ComponentProps<"h2">) {
33+
return (
34+
<h2
35+
className={cn(
36+
"text-text-primary text-xl font-bold leading-snug",
37+
className
38+
)}
39+
{...props}
40+
/>
41+
);
42+
}
43+
44+
export function SettingsSectionDescription({
45+
className,
46+
...props
47+
}: ComponentProps<"div">) {
48+
return (
49+
<div
50+
className={cn(
51+
"text-text-secondary font-base text-base leading-snug",
52+
className
53+
)}
54+
{...props}
55+
/>
56+
);
57+
}
58+
59+
/** Contains a list of `SettingsSection` elements and provides a gap between them */
60+
export function SettingsSectionContainer({
61+
className,
62+
...props
63+
}: ComponentProps<"div">) {
64+
return <div className={cn("flex flex-col gap-9", className)} {...props} />;
65+
}
66+
67+
export function ToggleSetting({
68+
label,
69+
description,
70+
...props
71+
}: ComponentPropsWithoutRef<typeof Switch> & {
72+
label: string;
73+
description?: string;
74+
}) {
75+
return (
76+
<label
77+
htmlFor={props.id}
78+
className="flex flex-row items-center justify-between space-x-4"
79+
>
80+
<div className="space-y-1">
81+
<p className="text-text-primary text-pretty text-base font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
82+
{label}
83+
</p>
84+
{description ? (
85+
<p className="text-text-secondary font-base text-pretty text-sm leading-normal peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
86+
{description}
87+
</p>
88+
) : null}
89+
</div>
90+
<Switch {...props} />
91+
</label>
92+
);
93+
}
94+
95+
export function LabelledSetting({
96+
label,
97+
description,
98+
children,
99+
}: PropsWithChildren<{
100+
label: string;
101+
description?: string;
102+
}>) {
103+
return (
104+
<div className="flex flex-row items-center justify-between space-x-4">
105+
<div className="block cursor-pointer space-y-1">
106+
<p className="text-text-primary text-pretty text-base font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
107+
{label}
108+
</p>
109+
{description ? (
110+
<p className="text-text-secondary font-base text-pretty text-sm leading-normal peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
111+
{description}
112+
</p>
113+
) : null}
114+
</div>
115+
{children}
116+
</div>
117+
);
118+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as React from "react";
2+
import * as SwitchPrimitives from "@radix-ui/react-switch";
3+
import { cn } from "@/utils";
4+
5+
const Switch = React.forwardRef<
6+
React.ElementRef<typeof SwitchPrimitives.Root>,
7+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
8+
>(({ className, ...props }, ref) => (
9+
<SwitchPrimitives.Root
10+
className={cn(
11+
"focus-visible:ring-primary-main focus-visible:ring-offset-background data-[state=checked]:bg-primary-main data-[state=unchecked]:bg-background-contrast-secondary peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
12+
className
13+
)}
14+
{...props}
15+
ref={ref}
16+
>
17+
<SwitchPrimitives.Thumb
18+
className={cn(
19+
"bg-background-default pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
20+
)}
21+
/>
22+
</SwitchPrimitives.Root>
23+
));
24+
Switch.displayName = SwitchPrimitives.Root.displayName;
25+
26+
export { Switch };

packages/graph-explorer/src/components/Typography.tsx

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,26 @@ export function PageHeading({ className, ...props }: ComponentProps<"h1">) {
55
return (
66
<h1
77
className={cn(
8-
"font-extraBold text-text-primary mb-2 text-4xl leading-relaxed",
8+
"font-extraBold text-text-primary text-4xl leading-snug",
99
className
1010
)}
1111
{...props}
1212
/>
1313
);
1414
}
1515

16-
export function SectionTitle({ className, ...props }: ComponentProps<"h2">) {
16+
export function Paragraph({ className, ...props }: ComponentProps<"p">) {
1717
return (
18-
<h2
18+
<p
1919
className={cn(
20-
"text-text-secondary text-xl font-bold leading-loose",
20+
"text-text-secondary my-2 text-pretty text-base font-light",
2121
className
2222
)}
2323
{...props}
2424
/>
2525
);
2626
}
2727

28-
export function Paragraph({ className, ...props }: ComponentProps<"p">) {
29-
return (
30-
<p
31-
className={cn("text-text-secondary my-2 text-lg font-light", className)}
32-
{...props}
33-
/>
34-
);
35-
}
36-
3728
export function ImportantBlock({
3829
className,
3930
children,

packages/graph-explorer/src/components/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ export * from "./CheckboxList";
1010
export { default as Chip } from "./Chip";
1111
export * from "./Chip";
1212

13+
export * from "./CommonAnimationProps";
14+
15+
export * from "./DefaultQueryErrorBoundary";
16+
1317
export { PanelEmptyState } from "./PanelEmptyState";
1418
export * from "./PanelEmptyState";
1519
export { default as PanelError } from "./PanelError";
@@ -62,8 +66,12 @@ export * from "./Select";
6266
export { default as SelectField } from "./SelectField";
6367
export * from "./SelectField";
6468

69+
export * from "./SettingsSection";
70+
6571
export * from "./SidebarTabs";
6672

73+
export * from "./Switch";
74+
6775
export * from "./Tooltip";
6876
export * from "./Typography";
6977

packages/graph-explorer/src/core/featureFlags.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,19 @@ export const featureFlagsSelector = atom(get => {
2828
export function useFeatureFlags() {
2929
return useAtomValue(featureFlagsSelector);
3030
}
31+
32+
/*
33+
* General App Settings
34+
*/
35+
36+
/** Setting that enables/disables the default limit for neighbor expansion. */
37+
export const defaultNeighborExpansionLimitEnabledAtom = atomWithLocalForage(
38+
true,
39+
"defaultNeighborExpansionLimitEnabled"
40+
);
41+
42+
/** Setting that defines the default limit for neighbor expansion. */
43+
export const defaultNeighborExpansionLimitAtom = atomWithLocalForage(
44+
10,
45+
"defaultNeighborExpansionLimit"
46+
);

0 commit comments

Comments
 (0)