diff --git a/app/api/db/migrations/20210925001652_add_project_forking/migration.sql b/app/api/db/migrations/20210925001652_add_project_forking/migration.sql
new file mode 100644
index 0000000..a5c9a3e
--- /dev/null
+++ b/app/api/db/migrations/20210925001652_add_project_forking/migration.sql
@@ -0,0 +1,5 @@
+-- AlterTable
+ALTER TABLE "Project" ADD COLUMN "forkedFromId" TEXT;
+
+-- AddForeignKey
+ALTER TABLE "Project" ADD FOREIGN KEY ("forkedFromId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;
diff --git a/app/api/db/schema.prisma b/app/api/db/schema.prisma
index 98cdfd0..d91dda8 100644
--- a/app/api/db/schema.prisma
+++ b/app/api/db/schema.prisma
@@ -53,9 +53,12 @@ model Project {
deleted Boolean @default(false)
cadPackage CadPackage @default(openscad)
socialCard SocialCard?
+ forkedFromId String?
+ forkedFrom Project? @relation("Fork", fields: [forkedFromId], references: [id])
- Comment Comment[]
- Reaction ProjectReaction[]
+ childForks Project[] @relation("Fork")
+ Comment Comment[]
+ Reaction ProjectReaction[]
@@unique([title, userId])
}
diff --git a/app/api/src/graphql/projects.sdl.ts b/app/api/src/graphql/projects.sdl.ts
index 7faa41c..507d1db 100644
--- a/app/api/src/graphql/projects.sdl.ts
+++ b/app/api/src/graphql/projects.sdl.ts
@@ -14,6 +14,9 @@ export const schema = gql`
socialCard: SocialCard
Comment: [Comment]!
Reaction(userId: String): [ProjectReaction]!
+ forkedFromId: String
+ forkedFrom: Project
+ childForks: [Project]!
}
enum CadPackage {
@@ -37,6 +40,11 @@ export const schema = gql`
cadPackage: CadPackage!
}
+ input ForkProjectInput {
+ userId: String!
+ forkedFromId: String
+ }
+
input UpdateProjectInput {
title: String
description: String
@@ -47,7 +55,7 @@ export const schema = gql`
type Mutation {
createProject(input: CreateProjectInput!): Project!
- forkProject(input: CreateProjectInput!): Project!
+ forkProject(input: ForkProjectInput!): Project!
updateProject(id: String!, input: UpdateProjectInput!): Project!
updateProjectImages(
id: String!
diff --git a/app/api/src/services/projects/projects.ts b/app/api/src/services/projects/projects.ts
index 2f0c806..94b3121 100644
--- a/app/api/src/services/projects/projects.ts
+++ b/app/api/src/services/projects/projects.ts
@@ -78,13 +78,26 @@ export const createProject = async ({ input }: CreateProjectArgs) => {
}
export const forkProject = async ({ input }) => {
- // Only difference between create and fork project is that fork project will generate a unique title
- // (for the user) if there is a conflict
+ requireAuth()
+ const projectData = await db.project.findUnique({
+ where: {
+ id: input.forkedFromId,
+ },
+ })
const isUniqueCallback = isUniqueProjectTitle(input.userId)
- const title = await generateUniqueString(input.title, isUniqueCallback)
- // TODO change the description to `forked from userName/projectName ${rest of description}`
+ let title = projectData.title
+
+ title = await generateUniqueString(title, isUniqueCallback)
+
+ const { code, description, cadPackage } = projectData
return db.project.create({
- data: foreignKeyReplacement({ ...input, title }),
+ data: foreignKeyReplacement({
+ ...input,
+ title,
+ code,
+ description,
+ cadPackage,
+ }),
})
}
diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx
index 7ca76a6..02e3a91 100644
--- a/app/web/src/components/IdeHeader/IdeHeader.tsx
+++ b/app/web/src/components/IdeHeader/IdeHeader.tsx
@@ -8,11 +8,24 @@ import ExternalScript from 'src/components/EncodedUrl/ExternalScript'
import Svg from 'src/components/Svg/Svg'
import NavPlusButton from 'src/components/NavPlusButton'
import ProfileSlashLogin from 'src/components/ProfileSlashLogin'
+import { useMutation } from '@redwoodjs/web'
import Gravatar from 'src/components/Gravatar/Gravatar'
import EditableProjectTitle from 'src/components/EditableProjecTitle/EditableProjecTitle'
import CaptureButton from 'src/components/CaptureButton/CaptureButton'
+
import { ReactNode } from 'react'
+const FORK_PROJECT_MUTATION = gql`
+ mutation ForkProjectMutation($input: ForkProjectInput!) {
+ forkProject(input: $input) {
+ id
+ title
+ description
+ code
+ }
+ }
+`
+
const TopButton = ({
onClick,
children,
@@ -111,7 +124,6 @@ const IdeHeader = ({
) : (
children
)}
- {/*