From 85ec720bf3a3db43d03007c2d3ef4b37d540223a Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Thu, 2 May 2024 04:03:35 -0600 Subject: [PATCH 01/16] skeleton of front end config editor --- .../src/views/AdminView/AdminView.vue | 8 +-- .../src/views/AdminView/ConfigView.vue | 51 +++++++++++++++++++ .../src/views/AdminView/QueueStatus.vue | 2 - 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/frontend/src/views/AdminView/ConfigView.vue diff --git a/src/main/resources/frontend/src/views/AdminView/AdminView.vue b/src/main/resources/frontend/src/views/AdminView/AdminView.vue index 9d2a16bbc..660f41570 100644 --- a/src/main/resources/frontend/src/views/AdminView/AdminView.vue +++ b/src/main/resources/frontend/src/views/AdminView/AdminView.vue @@ -9,6 +9,7 @@ import HonorChecker from "@/views/AdminView/HonorChecker.vue"; import {useAdminStore} from "@/stores/admin"; import StudentsView from "@/views/AdminView/StudentsView.vue"; import LogsView from "@/views/AdminView/LogsView.vue"; +import ConfigView from '@/views/AdminView/ConfigView.vue' useAdminStore().updateUsers(); @@ -19,13 +20,11 @@ useAdminStore().updateUsers(); + - - - @@ -33,6 +32,9 @@ useAdminStore().updateUsers(); + + + diff --git a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue new file mode 100644 index 000000000..6f44d1f74 --- /dev/null +++ b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue @@ -0,0 +1,51 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/frontend/src/views/AdminView/QueueStatus.vue b/src/main/resources/frontend/src/views/AdminView/QueueStatus.vue index 67c69889b..e8a44510c 100644 --- a/src/main/resources/frontend/src/views/AdminView/QueueStatus.vue +++ b/src/main/resources/frontend/src/views/AdminView/QueueStatus.vue @@ -65,7 +65,6 @@ const reRunQueue = async () => { \ No newline at end of file From 6a49ad38795c06e3919b0f0e8e815786d9d7b413 Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Fri, 3 May 2024 18:34:28 -0600 Subject: [PATCH 05/16] banner now appears on front end --- .../byu/cs/controller/ConfigController.java | 22 +++++++++++++++---- src/main/java/edu/byu/cs/server/Server.java | 4 +++- src/main/resources/frontend/src/App.vue | 22 ++++++++++++++++++- .../frontend/src/services/configService.ts | 9 +++++++- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/main/java/edu/byu/cs/controller/ConfigController.java b/src/main/java/edu/byu/cs/controller/ConfigController.java index dd8ffd32c..d8cf8e88a 100644 --- a/src/main/java/edu/byu/cs/controller/ConfigController.java +++ b/src/main/java/edu/byu/cs/controller/ConfigController.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import edu.byu.cs.dataAccess.ConfigurationDao; import edu.byu.cs.dataAccess.DaoService; +import edu.byu.cs.dataAccess.DataAccessException; import edu.byu.cs.model.User; import edu.byu.cs.model.appConfig.BannerMessage; import org.slf4j.Logger; @@ -14,16 +15,29 @@ public class ConfigController { private static final Logger LOGGER = LoggerFactory.getLogger(SubmissionController.class); - public static final Route getConfig = (req, res) -> { + public static final Route getConfigAdmin = (req, res) -> { + JsonObject response = getPublicConfig(); + + res.status(200); + return response.toString(); + }; + + public static final Route getConfigStudent = (req, res) -> { + String response = getPublicConfig().toString(); + + res.status(200); + return response; + }; + + private static JsonObject getPublicConfig() throws DataAccessException { ConfigurationDao dao = DaoService.getConfigurationDao(); JsonObject response = new JsonObject(); response.addProperty("bannerMessage", dao.getConfiguration(ConfigurationDao.Configuration.BANNER_MESSAGE, String.class)); - res.status(200); - return response.toString(); - }; + return response; + } public static final Route updateLivePhases = (req, res) -> { diff --git a/src/main/java/edu/byu/cs/server/Server.java b/src/main/java/edu/byu/cs/server/Server.java index adb15c137..1f4c83e5f 100644 --- a/src/main/java/edu/byu/cs/server/Server.java +++ b/src/main/java/edu/byu/cs/server/Server.java @@ -66,6 +66,8 @@ public static int setupEndpoints(int port) { get("/me", meGet); + get("/config", getConfigStudent); + path("/admin", () -> { before("/*", (req, res) -> { if (!req.requestMethod().equals("OPTIONS")) @@ -101,7 +103,7 @@ public static int setupEndpoints(int port) { get("/sections", sectionsGet); path("/config", () -> { - get("", getConfig); + get("", getConfigAdmin); post("/phases", updateLivePhases); post("/banner", updateBannerMessage); diff --git a/src/main/resources/frontend/src/App.vue b/src/main/resources/frontend/src/App.vue index 56c34f5be..f7b6ed1e8 100644 --- a/src/main/resources/frontend/src/App.vue +++ b/src/main/resources/frontend/src/App.vue @@ -1,11 +1,12 @@ \ No newline at end of file From 1808f6c9486aa4ca02c0ef73aff373c163cf5b51 Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Sat, 4 May 2024 20:54:52 -0600 Subject: [PATCH 13/16] make active phase config display reload on popup close This is so that when one clicks checkboxes, then closes the pop-up without saving, it still shows the accurate info --- src/main/resources/frontend/src/views/AdminView/ConfigView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue index 7a21df8a6..2870370c2 100644 --- a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue +++ b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue @@ -98,7 +98,7 @@ const submitLivePhases = async () => { + @closePopUp="openLivePhases = false; loadConfig()">

Live Phases

Enable student submissions for the following phases:

From d19d9c10587334f2547269ab3237add5dfc42fbe Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Tue, 14 May 2024 15:46:02 -0600 Subject: [PATCH 14/16] refactor config change logging --- .../java/edu/byu/cs/controller/ConfigController.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/byu/cs/controller/ConfigController.java b/src/main/java/edu/byu/cs/controller/ConfigController.java index aebc9fe0c..b1adea4eb 100644 --- a/src/main/java/edu/byu/cs/controller/ConfigController.java +++ b/src/main/java/edu/byu/cs/controller/ConfigController.java @@ -16,6 +16,10 @@ public class ConfigController { private static final Logger LOGGER = LoggerFactory.getLogger(SubmissionController.class); + private static void logConfigChange(String changeMessage, String adminNetId) { + LOGGER.info("[CONFIG] Admin %s has %s".formatted(adminNetId, changeMessage)); + } + public static final Route getConfigAdmin = (req, res) -> { JsonObject response = getPublicConfig(); @@ -50,7 +54,7 @@ private static JsonObject getPublicConfig() throws DataAccessException { dao.setConfiguration(ConfigurationDao.Configuration.STUDENT_SUBMISSIONS_ENABLED, phasesArray, ArrayList.class); User user = req.session().attribute("user"); - LOGGER.info("[CONFIG] Admin %s has set the following phases as live: %s".formatted(user.netId(), phasesArray)); + logConfigChange("set the following phases as live: %s".formatted(phasesArray), user.netId()); res.status(200); return ""; @@ -65,9 +69,9 @@ private static JsonObject getPublicConfig() throws DataAccessException { User user = req.session().attribute("user"); if (message.isEmpty()) { - LOGGER.info("[CONFIG] Admin %s has cleared the banner message".formatted(user.netId())); + logConfigChange("cleared the banner message", user.netId()); } else { - LOGGER.info("[CONFIG] Admin %s has set the banner message to: '%s'".formatted(user.netId(), message)); + logConfigChange("set the banner message to: '%s'".formatted(message), user.netId()); } res.status(200); From 3b9c436b04fdc626cf3e4420b2a5f1d899dba4d9 Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Tue, 14 May 2024 16:26:43 -0600 Subject: [PATCH 15/16] refactor config storage to appConfig.ts --- src/main/resources/frontend/src/App.vue | 19 +++---- .../frontend/src/services/configService.ts | 6 ++- .../frontend/src/stores/appConfig.ts | 24 ++++++++- .../resources/frontend/src/types/types.ts | 5 -- .../src/views/AdminView/ConfigView.vue | 52 +++++-------------- 5 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/main/resources/frontend/src/App.vue b/src/main/resources/frontend/src/App.vue index f7b6ed1e8..ccbe7b4f3 100644 --- a/src/main/resources/frontend/src/App.vue +++ b/src/main/resources/frontend/src/App.vue @@ -1,12 +1,12 @@ diff --git a/src/main/resources/frontend/src/services/configService.ts b/src/main/resources/frontend/src/services/configService.ts index 377b4d397..ca763efc6 100644 --- a/src/main/resources/frontend/src/services/configService.ts +++ b/src/main/resources/frontend/src/services/configService.ts @@ -1,5 +1,5 @@ -import { useAppConfigStore } from '@/stores/appConfig' -import { type Config, Phase } from '@/types/types' +import { type Config, useAppConfigStore } from '@/stores/appConfig' +import { Phase } from '@/types/types' import { useAuthStore } from '@/stores/auth' export const getConfig = async ():Promise => { @@ -38,6 +38,7 @@ export const setBannerMessage = async (message: String): Promise => { console.error(response); throw new Error(await response.text()); } + await useAppConfigStore().updateConfig(); } export const setLivePhases = async (phases: Array): Promise => { @@ -56,4 +57,5 @@ export const setLivePhases = async (phases: Array): Promise => { console.error(response); throw new Error(await response.text()); } + await useAppConfigStore().updateConfig(); } \ No newline at end of file diff --git a/src/main/resources/frontend/src/stores/appConfig.ts b/src/main/resources/frontend/src/stores/appConfig.ts index 792a5f1b9..652ae5ec6 100644 --- a/src/main/resources/frontend/src/stores/appConfig.ts +++ b/src/main/resources/frontend/src/stores/appConfig.ts @@ -1,14 +1,34 @@ -import { ref, computed } from 'vue' +import { ref, type Ref } from 'vue' import { defineStore } from 'pinia' +import { listOfPhases, Phase } from '@/types/types' +import { getConfig } from '@/services/configService' type ImportMeta = { VITE_APP_BACKEND_URL: string } +export type Config = { + bannerMessage: string + phases: Array +} + // @ts-ignore const env: ImportMeta = import.meta.env; export const useAppConfigStore = defineStore('appConfig', () => { const backendUrl = ref(env.VITE_APP_BACKEND_URL); - return { backendUrl } + const updateConfig = async () => { + const latestConfig = await getConfig(); + + bannerMessage.value = latestConfig.bannerMessage + for (const phase of listOfPhases() as Phase[]) { + activePhaseList.value[phase] = latestConfig.phases.includes(phase); + } + } + + const bannerMessage: Ref = ref("") + // using the enum, if phaseActivationList[phase] == true, then that phase is active + const activePhaseList: Ref = ref>([]) + + return { updateConfig, backendUrl, bannerMessage, phaseActivationList: activePhaseList } }) diff --git a/src/main/resources/frontend/src/types/types.ts b/src/main/resources/frontend/src/types/types.ts index 36ecb68bc..6807387a3 100644 --- a/src/main/resources/frontend/src/types/types.ts +++ b/src/main/resources/frontend/src/types/types.ts @@ -91,8 +91,3 @@ export type CanvasSection = { id: number, name: string } - -export type Config = { - bannerMessage: string - phases: Array -} diff --git a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue index 2870370c2..3a98132fa 100644 --- a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue +++ b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue @@ -1,63 +1,40 @@