');
+ }
+
+ const { id } = itemContext;
+
+ return {
+ id,
+ name: fieldContext.name,
+ formItemId: `${id}-form-item`,
+ formDescriptionId: `${id}-form-item-description`,
+ formMessageId: `${id}-form-item-message`,
+ ...fieldState,
+ };
+}
+
+function FormItem({ className, ...props }) {
+ const id = React.useId();
+ return (
+
+
+
+ );
+}
+
+function FormLabel({ className, ...props }) {
+ const { error, formItemId } = useFormField();
+ return (
+
+ );
+}
+
+function FormControl({ ...props }) {
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
+ return (
+
+ );
+}
+
+function FormDescription({ className, ...props }) {
+ const { formDescriptionId } = useFormField();
+ return (
+
+ );
+}
+
+function FormMessage({ className, ...props }) {
+ const { error, formMessageId } = useFormField();
+ const body = error ? String(error?.message ?? '') : props.children;
+ if (!body) {
+ return null;
+ }
+ return (
+
+ {body}
+
+ );
+}
+
+export {
+ useFormField,
+ Form,
+ FormItem,
+ FormLabel,
+ FormControl,
+ FormDescription,
+ FormMessage,
+ FormField,
+};
diff --git a/services/web/src/components/ui/input-otp.jsx b/services/web/src/components/ui/input-otp.jsx
new file mode 100644
index 000000000..52eefff1c
--- /dev/null
+++ b/services/web/src/components/ui/input-otp.jsx
@@ -0,0 +1,62 @@
+import { OTPInput, OTPInputContext } from 'input-otp';
+import { Minus } from 'lucide-react';
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function InputOTP({ className, containerClassName, ...props }) {
+ return (
+
+ );
+}
+
+function InputOTPGroup({ className, ...props }) {
+ return (
+
+ );
+}
+
+function InputOTPSlot({ index, className, ...props }) {
+ const inputOTPContext = React.useContext(OTPInputContext);
+ const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
+
+ return (
+
+ {char}
+ {hasFakeCaret && (
+
+ )}
+
+ );
+}
+
+function InputOTPSeparator({ ...props }) {
+ return (
+
+
+
+ );
+}
+
+export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
diff --git a/services/web/src/components/ui/input.jsx b/services/web/src/components/ui/input.jsx
new file mode 100644
index 000000000..69b123075
--- /dev/null
+++ b/services/web/src/components/ui/input.jsx
@@ -0,0 +1,19 @@
+import { cn } from '@/lib/utils';
+
+function Input({ className, type, ...props }) {
+ return (
+
+ );
+}
+
+export { Input };
diff --git a/services/web/src/components/ui/label.jsx b/services/web/src/components/ui/label.jsx
new file mode 100644
index 000000000..497e8967d
--- /dev/null
+++ b/services/web/src/components/ui/label.jsx
@@ -0,0 +1,18 @@
+import * as LabelPrimitive from '@radix-ui/react-label';
+
+import { cn } from '@/lib/utils';
+
+function Label({ className, ...props }) {
+ return (
+
+ );
+}
+
+export { Label };
diff --git a/services/web/src/components/ui/pagination.jsx b/services/web/src/components/ui/pagination.jsx
new file mode 100644
index 000000000..744276a35
--- /dev/null
+++ b/services/web/src/components/ui/pagination.jsx
@@ -0,0 +1,106 @@
+import { ChevronLeft, ChevronRight } from 'lucide-react';
+
+import { cn } from '@/lib/utils';
+
+const DOTS = 'dots';
+
+function range(start, end) {
+ const out = [];
+ for (let i = start; i <= end; i++) out.push(i);
+ return out;
+}
+
+/**
+ * Page range with leading/trailing boundaries and siblings around the current
+ * page, collapsing gaps into ellipses — mirrors Mantine's Pagination behaviour.
+ */
+function getPaginationRange(page, total, siblings = 2, boundaries = 2) {
+ const totalNumbers = siblings * 2 + 3 + boundaries * 2;
+ if (totalNumbers >= total) {
+ return range(1, total);
+ }
+
+ const leftSibling = Math.max(page - siblings, boundaries + 2);
+ const rightSibling = Math.min(page + siblings, total - boundaries - 1);
+
+ const showLeftDots = leftSibling > boundaries + 2;
+ const showRightDots = rightSibling < total - boundaries - 1;
+
+ const head = range(1, boundaries);
+ const tail = range(total - boundaries + 1, total);
+
+ if (!showLeftDots && showRightDots) {
+ const left = range(1, siblings * 2 + boundaries + 2);
+ return [...left, DOTS, ...tail];
+ }
+ if (showLeftDots && !showRightDots) {
+ const right = range(total - (siblings * 2 + boundaries + 1), total);
+ return [...head, DOTS, ...right];
+ }
+ return [
+ ...head,
+ DOTS,
+ ...range(leftSibling, rightSibling),
+ DOTS,
+ ...tail,
+ ];
+}
+
+const itemClass =
+ 'inline-flex h-9 min-w-9 cursor-pointer appearance-none items-center justify-center rounded-md border-0 bg-transparent px-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50';
+
+/**
+ * Controlled pagination. `page` is 1-based; `total` is the number of pages.
+ */
+export function Pagination({ page, total, onChange, disabled, className }) {
+ if (!total || total <= 1) {
+ return null;
+ }
+ const pages = getPaginationRange(page, total);
+
+ return (
+
+ onChange(page - 1)}>
+
+
+ {pages.map((p, i) =>
+ p === DOTS ? (
+
+ …
+
+ ) : (
+ onChange(p)}
+ className={cn(
+ itemClass,
+ p === page &&
+ 'bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground',
+ )}>
+ {p}
+
+ ),
+ )}
+ = total}
+ onClick={() => onChange(page + 1)}>
+
+
+
+ );
+}
diff --git a/services/web/src/components/ui/password-input.jsx b/services/web/src/components/ui/password-input.jsx
new file mode 100644
index 000000000..90b62350d
--- /dev/null
+++ b/services/web/src/components/ui/password-input.jsx
@@ -0,0 +1,28 @@
+import { Eye, EyeOff } from 'lucide-react';
+import * as React from 'react';
+
+import { Input } from '@/components/ui/input';
+import { cn } from '@/lib/utils';
+
+function PasswordInput({ className, ...props }) {
+ const [visible, setVisible] = React.useState(false);
+ return (
+
+
+ setVisible((v) => !v)}
+ aria-label={visible ? 'Hide password' : 'Show password'}
+ className="text-muted-foreground hover:text-foreground absolute inset-y-0 right-0 flex appearance-none cursor-pointer items-center border-0 bg-transparent pr-3">
+ {visible ? : }
+
+
+ );
+}
+
+export { PasswordInput };
diff --git a/services/web/src/components/ui/popover.jsx b/services/web/src/components/ui/popover.jsx
new file mode 100644
index 000000000..ed0b2bcfd
--- /dev/null
+++ b/services/web/src/components/ui/popover.jsx
@@ -0,0 +1,30 @@
+import * as PopoverPrimitive from '@radix-ui/react-popover';
+
+import { cn } from '@/lib/utils';
+
+function Popover(props) {
+ return ;
+}
+
+function PopoverTrigger(props) {
+ return ;
+}
+
+function PopoverContent({ className, align = 'center', sideOffset = 4, ...props }) {
+ return (
+
+
+
+ );
+}
+
+export { Popover, PopoverTrigger, PopoverContent };
diff --git a/services/web/src/components/ui/select.jsx b/services/web/src/components/ui/select.jsx
new file mode 100644
index 000000000..082b966fd
--- /dev/null
+++ b/services/web/src/components/ui/select.jsx
@@ -0,0 +1,129 @@
+import * as SelectPrimitive from '@radix-ui/react-select';
+import { Check, ChevronDown, ChevronUp } from 'lucide-react';
+
+import { cn } from '@/lib/utils';
+
+function Select(props) {
+ return ;
+}
+function SelectGroup(props) {
+ return ;
+}
+function SelectValue(props) {
+ return ;
+}
+
+function SelectTrigger({ className, size = 'default', children, ...props }) {
+ return (
+
+ {children}
+
+
+
+
+ );
+}
+
+function SelectContent({ className, children, position = 'popper', ...props }) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
+
+function SelectLabel({ className, ...props }) {
+ return (
+
+ );
+}
+
+function SelectItem({ className, children, ...props }) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function SelectSeparator({ className, ...props }) {
+ return (
+
+ );
+}
+
+function SelectScrollUpButton({ className, ...props }) {
+ return (
+
+
+
+ );
+}
+
+function SelectScrollDownButton({ className, ...props }) {
+ return (
+
+
+
+ );
+}
+
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+};
diff --git a/services/web/src/components/ui/separator.jsx b/services/web/src/components/ui/separator.jsx
new file mode 100644
index 000000000..76998a4c4
--- /dev/null
+++ b/services/web/src/components/ui/separator.jsx
@@ -0,0 +1,25 @@
+import * as SeparatorPrimitive from '@radix-ui/react-separator';
+
+import { cn } from '@/lib/utils';
+
+function Separator({
+ className,
+ orientation = 'horizontal',
+ decorative = true,
+ ...props
+}) {
+ return (
+
+ );
+}
+
+export { Separator };
diff --git a/services/web/src/components/ui/sheet.jsx b/services/web/src/components/ui/sheet.jsx
new file mode 100644
index 000000000..ac8938ec0
--- /dev/null
+++ b/services/web/src/components/ui/sheet.jsx
@@ -0,0 +1,94 @@
+import * as SheetPrimitive from '@radix-ui/react-dialog';
+import { X } from 'lucide-react';
+
+import { cn } from '@/lib/utils';
+
+function Sheet({ ...props }) {
+ return ;
+}
+
+function SheetTrigger({ ...props }) {
+ return ;
+}
+
+function SheetClose({ ...props }) {
+ return ;
+}
+
+function SheetOverlay({ className, ...props }) {
+ return (
+
+ );
+}
+
+function SheetContent({ className, children, side = 'right', ...props }) {
+ return (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+ );
+}
+
+function SheetHeader({ className, ...props }) {
+ return (
+
+ );
+}
+
+function SheetTitle({ className, ...props }) {
+ return (
+
+ );
+}
+
+function SheetDescription({ className, ...props }) {
+ return (
+
+ );
+}
+
+export {
+ Sheet,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetTitle,
+ SheetDescription,
+};
diff --git a/services/web/src/components/ui/skeleton.jsx b/services/web/src/components/ui/skeleton.jsx
new file mode 100644
index 000000000..62f94c237
--- /dev/null
+++ b/services/web/src/components/ui/skeleton.jsx
@@ -0,0 +1,13 @@
+import { cn } from '@/lib/utils';
+
+function Skeleton({ className, ...props }) {
+ return (
+
+ );
+}
+
+export { Skeleton };
diff --git a/services/web/src/components/ui/sonner.jsx b/services/web/src/components/ui/sonner.jsx
new file mode 100644
index 000000000..73e4e1b9f
--- /dev/null
+++ b/services/web/src/components/ui/sonner.jsx
@@ -0,0 +1,23 @@
+import { Toaster as Sonner } from 'sonner';
+
+import { useTheme } from '@/components/ThemeProvider';
+
+function Toaster(props) {
+ const { resolvedTheme } = useTheme();
+ return (
+
+ );
+}
+
+export { Toaster };
diff --git a/services/web/src/components/ui/spinner.jsx b/services/web/src/components/ui/spinner.jsx
new file mode 100644
index 000000000..828336090
--- /dev/null
+++ b/services/web/src/components/ui/spinner.jsx
@@ -0,0 +1,16 @@
+import { Loader2 } from 'lucide-react';
+
+import { cn } from '@/lib/utils';
+
+function Spinner({ className, ...props }) {
+ return (
+
+ );
+}
+
+export { Spinner };
diff --git a/services/web/src/components/ui/switch.jsx b/services/web/src/components/ui/switch.jsx
new file mode 100644
index 000000000..2ce5e3169
--- /dev/null
+++ b/services/web/src/components/ui/switch.jsx
@@ -0,0 +1,24 @@
+import * as SwitchPrimitive from '@radix-ui/react-switch';
+
+import { cn } from '@/lib/utils';
+
+function Switch({ className, ...props }) {
+ return (
+
+
+
+ );
+}
+
+export { Switch };
diff --git a/services/web/src/components/ui/table.jsx b/services/web/src/components/ui/table.jsx
new file mode 100644
index 000000000..f9d2832b5
--- /dev/null
+++ b/services/web/src/components/ui/table.jsx
@@ -0,0 +1,106 @@
+import { cn } from '@/lib/utils';
+
+function Table({ className, ...props }) {
+ return (
+
+ );
+}
+
+function TableHeader({ className, ...props }) {
+ return (
+
+ );
+}
+
+function TableBody({ className, ...props }) {
+ return (
+
+ );
+}
+
+function TableFooter({ className, ...props }) {
+ return (
+ tr]:last:border-b-0',
+ className,
+ )}
+ {...props}
+ />
+ );
+}
+
+function TableRow({ className, ...props }) {
+ return (
+
+ );
+}
+
+function TableHead({ className, ...props }) {
+ return (
+ [role=checkbox]]:translate-y-[2px]',
+ className,
+ )}
+ {...props}
+ />
+ );
+}
+
+function TableCell({ className, ...props }) {
+ return (
+ [role=checkbox]]:translate-y-[2px]',
+ className,
+ )}
+ {...props}
+ />
+ );
+}
+
+function TableCaption({ className, ...props }) {
+ return (
+
+ );
+}
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+};
diff --git a/services/web/src/components/ui/tabs.jsx b/services/web/src/components/ui/tabs.jsx
new file mode 100644
index 000000000..4fe0ec281
--- /dev/null
+++ b/services/web/src/components/ui/tabs.jsx
@@ -0,0 +1,51 @@
+import * as TabsPrimitive from '@radix-ui/react-tabs';
+
+import { cn } from '@/lib/utils';
+
+function Tabs({ className, ...props }) {
+ return (
+
+ );
+}
+
+function TabsList({ className, ...props }) {
+ return (
+
+ );
+}
+
+function TabsTrigger({ className, ...props }) {
+ return (
+
+ );
+}
+
+function TabsContent({ className, ...props }) {
+ return (
+
+ );
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent };
diff --git a/services/web/src/components/ui/textarea.jsx b/services/web/src/components/ui/textarea.jsx
new file mode 100644
index 000000000..45770dd86
--- /dev/null
+++ b/services/web/src/components/ui/textarea.jsx
@@ -0,0 +1,16 @@
+import { cn } from '@/lib/utils';
+
+function Textarea({ className, ...props }) {
+ return (
+
+ );
+}
+
+export { Textarea };
diff --git a/services/web/src/components/ui/tooltip.jsx b/services/web/src/components/ui/tooltip.jsx
new file mode 100644
index 000000000..eb8788636
--- /dev/null
+++ b/services/web/src/components/ui/tooltip.jsx
@@ -0,0 +1,45 @@
+import * as TooltipPrimitive from '@radix-ui/react-tooltip';
+
+import { cn } from '@/lib/utils';
+
+function TooltipProvider({ delayDuration = 0, ...props }) {
+ return (
+
+ );
+}
+
+function Tooltip({ ...props }) {
+ return (
+
+
+
+ );
+}
+
+function TooltipTrigger({ ...props }) {
+ return ;
+}
+
+function TooltipContent({ className, sideOffset = 4, children, ...props }) {
+ return (
+
+
+ {children}
+
+
+
+ );
+}
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
diff --git a/services/web/src/docs/components/EditButton.js b/services/web/src/docs/components/EditButton.js
index 2a966f167..90fd3362c 100644
--- a/services/web/src/docs/components/EditButton.js
+++ b/services/web/src/docs/components/EditButton.js
@@ -1,6 +1,7 @@
-import { ActionIcon } from '@mantine/core';
import { PiPencilSimpleBold } from 'react-icons/pi';
+import { Button } from '@/components/ui/button';
+
import { useClass } from 'helpers/bem';
import { useDocs } from '../utils/context';
@@ -9,11 +10,12 @@ export default function EditButton() {
const { mode, setMode } = useDocs();
const className = useClass('edit-button', mode === 'edit' ? 'active' : null);
return (
- setMode(mode === 'view' ? 'edit' : 'view')}>
-
+
);
}
diff --git a/services/web/src/docs/components/EditFieldModal.js b/services/web/src/docs/components/EditFieldModal.js
index eaa1780a4..223e81e18 100644
--- a/services/web/src/docs/components/EditFieldModal.js
+++ b/services/web/src/docs/components/EditFieldModal.js
@@ -1,10 +1,19 @@
-import { Button, Checkbox, Stack, TextInput, Textarea } from '@mantine/core';
import { get } from 'lodash';
import { useCallback, useEffect, useState } from 'react';
+import { Button } from '@/components/ui/button';
+import { Checkbox } from '@/components/ui/checkbox';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import { Spinner } from '@/components/ui/spinner';
+import { Textarea } from '@/components/ui/textarea';
+
import ErrorMessage from 'components/ErrorMessage';
+import { useModalContext } from 'components/ModalWrapper';
export default function EditFieldModal(props) {
+ const { close } = useModalContext();
+
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [updateModel, setUpdateModel] = useState(false);
@@ -39,7 +48,7 @@ export default function EditFieldModal(props) {
}
await props.updatePath(updatePath, value);
setLoading(false);
- props.close();
+ close();
} catch (err) {
setError(err);
setLoading(false);
@@ -57,53 +66,48 @@ export default function EditFieldModal(props) {
const { model } = props;
if (model) {
return (
- setUpdateModel(event.currentTarget.checked)}
- mt="md"
- />
+
+ setUpdateModel(checked === true)}
+ />
+ {`Update base ${model.toLowerCase()}.`}
+
);
}
return null;
}
return (
- <>
-
-
+
+
+
+ {props.markdown ? (
+
+ ) : (
+
+ )}
+ {renderUpdateModel()}
+
-
- Save
-
-
- >
+
+ {loading && }
+ Save
+
+
);
}
diff --git a/services/web/src/docs/components/EditableField.js b/services/web/src/docs/components/EditableField.js
index 37b836c76..5e08dc938 100644
--- a/services/web/src/docs/components/EditableField.js
+++ b/services/web/src/docs/components/EditableField.js
@@ -1,4 +1,3 @@
-import { Text } from '@mantine/core';
import { get, startCase } from 'lodash';
import PropTypes from 'prop-types';
import { useContext } from 'react';
@@ -40,19 +39,6 @@ export default function DocsEditableField(props) {
return [mode === 'edit' ? 'editable' : null, value ? 'filled' : 'empty'];
}
- function renderModalContent({ close }) {
- return (
-
- );
- }
-
function render() {
if (mode === 'edit') {
return (
@@ -60,9 +46,19 @@ export default function DocsEditableField(props) {
title={[
`Edit ${startCase(type)}`,
props.markdown && ' - Supports Markdown',
- ].filter(Boolean)}
- component={renderModalContent}
- trigger={{renderValue()} }
+ ]
+ .filter(Boolean)
+ .join('')}
+ component={
+
+ }
+ trigger={{renderValue()} }
/>
);
} else {
diff --git a/services/web/src/docs/components/Properties.js b/services/web/src/docs/components/Properties.js
index df03324f5..01fded46d 100644
--- a/services/web/src/docs/components/Properties.js
+++ b/services/web/src/docs/components/Properties.js
@@ -1,8 +1,13 @@
-import { Popover } from '@mantine/core';
import { get, isEqual } from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
+} from '@/components/ui/tooltip';
+
import { useClass } from 'helpers/bem';
import { JumpLink } from 'components/Link';
@@ -201,12 +206,14 @@ export default function DocsProperties(props) {
return (
{renderTypes(oneOf[0])}
-
-
+
+
*
-
- May also be an array.
-
+
+
+ May also be an array.
+
+
);
}
diff --git a/services/web/src/docs/components/RequestBuilder.js b/services/web/src/docs/components/RequestBuilder.js
index ad4089e83..de2d124e8 100644
--- a/services/web/src/docs/components/RequestBuilder.js
+++ b/services/web/src/docs/components/RequestBuilder.js
@@ -1,21 +1,3 @@
-import {
- ActionIcon,
- Affix,
- Divider,
- Drawer,
- Fieldset,
- Group,
- LoadingOverlay,
- Paper,
- SegmentedControl,
- Stack,
- Switch,
- Tabs,
- Text,
- TextInput,
-} from '@mantine/core';
-
-import { useDisclosure } from '@mantine/hooks';
import { get, set } from 'lodash';
import React, { useState } from 'react';
@@ -27,6 +9,26 @@ import {
PiTrashBold,
} from 'react-icons/pi';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import { Separator } from '@/components/ui/separator';
+import {
+ Sheet,
+ SheetContent,
+ SheetHeader,
+ SheetTitle,
+} from '@/components/ui/sheet';
+import { Spinner } from '@/components/ui/spinner';
+import { Switch } from '@/components/ui/switch';
+import {
+ Tabs,
+ TabsContent,
+ TabsList,
+ TabsTrigger,
+} from '@/components/ui/tabs';
+import { cn } from '@/lib/utils';
+
import Code from 'components/Code';
import ErrorMessage from 'components/ErrorMessage';
import RequestBlock from 'components/RequestBlock';
@@ -56,7 +58,15 @@ const TYPE_RANK = {
};
export default function RequestBuilder(props) {
- const [opened, { open, close }] = useDisclosure(false);
+ const [opened, setOpened] = useState(false);
+
+ function open() {
+ setOpened(true);
+ }
+
+ function close() {
+ setOpened(false);
+ }
const { route, trigger } = props;
@@ -153,13 +163,13 @@ export default function RequestBuilder(props) {
function renderRequestPane() {
return (
-
+
{renderParameters()}
{renderQuery()}
{renderBody()}
-
+
{renderOutput()}
-
+
);
}
@@ -207,9 +217,7 @@ export default function RequestBuilder(props) {
if (schema?.properties) {
return (
<>
-
- Body
-
+ Body
{renderSchema(schema, ['body'])}
>
);
@@ -275,9 +283,9 @@ export default function RequestBuilder(props) {
{key}{' '}
-
+
{open ? : }
-
+
{open && (
@@ -292,8 +300,9 @@ export default function RequestBuilder(props) {
{key}{' '}
- {
const p = [...path, key];
const values = get(req, p, []);
@@ -301,7 +310,7 @@ export default function RequestBuilder(props) {
setReq({ ...req });
}}>
-
+
{renderSchema(schema, [...path, key])}
@@ -323,12 +332,13 @@ export default function RequestBuilder(props) {
{values.map((value, i) => {
return (
-
+
{renderSchema(items, [...path, i], {
...options,
icon: (
-
{
const updated = values.filter((value, j) => {
return j !== i;
@@ -337,10 +347,10 @@ export default function RequestBuilder(props) {
setReq({ ...req });
}}>
-
+
),
})}
-
+
);
})}
@@ -372,34 +382,42 @@ export default function RequestBuilder(props) {
return renderCheckbox(path, options);
}
- function renderInput(path, options) {
+ function renderInput(path, options = {}) {
+ const { label, icon, ...rest } = options;
const value = get(req, path);
return (
-
{
- setField(event, { value: e.target.value, path, ...options });
- }}
- autoComplete="chrome-off"
- spellCheck="false"
- />
+
+ {label &&
{label} }
+
+ {
+ setField(e, { value: e.target.value, path, ...options });
+ }}
+ autoComplete="chrome-off"
+ spellCheck="false"
+ />
+ {icon}
+
+
);
}
- function renderCheckbox(path, options) {
+ function renderCheckbox(path, options = {}) {
+ const { label, icon } = options;
const value = get(req, path);
return (
- {
- setField(event, { value: e.target.checked, path, ...options });
- }}
- {...options}
- />
+
+ {
+ setField(null, { checked, type: 'checkbox', path, ...options });
+ }}
+ />
+ {label && {label} }
+ {icon}
+
);
}
@@ -419,15 +437,11 @@ export default function RequestBuilder(props) {
function renderResponsePane() {
if (res || error) {
return (
-
+
{res &&
{JSON.stringify(res, null, 2)}}
- {recorded && (
-
- Response Recorded
-
- )}
-
+ {recorded &&
Response Recorded
}
+
);
}
}
@@ -437,49 +451,60 @@ export default function RequestBuilder(props) {
{React.cloneElement(trigger, {
onClick: open,
})}
-
-
-
-
- setActiveTab(value === 'request' ? 0 : 1)}>
-
- Request
- Response
-
-
-
- {renderRequestPane()}
-
-
-
- {renderResponsePane()}
-
-
-
-
-
-
- {canEditDocs() && (
-
-
-
- )}
-
-
-
-
-
-
-
+ (value ? open() : close())}>
+
+
+ {route}
+
+
+ {loading && (
+
+
+
+ )}
+
+
+ setActiveTab(value === 'request' ? 0 : 1)
+ }>
+
+ Request
+ Response
+
+
+
+ {renderRequestPane()}
+
+
+
+ {renderResponsePane()}
+
+
+
+
+ {canEditDocs() && (
+
+
+
+ )}
+
+
+
+
+
+
);
}
@@ -509,24 +534,34 @@ function AnyOfSchema(props) {
const [selected, setSelected] = useState(0);
+ const items = anyOf
+ .map((schema, i) => {
+ return {
+ label: schema.type || '',
+ value: i,
+ };
+ })
+ .filter((item) => {
+ return item.label;
+ });
+
return (
- {
- return {
- label: schema.type || '',
- value: i,
- };
- })
- .filter((item) => {
- return item.label;
- })}
- onChange={(value) => {
- setSelected(value);
- }}
- />
+
+ {items.map((item) => {
+ return (
+ setSelected(item.value)}>
+ {item.label}
+
+ );
+ })}
+
{renderSchema(anyOf[selected])}
);
diff --git a/services/web/src/docs/components/RouteAuthentication.js b/services/web/src/docs/components/RouteAuthentication.js
index 4e5c653d5..bf4bbc896 100644
--- a/services/web/src/docs/components/RouteAuthentication.js
+++ b/services/web/src/docs/components/RouteAuthentication.js
@@ -1,5 +1,4 @@
import { Link } from '@bedrockio/router';
-import { Anchor } from '@mantine/core';
import { get } from 'lodash';
import React from 'react';
@@ -44,15 +43,19 @@ export default class Route extends React.Component {
renderAuth() {
if (this.authRequired()) {
return (
-
+
Required
-
+
);
} else if (this.authOptional()) {
return (
-
+
Optional
-
+
);
} else {
return 'None';
diff --git a/services/web/src/docs/components/RouteExample.js b/services/web/src/docs/components/RouteExample.js
index b44ffd63d..b4dc610c1 100644
--- a/services/web/src/docs/components/RouteExample.js
+++ b/services/web/src/docs/components/RouteExample.js
@@ -1,7 +1,8 @@
-import { ActionIcon, Group, Text } from '@mantine/core';
import { useState } from 'react';
import { PiMinus, PiPlus, PiTrashBold } from 'react-icons/pi';
+import { Button } from '@/components/ui/button';
+
import { useClass } from 'helpers/bem';
import { JumpLink } from 'components/Link';
@@ -70,14 +71,9 @@ export default function RouteExample(props) {
-
-
-
- {status}
-
+
+
+
{status}
+
-
+
}
/>
-
-
+
+
{canEditDocs() && (
Are you sure you want to delete this example?
+ Are you sure you want to delete this example?
}
trigger={
- {
evt.stopPropagation();
}}>
-
+
}
/>
)}
{open ? : }
-
-
+
+
{open && (