Skip to content

Commit 95aad32

Browse files
committed
Add created custom node to database
1 parent c6c8f5f commit 95aad32

6 files changed

Lines changed: 301 additions & 200 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"use server"
2+
3+
import {NodeDefinition} from "@/model/NodeDefinition";
4+
import {cookies} from "next/headers";
5+
import {createClient} from "@/utils/supabase/server";
6+
import {Json, NodeDefinitionVisibility} from "@/model/database/database.types";
7+
8+
export default async function(nodeDefinition: NodeDefinition, creatorId: string, teamId: number, visibility: NodeDefinitionVisibility): Promise<void> {
9+
10+
const cookieStore = cookies()
11+
const supabase = createClient(cookieStore, process.env.SUPABASE_SERVICE_KEY)
12+
13+
let { data, error } = await supabase
14+
.from("node_definition")
15+
.insert({
16+
definition: nodeDefinition as unknown as Json,
17+
created_by: creatorId,
18+
team_id: teamId,
19+
visibility: visibility,
20+
})
21+
.select()
22+
23+
if (error || !data) {
24+
throw Error(error?.message || "Error creating node definition")
25+
}
26+
27+
return
28+
}
Lines changed: 14 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -1,200 +1,16 @@
1-
"use client"
2-
3-
import {useState} from "react"
4-
import {Button} from "@/components/ui/button"
5-
import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card"
6-
import type {NodeDefinition} from "@/model/NodeDefinition"
7-
import {OptionsStructureType} from "@/model/OptionsModel"
8-
import {StepInfo} from "@/components/shop/create-node/StepInfo"
9-
import {StepGeneralInfo} from "@/components/shop/create-node/StepGeneralInfo"
10-
import {StepOptionsConfig} from "@/components/shop/create-node/StepOptionsConfig"
11-
import {StepServerConfig} from "@/components/shop/create-node/StepServerConfig"
12-
import {Progress} from "@/components/ui/progress"
13-
import {Check, ChevronLeft, ChevronRight, Save} from "lucide-react"
14-
import {useTranslations} from "next-intl";
15-
import PreviewDynamicOptions from "@/components/shop/details/PreviewDynamicOptions";
16-
17-
export default function CreateNodePage() {
18-
const t = useTranslations("shop.create-node")
19-
const [currentStep, setCurrentStep] = useState(1)
20-
const [nodeDefinition, setNodeDefinition] = useState<NodeDefinition>({
21-
id: undefined,
22-
name: "",
23-
icon: undefined,
24-
shortDescription: "",
25-
markdownDocumentation: "",
26-
executionMode: "Manual",
27-
executionUrl: "",
28-
optionsDefinition: {
29-
title: "",
30-
nodeId: "",
31-
structure: [],
32-
},
33-
})
34-
35-
const updateNodeDefinition = (updatedDefinition: NodeDefinition) => {
36-
setNodeDefinition(updatedDefinition)
37-
}
38-
39-
const handleNext = () => {
40-
if (currentStep < 4) {
41-
setCurrentStep(currentStep + 1)
42-
}
43-
}
44-
45-
const handlePrevious = () => {
46-
if (currentStep > 1) {
47-
setCurrentStep(currentStep - 1)
48-
}
49-
}
50-
51-
const processNestedStructure = (structure: any[]): any[] => {
52-
return structure.map((option) => {
53-
const processedOption = { ...option }
54-
if ("label" in option && option.label) {
55-
let keyString = toCamelCase(option.label as string)
56-
if (
57-
option.type === OptionsStructureType.VARIABLE_NAME_INPUT ||
58-
option.type === OptionsStructureType.MULTIPLE_VARIABLE_NAME_INPUT
59-
) {
60-
keyString = `outputs.${keyString}`
61-
}
62-
processedOption.keyString = keyString
63-
} else {
64-
processedOption.keyString = undefined
65-
}
66-
67-
if (option.type === OptionsStructureType.ROW && "structure" in option) {
68-
processedOption.structure = processNestedStructure(option.structure)
69-
}
70-
71-
if ("options" in option && Array.isArray(option.options)) {
72-
processedOption.options = option.options.map((opt: { dependentStructure: any[] }) => ({
73-
...opt,
74-
dependentStructure: opt.dependentStructure ? processNestedStructure(opt.dependentStructure) : undefined,
75-
}))
76-
}
77-
78-
return processedOption
79-
})
1+
import {cookies} from "next/headers";
2+
import {createClient} from "@/utils/supabase/server";
3+
import {redirect} from "next/navigation";
4+
import CreateNodePage from "@/components/shop/create-node/CreateNodePage";
5+
6+
export default async function CreateNode({ params }: { params: { teamId: number } }) {
7+
8+
const cookieStore = cookies()
9+
const supabase = createClient(cookieStore)
10+
const {data: userData, error} = await supabase.auth.getUser()
11+
if (error || !userData.user || !userData.user.id) {
12+
redirect("/authenticate")
8013
}
8114

82-
const saveNodeDefinition = () => {
83-
const definitionWithKeyStrings = {
84-
...nodeDefinition,
85-
optionsDefinition: {
86-
...nodeDefinition.optionsDefinition,
87-
structure: processNestedStructure(nodeDefinition.optionsDefinition.structure),
88-
},
89-
}
90-
console.log(JSON.stringify(definitionWithKeyStrings, null, 2))
91-
}
92-
93-
return (
94-
<div className="container mx-auto py-10 px-4 max-w-6xl">
95-
<h1 className="text-3xl font-bold mb-8 text-center">{t("title")}</h1>
96-
97-
<div className="mb-10">
98-
<div className="flex justify-between mb-3">
99-
{[1, 2, 3, 4].map((step) => (
100-
<div
101-
key={step}
102-
className={`flex items-center ${currentStep === step ? "text-primary font-medium" : "text-muted-foreground"}`}
103-
>
104-
<div
105-
className={`flex items-center justify-center w-10 h-10 rounded-full mr-2
106-
${
107-
currentStep > step
108-
? "bg-primary text-primary-foreground"
109-
: currentStep === step
110-
? "border-2 border-primary text-primary"
111-
: "border-2 border-muted-foreground text-muted-foreground"
112-
}`}
113-
>
114-
{currentStep > step ? <Check className="h-5 w-5" /> : step}
115-
</div>
116-
<span className="hidden sm:inline">
117-
{step === 1 && t("steps.information")}
118-
{step === 2 && t("steps.general-details")}
119-
{step === 3 && t("steps.options")}
120-
{step === 4 && t("steps.server-config")}
121-
</span>
122-
</div>
123-
))}
124-
</div>
125-
<Progress value={(currentStep / 4) * 100} indicatorColor="bg-primary" className="h-2" />
126-
</div>
127-
128-
<div className="flex flex-row space-x-4">
129-
<Card className="p-8 shadow-sm">
130-
{currentStep === 1 && <StepInfo onNext={handleNext} />}
131-
132-
{currentStep === 2 && (
133-
<StepGeneralInfo
134-
nodeDefinition={nodeDefinition}
135-
updateNodeDefinition={updateNodeDefinition}
136-
onNext={handleNext}
137-
onPrevious={handlePrevious}
138-
/>
139-
)}
140-
141-
{currentStep === 3 && (
142-
<StepOptionsConfig
143-
nodeDefinition={nodeDefinition}
144-
updateNodeDefinition={updateNodeDefinition}
145-
onNext={handleNext}
146-
onPrevious={handlePrevious}
147-
/>
148-
)}
149-
150-
{currentStep === 4 && (
151-
<StepServerConfig
152-
nodeDefinition={nodeDefinition}
153-
updateNodeDefinition={updateNodeDefinition}
154-
onPrevious={handlePrevious}
155-
onSave={saveNodeDefinition}
156-
/>
157-
)}
158-
</Card>
159-
160-
{ currentStep === 3 && <Card className="pt-4 shadow-sm w-[500px]">
161-
<CardHeader>
162-
<CardTitle>Preview</CardTitle>
163-
</CardHeader>
164-
<CardContent className="overscroll-y-auto">
165-
<PreviewDynamicOptions optionsDefinition={nodeDefinition.optionsDefinition} />
166-
</CardContent>
167-
</Card> }
168-
</div>
169-
170-
<div className="flex justify-between mt-8">
171-
{ currentStep !== 1 ? <Button variant="outline" onClick={handlePrevious} size="lg" className="px-6">
172-
<ChevronLeft className="mr-2 h-5 w-5" />
173-
{t("navigation.previous")}
174-
</Button> : <div></div> }
175-
176-
{currentStep < 4 ? (
177-
<Button onClick={handleNext} size="lg" className="px-6">
178-
{t("navigation.next")}
179-
<ChevronRight className="ml-2 h-5 w-5" />
180-
</Button>
181-
) : (
182-
<Button onClick={saveNodeDefinition} size="lg" className="px-6 bg-green-600 hover:bg-green-700">
183-
<Save className="mr-2 h-5 w-5" />
184-
{t("navigation.save")}
185-
</Button>
186-
)}
187-
</div>
188-
</div>
189-
)
190-
}
191-
192-
// Helper function
193-
function toCamelCase(str: string): string {
194-
return str
195-
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
196-
return index === 0 ? word.toLowerCase() : word.toUpperCase()
197-
})
198-
.replace(/\s+/g, "")
199-
}
200-
15+
return <CreateNodePage teamId={params.teamId} userId={userData.user.id} />
16+
}

0 commit comments

Comments
 (0)