From c3af97ad8508f5bdc4eed5cedb8d39b55d2d6940 Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 13:33:11 -0900 Subject: [PATCH 01/22] Got graph to appear behind contact us model --- src/components/ContactUsModal.js | 6 +++--- src/components/LeftSidebar.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ContactUsModal.js b/src/components/ContactUsModal.js index 11a4fe7..272d32b 100644 --- a/src/components/ContactUsModal.js +++ b/src/components/ContactUsModal.js @@ -83,7 +83,7 @@ export default function ContactUsModal ({ isOpen, handleClose }) { - @@ -92,9 +92,9 @@ export default function ContactUsModal ({ isOpen, handleClose }) { } return ( -
+
-
+
diff --git a/src/components/LeftSidebar.js b/src/components/LeftSidebar.js index 4fe461c..8b717fd 100644 --- a/src/components/LeftSidebar.js +++ b/src/components/LeftSidebar.js @@ -83,7 +83,7 @@ export default function LeftSidebar ({ className }) {
-
+
From a0f09f00dd41b5f5e898130943e691812939bae8 Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 14:38:02 -0900 Subject: [PATCH 02/22] Fixed bug where new users could not log in --- src/app/api/auth/[...nextauth]/options.js | 20 ++++++++++---------- src/app/api/mongoDB/createUser/createUser.js | 3 +-- src/app/api/mongoDB/createUser/route.js | 5 ----- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/app/api/auth/[...nextauth]/options.js b/src/app/api/auth/[...nextauth]/options.js index f9cc617..c857fcc 100644 --- a/src/app/api/auth/[...nextauth]/options.js +++ b/src/app/api/auth/[...nextauth]/options.js @@ -21,7 +21,7 @@ export const options = { async signIn ({ user, account, profile }) { const existingUser = await getUsers(null, user.email) - if (existingUser) { + if (existingUser && existingUser.length > 0) { return true } else { // Get first and last name @@ -30,17 +30,11 @@ export const options = { const lastName = nameParts.length > 1 ? nameParts.slice(1).join(' ') : '' // Create User - const newUser = await createUser(user.email, firstName, lastName) - return !!newUser // Return true if creation is successful + const createdUser = await createUser(user.email, firstName, lastName) + return !!createdUser // Return true if creation is successful } }, - async session ({ session, user, token }) { - // Assign the user ID to the session to make it available on the client side - session.userId = token.sub // 'sub' is typically the field where the user ID from the provider is stored - return session - }, - async jwt ({ token, user, account, profile, isNewUser }) { // This callback is called whenever a JWT is created. So session.userId is the mongo User _id if (user) { @@ -48,7 +42,13 @@ export const options = { token.sub = mongoUsers[0]._id } return token - } + }, + + async session ({ session, user, token }) { + // Assign the user ID to the session to make it available on the client side + session.userId = token.sub // 'sub' is typically the field where the user ID from the provider is stored + return session + }, } /* diff --git a/src/app/api/mongoDB/createUser/createUser.js b/src/app/api/mongoDB/createUser/createUser.js index 963cf82..7f1beac 100644 --- a/src/app/api/mongoDB/createUser/createUser.js +++ b/src/app/api/mongoDB/createUser/createUser.js @@ -21,8 +21,8 @@ import { URI } from '../mongoData.js' */ export async function createUser (email, firstName = null, lastName = null, username = null, teamIDs = []) { - if (mongoose.connection.readyState !== 1) await mongoose.connect(URI) + if (mongoose.connection.readyState !== 1) await mongoose.connect(URI); const user = await User.create({ email, firstName, @@ -30,6 +30,5 @@ export async function createUser (email, firstName = null, lastName = null, user username, teamIDs }) - return user } diff --git a/src/app/api/mongoDB/createUser/route.js b/src/app/api/mongoDB/createUser/route.js index a1b9629..76e394b 100644 --- a/src/app/api/mongoDB/createUser/route.js +++ b/src/app/api/mongoDB/createUser/route.js @@ -40,11 +40,6 @@ import { createUser } from './createUser' */ export async function POST (request) { try { - const session = await getServerSession(options) - if (!session) { - return NextResponse.json({ success: false, message: 'authentication failed' }, { status: 401 }) - } - const params = await request.json() if (!params.email) { From 0928db6aa66f04161236a10205b5ffa0e39875c6 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sat, 25 Nov 2023 14:50:55 -0900 Subject: [PATCH 03/22] some spacing changes in Graph.js --- package-lock.json | 17 +++++++++++++---- package.json | 1 + src/components/Graph.js | 20 +++++++++++++++++--- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index ee6bc96..1c903ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "autoprefixer": "10.4.15", "cookie-cutter": "^0.2.0", "cytoscape": "^3.26.0", + "cytoscape-cxtmenu": "^3.5.0", "dotenv": "^16.3.1", "eslint-config-next": "13.4.19", "mongodb": "^6.2.0", @@ -1803,6 +1804,14 @@ "node": ">=0.10" } }, + "node_modules/cytoscape-cxtmenu": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/cytoscape-cxtmenu/-/cytoscape-cxtmenu-3.5.0.tgz", + "integrity": "sha512-CoqgKAxvQhmHO5fEgJdBqqR2VjwK1dNkxehc2i0MUMqY0araA13z3oP/9KkprHp9Td++KlVBz6JnncNAD76T0Q==", + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -4605,9 +4614,9 @@ } }, "node_modules/next-auth": { - "version": "4.24.3", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.3.tgz", - "integrity": "sha512-n1EvmY7MwQMSOkCh6jhI6uBneB6VVtkYELVMEwVaCLD1mBD3IAAucwk+90kgxramW09nSp5drvynwfNCi1JjaQ==", + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.5.tgz", + "integrity": "sha512-3RafV3XbfIKk6rF6GlLE4/KxjTcuMCifqrmD+98ejFq73SRoj2rmzoca8u764977lH/Q7jo6Xu6yM+Re1Mz/Og==", "dependencies": { "@babel/runtime": "^7.20.13", "@panva/hkdf": "^1.0.2", @@ -4620,7 +4629,7 @@ "uuid": "^8.3.2" }, "peerDependencies": { - "next": "^12.2.5 || ^13", + "next": "^12.2.5 || ^13 || ^14", "nodemailer": "^6.6.5", "react": "^17.0.2 || ^18", "react-dom": "^17.0.2 || ^18" diff --git a/package.json b/package.json index 712d985..af275c8 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "autoprefixer": "10.4.15", "cookie-cutter": "^0.2.0", "cytoscape": "^3.26.0", + "cytoscape-cxtmenu": "^3.5.0", "dotenv": "^16.3.1", "eslint-config-next": "13.4.19", "mongodb": "^6.2.0", diff --git a/src/components/Graph.js b/src/components/Graph.js index fba2884..cb01b09 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -1,6 +1,7 @@ 'use client' import React, { useEffect, useRef, useState } from 'react' import cytoscape from 'cytoscape' +import cxtmenu from 'cytoscape-cxtmenu' /** * A component that fetches task data and renders it as a tree graph using the Cytoscape.js library. @@ -56,7 +57,7 @@ function TreeGraph ({ className, projectID }) { }) // Tailwind's bg-gray-200 #E5E7EB - cytoscape({ + const cy = cytoscape({ container: containerRef.current, elements, @@ -70,8 +71,8 @@ function TreeGraph ({ className, projectID }) { 'text-valign': 'center', label: 'data(label)', 'text-wrap': 'wrap', - 'text-max-width': 500, - padding: '30px', + 'text-max-width': 900, + padding: '50px', color: 'white', // Tailwind's text-gray-900 'font-size': 100, 'border-width': 10, @@ -96,6 +97,19 @@ function TreeGraph ({ className, projectID }) { directed: true } }) + + // Calculate and set node dimensions based on label text + cy.nodes().forEach(node => { + const label = node.data('label'); + const labelWidth = 1000; // Adjust the factor based on your font and styling + const labelHeight = label.height * 10; // Set a fixed height or adjust based on your design + + node.style({ + width: labelWidth + 'px', + height: labelHeight + 'px', + }); + }); + }, [tasks]) return ( From 9d98e6ca9cfcfe0ce5bc78b3a6fa49701f3b44e7 Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 15:06:29 -0900 Subject: [PATCH 04/22] Added dropdown movemnt --- src/components/Dropdown.js | 31 ++++++++++++++++++++----------- src/components/LeftSidebar.js | 3 +-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/components/Dropdown.js b/src/components/Dropdown.js index 3726366..fedf0d1 100644 --- a/src/components/Dropdown.js +++ b/src/components/Dropdown.js @@ -1,6 +1,7 @@ 'use client' import React from 'react' import Image from 'next/image' +import {useState } from 'react' import dropdownIcon from '../../public/svg/dropdown.svg' @@ -21,20 +22,28 @@ import dropdownIcon from '../../public/svg/dropdown.svg' * * @returns {React.Element} The rendered Dropdown button element. */ -const Dropdown = ({ label, clickAction, imagePath }) => { - return ( +const Dropdown = ({ label, imagePath, dropdownComponents}) => { + const [dropdownHidden, setDropdown] = useState(false) - +
+ {dropdownComponents}
- +
+ ) } diff --git a/src/components/LeftSidebar.js b/src/components/LeftSidebar.js index 8b717fd..76a742b 100644 --- a/src/components/LeftSidebar.js +++ b/src/components/LeftSidebar.js @@ -76,8 +76,7 @@ export default function LeftSidebar ({ className }) {
  • -
  • -
  • {projectsDiv}
  • +
  • From 7eaf0423242f91cb637768ce364413544ffd374d Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 15:20:42 -0900 Subject: [PATCH 05/22] Commented out some non-functional components for demo --- src/components/LeftSidebar.js | 4 +++- src/components/Navbar.js | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/LeftSidebar.js b/src/components/LeftSidebar.js index 76a742b..2b5bfb4 100644 --- a/src/components/LeftSidebar.js +++ b/src/components/LeftSidebar.js @@ -71,7 +71,9 @@ export default function LeftSidebar ({ className }) {
      -
    • + + {/* To be implemented */} + {/*
    • */}
    • diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 3178406..9951190 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -49,7 +49,7 @@ const Navbar = () => {
      -
      +
      {/* Hamburger */}
      @@ -65,7 +65,9 @@ const Navbar = () => {
      + {/* Current Directory */} + {/*
      { />
      + */} {/* Search Bar */}
      )} + {/* User */}
      {name}
      -
      From 2a03ee91aacd25360b2e8feb166b876e3343a681 Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 15:32:18 -0900 Subject: [PATCH 06/22] Adjusted images in navbar --- src/components/Navbar.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 9951190..9e6a3ef 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -5,6 +5,7 @@ import Image from 'next/image' import searchIcon from '../../public/svg/search.svg' import logo from '../../public/quaysideLogo.png' import { useSession, signOut } from 'next-auth/react' +import Button from '../components/Button' /** * A Navbar component that fetches a user's name from a specified API and displays a navigation bar with several interactive elements. @@ -60,7 +61,7 @@ const Navbar = () => { {/* Logo */}
      - quayside logo + quayside logo
      @@ -94,21 +95,23 @@ const Navbar = () => { {/* Sign Out */}
      - + +
      + + + {/* User */} +
      {name}
      {/* User Avatar Icon */} {session && session.user && ( -
      +
      )} - - {/* User */} -
      {name}
      From 4d88c84ded3d7008c63715108fd1eebee8ac8e8d Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 15:37:42 -0900 Subject: [PATCH 07/22] Created website title and link in navbar --- src/components/Dropdown.js | 1 + src/components/Navbar.js | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/Dropdown.js b/src/components/Dropdown.js index fedf0d1..3ee5a9f 100644 --- a/src/components/Dropdown.js +++ b/src/components/Dropdown.js @@ -3,6 +3,7 @@ import React from 'react' import Image from 'next/image' import {useState } from 'react' + import dropdownIcon from '../../public/svg/dropdown.svg' /** diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 9e6a3ef..8d02979 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -6,6 +6,7 @@ import searchIcon from '../../public/svg/search.svg' import logo from '../../public/quaysideLogo.png' import { useSession, signOut } from 'next-auth/react' import Button from '../components/Button' +import Link from 'next/link' /** * A Navbar component that fetches a user's name from a specified API and displays a navigation bar with several interactive elements. @@ -52,18 +53,23 @@ const Navbar = () => {
      {/* Hamburger */} -
      + {/*
      -
      +
      */} {/* Logo */}
      quayside logo
      +
      + + quayside.app + +
      From eae923d93b813e9b08545bfc7770879ae3cc42be Mon Sep 17 00:00:00 2001 From: Ashtonrcurry Date: Sat, 25 Nov 2023 16:27:21 -0900 Subject: [PATCH 08/22] added context menu --- src/components/Graph.js | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index cb01b09..461fdff 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from 'react' import cytoscape from 'cytoscape' import cxtmenu from 'cytoscape-cxtmenu' - +cytoscape.use(cxtmenu); /** * A component that fetches task data and renders it as a tree graph using the Cytoscape.js library. * @@ -98,6 +98,36 @@ function TreeGraph ({ className, projectID }) { } }) + //creates context radial menu around each node + cy.cxtmenu({ + menuRadius: function(ele){ return 40; }, + selector: 'node', + commands: [ + { + content: 'Add Child', + select: function(ele){ + console.log('Add Child clicked for node ' + ele.id()); + // Add logic to handle adding a child node + } + }, + { + content: 'Edit', + select: function(ele){ + console.log('Edit clicked for node ' + ele.id()); + // Add logic to handle editing the node + } + }, + { + content: 'Delete', + select: function(ele){ + console.log('Delete clicked for node ' + ele.id()); + // Add logic to handle deleting the node + } + } + // ... [more commands as needed] + ] + }); + // Calculate and set node dimensions based on label text cy.nodes().forEach(node => { const label = node.data('label'); From 91fb40622f91c33b3bcfcf27b2ef24a2fa77bc48 Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 16:38:23 -0900 Subject: [PATCH 09/22] Added to home page --- src/app/page.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/app/page.js b/src/app/page.js index f841903..5c8bc4c 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,9 +1,18 @@ export default function Home () { return ( -
      -
      - Create or Select a project. -
      +
      + +
      + quayside.app +
      + +
      + Ignite Collaborative Productivity +
      +
      + Create or select a project to get started... +
      +
      ) } From ffd90be1fd919ec43dbcd641bd5aa6490f565ee9 Mon Sep 17 00:00:00 2001 From: Mya Schroder <80082701+schromya@users.noreply.github.com> Date: Sat, 25 Nov 2023 16:40:53 -0900 Subject: [PATCH 10/22] Fixed formatting for the evil linter --- src/app/api/auth/[...nextauth]/options.js | 2 +- src/app/api/mongoDB/createUser/createUser.js | 3 +-- src/app/api/mongoDB/createUser/route.js | 2 -- src/app/page.js | 14 +++++++------- src/components/Dropdown.js | 11 ++++------- src/components/LeftSidebar.js | 5 ++--- src/components/Navbar.js | 7 ++----- 7 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/app/api/auth/[...nextauth]/options.js b/src/app/api/auth/[...nextauth]/options.js index c857fcc..8763af5 100644 --- a/src/app/api/auth/[...nextauth]/options.js +++ b/src/app/api/auth/[...nextauth]/options.js @@ -48,7 +48,7 @@ export const options = { // Assign the user ID to the session to make it available on the client side session.userId = token.sub // 'sub' is typically the field where the user ID from the provider is stored return session - }, + } } /* diff --git a/src/app/api/mongoDB/createUser/createUser.js b/src/app/api/mongoDB/createUser/createUser.js index 7f1beac..7f58293 100644 --- a/src/app/api/mongoDB/createUser/createUser.js +++ b/src/app/api/mongoDB/createUser/createUser.js @@ -21,8 +21,7 @@ import { URI } from '../mongoData.js' */ export async function createUser (email, firstName = null, lastName = null, username = null, teamIDs = []) { - - if (mongoose.connection.readyState !== 1) await mongoose.connect(URI); + if (mongoose.connection.readyState !== 1) await mongoose.connect(URI) const user = await User.create({ email, firstName, diff --git a/src/app/api/mongoDB/createUser/route.js b/src/app/api/mongoDB/createUser/route.js index 76e394b..3c859b5 100644 --- a/src/app/api/mongoDB/createUser/route.js +++ b/src/app/api/mongoDB/createUser/route.js @@ -1,5 +1,3 @@ -import { options } from '../../auth/[...nextauth]/options' -import { getServerSession } from 'next-auth/next' import { NextResponse } from 'next/server' import { createUser } from './createUser' diff --git a/src/app/page.js b/src/app/page.js index 5c8bc4c..8682fac 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -2,16 +2,16 @@ export default function Home () { return (
      -
      +
      quayside.app -
      +
      -
      +
      Ignite Collaborative Productivity -
      -
      - Create or select a project to get started... -
      +
      +
      + Create or select a project to get started... +
      ) diff --git a/src/components/Dropdown.js b/src/components/Dropdown.js index 3ee5a9f..e63ded3 100644 --- a/src/components/Dropdown.js +++ b/src/components/Dropdown.js @@ -1,8 +1,6 @@ 'use client' -import React from 'react' +import React, { useState } from 'react' import Image from 'next/image' -import {useState } from 'react' - import dropdownIcon from '../../public/svg/dropdown.svg' @@ -23,7 +21,7 @@ import dropdownIcon from '../../public/svg/dropdown.svg' * * @returns {React.Element} The rendered Dropdown button element. */ -const Dropdown = ({ label, imagePath, dropdownComponents}) => { +const Dropdown = ({ label, imagePath, dropdownComponents }) => { const [dropdownHidden, setDropdown] = useState(false) return ( @@ -31,13 +29,13 @@ const Dropdown = ({ label, imagePath, dropdownComponents}) => {
      @@ -45,7 +43,6 @@ const Dropdown = ({ label, imagePath, dropdownComponents}) => {
    - ) } diff --git a/src/components/LeftSidebar.js b/src/components/LeftSidebar.js index 2b5bfb4..84c937b 100644 --- a/src/components/LeftSidebar.js +++ b/src/components/LeftSidebar.js @@ -10,7 +10,6 @@ import ContactUsButton from '../components/ContactUsButton' import Dropdown from '../components/Dropdown' import Button from '../components/Button' -import plusIcon from '../../public/svg/plus.svg' import starIcon from '../../public/svg/star.svg' import tableIcon from '../../public/svg/table.svg' import teamIcon from '../../public/svg/team.svg' @@ -73,12 +72,12 @@ export default function LeftSidebar ({ className }) { {/* To be implemented */} - {/*
  • */} + {/*
  • */}
  • -
  • +
  • diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 8d02979..386dd3a 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -64,15 +64,13 @@ const Navbar = () => {
    quayside logo
    - -
    - quayside.app +
    + quayside.app
    - {/* Current Directory */} {/*
    @@ -104,7 +102,6 @@ const Navbar = () => {
    - {/* User */}
    {name}
    From 4a2d99c4df969c38331351b5beae665b93f62fa5 Mon Sep 17 00:00:00 2001 From: Ashtonrcurry Date: Sat, 25 Nov 2023 16:42:02 -0900 Subject: [PATCH 11/22] added graph context menu functionality --- src/components/Graph.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index 461fdff..af894f6 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -100,7 +100,8 @@ function TreeGraph ({ className, projectID }) { //creates context radial menu around each node cy.cxtmenu({ - menuRadius: function(ele){ return 40; }, + //adjust radius menu + menuRadius: function(ele){ return 100; }, selector: 'node', commands: [ { @@ -123,6 +124,13 @@ function TreeGraph ({ className, projectID }) { console.log('Delete clicked for node ' + ele.id()); // Add logic to handle deleting the node } + }, + { + content: 'Expand', + select: function(ele){ + console.log('Delete clicked for node ' + ele.id()); + // Add logic to handle expanding node + } } // ... [more commands as needed] ] From df2f66b818d565dc1fa806a67f829a5206ad4e04 Mon Sep 17 00:00:00 2001 From: Ashtonrcurry Date: Sat, 25 Nov 2023 16:55:29 -0900 Subject: [PATCH 12/22] adjusted context menu display --- src/components/Graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index af894f6..c482c78 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -101,7 +101,7 @@ function TreeGraph ({ className, projectID }) { //creates context radial menu around each node cy.cxtmenu({ //adjust radius menu - menuRadius: function(ele){ return 100; }, + menuRadius: function(ele){ return 70; }, selector: 'node', commands: [ { From 69a7369842b647558d114fcb7f0e9acf185a3f40 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sat, 25 Nov 2023 17:22:16 -0900 Subject: [PATCH 13/22] clicking on a node pulls up a prompt to update its text, routing works with the database --- src/app/api/mongoDB/editTask/editTask.js | 36 ++++++++++++ src/app/api/mongoDB/editTask/route.js | 72 ++++++++++++++++++++++++ src/components/Graph.js | 61 +++++++++++++++++--- 3 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 src/app/api/mongoDB/editTask/editTask.js create mode 100644 src/app/api/mongoDB/editTask/route.js diff --git a/src/app/api/mongoDB/editTask/editTask.js b/src/app/api/mongoDB/editTask/editTask.js new file mode 100644 index 0000000..5a5a1c1 --- /dev/null +++ b/src/app/api/mongoDB/editTask/editTask.js @@ -0,0 +1,36 @@ +import mongoose from 'mongoose' +import { Task } from '../mongoModels' +import { URI } from '../mongoData.js' + +/** + * Creates and stores a new task in the database. This function can be used server side. + * Alternatively the POST request in the route.js should be used on client side (which uses this logic). + * + * @param {string} taskId - The ObjectID of the task. Required. + * @param {string} name - The name of the task. Required. + * @returns {Promise} - A promise that resolves to the newly created task object. + * + * @example + * // Example of using editTask function + * const task = await editTask('65627e3f0deac40cffab844c', 'Develop New Feature'); + * + */ +export async function editTask(taskId, newName) { + try { + // Find the task by its ObjectId and update its name + const updatedTask = await Task.findByIdAndUpdate( + taskId, + { name: newName }, + { new: true } // Return the updated document + ); + + if (!updatedTask) { + throw new Error('Task not found'); + } + + return updatedTask; + } catch (error) { + console.error('Error updating task:', error); + throw error; // Re-throw the error for handling at a higher level + } + } \ No newline at end of file diff --git a/src/app/api/mongoDB/editTask/route.js b/src/app/api/mongoDB/editTask/route.js new file mode 100644 index 0000000..ae39f64 --- /dev/null +++ b/src/app/api/mongoDB/editTask/route.js @@ -0,0 +1,72 @@ +import mongoose from 'mongoose' +import { options } from '../../auth/[...nextauth]/options' +import { getServerSession } from 'next-auth/next' +import { NextResponse } from 'next/server' +import { Project } from '../mongoModels' +import { URI } from '../mongoData.js' +import { editTask } from './editTask' + +/** + * Handles a POST request to create and store a new task in the database. This function + * first authenticates the session, then validates the necessary parameters for task creation, + * such as 'name' and 'projectID'. If the parameters are valid and the associated project exists, + * it proceeds to create a new task with the given details. + * + * @param {Object} request - The request object containing the task details. + * @returns {Object} - A response object with a status code,and the task if completed successfully ({message:, task:{}}) + * + * @throws Will throw an error if any of the required fields are missing, if there's an issue connecting + * to the database, or if the session is not authenticated. + * + * @example + * // Example of using this function in a POST request + * fetch(`/api/tasks/createTask`, { + * method: 'POST', + * headers: { 'Content-Type': 'application/json' }, + * body: JSON.stringify({ + * name: 'New Task', + * projectID: 'proj123', + * // ...other task properties + * }), + * }).then(async (response) => { + * const body = await response.json(); + * if (!response.ok) { + * console.error('Task creation failed:', body.message); + * } else { + * console.log('Task created:', body.task); + * } + * }).catch(error => console.error('Error in creating task:', error)); + * + * @property {string} request.body.name - The name of the task. (Required) + */ + +export async function PUT(request) { + try { + const session = await getServerSession(options); + if (!session) { + return NextResponse.json({ success: false, message: 'Authentication failed' }, { status: 401 }); + } + + const params = await request.json(); + + if (!params.taskId || !params.newName) { + return NextResponse.json({ message: 'Task ID and new text are required.' }, { status: 400 }); + } + + if (mongoose.connection.readyState !== 1) await mongoose.connect(URI); + + // const projectExists = await Project.exists({ _id: params.projectID }); + // if (!projectExists) { + // return NextResponse.json({ message: `Project ${params.projectID} does not exist.` }, { status: 400 }); + // } + + const updatedTask = await editTask(params.taskId, params.newName); + + return NextResponse.json({ task: updatedTask }, { status: 200 }); + } catch (error) { + console.error('Error updating task:', error); + return NextResponse.json({ message: 'Error updating Task: ' + error }, { status: 500 }); + } + } + + diff --git a/src/components/Graph.js b/src/components/Graph.js index cb01b09..ba58c3a 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from 'react' import cytoscape from 'cytoscape' import cxtmenu from 'cytoscape-cxtmenu' +cytoscape.use( cxtmenu ) /** * A component that fetches task data and renders it as a tree graph using the Cytoscape.js library. @@ -100,15 +101,61 @@ function TreeGraph ({ className, projectID }) { // Calculate and set node dimensions based on label text cy.nodes().forEach(node => { - const label = node.data('label'); - const labelWidth = 1000; // Adjust the factor based on your font and styling - const labelHeight = label.height * 10; // Set a fixed height or adjust based on your design + const label = node.data('label'); + const labelWidth = 1000; // Adjust the factor based on your font and styling + const labelHeight = label.height * 10; // Set a fixed height or adjust based on your design + + node.style({ + width: labelWidth + 'px', + height: labelHeight + 'px', + }); + }); + + + // Click event handler for node + cy.on('click', 'node', function(event) { + const clickedNode = event.target; + const nodeId = clickedNode.id(); + console.log('Clicked node ID:', nodeId); + + // Prompt the user for new text (you can replace this with your own logic) + const newText = prompt('Enter new text for the node:', clickedNode.data('label')); + + // Update the label data of the clicked node + clickedNode.data('label', newText); + + // now newText needs to be in the database, id is clickedNode.id() + //below code doesn't work yet + updateTextInMongoDB(nodeId, newText); - node.style({ - width: labelWidth + 'px', - height: labelHeight + 'px', }); - }); + + const updateTextInMongoDB = async (taskId, newText) => { + try { + const response = await fetch(`/api/mongoDB/editTask`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ taskId: taskId, newName: newText }), + }); + + const result = await response.json(); + + if (!response.ok) { + console.error('Failed to update:', result.message); + // Handle error feedback to user + } else { + console.log('Text updated successfully in MongoDB.'); + // Handle success feedback to user + } + } + + catch (error) { + console.error('Error updating text in MongoDB:', error); + // Handle error feedback to user + } + }; }, [tasks]) From 7dd2530a8c75e7e99fda0641122b83e41427159c Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sat, 25 Nov 2023 17:31:37 -0900 Subject: [PATCH 14/22] changed editing a task now works when you go to edit in cxtmenu instead of left clicking on a node --- src/components/Graph.js | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index 79ebd15..a00f82d 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from 'react' import cytoscape from 'cytoscape' import cxtmenu from 'cytoscape-cxtmenu' +import { useRouter } from 'next/navigation' cytoscape.use(cxtmenu); /** @@ -19,6 +20,7 @@ cytoscape.use(cxtmenu); function TreeGraph ({ className, projectID }) { // Fetch Tree data const [tasks, setTasks] = useState(null) + const router = useRouter() const containerRef = useRef(null) @@ -116,7 +118,10 @@ function TreeGraph ({ className, projectID }) { content: 'Edit', select: function(ele){ console.log('Edit clicked for node ' + ele.id()); - // Add logic to handle editing the node + + const newText = prompt('Enter new text for the node:', ele.data('label')); + ele.data('label', newText); // Update the label data of the clicked node + updateTextInMongoDB(ele.id(), newText); // Update in database } }, { @@ -129,7 +134,7 @@ function TreeGraph ({ className, projectID }) { { content: 'Expand', select: function(ele){ - console.log('Delete clicked for node ' + ele.id()); + console.log('Expand clicked for node ' + ele.id()); // Add logic to handle expanding node } } @@ -150,23 +155,23 @@ function TreeGraph ({ className, projectID }) { }); - // Click event handler for node - cy.on('click', 'node', function(event) { - const clickedNode = event.target; - const nodeId = clickedNode.id(); - console.log('Clicked node ID:', nodeId); + // // Click event handler for node + // cy.on('click', 'node', function(event) { + // const clickedNode = event.target; + // const nodeId = clickedNode.id(); + // console.log('Clicked node ID:', nodeId); - // Prompt the user for new text (you can replace this with your own logic) - const newText = prompt('Enter new text for the node:', clickedNode.data('label')); + // // Prompt the user for new text (you can replace this with your own logic) + // const newText = prompt('Enter new text for the node:', clickedNode.data('label')); - // Update the label data of the clicked node - clickedNode.data('label', newText); + // // Update the label data of the clicked node + // clickedNode.data('label', newText); - // now newText needs to be in the database, id is clickedNode.id() - //below code doesn't work yet - updateTextInMongoDB(nodeId, newText); + // // now newText needs to be in the database, id is clickedNode.id() + // //below code doesn't work yet + // updateTextInMongoDB(nodeId, newText); - }); + // }); const updateTextInMongoDB = async (taskId, newText) => { try { From 5c0cb379b3c20c7cc1676db90b93b609875e4b92 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sat, 25 Nov 2023 17:38:25 -0900 Subject: [PATCH 15/22] small change --- src/components/Graph.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index a00f82d..bf25589 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -154,25 +154,6 @@ function TreeGraph ({ className, projectID }) { }); }); - - // // Click event handler for node - // cy.on('click', 'node', function(event) { - // const clickedNode = event.target; - // const nodeId = clickedNode.id(); - // console.log('Clicked node ID:', nodeId); - - // // Prompt the user for new text (you can replace this with your own logic) - // const newText = prompt('Enter new text for the node:', clickedNode.data('label')); - - // // Update the label data of the clicked node - // clickedNode.data('label', newText); - - // // now newText needs to be in the database, id is clickedNode.id() - // //below code doesn't work yet - // updateTextInMongoDB(nodeId, newText); - - // }); - const updateTextInMongoDB = async (taskId, newText) => { try { const response = await fetch(`/api/mongoDB/editTask`, { From 1a51d9e5c4303d4b305337ebab7a9c9885ed2214 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sat, 25 Nov 2023 18:07:34 -0900 Subject: [PATCH 16/22] changed how the graph looks a little --- package-lock.json | 29 +++++++++++++++++++++ package.json | 1 + src/components/Graph.js | 58 +++++++++++++++++++++++------------------ 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1c903ec..acb5040 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "cookie-cutter": "^0.2.0", "cytoscape": "^3.26.0", "cytoscape-cxtmenu": "^3.5.0", + "cytoscape-dagre": "^2.5.0", "dotenv": "^16.3.1", "eslint-config-next": "13.4.19", "mongodb": "^6.2.0", @@ -1812,6 +1813,26 @@ "cytoscape": "^3.2.0" } }, + "node_modules/cytoscape-dagre": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cytoscape-dagre/-/cytoscape-dagre-2.5.0.tgz", + "integrity": "sha512-VG2Knemmshop4kh5fpLO27rYcyUaaDkRw+6PiX4bstpB+QFt0p2oauMrsjVbUamGWQ6YNavh7x2em2uZlzV44g==", + "dependencies": { + "dagre": "^0.8.5" + }, + "peerDependencies": { + "cytoscape": "^3.2.22" + } + }, + "node_modules/dagre": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", + "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", + "dependencies": { + "graphlib": "^2.1.8", + "lodash": "^4.17.15" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -2988,6 +3009,14 @@ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dependencies": { + "lodash": "^4.17.15" + } + }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", diff --git a/package.json b/package.json index af275c8..b7d5ab4 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "cookie-cutter": "^0.2.0", "cytoscape": "^3.26.0", "cytoscape-cxtmenu": "^3.5.0", + "cytoscape-dagre": "^2.5.0", "dotenv": "^16.3.1", "eslint-config-next": "13.4.19", "mongodb": "^6.2.0", diff --git a/src/components/Graph.js b/src/components/Graph.js index bf25589..6033d98 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -2,8 +2,10 @@ import React, { useEffect, useRef, useState } from 'react' import cytoscape from 'cytoscape' import cxtmenu from 'cytoscape-cxtmenu' +import cydagre from 'cytoscape-dagre'; import { useRouter } from 'next/navigation' cytoscape.use(cxtmenu); +cytoscape.use(cydagre); /** * A component that fetches task data and renders it as a tree graph using the Cytoscape.js library. @@ -68,15 +70,16 @@ function TreeGraph ({ className, projectID }) { { selector: 'node', style: { - width: '1000', // Adjusts width based on label - height: '800', // Set a fixed height + 'shape': 'roundrectangle', + 'width': '1000', // Adjusts width based on label + 'height': '800', // Set a fixed height 'background-color': 'black', 'text-valign': 'center', - label: 'data(label)', + 'label': 'data(label)', 'text-wrap': 'wrap', 'text-max-width': 900, - padding: '50px', - color: 'white', // Tailwind's text-gray-900 + 'padding': '50px', + 'color': 'white', // Tailwind's text-gray-900 'font-size': 100, 'border-width': 10, 'border-color': '#FFFFFF' @@ -85,22 +88,39 @@ function TreeGraph ({ className, projectID }) { { selector: 'edge', style: { - curveStyle: 'bezier', + 'curveStyle': 'segments', 'line-color': 'white', // Tailwind's border-gray-300 #D1D5DB - width: 10, - targetArrowShape: 'triangle', + 'width': 10, + 'targetArrowShape': 'triangle', 'target-arrow-color': 'white' // Tailwind's border-gray-300 } } ], layout: { - name: 'breadthfirst', - spacingFactor: 1.3, - padding: 4, - directed: true - } + name: 'dagre', + spacingFactor: 1.5, + padding: 10, + directed: true, + avoidOverlap: true, + levelSpacing: 4 + + }, + minZoom: 0.03, // Minimum zoom level (e.g., 0.5 means the graph can be zoomed out to half its original size) + maxZoom: 1, // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) }) + // Calculate and set node dimensions based on label text + cy.nodes().forEach(node => { + const label = node.data('label'); + const labelWidth = 1000; // Adjust the factor based on your font and styling + const labelHeight = label.height * 10; // Set a fixed height or adjust based on your design + + node.style({ + width: labelWidth + 'px', + height: labelHeight + 'px', + }); + }); + //creates context radial menu around each node cy.cxtmenu({ //adjust radius menu @@ -142,18 +162,6 @@ function TreeGraph ({ className, projectID }) { ] }); - // Calculate and set node dimensions based on label text - cy.nodes().forEach(node => { - const label = node.data('label'); - const labelWidth = 1000; // Adjust the factor based on your font and styling - const labelHeight = label.height * 10; // Set a fixed height or adjust based on your design - - node.style({ - width: labelWidth + 'px', - height: labelHeight + 'px', - }); - }); - const updateTextInMongoDB = async (taskId, newText) => { try { const response = await fetch(`/api/mongoDB/editTask`, { From b45833a51328ba585a160335046af2d1f32c7950 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sun, 26 Nov 2023 10:56:11 -0900 Subject: [PATCH 17/22] dagre layout style --- src/components/Graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index 6033d98..9611f97 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -106,7 +106,7 @@ function TreeGraph ({ className, projectID }) { }, minZoom: 0.03, // Minimum zoom level (e.g., 0.5 means the graph can be zoomed out to half its original size) - maxZoom: 1, // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) + maxZoom: 0.5, // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) }) // Calculate and set node dimensions based on label text From 07a3c02a373a18e14e19c9ea04f9704f248cec96 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sun, 26 Nov 2023 12:10:38 -0900 Subject: [PATCH 18/22] sideways graph --- src/components/Graph.js | 42 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index 9611f97..3e3272c 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -3,7 +3,6 @@ import React, { useEffect, useRef, useState } from 'react' import cytoscape from 'cytoscape' import cxtmenu from 'cytoscape-cxtmenu' import cydagre from 'cytoscape-dagre'; -import { useRouter } from 'next/navigation' cytoscape.use(cxtmenu); cytoscape.use(cydagre); @@ -22,7 +21,6 @@ cytoscape.use(cydagre); function TreeGraph ({ className, projectID }) { // Fetch Tree data const [tasks, setTasks] = useState(null) - const router = useRouter() const containerRef = useRef(null) @@ -63,7 +61,6 @@ function TreeGraph ({ className, projectID }) { // Tailwind's bg-gray-200 #E5E7EB const cy = cytoscape({ - container: containerRef.current, elements, style: [ @@ -71,16 +68,16 @@ function TreeGraph ({ className, projectID }) { selector: 'node', style: { 'shape': 'roundrectangle', - 'width': '1000', // Adjusts width based on label - 'height': '800', // Set a fixed height + 'width': 1500, + 'height': 'label', // Use the 'label' keyword to dynamically size the width based on the label 'background-color': 'black', 'text-valign': 'center', 'label': 'data(label)', 'text-wrap': 'wrap', - 'text-max-width': 900, - 'padding': '50px', - 'color': 'white', // Tailwind's text-gray-900 - 'font-size': 100, + 'text-max-width': 1500, + 'padding': 75, + 'color': 'white', + 'font-size': 50, // Adjust font size as needed 'border-width': 10, 'border-color': '#FFFFFF' } @@ -88,38 +85,31 @@ function TreeGraph ({ className, projectID }) { { selector: 'edge', style: { - 'curveStyle': 'segments', - 'line-color': 'white', // Tailwind's border-gray-300 #D1D5DB + // 'curve-style': 'unbundled-bezier', + // 'control-point-distances': 100, // Sharpness of the bend + // 'control-point-weights': 0.5, // Position of the control point along the edge (0.5 is halfway) + 'line-color': 'white', 'width': 10, 'targetArrowShape': 'triangle', 'target-arrow-color': 'white' // Tailwind's border-gray-300 } } - ], + ], layout: { name: 'dagre', spacingFactor: 1.5, padding: 10, directed: true, avoidOverlap: true, - levelSpacing: 4 - + levelSpacing: 50, + rankDir: 'LR', + nodeSep: 50, + rankSep: 150 }, - minZoom: 0.03, // Minimum zoom level (e.g., 0.5 means the graph can be zoomed out to half its original size) + minZoom: 0.15, // Minimum zoom level (e.g., 0.5 means the graph can be zoomed out to half its original size) maxZoom: 0.5, // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) }) - // Calculate and set node dimensions based on label text - cy.nodes().forEach(node => { - const label = node.data('label'); - const labelWidth = 1000; // Adjust the factor based on your font and styling - const labelHeight = label.height * 10; // Set a fixed height or adjust based on your design - - node.style({ - width: labelWidth + 'px', - height: labelHeight + 'px', - }); - }); //creates context radial menu around each node cy.cxtmenu({ From 95fb216aa45a5f9d4ce2711c05a974ac18f2ccb9 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sun, 26 Nov 2023 12:45:21 -0900 Subject: [PATCH 19/22] added modal to edit task instead of a prommpt, the modal needs refining though --- src/app/api/mongoDB/editTask/editTask.js | 38 +++--- src/app/api/mongoDB/editTask/route.js | 47 ++++--- src/components/Graph.js | 157 ++++++++++++++--------- 3 files changed, 136 insertions(+), 106 deletions(-) diff --git a/src/app/api/mongoDB/editTask/editTask.js b/src/app/api/mongoDB/editTask/editTask.js index 5a5a1c1..2716a33 100644 --- a/src/app/api/mongoDB/editTask/editTask.js +++ b/src/app/api/mongoDB/editTask/editTask.js @@ -1,6 +1,4 @@ -import mongoose from 'mongoose' import { Task } from '../mongoModels' -import { URI } from '../mongoData.js' /** * Creates and stores a new task in the database. This function can be used server side. @@ -15,22 +13,22 @@ import { URI } from '../mongoData.js' * const task = await editTask('65627e3f0deac40cffab844c', 'Develop New Feature'); * */ -export async function editTask(taskId, newName) { - try { - // Find the task by its ObjectId and update its name - const updatedTask = await Task.findByIdAndUpdate( - taskId, - { name: newName }, - { new: true } // Return the updated document - ); - - if (!updatedTask) { - throw new Error('Task not found'); - } - - return updatedTask; - } catch (error) { - console.error('Error updating task:', error); - throw error; // Re-throw the error for handling at a higher level +export async function editTask (taskId, newName) { + try { + // Find the task by its ObjectId and update its name + const updatedTask = await Task.findByIdAndUpdate( + taskId, + { name: newName }, + { new: true } // Return the updated document + ) + + if (!updatedTask) { + throw new Error('Task not found') } - } \ No newline at end of file + + return updatedTask + } catch (error) { + console.error('Error updating task:', error) + throw error // Re-throw the error for handling at a higher level + } +} diff --git a/src/app/api/mongoDB/editTask/route.js b/src/app/api/mongoDB/editTask/route.js index ae39f64..5b7249e 100644 --- a/src/app/api/mongoDB/editTask/route.js +++ b/src/app/api/mongoDB/editTask/route.js @@ -2,7 +2,6 @@ import mongoose from 'mongoose' import { options } from '../../auth/[...nextauth]/options' import { getServerSession } from 'next-auth/next' import { NextResponse } from 'next/server' -import { Project } from '../mongoModels' import { URI } from '../mongoData.js' import { editTask } from './editTask' @@ -40,33 +39,31 @@ import { editTask } from './editTask' * @property {string} request.body.name - The name of the task. (Required) */ -export async function PUT(request) { - try { - const session = await getServerSession(options); - if (!session) { - return NextResponse.json({ success: false, message: 'Authentication failed' }, { status: 401 }); - } - - const params = await request.json(); - - if (!params.taskId || !params.newName) { - return NextResponse.json({ message: 'Task ID and new text are required.' }, { status: 400 }); - } - - if (mongoose.connection.readyState !== 1) await mongoose.connect(URI); - +export async function PUT (request) { + try { + const session = await getServerSession(options) + if (!session) { + return NextResponse.json({ success: false, message: 'Authentication failed' }, { status: 401 }) + } + + const params = await request.json() + + if (!params.taskId || !params.newName) { + return NextResponse.json({ message: 'Task ID and new text are required.' }, { status: 400 }) + } + + if (mongoose.connection.readyState !== 1) await mongoose.connect(URI) + // const projectExists = await Project.exists({ _id: params.projectID }); // if (!projectExists) { // return NextResponse.json({ message: `Project ${params.projectID} does not exist.` }, { status: 400 }); // } - - const updatedTask = await editTask(params.taskId, params.newName); - - return NextResponse.json({ task: updatedTask }, { status: 200 }); - } catch (error) { - console.error('Error updating task:', error); - return NextResponse.json({ message: 'Error updating Task: ' + error }, { status: 500 }); - } - } + const updatedTask = await editTask(params.taskId, params.newName) + return NextResponse.json({ task: updatedTask }, { status: 200 }) + } catch (error) { + console.error('Error updating task:', error) + return NextResponse.json({ message: 'Error updating Task: ' + error }, { status: 500 }) + } +} diff --git a/src/components/Graph.js b/src/components/Graph.js index 3e3272c..e6f0c39 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -2,9 +2,23 @@ import React, { useEffect, useRef, useState } from 'react' import cytoscape from 'cytoscape' import cxtmenu from 'cytoscape-cxtmenu' -import cydagre from 'cytoscape-dagre'; -cytoscape.use(cxtmenu); -cytoscape.use(cydagre); +import cydagre from 'cytoscape-dagre' +cytoscape.use(cxtmenu) +cytoscape.use(cydagre) + +const Modal = ({ show, onClose, onSubmit, children }) => { + if (!show) return null; + + return ( +
    +
    + {children} + + +
    +
    + ); +}; /** * A component that fetches task data and renders it as a tree graph using the Cytoscape.js library. @@ -21,9 +35,60 @@ cytoscape.use(cydagre); function TreeGraph ({ className, projectID }) { // Fetch Tree data const [tasks, setTasks] = useState(null) - const containerRef = useRef(null) + const [modalOpen, setModalOpen] = useState(false); + const [editLabel, setEditLabel] = useState(''); + const [editNode, setEditNode] = useState(null); + + const updateTextInMongoDB = async (taskId, newText) => { + try { + const response = await fetch('/api/mongoDB/editTask', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ taskId, newName: newText }) + }) + + const result = await response.json() + + if (!response.ok) { + console.error('Failed to update:', result.message) + // Handle error feedback to user + } else { + console.log('Text updated successfully in MongoDB.') + // Handle success feedback to user + } + } catch (error) { + console.error('Error updating text in MongoDB:', error) + // Handle error feedback to user + } + } + + // Function to handle the edit command + const handleEdit = (node) => { + setEditNode(node); + setEditLabel(node.data('label')); + setModalOpen(true); + }; + + // Function to close the modal + const handleCloseModal = () => { + setModalOpen(false); + }; + + // Function to submit the new label + const handleSubmitModal = () => { + setModalOpen(false); + const nodeId = editNode.id(); + const newText = editLabel; + updateTextInMongoDB(nodeId, newText); + editNode.data('label', newText); + setEditNode(null); + }; + + useEffect(() => { // Fetch Tree data fetch(`/api/mongoDB/getTasks?projectID=${projectID}`, { @@ -67,17 +132,17 @@ function TreeGraph ({ className, projectID }) { { selector: 'node', style: { - 'shape': 'roundrectangle', - 'width': 1500, - 'height': 'label', // Use the 'label' keyword to dynamically size the width based on the label + shape: 'roundrectangle', + width: 1500, + height: 'label', // Use the 'label' keyword to dynamically size the width based on the label 'background-color': 'black', 'text-valign': 'center', - 'label': 'data(label)', + label: 'data(label)', 'text-wrap': 'wrap', - 'text-max-width': 1500, - 'padding': 75, - 'color': 'white', - 'font-size': 50, // Adjust font size as needed + 'text-max-width': 1500, + padding: 75, + color: 'white', + 'font-size': 50, // Adjust font size as needed 'border-width': 10, 'border-color': '#FFFFFF' } @@ -89,12 +154,12 @@ function TreeGraph ({ className, projectID }) { // 'control-point-distances': 100, // Sharpness of the bend // 'control-point-weights': 0.5, // Position of the control point along the edge (0.5 is halfway) 'line-color': 'white', - 'width': 10, - 'targetArrowShape': 'triangle', + width: 10, + targetArrowShape: 'triangle', 'target-arrow-color': 'white' // Tailwind's border-gray-300 } } - ], + ], layout: { name: 'dagre', spacingFactor: 1.5, @@ -107,83 +172,53 @@ function TreeGraph ({ className, projectID }) { rankSep: 150 }, minZoom: 0.15, // Minimum zoom level (e.g., 0.5 means the graph can be zoomed out to half its original size) - maxZoom: 0.5, // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) + maxZoom: 0.5 // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) }) - - //creates context radial menu around each node + // creates context radial menu around each node cy.cxtmenu({ - //adjust radius menu - menuRadius: function(ele){ return 70; }, + // adjust radius menu + menuRadius: function (ele) { return 70 }, selector: 'node', commands: [ { content: 'Add Child', - select: function(ele){ - console.log('Add Child clicked for node ' + ele.id()); + select: function (ele) { + console.log('Add Child clicked for node ' + ele.id()) // Add logic to handle adding a child node } }, { content: 'Edit', - select: function(ele){ - console.log('Edit clicked for node ' + ele.id()); - - const newText = prompt('Enter new text for the node:', ele.data('label')); - ele.data('label', newText); // Update the label data of the clicked node - updateTextInMongoDB(ele.id(), newText); // Update in database + select: function (ele) { + handleEdit(ele) } }, { content: 'Delete', - select: function(ele){ - console.log('Delete clicked for node ' + ele.id()); + select: function (ele) { + console.log('Delete clicked for node ' + ele.id()) // Add logic to handle deleting the node } }, { content: 'Expand', - select: function(ele){ - console.log('Expand clicked for node ' + ele.id()); + select: function (ele) { + console.log('Expand clicked for node ' + ele.id()) // Add logic to handle expanding node } } // ... [more commands as needed] ] - }); - - const updateTextInMongoDB = async (taskId, newText) => { - try { - const response = await fetch(`/api/mongoDB/editTask`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ taskId: taskId, newName: newText }), - }); - - const result = await response.json(); - - if (!response.ok) { - console.error('Failed to update:', result.message); - // Handle error feedback to user - } else { - console.log('Text updated successfully in MongoDB.'); - // Handle success feedback to user - } - } - - catch (error) { - console.error('Error updating text in MongoDB:', error); - // Handle error feedback to user - } - }; - + }) }, [tasks]) return (
    + + setEditLabel(e.target.value)} /> +
    ) } From d70806d9946203e30af94e1219d42900e0b74938 Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sun, 26 Nov 2023 12:45:51 -0900 Subject: [PATCH 20/22] ran npx standard fix --- src/components/Graph.js | 45 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index e6f0c39..b6dc8e6 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -7,18 +7,18 @@ cytoscape.use(cxtmenu) cytoscape.use(cydagre) const Modal = ({ show, onClose, onSubmit, children }) => { - if (!show) return null; + if (!show) return null return ( -
    -
    +
    +
    {children}
    - ); -}; + ) +} /** * A component that fetches task data and renders it as a tree graph using the Cytoscape.js library. @@ -37,9 +37,9 @@ function TreeGraph ({ className, projectID }) { const [tasks, setTasks] = useState(null) const containerRef = useRef(null) - const [modalOpen, setModalOpen] = useState(false); - const [editLabel, setEditLabel] = useState(''); - const [editNode, setEditNode] = useState(null); + const [modalOpen, setModalOpen] = useState(false) + const [editLabel, setEditLabel] = useState('') + const [editNode, setEditNode] = useState(null) const updateTextInMongoDB = async (taskId, newText) => { try { @@ -68,26 +68,25 @@ function TreeGraph ({ className, projectID }) { // Function to handle the edit command const handleEdit = (node) => { - setEditNode(node); - setEditLabel(node.data('label')); - setModalOpen(true); - }; + setEditNode(node) + setEditLabel(node.data('label')) + setModalOpen(true) + } // Function to close the modal const handleCloseModal = () => { - setModalOpen(false); - }; + setModalOpen(false) + } // Function to submit the new label const handleSubmitModal = () => { - setModalOpen(false); - const nodeId = editNode.id(); - const newText = editLabel; - updateTextInMongoDB(nodeId, newText); - editNode.data('label', newText); - setEditNode(null); - }; - + setModalOpen(false) + const nodeId = editNode.id() + const newText = editLabel + updateTextInMongoDB(nodeId, newText) + editNode.data('label', newText) + setEditNode(null) + } useEffect(() => { // Fetch Tree data @@ -217,7 +216,7 @@ function TreeGraph ({ className, projectID }) {
    - setEditLabel(e.target.value)} /> + setEditLabel(e.target.value)} />
    ) From 4dc604d59ff4aa7136eff967914253706daca1fe Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sun, 26 Nov 2023 13:02:12 -0900 Subject: [PATCH 21/22] modal for ediitng a task --- src/components/Graph.js | 44 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index b6dc8e6..271cb27 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -9,12 +9,38 @@ cytoscape.use(cydagre) const Modal = ({ show, onClose, onSubmit, children }) => { if (!show) return null + const modalContentStyle = { + width: '30%', // Adjust the width of the modal as per your requirement + minWidth: '300px', // Minimum width to ensure responsiveness + marginTop: '20px', // Margin from the top to push the modal down a bit + backgroundColor: 'grey', // Background color of the modal + padding: '20px', // Padding inside the modal + borderRadius: '5px', // Rounded corners of the modal + boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)', // Box shadow for a subtle depth effect + display: 'flex', // Use flex layout + flexDirection: 'column', // Stack children vertically + alignItems: 'center' // Center-align children horizontally + } + + const modalBackdropStyle = { + position: 'fixed', // Fixes the backdrop in relation to the viewport + top: 0, // Aligns the top edge of the backdrop with the top of the viewport + left: 0, // Aligns the left edge of the backdrop with the left of the viewport + right: 0, // Aligns the right edge of the backdrop with the right of the viewport + bottom: 0, // Aligns the bottom edge of the backdrop with the bottom of the viewport + backgroundColor: 'rgba(0, 0, 0, 0.5)', // Semi-transparent black background + display: 'flex', // Uses flexbox layout + justifyContent: 'center', // Centers children horizontally + alignItems: 'flex-start', // Aligns children to the start of the cross axis, i.e., top + paddingTop: '50px' // Adds padding at the top + } + return ( -
    -
    +
    +
    {children} - - + +
    ) @@ -212,11 +238,19 @@ function TreeGraph ({ className, projectID }) { }) }, [tasks]) + const inputStyle = { + color: 'black', // Set font color to black + padding: '10px', // Optional: Add padding for better appearance + margin: '5px 0', // Optional: Add some margin for spacing + width: '100%' // Optional: Set width to fill the modal + // Add any other styles you need for the input + } + return (
    - setEditLabel(e.target.value)} /> + setEditLabel(e.target.value)} style={inputStyle} />
    ) From 6375432099f0066d030eae5229192b9ea756332e Mon Sep 17 00:00:00 2001 From: yumenoxana Date: Sun, 26 Nov 2023 19:14:16 -0900 Subject: [PATCH 22/22] fixed too zoomed in --- src/components/Graph.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Graph.js b/src/components/Graph.js index 271cb27..f580a73 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -196,8 +196,8 @@ function TreeGraph ({ className, projectID }) { nodeSep: 50, rankSep: 150 }, - minZoom: 0.15, // Minimum zoom level (e.g., 0.5 means the graph can be zoomed out to half its original size) - maxZoom: 0.5 // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) + minZoom: 0.08, // Minimum zoom level (e.g., 0.5 means the graph can be zoomed out to half its original size) + maxZoom: 1 // Maximum zoom level (e.g., 2 means the graph can be zoomed in to twice its original size) }) // creates context radial menu around each node