From 02463db741e57e6300d2ddc8399212e9cca1fade Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 25 Sep 2021 12:54:04 +1000 Subject: [PATCH 1/6] Start project fork feature Updated schema, project service and UI Still some polish to go. Co-authored-by: Frank Noirot --- .../migration.sql | 5 +++ app/api/db/schema.prisma | 7 ++- app/api/src/graphql/projects.sdl.ts | 10 ++++- app/api/src/services/projects/projects.ts | 23 +++++++--- .../src/components/IdeHeader/IdeHeader.tsx | 43 ++++++++++++++++++- 5 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 app/api/db/migrations/20210925001652_add_project_forking/migration.sql 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 )} - {/* Fork */}
@@ -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: Image/s saved!, + // error: Problem saving., + // }) + } + return ( <> {canEdit && !projectTitle && ( @@ -212,6 +244,15 @@ function DefaultTopButtons({ ) }} + {currentUser?.id && ( + + + + )} ) } From 2d7fb91f929f612d4e3521d33939cb02229a5d2b Mon Sep 17 00:00:00 2001 From: Frank Johnson Date: Sun, 26 Sep 2021 23:37:57 -0400 Subject: [PATCH 2/6] added navigation to new project on fork --- app/api/src/services/projects/projects.ts | 16 ++++++----- .../src/components/IdeHeader/IdeHeader.tsx | 28 +++++++++++++------ .../components/ProjectCell/ProjectCell.tsx | 8 ++++++ .../ProjectProfile/ProjectProfile.tsx | 5 ++++ 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/app/api/src/services/projects/projects.ts b/app/api/src/services/projects/projects.ts index 94b3121..ece8a60 100644 --- a/app/api/src/services/projects/projects.ts +++ b/app/api/src/services/projects/projects.ts @@ -90,14 +90,16 @@ export const forkProject = async ({ input }) => { title = await generateUniqueString(title, isUniqueCallback) const { code, description, cadPackage } = projectData + const data = foreignKeyReplacement({ + ...input, + title, + code, + description, + cadPackage, + }) + console.log('forking data', data) return db.project.create({ - data: foreignKeyReplacement({ - ...input, - title, - code, - description, - cadPackage, - }), + data }) } diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx index 02e3a91..24d33b9 100644 --- a/app/web/src/components/IdeHeader/IdeHeader.tsx +++ b/app/web/src/components/IdeHeader/IdeHeader.tsx @@ -12,6 +12,7 @@ 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 { toast } from '@redwoodjs/web/toast' import { ReactNode } from 'react' @@ -20,8 +21,10 @@ const FORK_PROJECT_MUTATION = gql` forkProject(input: $input) { id title - description - code + user { + id + userName + } } } ` @@ -144,7 +147,14 @@ function DefaultTopButtons({ }) { const { currentUser } = useAuth() const [createFork] = useMutation(FORK_PROJECT_MUTATION, { - onCompleted: () => {}, + onCompleted: ({ forkProject }) => { + navigate( + routes.ide({ + userName: forkProject?.user?.userName, + projectTitle: forkProject?.title, + }) + ) + }, }) const handleFork = () => { const prom = createFork({ @@ -155,11 +165,11 @@ function DefaultTopButtons({ }, }, }) - // toast.promise(prom, { - // loading: 'Saving Image/s', - // success: Image/s saved!, - // error: Problem saving., - // }) + toast.promise(prom, { + loading: 'Forking...', + success: Forked successfully!, + error: Problem forking., + }) } return ( @@ -244,7 +254,7 @@ function DefaultTopButtons({ ) }} - {currentUser?.id && ( + {currentUser?.sub && ( emote) useEffect(() => { @@ -145,6 +147,9 @@ const ProjectProfile = ({ {new Date(project?.updatedAt).toDateString()} + { project.forkedFrom && + { project.forkedFrom.title } by { project.forkedFrom.user.userName } + } Date: Mon, 27 Sep 2021 18:51:26 +1000 Subject: [PATCH 3/6] Add forking graphQL resolvers --- app/api/src/services/projects/projects.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/api/src/services/projects/projects.ts b/app/api/src/services/projects/projects.ts index ece8a60..4de1ada 100644 --- a/app/api/src/services/projects/projects.ts +++ b/app/api/src/services/projects/projects.ts @@ -267,6 +267,10 @@ export const deleteProject = async ({ id }: Prisma.ProjectWhereUniqueInput) => { } export const Project = { + forkedFrom: (_obj, { root }) => + root.forkedFromId && db.project.findUnique({where: { id: root.forkedFromId}}), + childForks: (_obj, { root }) => + db.project.findMany({where: { forkedFromId: root.id}}), user: (_obj, { root }: ResolverArgs>) => db.project.findUnique({ where: { id: root.id } }).user(), socialCard: (_obj, { root }: ResolverArgs>) => From 7540c908e70ef7ab10e27abc00686c3a667212bf Mon Sep 17 00:00:00 2001 From: Frank Johnson Date: Mon, 27 Sep 2021 08:24:15 -0400 Subject: [PATCH 4/6] Added link in ProjectProfile and fork count to ProjectCard --- app/api/src/services/projects/projects.ts | 22 +++++++++---------- .../src/components/IdeHeader/IdeHeader.tsx | 16 +++++++++----- .../components/ProjectCard/ProjectCard.tsx | 12 ++++++++-- .../components/ProjectCell/ProjectCell.tsx | 2 -- .../ProjectProfile/ProjectProfile.tsx | 20 ++++++++++++----- app/web/src/components/Projects/Projects.tsx | 6 ++++- .../components/ProjectsCell/ProjectsCell.tsx | 3 +++ .../ProjectsOfUserCell/ProjectsOfUserCell.tsx | 3 +++ app/web/src/index.css | 1 + 9 files changed, 59 insertions(+), 26 deletions(-) diff --git a/app/api/src/services/projects/projects.ts b/app/api/src/services/projects/projects.ts index 4de1ada..bb83798 100644 --- a/app/api/src/services/projects/projects.ts +++ b/app/api/src/services/projects/projects.ts @@ -90,16 +90,15 @@ export const forkProject = async ({ input }) => { title = await generateUniqueString(title, isUniqueCallback) const { code, description, cadPackage } = projectData - const data = foreignKeyReplacement({ - ...input, - title, - code, - description, - cadPackage, - }) - console.log('forking data', data) + return db.project.create({ - data + data: foreignKeyReplacement({ + ...input, + title, + code, + description, + cadPackage, + }), }) } @@ -268,9 +267,10 @@ export const deleteProject = async ({ id }: Prisma.ProjectWhereUniqueInput) => { export const Project = { forkedFrom: (_obj, { root }) => - root.forkedFromId && db.project.findUnique({where: { id: root.forkedFromId}}), + root.forkedFromId && + db.project.findUnique({ where: { id: root.forkedFromId } }), childForks: (_obj, { root }) => - db.project.findMany({where: { forkedFromId: root.id}}), + db.project.findMany({ where: { forkedFromId: root.id } }), user: (_obj, { root }: ResolverArgs>) => db.project.findUnique({ where: { id: root.id } }).user(), socialCard: (_obj, { root }: ResolverArgs>) => diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx index 24d33b9..b85c868 100644 --- a/app/web/src/components/IdeHeader/IdeHeader.tsx +++ b/app/web/src/components/IdeHeader/IdeHeader.tsx @@ -1,4 +1,5 @@ import { useAuth } from '@redwoodjs/auth' +import { useLocation } from '@redwoodjs/router' import { Popover } from '@headlessui/react' import { Link, navigate, routes } from '@redwoodjs/router' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' @@ -120,6 +121,7 @@ const IdeHeader = ({ { + const params = { + userName: forkProject?.user?.userName, + projectTitle: forkProject?.title, + } navigate( - routes.ide({ - userName: forkProject?.user?.userName, - projectTitle: forkProject?.title, - }) + pathname.includes('/ide') ? routes.ide(params) : routes.project(params) ) }, }) @@ -161,7 +167,7 @@ function DefaultTopButtons({ variables: { input: { userId: currentUser.sub, - forkedFromId: project.id, + forkedFromId: project?.id || projectId, }, }, }) diff --git a/app/web/src/components/ProjectCard/ProjectCard.tsx b/app/web/src/components/ProjectCard/ProjectCard.tsx index 6652690..2463bcf 100644 --- a/app/web/src/components/ProjectCard/ProjectCard.tsx +++ b/app/web/src/components/ProjectCard/ProjectCard.tsx @@ -6,7 +6,14 @@ import { countEmotes } from 'src/helpers/emote' import ImageUploader from 'src/components/ImageUploader' import { ImageFallback } from '../ImageUploader/ImageUploader' -const ProjectCard = ({ title, mainImage, user, Reaction, cadPackage }) => ( +const ProjectCard = ({ + title, + mainImage, + user, + Reaction, + cadPackage, + childForks, +}) => (
  • ( {countEmotes(Reaction).reduce((prev, { count }) => prev + count, 0)}
    - 0 + + {childForks?.length || 0}
    diff --git a/app/web/src/components/ProjectCell/ProjectCell.tsx b/app/web/src/components/ProjectCell/ProjectCell.tsx index 509fb9c..30a2b36 100644 --- a/app/web/src/components/ProjectCell/ProjectCell.tsx +++ b/app/web/src/components/ProjectCell/ProjectCell.tsx @@ -26,9 +26,7 @@ export const QUERY = gql` mainImage createdAt updatedAt - userId cadPackage - forkedFromId forkedFrom { id title diff --git a/app/web/src/components/ProjectProfile/ProjectProfile.tsx b/app/web/src/components/ProjectProfile/ProjectProfile.tsx index b4e30d4..b5bf735 100644 --- a/app/web/src/components/ProjectProfile/ProjectProfile.tsx +++ b/app/web/src/components/ProjectProfile/ProjectProfile.tsx @@ -38,7 +38,6 @@ const ProjectProfile = ({ const hasPermissionToEdit = currentUser?.sub === userProject.id || currentUser?.roles.includes('admin') const project = userProject?.Project - console.log({ project }) const emotes = countEmotes(project?.Reaction) const userEmotes = project?.userReactions.map(({ emote }) => emote) @@ -73,10 +72,10 @@ const ProjectProfile = ({
    {}} - projectTitle={project?.title} projectOwner={userProject?.userName} projectOwnerImage={userProject?.image} projectOwnerId={userProject?.id} + projectTitle={project?.title} projectId={project?.id} />
    @@ -147,9 +146,20 @@ const ProjectProfile = ({ {new Date(project?.updatedAt).toDateString()} - { project.forkedFrom && - { project.forkedFrom.title } by { project.forkedFrom.user.userName } - } + {project.forkedFrom && ( + + + {project.forkedFrom.title} + {' '} + by {project.forkedFrom.user.userName} + + )} {filteredProjects.map( - ({ title, mainImage, user, Reaction, cadPackage }, index) => ( + ( + { title, mainImage, user, Reaction, cadPackage, childForks }, + index + ) => ( ) )} diff --git a/app/web/src/components/ProjectsCell/ProjectsCell.tsx b/app/web/src/components/ProjectsCell/ProjectsCell.tsx index 63ee987..4acb694 100644 --- a/app/web/src/components/ProjectsCell/ProjectsCell.tsx +++ b/app/web/src/components/ProjectsCell/ProjectsCell.tsx @@ -9,6 +9,9 @@ export const QUERY = gql` title cadPackage mainImage + childForks { + id + } createdAt updatedAt user { diff --git a/app/web/src/components/ProjectsOfUserCell/ProjectsOfUserCell.tsx b/app/web/src/components/ProjectsOfUserCell/ProjectsOfUserCell.tsx index e77725c..b3a7b22 100644 --- a/app/web/src/components/ProjectsOfUserCell/ProjectsOfUserCell.tsx +++ b/app/web/src/components/ProjectsOfUserCell/ProjectsOfUserCell.tsx @@ -9,6 +9,9 @@ export const QUERY = gql` title mainImage cadPackage + childForks { + id + } createdAt updatedAt user { diff --git a/app/web/src/index.css b/app/web/src/index.css index a0cd4de..d1ccb29 100644 --- a/app/web/src/index.css +++ b/app/web/src/index.css @@ -52,6 +52,7 @@ .markdown-overrides div { @apply text-ch-gray-300 bg-transparent; } +.pink-link, .markdown-overrides a, .markdown-overrides div a { @apply text-ch-pink-500 underline bg-transparent; From 77799a587022ebf672aac6795733e08ca70b4f50 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 28 Sep 2021 20:15:45 +1000 Subject: [PATCH 5/6] Refactor IdeHeader to take middle buttons as children --- .../src/components/IdeHeader/IdeHeader.tsx | 324 ++++++++---------- .../src/components/IdeWrapper/IdeWrapper.tsx | 14 +- .../components/ProjectCell/ProjectCell.tsx | 68 ++-- .../ProjectProfile/ProjectProfile.tsx | 14 +- app/web/src/components/TopNav/TopNav.tsx | 31 ++ .../components/UserProfile/UserProfile.tsx | 17 +- app/web/src/pages/DevIdePage/DevIdePage.tsx | 5 +- app/web/src/pages/ProjectPage/ProjectPage.tsx | 15 +- 8 files changed, 231 insertions(+), 257 deletions(-) create mode 100644 app/web/src/components/TopNav/TopNav.tsx diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx index b85c868..ecc4863 100644 --- a/app/web/src/components/IdeHeader/IdeHeader.tsx +++ b/app/web/src/components/IdeHeader/IdeHeader.tsx @@ -1,21 +1,17 @@ import { useAuth } from '@redwoodjs/auth' -import { useLocation } from '@redwoodjs/router' +import { useMutation } from '@redwoodjs/web' import { Popover } from '@headlessui/react' import { Link, navigate, routes } from '@redwoodjs/router' -import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import { Tab, Tabs, TabList, TabPanel } from 'react-tabs' + import FullScriptEncoding from 'src/components/EncodedUrl/FullScriptEncoding' 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 { toast } from '@redwoodjs/web/toast' +import CaptureButton from 'src/components/CaptureButton/CaptureButton' +import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import Gravatar from 'src/components/Gravatar/Gravatar' import EditableProjectTitle from 'src/components/EditableProjecTitle/EditableProjecTitle' -import CaptureButton from 'src/components/CaptureButton/CaptureButton' -import { toast } from '@redwoodjs/web/toast' - -import { ReactNode } from 'react' const FORK_PROJECT_MUTATION = gql` mutation ForkProjectMutation($input: ForkProjectInput!) { @@ -55,101 +51,21 @@ const TopButton = ({ ) } -interface IdeHeaderProps { - handleRender: () => void - projectTitle?: string - projectOwner?: string - projectOwnerId?: string - projectOwnerImage?: string - projectId?: string - children?: ReactNode -} - -const IdeHeader = ({ +export default function IdeHeader({ handleRender, - projectOwner, - projectTitle, - projectOwnerImage, - projectId, - projectOwnerId, - children, -}: IdeHeaderProps) => { - const { currentUser } = useAuth() - const { project } = useIdeContext() - const canEdit = - (currentUser && - currentUser?.sub === (project?.user?.id || projectOwnerId)) || - currentUser?.roles.includes('admin') - const _projectId = projectId || project?.id - const _projectOwner = project?.user?.userName || projectOwner - - return ( -
    -
    -
    - - - -
    - {_projectId && ( - <> - - - - {_projectOwner} - - - - - )} -
    -
    - {!children ? ( - - ) : ( - children - )} -
    - -
    - -
    -
    - ) -} - -export default IdeHeader - -function DefaultTopButtons({ - project, - projectTitle, - projectId, - _projectOwner, - handleRender, - canEdit, + context, +}: { + handleRender?: () => void + context: 'ide' | 'profile' }) { const { currentUser } = useAuth() - const { pathname } = useLocation() + const { project } = useIdeContext() + + const isProfile = context === 'profile' + const canEdit = + (currentUser && currentUser?.sub === project?.user?.id) || + currentUser?.roles?.includes('admin') + const projectOwner = project?.user?.userName const [createFork] = useMutation(FORK_PROJECT_MUTATION, { onCompleted: ({ forkProject }) => { @@ -157,9 +73,7 @@ function DefaultTopButtons({ userName: forkProject?.user?.userName, projectTitle: forkProject?.title, } - navigate( - pathname.includes('/ide') ? routes.ide(params) : routes.project(params) - ) + navigate(!isProfile ? routes.ide(params) : routes.project(params)) }, }) const handleFork = () => { @@ -167,7 +81,7 @@ function DefaultTopButtons({ variables: { input: { userId: currentUser.sub, - forkedFromId: project?.id || projectId, + forkedFromId: project?.id, }, }, }) @@ -180,95 +94,127 @@ function DefaultTopButtons({ return ( <> - {canEdit && !projectTitle && ( - ( +
    +
    + {project?.id && ( + <> + + + + {projectOwner} + + + + + )} +
    +
    + {canEdit && !isProfile && ( + ( + + + + )} + /> + )} + {!isProfile && ( - + )} - /> - )} - {!projectTitle && ( - - - - )} - {projectTitle && ( - - navigate(routes.ide({ userName: _projectOwner, projectTitle })) - } - name="Editor" - > - - - )} - - {({ open }) => { - return ( - <> - - - - - - {open && ( - - - - - - - - + {isProfile && ( + + navigate( + routes.ide({ + userName: projectOwner, + projectTitle: project.title, + }) + ) + } + name="Editor" + > + + + )} + + {({ open }) => { + return ( + <> + + + + + + {open && ( + + + + + + + + - - encoded script - external script - - - - )} - - ) - }} - - {currentUser?.sub && ( - - - - )} + + encoded script + external script + + + + )} + + ) + }} + + {currentUser?.sub && ( + + + + )} +
    +
    ) } diff --git a/app/web/src/components/IdeWrapper/IdeWrapper.tsx b/app/web/src/components/IdeWrapper/IdeWrapper.tsx index 7b52242..2e7f529 100644 --- a/app/web/src/components/IdeWrapper/IdeWrapper.tsx +++ b/app/web/src/components/IdeWrapper/IdeWrapper.tsx @@ -1,17 +1,17 @@ -import { useEffect, useState } from 'react' +import { useState } from 'react' import IdeContainer from 'src/components/IdeContainer/IdeContainer' import { useRender } from './useRender' -import OutBound from 'src/components/OutBound/OutBound' import IdeSideBar from 'src/components/IdeSideBar/IdeSideBar' -import IdeHeader from 'src/components/IdeHeader/IdeHeader' -import Svg from 'src/components/Svg/Svg' +import TopNav from 'src/components/TopNav/TopNav' import { useIdeInit } from 'src/components/EncodedUrl/helpers' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import { useSaveCode } from 'src/components/IdeWrapper/useSaveCode' import { ShortcutsModalContext } from 'src/components/EditorMenu/AllShortcutsModal' +import IdeHeader from 'src/components/IdeHeader/IdeHeader' +import type { CadPackageType } from 'src/components/CadPackage/CadPackage' interface Props { - cadPackage: string + cadPackage: CadPackageType } const IdeWrapper = ({ cadPackage }: Props) => { @@ -33,7 +33,9 @@ const IdeWrapper = ({ cadPackage }: Props) => {
    diff --git a/app/web/src/components/ProjectCell/ProjectCell.tsx b/app/web/src/components/ProjectCell/ProjectCell.tsx index 30a2b36..75fc19b 100644 --- a/app/web/src/components/ProjectCell/ProjectCell.tsx +++ b/app/web/src/components/ProjectCell/ProjectCell.tsx @@ -2,6 +2,8 @@ import { useMutation } from '@redwoodjs/web' import { toast } from '@redwoodjs/web/toast' import { navigate, routes } from '@redwoodjs/router' import { useAuth } from '@redwoodjs/auth' +import { useIdeState } from 'src/helpers/hooks/useIdeState' +import { IdeContext } from 'src/helpers/hooks/useIdeContext' import ProjectProfile from 'src/components/ProjectProfile/ProjectProfile' import { QUERY as PROJECT_REACTION_QUERY } from 'src/components/ProjectReactionsCell' @@ -120,26 +122,20 @@ export const Empty = () =>
    Empty
    export const Failure = ({ error }) =>
    Error: {error.message}
    -export const Success = ({ - userProject, - variables: { isEditable }, - refetch, -}) => { +export const Success = ({ userProject, refetch }) => { const { currentUser } = useAuth() - const [updateProject, { loading, error }] = useMutation( - UPDATE_PROJECT_MUTATION, - { - onCompleted: ({ updateProject }) => { - navigate( - routes.project({ - userName: updateProject.user.userName, - projectTitle: updateProject.title, - }) - ) - toast.success('Project updated.') - }, - } - ) + const [state, thunkDispatch] = useIdeState() + const [updateProject] = useMutation(UPDATE_PROJECT_MUTATION, { + onCompleted: ({ updateProject }) => { + navigate( + routes.project({ + userName: updateProject.user.userName, + projectTitle: updateProject.title, + }) + ) + toast.success('Project updated.') + }, + }) const [createProject] = useMutation(CREATE_PROJECT_MUTATION, { onCompleted: ({ createProject }) => { navigate( @@ -160,7 +156,7 @@ export const Success = ({ refetch() } const [deleteProject] = useMutation(DELETE_PROJECT_MUTATION, { - onCompleted: ({ deleteProject }) => { + onCompleted: () => { navigate(routes.home()) toast.success('Project deleted.') }, @@ -206,15 +202,27 @@ export const Success = ({ }) return ( - + + + ) } diff --git a/app/web/src/components/ProjectProfile/ProjectProfile.tsx b/app/web/src/components/ProjectProfile/ProjectProfile.tsx index b5bf735..9fe52dd 100644 --- a/app/web/src/components/ProjectProfile/ProjectProfile.tsx +++ b/app/web/src/components/ProjectProfile/ProjectProfile.tsx @@ -10,6 +10,7 @@ import Button from 'src/components/Button/Button' import ProjectReactionsCell from '../ProjectReactionsCell' import { countEmotes } from 'src/helpers/emote' import { getActiveClasses } from 'get-active-classes' +import TopNav from 'src/components/TopNav/TopNav' import IdeHeader from 'src/components/IdeHeader/IdeHeader' import CadPackage from 'src/components/CadPackage/CadPackage' import Gravatar from 'src/components/Gravatar/Gravatar' @@ -50,7 +51,7 @@ const ProjectProfile = ({ projectTitle: project?.title, }) ) - }, [currentUser]) + }, [currentUser, project?.title, userProject.userName]) useIdeInit(project?.cadPackage, project?.code, 'viewer') const [newDescription, setNewDescription] = useState(project?.description) const onDescriptionChange = (description) => setNewDescription(description()) @@ -70,14 +71,9 @@ const ProjectProfile = ({ <>
    - {}} - projectOwner={userProject?.userName} - projectOwnerImage={userProject?.image} - projectOwnerId={userProject?.id} - projectTitle={project?.title} - projectId={project?.id} - /> + + +
    diff --git a/app/web/src/components/TopNav/TopNav.tsx b/app/web/src/components/TopNav/TopNav.tsx new file mode 100644 index 0000000..0f015eb --- /dev/null +++ b/app/web/src/components/TopNav/TopNav.tsx @@ -0,0 +1,31 @@ +import { Link, routes } from '@redwoodjs/router' +import Svg from 'src/components/Svg/Svg' +import NavPlusButton from 'src/components/NavPlusButton' +import ProfileSlashLogin from 'src/components/ProfileSlashLogin' +import { ReactNode } from 'react' +interface IdeHeaderProps { + children: ReactNode +} + +const TopNav = ({ children }: IdeHeaderProps) => { + return ( +
    +
    +
    + + + +
    +
    + {children} +
    +
    + +
    + +
    +
    + ) +} + +export default TopNav diff --git a/app/web/src/components/UserProfile/UserProfile.tsx b/app/web/src/components/UserProfile/UserProfile.tsx index ae6cfb2..0ffe9b5 100644 --- a/app/web/src/components/UserProfile/UserProfile.tsx +++ b/app/web/src/components/UserProfile/UserProfile.tsx @@ -1,9 +1,8 @@ import { useEffect, useReducer } from 'react' import { useAuth } from '@redwoodjs/auth' -import { Link, navigate, routes } from '@redwoodjs/router' +import { navigate, routes } from '@redwoodjs/router' import ProjectsOfUser from 'src/components/ProjectsOfUserCell' -import IdeHeader from 'src/components/IdeHeader/IdeHeader' -import Svg from 'src/components/Svg/Svg' +import TopNav from 'src/components/TopNav/TopNav' import { fieldComponents, fieldReducer, @@ -27,13 +26,7 @@ function buildFieldsConfig(fieldsConfig, user, hasPermissionToEdit) { ) } -const UserProfile = ({ - user, - isEditing, - loading, - onSave, - error, -}: UserProfileType) => { +const UserProfile = ({ user, isEditing, onSave }: UserProfileType) => { const { currentUser } = useAuth() const hasPermissionToEdit = currentUser?.sub === user.id useEffect(() => { @@ -60,14 +53,14 @@ const UserProfile = ({ <>
    - {}} projectOwner={user?.userName} projectOwnerImage={user?.image} projectOwnerId={user?.id} > - +
    diff --git a/app/web/src/pages/DevIdePage/DevIdePage.tsx b/app/web/src/pages/DevIdePage/DevIdePage.tsx index 0c98170..a39195f 100644 --- a/app/web/src/pages/DevIdePage/DevIdePage.tsx +++ b/app/web/src/pages/DevIdePage/DevIdePage.tsx @@ -4,6 +4,7 @@ import { Toaster } from '@redwoodjs/web/toast' import { useIdeState } from 'src/helpers/hooks/useIdeState' import type { Project } from 'src/components/IdeProjectCell/IdeProjectCell' import { IdeContext } from 'src/helpers/hooks/useIdeContext' +import type { CadPackageType } from 'src/components/CadPackage/CadPackage' interface Props { cadPackage: string @@ -21,7 +22,9 @@ const DevIdePage = ({ cadPackage, project }: Props) => { /> - +
    ) diff --git a/app/web/src/pages/ProjectPage/ProjectPage.tsx b/app/web/src/pages/ProjectPage/ProjectPage.tsx index 4bd6c23..3110a8f 100644 --- a/app/web/src/pages/ProjectPage/ProjectPage.tsx +++ b/app/web/src/pages/ProjectPage/ProjectPage.tsx @@ -2,14 +2,11 @@ import { useAuth } from '@redwoodjs/auth' import ProjectCell from 'src/components/ProjectCell' import Seo from 'src/components/Seo/Seo' -import { useIdeState } from 'src/helpers/hooks/useIdeState' -import { IdeContext } from 'src/helpers/hooks/useIdeContext' import { Toaster } from '@redwoodjs/web/toast' import { makeSocialPublicId } from 'src/helpers/hooks/useUpdateProjectImages' const ProjectPage = ({ userName, projectTitle }) => { const { currentUser } = useAuth() - const [state, thunkDispatch] = useIdeState() const socialImageUrl = `http://res.cloudinary.com/irevdev/image/upload/c_scale,w_1200/v1/CadHub/${makeSocialPublicId( userName, projectTitle @@ -23,13 +20,11 @@ const ProjectPage = ({ userName, projectTitle }) => { lang="en-US" /> - - - + ) } From 965e5b0f543c11a0a005d55a8438a6e448a63688 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 28 Sep 2021 20:35:56 +1000 Subject: [PATCH 6/6] Update TopNav in UserProfile to remove unneeded props --- app/web/src/components/TopNav/TopNav.tsx | 2 +- app/web/src/components/UserProfile/UserProfile.tsx | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/app/web/src/components/TopNav/TopNav.tsx b/app/web/src/components/TopNav/TopNav.tsx index 0f015eb..22a743d 100644 --- a/app/web/src/components/TopNav/TopNav.tsx +++ b/app/web/src/components/TopNav/TopNav.tsx @@ -4,7 +4,7 @@ import NavPlusButton from 'src/components/NavPlusButton' import ProfileSlashLogin from 'src/components/ProfileSlashLogin' import { ReactNode } from 'react' interface IdeHeaderProps { - children: ReactNode + children?: ReactNode } const TopNav = ({ children }: IdeHeaderProps) => { diff --git a/app/web/src/components/UserProfile/UserProfile.tsx b/app/web/src/components/UserProfile/UserProfile.tsx index 0ffe9b5..507b3c7 100644 --- a/app/web/src/components/UserProfile/UserProfile.tsx +++ b/app/web/src/components/UserProfile/UserProfile.tsx @@ -53,14 +53,7 @@ const UserProfile = ({ user, isEditing, onSave }: UserProfileType) => { <>
    - {}} - projectOwner={user?.userName} - projectOwnerImage={user?.image} - projectOwnerId={user?.id} - > - - +