From 587ca2647529a8293eaad6fc30aac0e735ae522e Mon Sep 17 00:00:00 2001 From: jakeaturner Date: Thu, 8 Feb 2024 14:13:55 -0800 Subject: [PATCH 1/4] feat(Conductor): add create project opt to Home --- .../{CreateProject.jsx => CreateProject.tsx} | 81 +++++++------------ client/src/screens/conductor/Home/index.tsx | 57 ++++++++++++- 2 files changed, 80 insertions(+), 58 deletions(-) rename client/src/components/projects/{CreateProject.jsx => CreateProject.tsx} (55%) diff --git a/client/src/components/projects/CreateProject.jsx b/client/src/components/projects/CreateProject.tsx similarity index 55% rename from client/src/components/projects/CreateProject.jsx rename to client/src/components/projects/CreateProject.tsx index 8861851c..9be4204f 100644 --- a/client/src/components/projects/CreateProject.jsx +++ b/client/src/components/projects/CreateProject.tsx @@ -1,25 +1,28 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import { useHistory } from 'react-router-dom'; -import { useSelector } from 'react-redux'; -import axios from 'axios'; -import { Button, Form, Icon, Modal } from 'semantic-ui-react'; -import { visibilityOptions } from '../util/ProjectHelpers'; -import useGlobalError from '../error/ErrorHooks'; +import React, { useState } from "react"; +import { useHistory } from "react-router-dom"; +import axios from "axios"; +import { Button, Form, Icon, Modal } from "semantic-ui-react"; +import { visibilityOptions } from "../util/ProjectHelpers"; +import useGlobalError from "../error/ErrorHooks"; +import { useTypedSelector } from "../../state/hooks"; + +interface CreateProjectProps { + show: boolean; + onClose: () => void; +} /** * Modal tool to create a new Project. */ -const CreateProject = ({ show, onClose }) => { - +const CreateProject: React.FC = ({ show, onClose }) => { // Global state and error handling const { handleGlobalError } = useGlobalError(); const history = useHistory(); - const org = useSelector((state) => state.org); + const org = useTypedSelector((state) => state.org); // Form Data - const [projTitle, setProjTitle] = useState(''); - const [projVis, setProjVis] = useState('private'); + const [projTitle, setProjTitle] = useState(""); + const [projVis, setProjVis] = useState("private"); // Form State const [loading, setLoading] = useState(false); @@ -55,15 +58,17 @@ const CreateProject = ({ show, onClose }) => { if (validateForm()) { try { setLoading(true); - const createRes = await axios.post('/project', { + const createRes = await axios.post("/project", { title: projTitle, visibility: projVis, }); if (createRes.data.err) { - throw (new Error(createRes.data.errMsg)); + throw new Error(createRes.data.errMsg); } if (createRes.data.projectID) { - history.push(`/projects/${createRes.data.projectID}?projectCreated=true`); + history.push( + `/projects/${createRes.data.projectID}?projectCreated=true` + ); } else { history.push(`/projects?projectCreated=true`); } @@ -74,31 +79,14 @@ const CreateProject = ({ show, onClose }) => { } } - /** - * Updates the new Title in state. - * - * @param {React.ChangeEvent} e - Event that activated the handler. - */ - function handleProjectTitleChange(e) { - setProjTitle(e.target.value); - } - - /** - * Updates the new Visibility setting in state. - * - * @param {React.ChangeEvent} _e - Event that activated the handler. - * @param {object} data - Date passed from the UI element. - * @param {string} data.value - The new visibility setting selection. - */ - function handleProjectVisibilityChange(_e, { value }) { - setProjVis(value); - } - return ( Create Project -

This project will be created within {org.name}. You can add tags, collaborators, and more after creation.

+

+ This project will be created within {org.name}. You + can add tags, collaborators, and more after creation. +

{ required type="text" value={projTitle} - onChange={handleProjectTitleChange} + onChange={(e) => setProjTitle(e.target.value)} error={titleErr} /> { label="Project Visibility" placeholder="Visibility..." options={visibilityOptions} - onChange={handleProjectVisibilityChange} + onChange={(e, { value }) => setProjVis(value as string)} value={projVis} /> @@ -131,19 +119,4 @@ const CreateProject = ({ show, onClose }) => { ); }; -CreateProject.propTypes = { - /** - * Opens or closes the modal. - */ - show: PropTypes.bool.isRequired, - /** - * Handler to activate when the modal is closed. - */ - onClose: PropTypes.func, -}; - -CreateProject.defaultProps = { - onClose: () => { }, -}; - export default CreateProject; diff --git a/client/src/screens/conductor/Home/index.tsx b/client/src/screens/conductor/Home/index.tsx index 5fafd0db..7626027f 100644 --- a/client/src/screens/conductor/Home/index.tsx +++ b/client/src/screens/conductor/Home/index.tsx @@ -10,6 +10,7 @@ import { Loader, Card, Popup, + SegmentProps, } from "semantic-ui-react"; import { useEffect, useState, useCallback, lazy } from "react"; import { useTypedSelector } from "../../../state/hooks"; @@ -24,6 +25,7 @@ import useGlobalError from "../../../components/error/ErrorHooks"; import { pinProject } from "../../../utils/projectHelpers"; import Annnouncement from "../../../components/Home/Announcement"; import UserMenu from "../../../components/Home/UserMenu"; +import { useMediaQuery } from "react-responsive"; const NewMemberModal = lazy( () => import("../../../components/Home/NewMemberModal") ); @@ -36,6 +38,9 @@ const ViewAnnouncementModal = lazy( const NewAnnouncementModal = lazy( () => import("../../../components/Home/NewAnnouncementModal") ); +const CreateProjectModal = lazy( + () => import("../../../components/projects/CreateProject") +); const Home = () => { const { handleGlobalError } = useGlobalError(); @@ -75,6 +80,15 @@ const Home = () => { // Edit Pinned Projects Modal const [showPinnedModal, setShowPinnedModal] = useState(false); + // Create Project Modal + const [showCreateProjectModal, setShowCreateProjectModal] = + useState(false); + + const isTailwindXl = useMediaQuery( + { minWidth: 1280 }, // Tailwind XL breakpoint + undefined + ); + /** * Check for query string values and update UI if necessary. */ @@ -228,6 +242,32 @@ const Home = () => { setLoadedAllPinned(false); } + const CreateProjectSegment = () => { + return ( + +
+

Create a Project

+
+ setShowCreateProjectModal(true)} + icon + circular + > + + + } + position="top center" + /> +
+
+
+ ); + }; + return (
@@ -246,9 +286,10 @@ const Home = () => {
)}
-
+
+ {!isTailwindXl && }
0} @@ -331,11 +372,14 @@ const Home = () => {
+ {isTailwindXl && ( +
+ +
+ )}
-

- Announcements -

+

Announcements

{(user.isCampusAdmin === true || user.isSuperAdmin === true) && (
{ onDataChange={() => getPinnedProjects()} onClose={() => setShowPinnedModal(false)} /> + {/* Create Project Modal */} + setShowCreateProjectModal(false)} + /> ); }; From 679548dffc5f86d08d87c93a4ebb1215a06d0843 Mon Sep 17 00:00:00 2001 From: jakeaturner Date: Thu, 8 Feb 2024 14:32:32 -0800 Subject: [PATCH 2/4] feat(Projects): move create book button --- .../projects/ProjectLinkButtons.tsx | 35 +++++++++++++++++-- .../projects/ProjectPropertiesModal.tsx | 19 ---------- .../src/components/projects/ProjectView.jsx | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/client/src/components/projects/ProjectLinkButtons.tsx b/client/src/components/projects/ProjectLinkButtons.tsx index cfd77994..ef66f884 100644 --- a/client/src/components/projects/ProjectLinkButtons.tsx +++ b/client/src/components/projects/ProjectLinkButtons.tsx @@ -1,6 +1,8 @@ import { Button, Header, Icon, Popup } from "semantic-ui-react"; import { normalizeURL } from "../util/HelperFunctions"; import { buildCommonsUrl, buildWorkbenchURL } from "../../utils/projectHelpers"; +import { lazy, useState } from "react"; +const CreateWorkbenchModal = lazy(() => import("./CreateWorkbenchModal")); interface ProjectLinkButtonsProps { libreLibrary?: string; @@ -8,6 +10,8 @@ interface ProjectLinkButtonsProps { projectLink?: string; didCreateWorkbench?: boolean; hasCommonsBook?: boolean; + projectID?: string; + projectTitle?: string; } const ProjectLinkButtons: React.FC = ({ @@ -16,14 +20,28 @@ const ProjectLinkButtons: React.FC = ({ projectLink, didCreateWorkbench, hasCommonsBook = false, + projectID, + projectTitle, }) => { + const [showCreateWorkbenchModal, setShowCreateWorkbenchModal] = + useState(false); const validWorkbench = didCreateWorkbench && libreCoverID && libreLibrary; + return (
Important Links:{" "}
+ {!projectLink && !didCreateWorkbench && ( + + )} = ({ : () => {} } className={ - hasCommonsBook && libreCoverID && libreLibrary ? "" : "!cursor-default opacity-45" + hasCommonsBook && libreCoverID && libreLibrary + ? "" + : "!cursor-default opacity-45" + } + color={ + hasCommonsBook && libreCoverID && libreLibrary ? "blue" : "grey" } - color={hasCommonsBook && libreCoverID && libreLibrary ? "blue" : "grey"} > Commons Page } /> + {projectID && projectTitle && ( + setShowCreateWorkbenchModal(false)} + onSuccess={() => window.location.reload()} + /> + )}
); diff --git a/client/src/components/projects/ProjectPropertiesModal.tsx b/client/src/components/projects/ProjectPropertiesModal.tsx index 760026e4..42b41756 100644 --- a/client/src/components/projects/ProjectPropertiesModal.tsx +++ b/client/src/components/projects/ProjectPropertiesModal.tsx @@ -530,18 +530,6 @@ const ProjectPropertiesModal: React.FC = ({ id="projectURL" /> -
- {!getValues("projectURL") && ( - - )} -
)} @@ -978,13 +966,6 @@ const ProjectPropertiesModal: React.FC = ({ }, ]} /> - setShowCreateWorkbenchModal(false)} - onSuccess={() => window.location.reload()} - /> diff --git a/client/src/components/projects/ProjectView.jsx b/client/src/components/projects/ProjectView.jsx index d734bb27..6cee854f 100644 --- a/client/src/components/projects/ProjectView.jsx +++ b/client/src/components/projects/ProjectView.jsx @@ -1848,7 +1848,7 @@ const ProjectView = (props) => {
} - + {(project.adaptCourseID && project.adaptCourseID !== '') && (
Date: Thu, 8 Feb 2024 14:39:42 -0800 Subject: [PATCH 3/4] perf(Tasks): add indices --- server/models/task.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/models/task.ts b/server/models/task.ts index 6e36620c..80698b01 100644 --- a/server/models/task.ts +++ b/server/models/task.ts @@ -26,11 +26,13 @@ const TaskSchema = new Schema( // the projectID the task belongs to type: String, required: true, + index: true, }, taskID: { // base62 16-digit identifier type: String, required: true, + index: true, }, title: { // task title From 0871ba5f9dd9c3f3fc0bdc1c3e450e9eb20e56a3 Mon Sep 17 00:00:00 2001 From: jakeaturner Date: Thu, 8 Feb 2024 14:40:48 -0800 Subject: [PATCH 4/4] perf(Collections): add indices --- server/models/collection.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/models/collection.ts b/server/models/collection.ts index 72c35d04..e0d9804a 100644 --- a/server/models/collection.ts +++ b/server/models/collection.ts @@ -20,11 +20,13 @@ const CollectionSchema = new Schema( // the organization's internal identifier string type: String, required: true, + index: true, }, collID: { // base62 8-digit identifier type: String, required: true, + index: true, }, title: { // the collection title/name