Start project fork feature

Updated schema, project service and UI
Still some polish to go.

Co-authored-by: Frank Noirot <franknoirot@users.noreply.github.com>
This commit is contained in:
Kurt Hutten
2021-09-25 12:54:04 +10:00
parent 38b905e180
commit 02463db741
5 changed files with 79 additions and 9 deletions

View File

@@ -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;

View File

@@ -53,7 +53,10 @@ model Project {
deleted Boolean @default(false)
cadPackage CadPackage @default(openscad)
socialCard SocialCard?
forkedFromId String?
forkedFrom Project? @relation("Fork", fields: [forkedFromId], references: [id])
childForks Project[] @relation("Fork")
Comment Comment[]
Reaction ProjectReaction[]
@@unique([title, userId])

View File

@@ -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!

View File

@@ -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,
}),
})
}

View File

@@ -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
)}
{/* <TopButton>Fork</TopButton> */}
<div className="h-8 w-8">
<NavPlusButton />
</div>
@@ -130,6 +142,26 @@ function DefaultTopButtons({
handleRender,
canEdit,
}) {
const { currentUser } = useAuth()
const [createFork] = useMutation(FORK_PROJECT_MUTATION, {
onCompleted: () => {},
})
const handleFork = () => {
const prom = createFork({
variables: {
input: {
userId: currentUser.sub,
forkedFromId: project.id,
},
},
})
// toast.promise(prom, {
// loading: 'Saving Image/s',
// success: <b>Image/s saved!</b>,
// error: <b>Problem saving.</b>,
// })
}
return (
<>
{canEdit && !projectTitle && (
@@ -212,6 +244,15 @@ function DefaultTopButtons({
)
}}
</Popover>
{currentUser?.id && (
<TopButton
onClick={handleFork}
name="Fork"
className=" bg-ch-blue-650 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
>
<Svg name="fork-new" className="w-6 h-6 text-ch-blue-400" />
</TopButton>
)}
</>
)
}