Skip to content

Commit 340baba

Browse files
adamshiervaniym
andauthored
feat(network): enhance network settings UI (#364)
* feat(network): enhance network settings UI with domain management and improved layout - Added custom domain input and selection options for DHCP and local domains. - Improved layout for displaying network settings, including DHCP lease information and IPv6 addresses. - Refactored state management for network settings and added handlers for hostname and domain changes. - Updated the display of network settings to enhance user experience and accessibility. * Re-add save button * fix: add ConfirmDialog for renewing DHCP lease and improve network settings layout - Integrated ConfirmDialog component to confirm DHCP lease renewal. - Enhanced the layout of network settings, including better organization of IPv4 and IPv6 information. - Updated state management for displaying network settings and lease information. - Improved user experience with clearer descriptions and structured UI elements. * Fix lint errors * fix: useRef TS2554 --------- Co-authored-by: Siyuan Miao <[email protected]>
1 parent 2aa7b85 commit 340baba

File tree

8 files changed

+1033
-619
lines changed

8 files changed

+1033
-619
lines changed

ui/src/components/Combobox.tsx

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { useRef } from "react";
22
import clsx from "clsx";
3-
import { Combobox as HeadlessCombobox, ComboboxInput, ComboboxOption, ComboboxOptions } from "@headlessui/react";
3+
import {
4+
Combobox as HeadlessCombobox,
5+
ComboboxInput,
6+
ComboboxOption,
7+
ComboboxOptions,
8+
} from "@headlessui/react";
9+
410
import { cva } from "@/cva.config";
11+
512
import Card from "./Card";
613

714
export interface ComboboxOption {
@@ -22,7 +29,7 @@ const comboboxVariants = cva({
2229

2330
type BaseProps = React.ComponentProps<typeof HeadlessCombobox>;
2431

25-
interface ComboboxProps extends Omit<BaseProps, 'displayValue'> {
32+
interface ComboboxProps extends Omit<BaseProps, "displayValue"> {
2633
displayValue: (option: ComboboxOption) => string;
2734
onInputChange: (option: string) => void;
2835
options: () => ComboboxOption[];
@@ -48,72 +55,68 @@ export function Combobox({
4855
const classes = comboboxVariants({ size });
4956

5057
return (
51-
<HeadlessCombobox
52-
onChange={onChange}
53-
{...otherProps}
54-
>
58+
<HeadlessCombobox onChange={onChange} {...otherProps}>
5559
{() => (
5660
<>
5761
<Card className="w-auto !border border-solid !border-slate-800/30 shadow outline-0 dark:!border-slate-300/30">
5862
<ComboboxInput
59-
ref={inputRef}
60-
className={clsx(
61-
classes,
62-
63-
// General styling
64-
"block w-full cursor-pointer rounded border-none py-0 font-medium shadow-none outline-0 transition duration-300",
65-
66-
// Hover
67-
"hover:bg-blue-50/80 active:bg-blue-100/60",
68-
69-
// Dark mode
70-
"dark:bg-slate-800 dark:text-white dark:hover:bg-slate-700 dark:active:bg-slate-800/60",
71-
72-
// Focus
73-
"focus:outline-blue-600 focus:ring-2 focus:ring-blue-700 focus:ring-offset-2 dark:focus:outline-blue-500 dark:focus:ring-blue-500",
74-
75-
// Disabled
76-
disabled && "pointer-events-none select-none bg-slate-50 text-slate-500/80 dark:bg-slate-800 dark:text-slate-400/80 disabled:hover:bg-white dark:disabled:hover:bg-slate-800"
77-
)}
78-
placeholder={disabled ? disabledMessage : placeholder}
79-
displayValue={displayValue}
80-
onChange={(event) => onInputChange(event.target.value)}
81-
disabled={disabled}
63+
ref={inputRef}
64+
className={clsx(
65+
classes,
66+
67+
// General styling
68+
"block w-full cursor-pointer rounded border-none py-0 font-medium shadow-none outline-0 transition duration-300",
69+
70+
// Hover
71+
"hover:bg-blue-50/80 active:bg-blue-100/60",
72+
73+
// Dark mode
74+
"dark:bg-slate-800 dark:text-white dark:hover:bg-slate-700 dark:active:bg-slate-800/60",
75+
76+
// Focus
77+
"focus:outline-blue-600 focus:ring-2 focus:ring-blue-700 focus:ring-offset-2 dark:focus:outline-blue-500 dark:focus:ring-blue-500",
78+
79+
// Disabled
80+
disabled &&
81+
"pointer-events-none select-none bg-slate-50 text-slate-500/80 disabled:hover:bg-white dark:bg-slate-800 dark:text-slate-400/80 dark:disabled:hover:bg-slate-800",
82+
)}
83+
placeholder={disabled ? disabledMessage : placeholder}
84+
displayValue={displayValue}
85+
onChange={event => onInputChange(event.target.value)}
86+
disabled={disabled}
8287
/>
8388
</Card>
84-
89+
8590
{options().length > 0 && (
86-
<ComboboxOptions className="absolute left-0 z-[100] mt-1 w-full max-h-60 overflow-auto rounded-md bg-white py-1 text-sm shadow-lg ring-1 ring-black/5 dark:bg-slate-800 dark:ring-slate-700 hide-scrollbar">
87-
{options().map((option) => (
88-
<ComboboxOption
89-
key={option.value}
90-
value={option}
91-
className={clsx(
92-
// General styling
93-
"cursor-default select-none py-2 px-4",
94-
95-
// Hover and active states
96-
"hover:bg-blue-50/80 ui-active:bg-blue-50/80 ui-active:text-blue-900",
97-
98-
// Dark mode
99-
"dark:text-slate-300 dark:hover:bg-slate-700 dark:ui-active:bg-slate-700 dark:ui-active:text-blue-200"
100-
)}
91+
<ComboboxOptions className="hide-scrollbar absolute left-0 z-[100] mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-sm shadow-lg ring-1 ring-black/5 dark:bg-slate-800 dark:ring-slate-700">
92+
{options().map(option => (
93+
<ComboboxOption
94+
key={option.value}
95+
value={option}
96+
className={clsx(
97+
// General styling
98+
"cursor-default select-none px-4 py-2",
99+
100+
// Hover and active states
101+
"hover:bg-blue-50/80 ui-active:bg-blue-50/80 ui-active:text-blue-900",
102+
103+
// Dark mode
104+
"dark:text-slate-300 dark:hover:bg-slate-700 dark:ui-active:bg-slate-700 dark:ui-active:text-blue-200",
105+
)}
101106
>
102107
{option.label}
103108
</ComboboxOption>
104109
))}
105110
</ComboboxOptions>
106111
)}
107-
112+
108113
{options().length === 0 && inputRef.current?.value && (
109-
<div className="absolute left-0 z-[100] mt-1 w-full rounded-md bg-white dark:bg-slate-800 py-2 px-4 text-sm shadow-lg ring-1 ring-black/5 dark:ring-slate-700">
110-
<div className="text-slate-500 dark:text-slate-400">
111-
{emptyMessage}
112-
</div>
114+
<div className="absolute left-0 z-[100] mt-1 w-full rounded-md bg-white px-4 py-2 text-sm shadow-lg ring-1 ring-black/5 dark:bg-slate-800 dark:ring-slate-700">
115+
<div className="text-slate-500 dark:text-slate-400">{emptyMessage}</div>
113116
</div>
114117
)}
115118
</>
116119
)}
117120
</HeadlessCombobox>
118121
);
119-
}
122+
}

ui/src/components/ConfirmDialog.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { ExclamationTriangleIcon, CheckCircleIcon, InformationCircleIcon } from "@heroicons/react/24/outline";
1+
import {
2+
ExclamationTriangleIcon,
3+
CheckCircleIcon,
4+
InformationCircleIcon,
5+
} from "@heroicons/react/24/outline";
6+
27
import { cx } from "@/cva.config";
38
import { Button } from "@/components/Button";
49
import Modal from "@/components/Modal";
@@ -42,12 +47,15 @@ const variantConfig = {
4247
iconBgClass: "bg-blue-100",
4348
buttonTheme: "primary",
4449
},
45-
} as Record<Variant, {
50+
} as Record<
51+
Variant,
52+
{
4653
icon: React.ElementType;
4754
iconClass: string;
4855
iconBgClass: string;
4956
buttonTheme: "danger" | "primary" | "blank" | "light" | "lightDanger";
50-
}>;
57+
}
58+
>;
5159

5260
export function ConfirmDialog({
5361
open,
@@ -65,13 +73,18 @@ export function ConfirmDialog({
6573
return (
6674
<Modal open={open} onClose={onClose}>
6775
<div className="mx-auto max-w-xl px-4 transition-all duration-300 ease-in-out">
68-
<div className="relative w-full overflow-hidden rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all dark:bg-slate-800 pointer-events-auto">
76+
<div className="pointer-events-auto relative w-full overflow-hidden rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all dark:bg-slate-800">
6977
<div className="space-y-4">
7078
<div className="sm:flex sm:items-start">
71-
<div className={cx("mx-auto flex size-12 shrink-0 items-center justify-center rounded-full sm:mx-0 sm:size-10", iconBgClass)}>
79+
<div
80+
className={cx(
81+
"mx-auto flex size-12 shrink-0 items-center justify-center rounded-full sm:mx-0 sm:size-10",
82+
iconBgClass,
83+
)}
84+
>
7285
<Icon aria-hidden="true" className={cx("size-6", iconClass)} />
7386
</div>
74-
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
87+
<div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left">
7588
<h2 className="text-lg font-bold leading-tight text-black dark:text-white">
7689
{title}
7790
</h2>
@@ -83,12 +96,7 @@ export function ConfirmDialog({
8396

8497
<div className="flex justify-end gap-x-2">
8598
{cancelText && (
86-
<Button
87-
size="SM"
88-
theme="blank"
89-
text={cancelText}
90-
onClick={onClose}
91-
/>
99+
<Button size="SM" theme="blank" text={cancelText} onClick={onClose} />
92100
)}
93101
<Button
94102
size="SM"
@@ -103,4 +111,4 @@ export function ConfirmDialog({
103111
</div>
104112
</Modal>
105113
);
106-
}
114+
}

0 commit comments

Comments
 (0)