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 ( +
+
+

Edit Part {part.id}

+
+
+ +
+
+ ) +} 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 ( +
+
+

New Part

+
+
+ +
+
+ ) +} + +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)}
+ +
+ +
+
+ Cascade Studio 0.0.6 + makeMainProject()}>Make Main Project + saveProject()}>Save Project + + threejsViewport.saveShapeSTEP()}>Save STEP + threejsViewport.saveShapeSTL()}>Save STL + threejsViewport.saveShapeOBJ()}>Save OBJ + + clearExternalFiles()}>Clear Imported Files + { + window.localStorage.clear(); + window.history.replaceState({}, 'Cascade Studio','?') + }}>Reset Project +
+
+
+ +
+ + ) +} + +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 ( +
+
+ + + + + + + + + + + + + + + + + + +
+ + Save + +
+ +
+ ) +} + +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 ( +
+ + + + + + + + + + + + + + {parts.map((part) => ( + + + + + + + + + + ))} + +
IdTitleDescriptionCodeMain imageCreated at 
{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}
-

Cascade Studio 0.0.6 makeMainProject()}>Make Main Project @@ -70,7 +69,7 @@ const HomePage = () => {
footer
-
+
) } 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 ( - - - + + + + + ) }