-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from joshtyf/feature/implement-service-catalog…
…-sub-pages Implement service catalog sub pages
- Loading branch information
Showing
22 changed files
with
1,526 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
.../src/app/(authenticated)/service-catalog/[serviceRequestId]/_hooks/use-service-request.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { ServiceRequest } from "@/types/service" | ||
import { IChangeEvent } from "@rjsf/core" | ||
import { RJSFSchema } from "@rjsf/utils" | ||
|
||
interface UseServiceRequestProps { | ||
serviceRequestId: string | ||
} | ||
|
||
const useServiceRequest = ({ serviceRequestId }: UseServiceRequestProps) => { | ||
const serviceRequest: ServiceRequest = { | ||
name: "Sample Service Request", | ||
description: "Sample Service Request Form", | ||
form: { | ||
input: { | ||
title: "Input", | ||
type: "input", | ||
description: "Input Description with minimum length 1", | ||
minLength: 1, | ||
required: true, | ||
}, | ||
select: { | ||
title: "Select Option", | ||
type: "select", | ||
description: "Dropdown selection with default value as Item 1", | ||
options: ["Item 1", "Item 2", "Item 3"], | ||
required: true, | ||
}, | ||
checkboxes: { | ||
title: "Checkboxes", | ||
type: "checkboxes", | ||
description: "You can select more than 1 item", | ||
options: ["Item 1", "Item 2", "Item 3"], | ||
required: false, | ||
}, | ||
}, | ||
} | ||
|
||
const handleSubmit = (data: IChangeEvent<object, RJSFSchema, object>) => { | ||
// TODO: Replace with API call | ||
// TODO: Add validations | ||
console.log( | ||
"Data submitted: ", | ||
"Service id: " + serviceRequestId, | ||
data.formData | ||
) | ||
} | ||
return { | ||
serviceRequest, | ||
handleSubmit, | ||
} | ||
} | ||
|
||
export default useServiceRequest |
81 changes: 81 additions & 0 deletions
81
frontend/src/app/(authenticated)/service-catalog/[serviceRequestId]/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
"use client" | ||
|
||
import React from "react" | ||
import { useParams, useRouter } from "next/navigation" | ||
import HeaderAccessory from "@/components/ui/header-accessory" | ||
import { Button } from "@/components/ui/button" | ||
import { ChevronLeft } from "lucide-react" | ||
import useServiceRequest from "./_hooks/use-service-request" | ||
import validator from "@rjsf/validator-ajv8" | ||
import Form from "@rjsf/core" | ||
import FieldTemplate from "@/components/form/custom-templates/field-template" | ||
import FieldErrorTemplate from "@/components/form/custom-templates/field-error-template" | ||
import BaseInputTemplate from "@/components/form/custom-templates/base-input-template" | ||
import ArrayFieldTemplate from "@/components/form/custom-templates/array-field-template" | ||
import { | ||
convertServiceRequestFormToRJSFSchema, | ||
generateUiSchema, | ||
} from "@/lib/utils" | ||
import { RegistryWidgetsType } from "@rjsf/utils" | ||
import CustomCheckboxes from "@/components/form/custom-widgets/custom-checkboxes" | ||
import CustomSelect from "@/components/form/custom-widgets/custom-select" | ||
|
||
const widgets: RegistryWidgetsType = { | ||
CheckboxesWidget: CustomCheckboxes, | ||
SelectWidget: CustomSelect, | ||
} | ||
|
||
export default function ServiceRequestPage() { | ||
const { serviceRequestId } = useParams() | ||
const serviceRequestIdString = Array.isArray(serviceRequestId) | ||
? serviceRequestId[0] | ||
: serviceRequestId | ||
const router = useRouter() | ||
const { serviceRequest, handleSubmit } = useServiceRequest({ | ||
serviceRequestId: serviceRequestIdString, | ||
}) | ||
|
||
const { name, description, form } = serviceRequest | ||
|
||
const uiSchema = generateUiSchema(serviceRequest) | ||
const rjsfSchema = convertServiceRequestFormToRJSFSchema(form) | ||
|
||
return ( | ||
<> | ||
<div className="flex flex-col justify-start py-10"> | ||
<HeaderAccessory /> | ||
<div className="flex items-baseline space-x-2"> | ||
<Button size="icon" variant="ghost" onClick={() => router.back()}> | ||
<ChevronLeft /> | ||
</Button> | ||
<p className="font-bold text-3xl pt-5">{name}</p> | ||
</div> | ||
<p className="text-lg pt-3 ml-12 text-gray-500">{description}</p> | ||
</div> | ||
<div className="w-full flex justify-center"> | ||
<div className="w-4/5"> | ||
<Form | ||
schema={rjsfSchema} | ||
uiSchema={uiSchema} | ||
validator={validator} | ||
onSubmit={handleSubmit} | ||
templates={{ | ||
FieldTemplate, | ||
FieldErrorTemplate, | ||
BaseInputTemplate, | ||
ArrayFieldTemplate, | ||
}} | ||
widgets={widgets} | ||
showErrorList={false} | ||
> | ||
<div className="flex justify-end"> | ||
<Button size="lg" type="submit"> | ||
Submit | ||
</Button> | ||
</div> | ||
</Form> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
frontend/src/app/(authenticated)/service-catalog/create-service/_hooks/use-create-service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { ServiceRequestWithSteps } from "@/types/service" | ||
import { useForm } from "react-hook-form" | ||
import { z } from "zod" | ||
import { zodResolver } from "@hookform/resolvers/zod" | ||
import { isJson } from "@/lib/utils" | ||
import { KeyboardEvent, KeyboardEventHandler } from "react" | ||
import { validateFormSchema } from "../_utils/validation" | ||
|
||
const DEFAULT_FORM = { | ||
input: { title: "", description: "", type: "input", required: true }, | ||
select: { | ||
title: "", | ||
description: "", | ||
type: "select", | ||
required: true, | ||
options: ["Option 1", "Option 2", "Option 3"], | ||
}, | ||
checkBoxes: { | ||
title: "", | ||
description: "", | ||
type: "checkboxes", | ||
required: false, | ||
options: ["Option 1", "Option 2", "Option 3"], | ||
}, | ||
} | ||
|
||
const DEFAULT_STEPS = { | ||
Approval: { | ||
name: "Approval", | ||
type: "approval", | ||
next: "", | ||
start: true, | ||
}, | ||
} | ||
|
||
const createServiceSchema = z.object({ | ||
name: z.string().min(1, "Name is required"), | ||
description: z.string(), | ||
form: z | ||
.string() | ||
.min(1, "Form Schema is required") | ||
.superRefine((val, ctx) => { | ||
const errorList = validateFormSchema(val) | ||
if (errorList.length > 0) { | ||
ctx.addIssue({ | ||
code: z.ZodIssueCode.custom, | ||
message: errorList.join(" , "), | ||
}) | ||
} | ||
}) | ||
.refine((arg) => isJson(arg), { | ||
message: "Ensure that Form is valid JSON Schema", | ||
}), | ||
steps: z | ||
.string() | ||
.min(1, "Pipeline Steps Schema is required") | ||
.refine((arg) => isJson(arg), { | ||
message: "Ensure that Form is valid JSON Schema", | ||
}), | ||
}) | ||
const useCreateService = () => { | ||
const form = useForm<z.infer<typeof createServiceSchema>>({ | ||
resolver: zodResolver(createServiceSchema), | ||
defaultValues: { | ||
name: "", | ||
description: "", | ||
form: JSON.stringify(DEFAULT_FORM, null, 4), | ||
steps: JSON.stringify(DEFAULT_STEPS, null, 4), | ||
}, | ||
}) | ||
|
||
const handleSubmitForm = (values: z.infer<typeof createServiceSchema>) => { | ||
const { description, form, name, steps } = values | ||
|
||
// TODO: Replace with API call | ||
console.log("Submitting:", { | ||
name, | ||
description, | ||
form: JSON.parse(form), | ||
steps: JSON.parse(steps), | ||
}) | ||
} | ||
|
||
function handleTextAreaTabKeyDown(event: KeyboardEvent): void { | ||
if (event.key == "Tab") { | ||
event.preventDefault() | ||
const htmlTextElement = event.target as HTMLTextAreaElement | ||
const start = htmlTextElement.selectionStart | ||
const end = htmlTextElement.selectionEnd | ||
|
||
htmlTextElement.value = | ||
htmlTextElement.value.substring(0, start) + | ||
"\t" + | ||
htmlTextElement.value.substring(end) | ||
|
||
htmlTextElement.selectionStart = htmlTextElement.selectionEnd = start + 1 | ||
} | ||
} | ||
|
||
return { | ||
form, | ||
handleSubmitForm, | ||
handleTextAreaTabKeyDown, | ||
} | ||
} | ||
|
||
export default useCreateService |
Oops, something went wrong.