From ab7e4588c1522dd65377fccdf5114318717c24a9 Mon Sep 17 00:00:00 2001 From: Yi Xhan Date: Tue, 7 Oct 2025 15:54:17 -0400 Subject: [PATCH 1/4] global search bar added with all equipment, trainings, rooms, makerspaces (redirects to new page with just the name of the item searched) --- client/src/AppRoutes.tsx | 2 + .../both/globalsearch/GlobalSearchPage.tsx | 10 +++ client/src/top_nav/GlobalSearchBar.tsx | 62 +++++++++++++++++++ client/src/top_nav/TopNav.tsx | 3 + 4 files changed, 77 insertions(+) create mode 100644 client/src/pages/both/globalsearch/GlobalSearchPage.tsx create mode 100644 client/src/top_nav/GlobalSearchBar.tsx diff --git a/client/src/AppRoutes.tsx b/client/src/AppRoutes.tsx index 8449cf10d..205a52e21 100644 --- a/client/src/AppRoutes.tsx +++ b/client/src/AppRoutes.tsx @@ -49,6 +49,7 @@ import NewEquipmentPage from "./pages/makerspace_page/equipment_pages/NewEquipme import EquipmentRedirector from "./pages/makerspace_page/equipment_pages/EquipmentRedirector"; import HelpPage from "./pages/maker/signup/HelpPage"; import UserPage from "./pages/lab_management/users/UserPage"; +import GlobalSearchPage from "./pages/both/globalsearch/GlobalSearchPage"; // This is where we map the browser's URL to a // React component with the help of React Router. @@ -127,6 +128,7 @@ export default function AppRoutes() { } /> } /> } /> + } /> {/* Routes that need to be protected by auth */} }> diff --git a/client/src/pages/both/globalsearch/GlobalSearchPage.tsx b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx new file mode 100644 index 000000000..c91959d2e --- /dev/null +++ b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx @@ -0,0 +1,10 @@ +import { Typography } from "@mui/material"; +import { useParams } from "react-router-dom"; + +export default function GlobalSearchPage (){ + const {query} = useParams(); + + return( + {query} + ); +} \ No newline at end of file diff --git a/client/src/top_nav/GlobalSearchBar.tsx b/client/src/top_nav/GlobalSearchBar.tsx new file mode 100644 index 000000000..42396f8ba --- /dev/null +++ b/client/src/top_nav/GlobalSearchBar.tsx @@ -0,0 +1,62 @@ +import { Autocomplete, TextField } from "@mui/material"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { GET_ALL_EQUIPMENTS } from "../queries/equipmentQueries"; +import { useQuery } from "@apollo/client"; +import GET_TRAINING_MODULES from "../queries/trainingQueries"; +import GET_ROOMS from "../queries/roomQueries"; +import { GET_MAKERSPACES } from "../queries/makerspaceQueries"; + +export default function GlobalSearchBar() { + const navigate = useNavigate(); + const [searchQuery, setSearchQuery] = useState(""); + + const getEquipment = useQuery(GET_ALL_EQUIPMENTS) + const getTrainings = useQuery(GET_TRAINING_MODULES) + const getRooms = useQuery(GET_ROOMS) + const getMakerspaces = useQuery(GET_MAKERSPACES) + + const options: any[] = getEquipment.data?.allEquipment.map((equipment:{ id:number, name:string, archived:boolean}) => ({label:equipment.name, category:"Equipments", item:equipment})); + getTrainings.data?.modules.forEach((module:{ id:number, name:string, archived:boolean}) => { + options.push({label:module.name, category:"Trainings", item:module}) + }); + getRooms.data?.rooms.forEach((room:{id:number, name:string}) => { + options.push({label:room.name, category:"Rooms", item:room}) + }); + getMakerspaces.data?.makerspaces.forEach((makerspace:{id:number, name:string}) => { + options.push({label:makerspace.name, category:"Makerspaces", item:makerspace}) + }) + + const handleRedirect = (reason:string, value:any, origin:string) => { + switch(reason){ + case 'input': + setSearchQuery(value) + break + case 'createOption': + navigate(`/search/` + searchQuery) + break + case 'selectOption': + { + const encodedLabel = value.label.replace('/', '%2F') + navigate(`/search/` + encodedLabel) + break + } + + } + }; + + return ( + option.category} + sx={{ width: 300 }} + freeSolo={true} + autoHighlight={false} + onChange={(e, v, r) => r === 'selectOption' || r=== 'createOption' ? handleRedirect(r, v === null ? "": v, "change") : {}} + onInputChange={(e, v:string, r) => r === 'input' ? handleRedirect(r, v, "input"): {}} + renderInput={(params) => } + /> + + ); +} \ No newline at end of file diff --git a/client/src/top_nav/TopNav.tsx b/client/src/top_nav/TopNav.tsx index cad7da369..188abad39 100644 --- a/client/src/top_nav/TopNav.tsx +++ b/client/src/top_nav/TopNav.tsx @@ -18,6 +18,7 @@ import StorefrontIcon from '@mui/icons-material/Storefront'; import ArticleIcon from '@mui/icons-material/Article'; import TuneIcon from '@mui/icons-material/Tune'; import LogoutIcon from '@mui/icons-material/Logout'; +import GlobalSearchBar from "./GlobalSearchBar"; const StyledLogo = styled.img` padding: 12px; @@ -182,8 +183,10 @@ export default function TopNav() { {navlinks} + {userProfileButton} {userMenu} + From ba5151e36566ae396bc4e35eada54b91589b9016 Mon Sep 17 00:00:00 2001 From: Yi Xhan Date: Wed, 15 Oct 2025 10:48:34 -0400 Subject: [PATCH 2/4] search results page with equipment, trainings and makerspaces --- .../both/globalsearch/GlobalSearchPage.tsx | 85 ++++++++++++++++++- client/src/top_nav/GlobalSearchBar.tsx | 49 ++++++----- 2 files changed, 111 insertions(+), 23 deletions(-) diff --git a/client/src/pages/both/globalsearch/GlobalSearchPage.tsx b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx index c91959d2e..167237dd2 100644 --- a/client/src/pages/both/globalsearch/GlobalSearchPage.tsx +++ b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx @@ -1,10 +1,91 @@ -import { Typography } from "@mui/material"; +import { Divider, Grid, Stack, Typography } from "@mui/material"; import { useParams } from "react-router-dom"; +import Equipment from "../../../types/Equipment"; +import { GET_EQUIPMENTS } from "../../../queries/equipmentQueries"; +import { useQuery } from "@apollo/client"; +import EquipmentCard from "../../../common/EquipmentCard"; +import { useIsMobile } from "../../../common/IsMobileProvider"; +import { useCurrentUser } from "../../../common/CurrentUserProvider"; +import RequestWrapper from "../../../common/RequestWrapper"; +import GET_TRAINING_MODULES from "../../../queries/trainingQueries"; +import { ModuleStatus, moduleStatusMapper, TrainingModule } from "../../../common/TrainingModuleUtils"; +import ModuleStatusRow from "../../../common/ModuleStatusRow"; +import { GET_MAKERSPACES_WITH_HOURS, MakerspaceWithHours } from "../../../queries/makerspaceQueries"; +import MakerspaceCard from "../homepage/MakerspaceCard"; export default function GlobalSearchPage (){ const {query} = useParams(); + const { passedModules, trainingHolds } = useCurrentUser(); + const isMobile = useIsMobile(); + + const getEquipment = useQuery(GET_EQUIPMENTS); + const filteredEquipment = getEquipment.data?.equipments.filter((equipment: Equipment) => equipment.name.toLowerCase().includes(query!.toLowerCase())); + const foundEquipments = filteredEquipment?.map((equipment: Equipment) => ( + + + + )); + + const getTrainings = useQuery(GET_TRAINING_MODULES); + const filteredTrainings = getTrainings.data?.modules.filter((training: TrainingModule) => training.name.toLowerCase().includes(query!.toLowerCase())); + const moduleStatuses = filteredTrainings?.map( + moduleStatusMapper(passedModules, trainingHolds) + ); + const foundTrainings = moduleStatuses?.map((moduleStatus: ModuleStatus)=> ( + + + + )); + + const getMakerspaces = useQuery(GET_MAKERSPACES_WITH_HOURS) + const filteredMakerspaces = getMakerspaces.data?.makerspaces.filter((makerspace: MakerspaceWithHours) => makerspace.name.toLowerCase().includes(query!.toLowerCase())) + const foundMakerspaces = filteredMakerspaces?.map((makerspace: MakerspaceWithHours) => + + + + ) return( - {query} + + }> + {`${query} - Search Results`} + Equipment + {foundEquipments?.length > 0 ? + + {foundEquipments} + + : No Equipment Found + } + + Trainings + {foundTrainings?.length > 0 ? + + {foundTrainings} + + : No Trainings Found + } + + Makerspaces + {foundMakerspaces?.length > 0 ? + + {foundMakerspaces} + + : No Makerspaces Found + } + + + ); } \ No newline at end of file diff --git a/client/src/top_nav/GlobalSearchBar.tsx b/client/src/top_nav/GlobalSearchBar.tsx index 42396f8ba..6bf811c5e 100644 --- a/client/src/top_nav/GlobalSearchBar.tsx +++ b/client/src/top_nav/GlobalSearchBar.tsx @@ -5,7 +5,10 @@ import { GET_ALL_EQUIPMENTS } from "../queries/equipmentQueries"; import { useQuery } from "@apollo/client"; import GET_TRAINING_MODULES from "../queries/trainingQueries"; import GET_ROOMS from "../queries/roomQueries"; -import { GET_MAKERSPACES } from "../queries/makerspaceQueries"; +import { FullMakerspace, GET_FULL_MAKERSPACES, GET_MAKERSPACES } from "../queries/makerspaceQueries"; +import Equipment from "../types/Equipment"; +import { TrainingModule } from "../common/TrainingModuleUtils"; +import Room from "../types/Room"; export default function GlobalSearchBar() { const navigate = useNavigate(); @@ -14,26 +17,30 @@ export default function GlobalSearchBar() { const getEquipment = useQuery(GET_ALL_EQUIPMENTS) const getTrainings = useQuery(GET_TRAINING_MODULES) const getRooms = useQuery(GET_ROOMS) - const getMakerspaces = useQuery(GET_MAKERSPACES) + const getMakerspaces = useQuery(GET_FULL_MAKERSPACES) - const options: any[] = getEquipment.data?.allEquipment.map((equipment:{ id:number, name:string, archived:boolean}) => ({label:equipment.name, category:"Equipments", item:equipment})); - getTrainings.data?.modules.forEach((module:{ id:number, name:string, archived:boolean}) => { + const options: any[] = []; + getEquipment.data?.allEquipment.forEach((equipment:Equipment) => { + options.push({label:equipment.name, category:"Equipments", item:equipment}) + }); + getTrainings.data?.modules.forEach((module:TrainingModule) => { options.push({label:module.name, category:"Trainings", item:module}) }); - getRooms.data?.rooms.forEach((room:{id:number, name:string}) => { + getRooms.data?.rooms.forEach((room:Room) => { options.push({label:room.name, category:"Rooms", item:room}) }); - getMakerspaces.data?.makerspaces.forEach((makerspace:{id:number, name:string}) => { + getMakerspaces.data?.makerspaces.forEach((makerspace:FullMakerspace) => { options.push({label:makerspace.name, category:"Makerspaces", item:makerspace}) - }) + }); - const handleRedirect = (reason:string, value:any, origin:string) => { + const handleRedirect = (reason:string, value:any) => { switch(reason){ case 'input': setSearchQuery(value) break case 'createOption': - navigate(`/search/` + searchQuery) + const encodedQuery = searchQuery.replace('/', '%2F') + navigate(`/search/` + encodedQuery) break case 'selectOption': { @@ -46,17 +53,17 @@ export default function GlobalSearchBar() { }; return ( - option.category} - sx={{ width: 300 }} - freeSolo={true} - autoHighlight={false} - onChange={(e, v, r) => r === 'selectOption' || r=== 'createOption' ? handleRedirect(r, v === null ? "": v, "change") : {}} - onInputChange={(e, v:string, r) => r === 'input' ? handleRedirect(r, v, "input"): {}} - renderInput={(params) => } - /> - + option.category} + sx={{ width: 300 }} + freeSolo={true} + autoHighlight={false} + blurOnSelect={true} + onChange={(e, v, r) => {r === 'selectOption' || r === 'createOption' ? handleRedirect(r, v === null ? "" : v) : {}}} + onInputChange={(e, v: string, r) => r === 'input' ? handleRedirect(r, v) : {}} + renderInput={(params) => {event.target.select()}}/>} + /> ); } \ No newline at end of file From d08afedc71edbd1d1d0fe1b6a1c45dd529e59ae7 Mon Sep 17 00:00:00 2001 From: Yi Xhan Date: Wed, 15 Oct 2025 14:22:55 -0400 Subject: [PATCH 3/4] prep for fixing training search on results for visitors --- .../both/globalsearch/GlobalSearchPage.tsx | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/client/src/pages/both/globalsearch/GlobalSearchPage.tsx b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx index 167237dd2..888eb83d6 100644 --- a/client/src/pages/both/globalsearch/GlobalSearchPage.tsx +++ b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx @@ -1,5 +1,5 @@ -import { Divider, Grid, Stack, Typography } from "@mui/material"; -import { useParams } from "react-router-dom"; +import { CardActionArea, Divider, Grid, Link, Stack, Typography } from "@mui/material"; +import { useNavigate, useParams } from "react-router-dom"; import Equipment from "../../../types/Equipment"; import { GET_EQUIPMENTS } from "../../../queries/equipmentQueries"; import { useQuery } from "@apollo/client"; @@ -15,8 +15,9 @@ import MakerspaceCard from "../homepage/MakerspaceCard"; export default function GlobalSearchPage (){ const {query} = useParams(); - const { passedModules, trainingHolds } = useCurrentUser(); + const user = useCurrentUser(); const isMobile = useIsMobile(); + const navigate = useNavigate(); const getEquipment = useQuery(GET_EQUIPMENTS); const filteredEquipment = getEquipment.data?.equipments.filter((equipment: Equipment) => equipment.name.toLowerCase().includes(query!.toLowerCase())); @@ -26,16 +27,27 @@ export default function GlobalSearchPage (){ )); + + // TODO: make a new query for published only and/or to allow visitors to query this const getTrainings = useQuery(GET_TRAINING_MODULES); const filteredTrainings = getTrainings.data?.modules.filter((training: TrainingModule) => training.name.toLowerCase().includes(query!.toLowerCase())); const moduleStatuses = filteredTrainings?.map( - moduleStatusMapper(passedModules, trainingHolds) + moduleStatusMapper(user.passedModules, user.trainingHolds) ); - const foundTrainings = moduleStatuses?.map((moduleStatus: ModuleStatus)=> ( - + const foundTrainingsVisitor = getTrainings?.data?.modules?.map((module: TrainingModule) => ( + navigate(`/maker/training/${module.moduleID}`)} sx={{ width: "unset" }}> + + + {module.moduleName} + + + )); + const foundTrainingsUser = moduleStatuses?.map((moduleStatus: ModuleStatus) => ( + )); + const foundTrainings = user.visitor ? foundTrainingsVisitor : foundTrainingsUser const getMakerspaces = useQuery(GET_MAKERSPACES_WITH_HOURS) const filteredMakerspaces = getMakerspaces.data?.makerspaces.filter((makerspace: MakerspaceWithHours) => makerspace.name.toLowerCase().includes(query!.toLowerCase())) From 677a605b718dbdee61f5142ebc9d54e7cca85bf0 Mon Sep 17 00:00:00 2001 From: Yi Xhan Date: Tue, 4 Nov 2025 16:54:57 -0500 Subject: [PATCH 4/4] selecting options navigation --- .../both/globalsearch/GlobalSearchPage.tsx | 20 ++++---------- client/src/queries/equipmentQueries.ts | 15 +++++++++++ client/src/queries/trainingQueries.ts | 11 ++++++++ client/src/top_nav/GlobalSearchBar.tsx | 27 ++++++++++++------- .../src/resolvers/trainingModuleResolver.ts | 8 ++++++ server/src/schemas/trainingModuleSchema.ts | 1 + 6 files changed, 58 insertions(+), 24 deletions(-) diff --git a/client/src/pages/both/globalsearch/GlobalSearchPage.tsx b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx index 888eb83d6..cd1d358f3 100644 --- a/client/src/pages/both/globalsearch/GlobalSearchPage.tsx +++ b/client/src/pages/both/globalsearch/GlobalSearchPage.tsx @@ -1,4 +1,4 @@ -import { CardActionArea, Divider, Grid, Link, Stack, Typography } from "@mui/material"; +import { Divider, Grid, Stack, Typography } from "@mui/material"; import { useNavigate, useParams } from "react-router-dom"; import Equipment from "../../../types/Equipment"; import { GET_EQUIPMENTS } from "../../../queries/equipmentQueries"; @@ -7,7 +7,7 @@ import EquipmentCard from "../../../common/EquipmentCard"; import { useIsMobile } from "../../../common/IsMobileProvider"; import { useCurrentUser } from "../../../common/CurrentUserProvider"; import RequestWrapper from "../../../common/RequestWrapper"; -import GET_TRAINING_MODULES from "../../../queries/trainingQueries"; +import { GET_PUBLISHED_TRAINING_MODULES } from "../../../queries/trainingQueries"; import { ModuleStatus, moduleStatusMapper, TrainingModule } from "../../../common/TrainingModuleUtils"; import ModuleStatusRow from "../../../common/ModuleStatusRow"; import { GET_MAKERSPACES_WITH_HOURS, MakerspaceWithHours } from "../../../queries/makerspaceQueries"; @@ -28,26 +28,16 @@ export default function GlobalSearchPage (){ )); - // TODO: make a new query for published only and/or to allow visitors to query this - const getTrainings = useQuery(GET_TRAINING_MODULES); - const filteredTrainings = getTrainings.data?.modules.filter((training: TrainingModule) => training.name.toLowerCase().includes(query!.toLowerCase())); + const getTrainings = useQuery(GET_PUBLISHED_TRAINING_MODULES); + const filteredTrainings = getTrainings.data?.publishedModules.filter((training: TrainingModule) => training.name.toLowerCase().includes(query!.toLowerCase())); const moduleStatuses = filteredTrainings?.map( moduleStatusMapper(user.passedModules, user.trainingHolds) ); - const foundTrainingsVisitor = getTrainings?.data?.modules?.map((module: TrainingModule) => ( - navigate(`/maker/training/${module.moduleID}`)} sx={{ width: "unset" }}> - - - {module.moduleName} - - - )); - const foundTrainingsUser = moduleStatuses?.map((moduleStatus: ModuleStatus) => ( + const foundTrainings = moduleStatuses?.map((moduleStatus: ModuleStatus) => ( )); - const foundTrainings = user.visitor ? foundTrainingsVisitor : foundTrainingsUser const getMakerspaces = useQuery(GET_MAKERSPACES_WITH_HOURS) const filteredMakerspaces = getMakerspaces.data?.makerspaces.filter((makerspace: MakerspaceWithHours) => makerspace.name.toLowerCase().includes(query!.toLowerCase())) diff --git a/client/src/queries/equipmentQueries.ts b/client/src/queries/equipmentQueries.ts index a42271c51..757444b57 100644 --- a/client/src/queries/equipmentQueries.ts +++ b/client/src/queries/equipmentQueries.ts @@ -35,6 +35,21 @@ export const GET_ALL_EQUIPMENTS = gql` } `; +export const GET_ALL_PUBLISHED_EQUIPMENTS = gql` + query GetAllPublishedEquipment { + equipments { + id + name + archived + room { + makerspace { + id + } + } + } + } +` + export const GET_EQUIPMENT_BY_ID = gql` query GetEquipmentByID($id: ID!) { equipment(id: $id) { diff --git a/client/src/queries/trainingQueries.ts b/client/src/queries/trainingQueries.ts index fa5f5be51..370e53812 100644 --- a/client/src/queries/trainingQueries.ts +++ b/client/src/queries/trainingQueries.ts @@ -62,6 +62,17 @@ export const GET_ARCHIVED_TRAINING_MODULES = gql` } `; +export const GET_PUBLISHED_TRAINING_MODULES = gql` + query GetPublishedTrainingModules { + publishedModules { + id + name + archived + makerspaceID + } + } +` + export const CREATE_TRAINING_MODULE = gql` mutation CreateTrainingModule($name: String!, $quiz: JSON!, $makerspaceID: ID) { createModule(name: $name, quiz: $quiz, makerspaceID: $makerspaceID) { diff --git a/client/src/top_nav/GlobalSearchBar.tsx b/client/src/top_nav/GlobalSearchBar.tsx index 6bf811c5e..5b622851a 100644 --- a/client/src/top_nav/GlobalSearchBar.tsx +++ b/client/src/top_nav/GlobalSearchBar.tsx @@ -1,9 +1,9 @@ import { Autocomplete, TextField } from "@mui/material"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; -import { GET_ALL_EQUIPMENTS } from "../queries/equipmentQueries"; +import { GET_ALL_PUBLISHED_EQUIPMENTS } from "../queries/equipmentQueries"; import { useQuery } from "@apollo/client"; -import GET_TRAINING_MODULES from "../queries/trainingQueries"; +import { GET_PUBLISHED_TRAINING_MODULES } from "../queries/trainingQueries"; import GET_ROOMS from "../queries/roomQueries"; import { FullMakerspace, GET_FULL_MAKERSPACES, GET_MAKERSPACES } from "../queries/makerspaceQueries"; import Equipment from "../types/Equipment"; @@ -14,16 +14,16 @@ export default function GlobalSearchBar() { const navigate = useNavigate(); const [searchQuery, setSearchQuery] = useState(""); - const getEquipment = useQuery(GET_ALL_EQUIPMENTS) - const getTrainings = useQuery(GET_TRAINING_MODULES) + const getEquipment = useQuery(GET_ALL_PUBLISHED_EQUIPMENTS) + const getTrainings = useQuery(GET_PUBLISHED_TRAINING_MODULES) const getRooms = useQuery(GET_ROOMS) const getMakerspaces = useQuery(GET_FULL_MAKERSPACES) const options: any[] = []; - getEquipment.data?.allEquipment.forEach((equipment:Equipment) => { + getEquipment.data?.equipments.forEach((equipment:Equipment) => { options.push({label:equipment.name, category:"Equipments", item:equipment}) }); - getTrainings.data?.modules.forEach((module:TrainingModule) => { + getTrainings.data?.publishedModules.forEach((module:TrainingModule) => { options.push({label:module.name, category:"Trainings", item:module}) }); getRooms.data?.rooms.forEach((room:Room) => { @@ -43,12 +43,21 @@ export default function GlobalSearchBar() { navigate(`/search/` + encodedQuery) break case 'selectOption': - { - const encodedLabel = value.label.replace('/', '%2F') + const category = value.category + const encodedLabel = value.label.replace('/', '%2F') + if(category === "Equipments"){ + navigate(`/makerspace/` + value.item.room.makerspace.id + `?a=${encodedLabel}`) + } + else if(category === "Trainings"){ + navigate(`/maker/training/${value.item.id}`) + } + else if(category === "Makerspaces"){ + navigate(`/makerspace/${value.item.id}`) + } + else{ navigate(`/search/` + encodedLabel) break } - } }; diff --git a/server/src/resolvers/trainingModuleResolver.ts b/server/src/resolvers/trainingModuleResolver.ts index c8ac2c71b..eb05c7a74 100644 --- a/server/src/resolvers/trainingModuleResolver.ts +++ b/server/src/resolvers/trainingModuleResolver.ts @@ -252,6 +252,14 @@ const TrainingModuleResolvers = { return module; }), + publishedModules: async ( + _parent: any, + _args: any, + ) => { + return await ModuleRepo.getModulesWhereArchived(false); + }, + + /** * Fetch an array of AccessProgress items representing progress on gaining access to all equipment relating to the noted TrainingModule * @argument sourceTrainingModuleID ID of TrainingModule to source from diff --git a/server/src/schemas/trainingModuleSchema.ts b/server/src/schemas/trainingModuleSchema.ts index 421f4224e..e7cfe650b 100644 --- a/server/src/schemas/trainingModuleSchema.ts +++ b/server/src/schemas/trainingModuleSchema.ts @@ -56,6 +56,7 @@ export const TrainingModuleTypeDefs = gql` module(id: ID!): TrainingModule moduleWithAnswers(id: ID!): TrainingModule archivedModules: [TrainingModule] + publishedModules: [TrainingModule] archivedModule(id: ID!): TrainingModule relatedAccessProgress(sourceTrainingModuleID: ID!): [AccessProgress] }