Skip to content

Commit

Permalink
feat: edit panel state change and panel styling (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
minsgy authored Jun 7, 2024
2 parents f05b2fa + d817a36 commit 8da66fd
Show file tree
Hide file tree
Showing 20 changed files with 706 additions and 56 deletions.
25 changes: 19 additions & 6 deletions example/src/mocks/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
import { http, HttpResponse } from "msw"
import { HttpResponse } from "msw"
import { http } from "msw-devtools"

export const handlers = [
http.get("https://api.example.com/user", () => {
return HttpResponse.json({
firstName: "John",
lastName: "Maverick",
http
.get("https://api.example.com/user", () => {
return HttpResponse.json({
firstName: "John",
lastName: "Maverick",
})
})
}),
.presets([
{
status: 200,
description: "Success",
response: {
firstName: "John",
lastName: "Maverick",
},
},
]),
http.post("https://api.example.com/user", () => {
return HttpResponse.json({ success: true })
}),
http.put("https://api.example.com/user/:id", () => {
return HttpResponse.json({ success: true })
}),

http.delete("https://api.example.com/user/:id", () => {
return HttpResponse.json({ success: true })
}),
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"./styles": "./dist/index.css"
},
"scripts": {
"dev": "tsup src/index.ts --format cjs,esm --dts --watch ",
"build": "tsup src/index.ts --format cjs,esm --dts --minify ",
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
"build": "tsup src/index.ts --format cjs,esm --dts --minify",
"example": "pnpm build && cd example && pnpm i && pnpm dev"
},
"dependencies": {
Expand Down Expand Up @@ -70,7 +70,7 @@
"tailwind-merge": "2.3.0",
"tailwindcss-animate": "1.0.7",
"ts-pattern": "^5.1.2",
"typescript": "5.1.6"
"typescript": "5.4.5"
},
"devDependencies": {
"autoprefixer": "^10.4.19",
Expand Down
27 changes: 18 additions & 9 deletions src/features/DevtoolsHandlerList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { match } from "ts-pattern"

import { cn } from "@/shared/lib/cn"
import { Checkbox } from "@/shared/ui/checkbox"
import { InlineCode, P } from "@/shared/ui/typography"
import { HttpMethods } from "msw"
import {
Expand All @@ -12,32 +11,42 @@ import {
} from "@/providers/useMswDevtoolsContext"
import { HandlerSelect } from "./HandlerSelect"
import { Button } from "@/shared/ui/button"
import { InputContainer } from "@/shared/ui/input-container"
import { Label } from "@/shared/ui/label"
import { Switch } from "@/shared/ui/switch"

export const DevtoolsHandlerList = () => {
const { routes, onToggleHandler } = useRoute()
const { onOpenEditPanel } = useEditorRouteState()

return (
<ul className=" list-none overflow-y-auto h-[250px] scrollbar-hide bg-secondary rounded-[4px]">
<ul className="list-none overflow-y-auto h-[250px] scrollbar-hide rounded-[4px] bg-transparent">
<li className="p-[12px] flex items-center">
<P className="font-semibold">Skip</P>
<P className="font-semibold">Actions</P>
<P className="font-semibold">Options</P>
</li>
{routes.map((route) => (
<li key={route.id} className="p-[12px] flex items-center">
<Checkbox
id={route.id}
<Switch
checked={route.isSkip}
onCheckedChange={(checked) => {
onToggleHandler(route.id)
onToggleHandler(route.id, checked)
}}
/>
<label
<Label
htmlFor={route.id}
className="pl-[12px] flex items-center w-full"
>
<MethodTag method={route.method} />
<span className="font-semibold">{route.url}</span>
<div className="ml-auto flex items-center">
<InputContainer label="delay" />
<HandlerSelect
options={route.handlers}
defaultValue={route.handlers[0].id}
options={route.handlers ?? []}
defaultValue={
route.handlers?.[route.selectedHandlerIndex]?.id ?? undefined
}
/>
<Button
className="ml-[12px]"
Expand All @@ -49,7 +58,7 @@ export const DevtoolsHandlerList = () => {
Edit
</Button>
</div>
</label>
</Label>
</li>
))}
</ul>
Expand Down
6 changes: 3 additions & 3 deletions src/features/HandlerSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export const HandlerSelect = ({ options, ...rest }: HandlerSelectProps) => {
return (
<Select {...rest}>
<SelectTrigger className="w-[280px]">
<SelectValue placeholder="Select a timezone" />
<SelectValue placeholder="test" />
</SelectTrigger>
<SelectContent>
{options.map(({ id, description }) => (
{options?.map(({ id, description, status }) => (
<SelectItem key={id} value={id}>
{description}
{status} - {description}
</SelectItem>
))}
</SelectContent>
Expand Down
125 changes: 125 additions & 0 deletions src/features/RouteEditPanel/CreateEditForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Button } from "@/shared/ui/button"
import { Input } from "@/shared/ui/input"
import { H4, P } from "@/shared/ui/typography"
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from "@/shared/ui/select"
import { format } from "prettier"
import { ResponseJsonEditor } from "./ResponseJsonEditor"
import { StatusSelect } from "./StatusSelect"
import babel from "prettier/plugins/babel"
import prettierPluginEstree from "prettier/plugins/estree"
import { Separator } from "@/shared/ui/separator"
import { Controller, useForm } from "react-hook-form"
import { HttpMethods } from "msw"
import { ROUTE_METHODS } from "@/constants"

type CreateEditFormValues = {
delay?: string
description?: string
method: HttpMethods
url: string
status: string
response: string
}

export const CreateEditForm = () => {
const {
register,
control,
handleSubmit,
setError,
formState: { errors },
} = useForm<CreateEditFormValues>({
defaultValues: {
method: HttpMethods.GET,
url: "",
status: "200",
response: "{}",
},
})

return (
<form
onSubmit={handleSubmit((value) => {
console.log(value)
})}
>
<div className="flex py-[12px] px-[16px]">
<Controller
control={control}
name="method"
render={({ field }) => (
<Select defaultValue={field.value} onValueChange={field.onChange}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
{ROUTE_METHODS.map((method) => (
<SelectItem key={method} value={method}>
{method}
</SelectItem>
))}
</SelectContent>
</Select>
)}
/>
<Input
placeholder="Route URL https://example.com/..."
{...register("url")}
/>
<Button type="submit">Save</Button>
</div>
<Separator />
<div className="flex py-[12px] px-[16px]">
<StatusSelect defaultValue={"200"} />
<Input placeholder="Description" {...register("description")} />
<Input placeholder="delay" {...register("delay")} />
</div>
<Separator />
<div className="flex justify-between w-full text-left py-[12px] px-[16px]">
<H4>Response Body</H4>
{errors.response && (
<P className="text-red-500">{errors.response.message}</P>
)}
</div>
<div className="py-[12px] px-[16px] text-left">
<Controller
control={control}
name="response"
render={({ field }) => (
<ResponseJsonEditor
value={field.value}
onChange={(value) => {
console.log(value)
field.onChange(value)
}}
onSave={async () => {
try {
const formattedResponse = await format(field.value, {
tabWidth: 2,
printWidth: 100,
parser: "json5",
plugins: [babel, prettierPluginEstree],
})
// LINK: https://github.com/prettier/prettier/issues/6360
field.onChange(formattedResponse.replace(/[\r\n]+$/, ""))
} catch (error) {
const formattedError =
error instanceof Error ? error.message : "Unknown Error"
setError("response", {
message: formattedError,
})
}
}}
/>
)}
/>
</div>
</form>
)
}
65 changes: 65 additions & 0 deletions src/features/RouteEditPanel/ResponseJsonEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import CodeMirror, {
KeyBinding,
ReactCodeMirrorProps,
hoverTooltip,
keymap,
} from "@uiw/react-codemirror"
import { githubDark } from "@uiw/codemirror-theme-github"
import { linter } from "@codemirror/lint"
import { jsonAutoComplete } from "./utils/jsonAutoComplete"
import { autocompletion, closeBracketsKeymap } from "@codemirror/autocomplete"
import { defaultKeymap, historyKeymap } from "@codemirror/commands"
import { json5, json5ParseLinter } from "codemirror-json5"

export type ResponseJsonEditorProps = ReactCodeMirrorProps & {
onSave?: VoidFunction
}

export const ResponseJsonEditor = ({
onSave,
...rest
}: ResponseJsonEditorProps) => {
const savedKeymap: KeyBinding = {
key: "Ctrl-s",
preventDefault: true,
run: (editor) => {
onSave?.()
return editor.hasFocus
},
}

return (
<CodeMirror
style={{ height: "100%" }}
extensions={[
json5(),
linter(json5ParseLinter(), {
delay: 300,
}),
autocompletion({
defaultKeymap: true,
icons: true,
aboveCursor: true,
activateOnTyping: true,
}),
jsonAutoComplete(),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
savedKeymap,
]),
]}
theme={githubDark}
basicSetup={{
lineNumbers: true,
highlightActiveLine: true,
highlightActiveLineGutter: true,
indentOnInput: true,
history: true,
bracketMatching: true,
}}
{...rest}
/>
)
}
28 changes: 28 additions & 0 deletions src/features/RouteEditPanel/StatusSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/shared/ui/select"
import { STATUS_CODES } from "./constants"
import { SelectProps } from "@radix-ui/react-select"

export const StatusSelect = ({ ...rest }: SelectProps) => {
return (
<Select {...rest}>
<SelectTrigger className="w-[280px]">
<SelectValue placeholder="Select HTTP Status" />
</SelectTrigger>
<SelectContent>
{STATUS_CODES.map(({ label, value }) => {
return (
<SelectItem key={value} value={String(value)}>
{label}
</SelectItem>
)
})}
</SelectContent>
</Select>
)
}
Loading

0 comments on commit 8da66fd

Please sign in to comment.