diff --git a/api/prisma/migrations/20201011043647-create-parts/README.md b/api/prisma/migrations/20201011043647-create-parts/README.md
new file mode 100644
index 0000000..1def1c5
--- /dev/null
+++ b/api/prisma/migrations/20201011043647-create-parts/README.md
@@ -0,0 +1,52 @@
+# Migration `20201011043647-create-parts`
+
+This migration has been generated by Kurt Hutten at 10/11/2020, 3:36:47 PM.
+You can check out the [state of the schema](./schema.prisma) after the migration.
+
+## Database Steps
+
+```sql
+CREATE TABLE "Part" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "title" TEXT NOT NULL,
+ "description" TEXT NOT NULL,
+ "mainImage" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+```
+
+## Changes
+
+```diff
+diff --git schema.prisma schema.prisma
+migration 20201009213512-create-posts..20201011043647-create-parts
+--- datamodel.dml
++++ datamodel.dml
+@@ -1,9 +1,9 @@
+ datasource DS {
+ // optionally set multiple providers
+ // example: provider = ["sqlite", "postgresql"]
+ provider = "sqlite"
+- url = "***"
++ url = "***"
+ }
+ generator client {
+ provider = "prisma-client-js"
+@@ -15,4 +15,14 @@
+ title String
+ body String
+ createdAt DateTime @default(now())
+ }
++
++model Part {
++ id Int @id @default(autoincrement())
++ title String
++ description String // markdown string
++ mainImage String // link to cloudinary
++ createdAt DateTime @default(now())
++ // userId
++ //likes, comments, reactions
++}
+```
+
+
diff --git a/api/prisma/migrations/20201011043647-create-parts/schema.prisma b/api/prisma/migrations/20201011043647-create-parts/schema.prisma
new file mode 100644
index 0000000..6d2b834
--- /dev/null
+++ b/api/prisma/migrations/20201011043647-create-parts/schema.prisma
@@ -0,0 +1,28 @@
+datasource DS {
+ // optionally set multiple providers
+ // example: provider = ["sqlite", "postgresql"]
+ provider = "sqlite"
+ url = "***"
+}
+
+generator client {
+ provider = "prisma-client-js"
+ binaryTargets = "native"
+}
+
+model Post {
+ id Int @id @default(autoincrement())
+ title String
+ body String
+ createdAt DateTime @default(now())
+}
+
+model Part {
+ id Int @id @default(autoincrement())
+ title String
+ description String // markdown string
+ mainImage String // link to cloudinary
+ createdAt DateTime @default(now())
+ // userId
+ //likes, comments, reactions
+}
diff --git a/api/prisma/migrations/20201011043647-create-parts/steps.json b/api/prisma/migrations/20201011043647-create-parts/steps.json
new file mode 100644
index 0000000..3328ce6
--- /dev/null
+++ b/api/prisma/migrations/20201011043647-create-parts/steps.json
@@ -0,0 +1,105 @@
+{
+ "version": "0.3.14-fixed",
+ "steps": [
+ {
+ "tag": "CreateModel",
+ "model": "Part"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "id",
+ "type": "Int",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "id"
+ },
+ "directive": "id"
+ }
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "id"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "id"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "autoincrement()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "title",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "description",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "mainImage",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "createdAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "now()"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201011052155-add-code-to-part/README.md b/api/prisma/migrations/20201011052155-add-code-to-part/README.md
new file mode 100644
index 0000000..ffbd7bc
--- /dev/null
+++ b/api/prisma/migrations/20201011052155-add-code-to-part/README.md
@@ -0,0 +1,65 @@
+# Migration `20201011052155-add-code-to-part`
+
+This migration has been generated by Kurt Hutten at 10/11/2020, 4:21:55 PM.
+You can check out the [state of the schema](./schema.prisma) after the migration.
+
+## Database Steps
+
+```sql
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Part" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "title" TEXT NOT NULL,
+ "description" TEXT NOT NULL,
+ "code" TEXT NOT NULL DEFAULT '// Welcome to Cascade Studio! Here are some useful functions:
+// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()
+// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()
+// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),
+// FilletEdges(), ChamferEdges(),
+// Slider(), Button(), Checkbox()
+let holeRadius = Slider("Radius", 30 , 20 , 40);
+let sphere = Sphere(50);
+let cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));
+let cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));
+
+Translate([-25, 0, 40], Text3D("Hi!"));/n// Don''t forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!',
+ "mainImage" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+INSERT INTO "new_Part" ("id", "title", "description", "mainImage", "createdAt") SELECT "id", "title", "description", "mainImage", "createdAt" FROM "Part";
+DROP TABLE "Part";
+ALTER TABLE "new_Part" RENAME TO "Part";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON
+```
+
+## Changes
+
+```diff
+diff --git schema.prisma schema.prisma
+migration 20201011043647-create-parts..20201011052155-add-code-to-part
+--- datamodel.dml
++++ datamodel.dml
+@@ -1,9 +1,9 @@
+ datasource DS {
+ // optionally set multiple providers
+ // example: provider = ["sqlite", "postgresql"]
+ provider = "sqlite"
+- url = "***"
++ url = "***"
+ }
+ generator client {
+ provider = "prisma-client-js"
+@@ -20,8 +20,9 @@
+ model Part {
+ id Int @id @default(autoincrement())
+ title String
+ description String // markdown string
++ code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
+ mainImage String // link to cloudinary
+ createdAt DateTime @default(now())
+ // userId
+ //likes, comments, reactions
+```
+
+
diff --git a/api/prisma/migrations/20201011052155-add-code-to-part/schema.prisma b/api/prisma/migrations/20201011052155-add-code-to-part/schema.prisma
new file mode 100644
index 0000000..41ca83b
--- /dev/null
+++ b/api/prisma/migrations/20201011052155-add-code-to-part/schema.prisma
@@ -0,0 +1,29 @@
+datasource DS {
+ // optionally set multiple providers
+ // example: provider = ["sqlite", "postgresql"]
+ provider = "sqlite"
+ url = "***"
+}
+
+generator client {
+ provider = "prisma-client-js"
+ binaryTargets = "native"
+}
+
+model Post {
+ id Int @id @default(autoincrement())
+ title String
+ body String
+ createdAt DateTime @default(now())
+}
+
+model Part {
+ id Int @id @default(autoincrement())
+ title String
+ description String // markdown string
+ code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
+ mainImage String // link to cloudinary
+ createdAt DateTime @default(now())
+ // userId
+ //likes, comments, reactions
+}
diff --git a/api/prisma/migrations/20201011052155-add-code-to-part/steps.json b/api/prisma/migrations/20201011052155-add-code-to-part/steps.json
new file mode 100644
index 0000000..0c8bd6f
--- /dev/null
+++ b/api/prisma/migrations/20201011052155-add-code-to-part/steps.json
@@ -0,0 +1,37 @@
+{
+ "version": "0.3.14-fixed",
+ "steps": [
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "code",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "code"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "code"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "\"// Welcome to Cascade Studio! Here are some useful functions:\\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\\n// FilletEdges(), ChamferEdges(),\\n// Slider(), Button(), Checkbox()\\nlet holeRadius = Slider(\\\"Radius\\\", 30 , 20 , 40);\\nlet sphere = Sphere(50);\\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\\n\\nTranslate([-25, 0, 40], Text3D(\\\"Hi!\\\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!\""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/README.md b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/README.md
new file mode 100644
index 0000000..1e30c97
--- /dev/null
+++ b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/README.md
@@ -0,0 +1,69 @@
+# Migration `20201011082558-add-code-not-needed-upon-create`
+
+This migration has been generated by Kurt Hutten at 10/11/2020, 7:25:58 PM.
+You can check out the [state of the schema](./schema.prisma) after the migration.
+
+## Database Steps
+
+```sql
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Part" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "title" TEXT NOT NULL,
+ "description" TEXT NOT NULL,
+ "code" TEXT NOT NULL DEFAULT '// Welcome to Cascade Studio! Here are some useful functions:
+// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()
+// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()
+// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),
+// FilletEdges(), ChamferEdges(),
+// Slider(), Button(), Checkbox()
+let holeRadius = Slider("Radius", 30 , 20 , 40);
+let sphere = Sphere(50);
+let cylinderZ = Cylinder(holeRadius, 200, true);
+let cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));
+let cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));
+Translate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));
+
+Translate([-25, 0, 40], Text3D("Hi!"));
+// Don''t forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!',
+ "mainImage" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+INSERT INTO "new_Part" ("id", "title", "description", "mainImage", "createdAt", "code") SELECT "id", "title", "description", "mainImage", "createdAt", "code" FROM "Part";
+DROP TABLE "Part";
+ALTER TABLE "new_Part" RENAME TO "Part";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON
+```
+
+## Changes
+
+```diff
+diff --git schema.prisma schema.prisma
+migration 20201011052155-add-code-to-part..20201011082558-add-code-not-needed-upon-create
+--- datamodel.dml
++++ datamodel.dml
+@@ -1,9 +1,9 @@
+ datasource DS {
+ // optionally set multiple providers
+ // example: provider = ["sqlite", "postgresql"]
+ provider = "sqlite"
+- url = "***"
++ url = "***"
+ }
+ generator client {
+ provider = "prisma-client-js"
+@@ -20,9 +20,9 @@
+ model Part {
+ id Int @id @default(autoincrement())
+ title String
+ description String // markdown string
+- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
++ code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
+ mainImage String // link to cloudinary
+ createdAt DateTime @default(now())
+ // userId
+ //likes, comments, reactions
+```
+
+
diff --git a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/schema.prisma b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/schema.prisma
new file mode 100644
index 0000000..f22b4b7
--- /dev/null
+++ b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/schema.prisma
@@ -0,0 +1,29 @@
+datasource DS {
+ // optionally set multiple providers
+ // example: provider = ["sqlite", "postgresql"]
+ provider = "sqlite"
+ url = "***"
+}
+
+generator client {
+ provider = "prisma-client-js"
+ binaryTargets = "native"
+}
+
+model Post {
+ id Int @id @default(autoincrement())
+ title String
+ body String
+ createdAt DateTime @default(now())
+}
+
+model Part {
+ id Int @id @default(autoincrement())
+ title String
+ description String // markdown string
+ code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
+ mainImage String // link to cloudinary
+ createdAt DateTime @default(now())
+ // userId
+ //likes, comments, reactions
+}
diff --git a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/steps.json b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/steps.json
new file mode 100644
index 0000000..8c127a5
--- /dev/null
+++ b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/steps.json
@@ -0,0 +1,19 @@
+{
+ "version": "0.3.14-fixed",
+ "steps": [
+ {
+ "tag": "UpdateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "code"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "newValue": "\"// Welcome to Cascade Studio! Here are some useful functions:\\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\\n// FilletEdges(), ChamferEdges(),\\n// Slider(), Button(), Checkbox()\\nlet holeRadius = Slider(\\\"Radius\\\", 30 , 20 , 40);\\nlet sphere = Sphere(50);\\nlet cylinderZ = Cylinder(holeRadius, 200, true);\\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\\n\\nTranslate([-25, 0, 40], Text3D(\\\"Hi!\\\"));\\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!\""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/api/prisma/migrations/migrate.lock b/api/prisma/migrations/migrate.lock
index a23e9cb..299515f 100644
--- a/api/prisma/migrations/migrate.lock
+++ b/api/prisma/migrations/migrate.lock
@@ -1,3 +1,6 @@
# Prisma Migrate lockfile v1
-20201009213512-create-posts
\ No newline at end of file
+20201009213512-create-posts
+20201011043647-create-parts
+20201011052155-add-code-to-part
+20201011082558-add-code-not-needed-upon-create
\ No newline at end of file
diff --git a/api/prisma/schema.prisma b/api/prisma/schema.prisma
index 929fed4..449c8ad 100644
--- a/api/prisma/schema.prisma
+++ b/api/prisma/schema.prisma
@@ -16,3 +16,14 @@ model Post {
body String
createdAt DateTime @default(now())
}
+
+model Part {
+ id Int @id @default(autoincrement())
+ title String
+ description String // markdown string
+ code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
+ mainImage String // link to cloudinary
+ createdAt DateTime @default(now())
+ // userId
+ //likes, comments, reactions
+}
diff --git a/api/src/graphql/parts.sdl.js b/api/src/graphql/parts.sdl.js
new file mode 100644
index 0000000..bec69fa
--- /dev/null
+++ b/api/src/graphql/parts.sdl.js
@@ -0,0 +1,35 @@
+export const schema = gql`
+ type Part {
+ id: Int!
+ title: String!
+ description: String!
+ code: String!
+ mainImage: String!
+ createdAt: DateTime!
+ }
+
+ type Query {
+ parts: [Part!]!
+ part(id: Int!): Part
+ }
+
+ input CreatePartInput {
+ title: String!
+ description: String!
+ code: String
+ mainImage: String
+ }
+
+ input UpdatePartInput {
+ title: String
+ description: String
+ code: String
+ mainImage: String
+ }
+
+ type Mutation {
+ createPart(input: CreatePartInput!): Part!
+ updatePart(id: Int!, input: UpdatePartInput!): Part!
+ deletePart(id: Int!): Part!
+ }
+`
diff --git a/api/src/services/parts/parts.js b/api/src/services/parts/parts.js
new file mode 100644
index 0000000..98c6243
--- /dev/null
+++ b/api/src/services/parts/parts.js
@@ -0,0 +1,30 @@
+import { db } from 'src/lib/db'
+
+export const parts = () => {
+ return db.part.findMany()
+}
+
+export const part = ({ id }) => {
+ return db.part.findOne({
+ where: { id },
+ })
+}
+
+export const createPart = ({ input }) => {
+ return db.part.create({
+ data: input,
+ })
+}
+
+export const updatePart = ({ id, input }) => {
+ return db.part.update({
+ data: input,
+ where: { id },
+ })
+}
+
+export const deletePart = ({ id }) => {
+ return db.part.delete({
+ where: { id },
+ })
+}
diff --git a/api/src/services/parts/parts.test.js b/api/src/services/parts/parts.test.js
new file mode 100644
index 0000000..e8b80ce
--- /dev/null
+++ b/api/src/services/parts/parts.test.js
@@ -0,0 +1,9 @@
+/*
+import { parts } from './parts'
+*/
+
+describe('parts', () => {
+ it('returns true', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/web/src/Routes.js b/web/src/Routes.js
index 4b19643..0245da0 100644
--- a/web/src/Routes.js
+++ b/web/src/Routes.js
@@ -12,13 +12,17 @@ import { Router, Route } from '@redwoodjs/router'
const Routes = () => {
return (
+
+
+
+
-
+
)
diff --git a/web/src/cascade b/web/src/cascade
index b536e6a..e634591 160000
--- a/web/src/cascade
+++ b/web/src/cascade
@@ -1 +1 @@
-Subproject commit b536e6a09a261650161b284fbef9c125c0e464be
+Subproject commit e634591e27dd41fec1638b278be3c298c6ab4b5a
diff --git a/web/src/components/EditPartCell/EditPartCell.js b/web/src/components/EditPartCell/EditPartCell.js
new file mode 100644
index 0000000..ca617e4
--- /dev/null
+++ b/web/src/components/EditPartCell/EditPartCell.js
@@ -0,0 +1,51 @@
+import { useMutation, useFlash } from '@redwoodjs/web'
+import { navigate, routes } from '@redwoodjs/router'
+import PartForm from 'src/components/PartForm'
+
+export const QUERY = gql`
+ query FIND_PART_BY_ID($id: Int!) {
+ part: part(id: $id) {
+ id
+ title
+ description
+ code
+ mainImage
+ createdAt
+ }
+ }
+`
+const UPDATE_PART_MUTATION = gql`
+ mutation UpdatePartMutation($id: Int!, $input: UpdatePartInput!) {
+ updatePart(id: $id, input: $input) {
+ id
+ code
+ }
+ }
+`
+
+export const Loading = () =>
Loading...
+
+export const Success = ({ part }) => {
+ const { addMessage } = useFlash()
+ const [updatePart, { loading, error }] = useMutation(UPDATE_PART_MUTATION, {
+ onCompleted: () => {
+ navigate(routes.parts())
+ addMessage('Part updated.', { classes: 'rw-flash-success' })
+ },
+ })
+
+ const onSave = (input, id) => {
+ updatePart({ variables: { id, input } })
+ }
+
+ return (
+
+ )
+}
diff --git a/web/src/components/NewPart/NewPart.js b/web/src/components/NewPart/NewPart.js
new file mode 100644
index 0000000..3b7e5ed
--- /dev/null
+++ b/web/src/components/NewPart/NewPart.js
@@ -0,0 +1,38 @@
+import { useMutation, useFlash } from '@redwoodjs/web'
+import { navigate, routes } from '@redwoodjs/router'
+import PartForm from 'src/components/PartForm'
+
+const CREATE_PART_MUTATION = gql`
+ mutation CreatePartMutation($input: CreatePartInput!) {
+ createPart(input: $input) {
+ id
+ }
+ }
+`
+
+const NewPart = () => {
+ const { addMessage } = useFlash()
+ const [createPart, { loading, error }] = useMutation(CREATE_PART_MUTATION, {
+ onCompleted: () => {
+ navigate(routes.parts())
+ addMessage('Part created.', { classes: 'rw-flash-success' })
+ },
+ })
+
+ const onSave = (input) => {
+ createPart({ variables: { input } })
+ }
+
+ return (
+
+ )
+}
+
+export default NewPart
diff --git a/web/src/components/Part/Part.js b/web/src/components/Part/Part.js
new file mode 100644
index 0000000..b132dbc
--- /dev/null
+++ b/web/src/components/Part/Part.js
@@ -0,0 +1,110 @@
+import { useMutation, useFlash } from '@redwoodjs/web'
+import { Link, routes, navigate } from '@redwoodjs/router'
+import { initialize } from 'src/cascade/js/MainPage/CascadeMain'
+import { useEffect, useState } from 'react'
+
+const DELETE_PART_MUTATION = gql`
+ mutation DeletePartMutation($id: Int!) {
+ deletePart(id: $id) {
+ id
+ }
+ }
+`
+
+const Part = ({ part, saveCode, loading, error}) => {
+ const [code, setCode] = useState(part.code)
+ useEffect(() => {
+ const sickCallback = (code) => setCode(code)
+ initialize(sickCallback, part.code)
+ }, [])
+ const hasChanges = code !== part.code
+ const { addMessage } = useFlash()
+ const [deletePart] = useMutation(DELETE_PART_MUTATION, {
+ onCompleted: () => {
+ navigate(routes.parts())
+ addMessage('Part deleted.', { classes: 'rw-flash-success' })
+ },
+ })
+
+ const onDeleteClick = (id) => {
+ if (confirm('Are you sure you want to delete part ' + id + '?')) {
+ deletePart({ variables: { id } })
+ }
+ }
+
+ return (
+ <>
+
+
+
+ Part {part.id} Detail
+
+
+
+
+
+ | Title |
+ {part.title} |
+
+
+ | Description |
+ {part.description} |
+
+ {/*
+ | Code |
+ {part.code} |
+
*/}
+ {/*
+ | Main image |
+ {part.mainImage} |
+
*/}
+ {/*
+ | Created at |
+ {timeTag(part.createdAt)} |
+
*/}
+
+
+

+
+
+
+ >
+ )
+}
+
+export default Part
diff --git a/web/src/components/PartCell/PartCell.js b/web/src/components/PartCell/PartCell.js
new file mode 100644
index 0000000..3b95c0b
--- /dev/null
+++ b/web/src/components/PartCell/PartCell.js
@@ -0,0 +1,46 @@
+import { useMutation, useFlash } from '@redwoodjs/web'
+import { navigate, routes } from '@redwoodjs/router'
+import Part from 'src/components/Part'
+
+export const QUERY = gql`
+ query FIND_PART_BY_ID($id: Int!) {
+ part: part(id: $id) {
+ id
+ title
+ description
+ code
+ mainImage
+ createdAt
+ }
+ }
+`
+
+const UPDATE_PART_MUTATION = gql`
+ mutation UpdatePartMutation($id: Int!, $input: UpdatePartInput!) {
+ updatePart(id: $id, input: $input) {
+ id
+ }
+ }
+`
+
+export const Loading = () => Loading...
+
+export const Empty = () => Part not found
+
+export const Success = ({ part }) => {
+ const { addMessage } = useFlash()
+ const [updatePart, { loading, error }] = useMutation(UPDATE_PART_MUTATION, {
+ onCompleted: () => {
+ // navigate(routes.part({id: updatePart.id}))
+ addMessage('Part updated.', { classes: 'rw-flash-success' })
+ },
+ })
+ console.log({updatePart})
+
+
+ const saveCode = (input, id) => {
+ console.log(id, input, 'wowow')
+ updatePart({ variables: { id, input } })
+ }
+ return
+}
diff --git a/web/src/components/PartForm/PartForm.js b/web/src/components/PartForm/PartForm.js
new file mode 100644
index 0000000..433987b
--- /dev/null
+++ b/web/src/components/PartForm/PartForm.js
@@ -0,0 +1,100 @@
+import {
+ Form,
+ FormError,
+ FieldError,
+ Label,
+ TextField,
+ TextAreaField,
+ Submit,
+} from '@redwoodjs/forms'
+
+const PartForm = (props) => {
+ const onSubmit = (data) => {
+ props.onSave(data, props?.part?.id)
+ }
+
+ return (
+
+ )
+}
+
+export default PartForm
diff --git a/web/src/components/Parts/Parts.js b/web/src/components/Parts/Parts.js
new file mode 100644
index 0000000..c868554
--- /dev/null
+++ b/web/src/components/Parts/Parts.js
@@ -0,0 +1,109 @@
+import { useMutation, useFlash } from '@redwoodjs/web'
+import { Link, routes } from '@redwoodjs/router'
+
+const DELETE_PART_MUTATION = gql`
+ mutation DeletePartMutation($id: Int!) {
+ deletePart(id: $id) {
+ id
+ }
+ }
+`
+
+const MAX_STRING_LENGTH = 150
+
+const truncate = (text) => {
+ let output = text
+ if (text && text.length > MAX_STRING_LENGTH) {
+ output = output.substring(0, MAX_STRING_LENGTH) + '...'
+ }
+ return output
+}
+
+const jsonTruncate = (obj) => {
+ return truncate(JSON.stringify(obj, null, 2))
+}
+
+const timeTag = (datetime) => {
+ return (
+
+ )
+}
+
+const checkboxInputTag = (checked) => {
+ return
+}
+
+const PartsList = ({ parts }) => {
+ const { addMessage } = useFlash()
+ const [deletePart] = useMutation(DELETE_PART_MUTATION, {
+ onCompleted: () => {
+ addMessage('Part deleted.', { classes: 'rw-flash-success' })
+ },
+ })
+
+ const onDeleteClick = (id) => {
+ if (confirm('Are you sure you want to delete part ' + id + '?')) {
+ deletePart({ variables: { id }, refetchQueries: ['PARTS'] })
+ }
+ }
+
+ return (
+
+
+
+
+ | Id |
+ Title |
+ Description |
+ Code |
+ Main image |
+ Created at |
+ |
+
+
+
+ {parts.map((part) => (
+
+ | {truncate(part.id)} |
+ {truncate(part.title)} |
+ {truncate(part.description)} |
+ {truncate(part.code)} |
+ {truncate(part.mainImage)} |
+ {timeTag(part.createdAt)} |
+
+
+ |
+
+ ))}
+
+
+
+ )
+}
+
+export default PartsList
diff --git a/web/src/components/PartsCell/PartsCell.js b/web/src/components/PartsCell/PartsCell.js
new file mode 100644
index 0000000..98380e8
--- /dev/null
+++ b/web/src/components/PartsCell/PartsCell.js
@@ -0,0 +1,33 @@
+import { Link, routes } from '@redwoodjs/router'
+
+import Parts from 'src/components/Parts'
+
+export const QUERY = gql`
+ query PARTS {
+ parts {
+ id
+ title
+ description
+ code
+ mainImage
+ createdAt
+ }
+ }
+`
+
+export const Loading = () => Loading...
+
+export const Empty = () => {
+ return (
+
+ {'No parts yet. '}
+
+ {'Create one?'}
+
+
+ )
+}
+
+export const Success = ({ parts }) => {
+ return
+}
diff --git a/web/src/index.html b/web/src/index.html
index bec0953..a8fa947 100644
--- a/web/src/index.html
+++ b/web/src/index.html
@@ -25,7 +25,7 @@
// Begins loading the CAD Kernel Web Worker
if (window.Worker) {
- cascadeStudioWorker = new Worker('./src/cascade/js/CADWorker/CascadeStudioMainWorker.js');
+ cascadeStudioWorker = new Worker('/src/cascade/js/CADWorker/CascadeStudioMainWorker.js');
// Ping Pong Messages Back and Forth based on their registration in messageHandlers
// var messageHandlers = {};
cascadeStudioWorker.onmessage = function (e) {
diff --git a/web/src/layouts/MainLayout/MainLayout.js b/web/src/layouts/MainLayout/MainLayout.js
new file mode 100644
index 0000000..8412653
--- /dev/null
+++ b/web/src/layouts/MainLayout/MainLayout.js
@@ -0,0 +1,26 @@
+import { Link, routes } from '@redwoodjs/router'
+
+const MainLayout = ({ children }) => {
+ return (
+ <>
+
+
+
+ {children}
+ >
+ )
+}
+
+export default MainLayout
diff --git a/web/src/layouts/MainLayout/MainLayout.stories.js b/web/src/layouts/MainLayout/MainLayout.stories.js
new file mode 100644
index 0000000..44eb671
--- /dev/null
+++ b/web/src/layouts/MainLayout/MainLayout.stories.js
@@ -0,0 +1,7 @@
+import MainLayout from './MainLayout'
+
+export const generated = () => {
+ return
+}
+
+export default { title: 'Layouts/MainLayout' }
diff --git a/web/src/layouts/MainLayout/MainLayout.test.js b/web/src/layouts/MainLayout/MainLayout.test.js
new file mode 100644
index 0000000..eb404a9
--- /dev/null
+++ b/web/src/layouts/MainLayout/MainLayout.test.js
@@ -0,0 +1,11 @@
+import { render } from '@redwoodjs/testing'
+
+import MainLayout from './MainLayout'
+
+describe('MainLayout', () => {
+ it('renders successfully', () => {
+ expect(() => {
+ render()
+ }).not.toThrow()
+ })
+})
diff --git a/web/src/layouts/PartsLayout/PartsLayout.js b/web/src/layouts/PartsLayout/PartsLayout.js
new file mode 100644
index 0000000..f0ecd0c
--- /dev/null
+++ b/web/src/layouts/PartsLayout/PartsLayout.js
@@ -0,0 +1,23 @@
+import { Link, routes } from '@redwoodjs/router'
+import { Flash } from '@redwoodjs/web'
+
+const PartsLayout = (props) => {
+ return (
+
+
+
+
+
+ Parts
+
+
+
+ +
New Part
+
+
+
{props.children}
+
+ )
+}
+
+export default PartsLayout
diff --git a/web/src/pages/EditPartPage/EditPartPage.js b/web/src/pages/EditPartPage/EditPartPage.js
new file mode 100644
index 0000000..3634709
--- /dev/null
+++ b/web/src/pages/EditPartPage/EditPartPage.js
@@ -0,0 +1,12 @@
+import PartsLayout from 'src/layouts/PartsLayout'
+import EditPartCell from 'src/components/EditPartCell'
+
+const EditPartPage = ({ id }) => {
+ return (
+
+
+
+ )
+}
+
+export default EditPartPage
diff --git a/web/src/pages/HomePage/HomePage.js b/web/src/pages/HomePage/HomePage.js
index 0f9d2c7..94f1f89 100644
--- a/web/src/pages/HomePage/HomePage.js
+++ b/web/src/pages/HomePage/HomePage.js
@@ -1,4 +1,4 @@
-import BlogLayout from 'src/layouts/BlogLayout'
+import MainLayout from 'src/layouts/MainLayout'
import BlogPostsCell from 'src/components/BlogPostsCell'
import { initialize } from 'src/cascade/js/MainPage/CascadeMain'
import { useEffect, useState } from 'react'
@@ -35,11 +35,10 @@ const HomePage = () => {
}, [])
return (
-
+
current code {code}
-
+
)
}
diff --git a/web/src/pages/NewPartPage/NewPartPage.js b/web/src/pages/NewPartPage/NewPartPage.js
new file mode 100644
index 0000000..4f39148
--- /dev/null
+++ b/web/src/pages/NewPartPage/NewPartPage.js
@@ -0,0 +1,12 @@
+import PartsLayout from 'src/layouts/PartsLayout'
+import NewPart from 'src/components/NewPart'
+
+const NewPartPage = () => {
+ return (
+
+
+
+ )
+}
+
+export default NewPartPage
diff --git a/web/src/pages/PartPage/PartPage.js b/web/src/pages/PartPage/PartPage.js
new file mode 100644
index 0000000..b9bcd31
--- /dev/null
+++ b/web/src/pages/PartPage/PartPage.js
@@ -0,0 +1,15 @@
+import PartsLayout from 'src/layouts/PartsLayout'
+import MainLayout from 'src/layouts/MainLayout'
+import PartCell from 'src/components/PartCell'
+
+const PartPage = ({ id }) => {
+ return (
+
+
+
+
+
+ )
+}
+
+export default PartPage
diff --git a/web/src/pages/PartsPage/PartsPage.js b/web/src/pages/PartsPage/PartsPage.js
new file mode 100644
index 0000000..ae36f11
--- /dev/null
+++ b/web/src/pages/PartsPage/PartsPage.js
@@ -0,0 +1,15 @@
+import MainLayout from 'src/layouts/MainLayout'
+import PartsLayout from 'src/layouts/PartsLayout'
+import PartsCell from 'src/components/PartsCell'
+
+const PartsPage = () => {
+ return (
+
+
+
+
+
+ )
+}
+
+export default PartsPage
diff --git a/web/src/pages/PostsPage/PostsPage.js b/web/src/pages/PostsPage/PostsPage.js
index 7318d9b..b5392dc 100644
--- a/web/src/pages/PostsPage/PostsPage.js
+++ b/web/src/pages/PostsPage/PostsPage.js
@@ -1,11 +1,14 @@
+import MainLayout from 'src/layouts/MainLayout'
import PostsLayout from 'src/layouts/PostsLayout'
import PostsCell from 'src/components/PostsCell'
const PostsPage = () => {
return (
-
-
-
+
+
+
+
+
)
}