diff --git a/gui/src/containers/Applications/Overview/index.vue b/gui/src/containers/Applications/Overview/index.vue index 97795f2..a124006 100644 --- a/gui/src/containers/Applications/Overview/index.vue +++ b/gui/src/containers/Applications/Overview/index.vue @@ -7,30 +7,30 @@

{{ application.title }}

+ application.status =='deployed' ? 'bg-success' : + application.status =='undeploying' ? 'bg-red-400' : ''" + v-if="application.status"> {{application.status}}

+ v-if="!application.status"> unknown

-
- - + - + +
@@ -43,11 +43,11 @@

{{ application.latency || 0 }} MS

@@ -58,11 +58,11 @@

{{ application.reconfigurations || 0 }}

@@ -74,11 +74,11 @@ @@ -90,11 +90,11 @@ @@ -113,7 +113,7 @@ + +const undeployApplication = (application: IApplication) => { + applicationStore.undeployApplication(application.uuid).then(() => { + + application.status = "undeploying"; + applicationStore.startPolling(); + + uiStore.setSnackbarMessage({ + message: `You need to manually undeploy resources.`, + type: SNACKBAR_MESSAGE_TYPES.INFO + }); + applicationStore.startPolling(); + + }).catch(() => { + uiStore.setSnackbarMessage({ + message: `Failed to undeploy application ${application.title}`, + type: SNACKBAR_MESSAGE_TYPES.ERROR + }); + }); +}; + +onMounted(() => { + // Retrieve applications and then start polling + applicationStore.getAllApplications().then(() => { + applicationStore.startPolling(); + }); +}); + +onBeforeUnmount(() => { + applicationStore.stopPolling(); +}); + + \ No newline at end of file diff --git a/gui/src/store/api-services/application.service.ts b/gui/src/store/api-services/application.service.ts index e04e7d5..f9496f7 100644 --- a/gui/src/store/api-services/application.service.ts +++ b/gui/src/store/api-services/application.service.ts @@ -141,7 +141,11 @@ export default { }, async duplicateApplication(uuid: string): Promise { return axios.post(`/api/v1/application/${uuid}/uuid/duplicate`).then(({data}) => data) - } - - -} + }, + async undeployApplication(uuid: string): Promise { + return axios.post(`/api/v1/application/${uuid}/uuid/undeploy`).then(({data}) => data) + }, + async checkApplicationStatus(uuids: string[]): Promise> { + return axios.post("/api/v1/application/status", { uuids }).then(({ data }) => data) + }, +} \ No newline at end of file diff --git a/gui/src/store/modules/application.ts b/gui/src/store/modules/application.ts index b401296..6d81715 100644 --- a/gui/src/store/modules/application.ts +++ b/gui/src/store/modules/application.ts @@ -1,14 +1,18 @@ import { defineStore } from "pinia" import applicationService from "@/store/api-services/application.service.ts" import { IApplication, IApplicationOverview } from "@/interfaces/application.interface.ts" +import { useUIStore } from "@/store/modules/ui.ts"; // Import the UI store +import { SNACKBAR_MESSAGE_TYPES } from "@/constants"; interface ApplicationState { applications: IPagination + pollingTimerId?: number; } export const useApplicationStore = defineStore("application", { state: (): ApplicationState => ({ - applications: { pages: 0, currentPage: 0, results: [] } + applications: { pages: 0, currentPage: 0, results: [] }, + pollingTimerId: undefined, }), actions: { async validateApplication(payload: Partial): Promise { @@ -63,6 +67,87 @@ export const useApplicationStore = defineStore("application", { const duplicatedApplication: IApplicationOverview = await applicationService.duplicateApplication(uuid) this.applications.results.unshift(duplicatedApplication) return duplicatedApplication - } - } -}) + }, + async undeployApplication(uuid: string): Promise { + return applicationService.undeployApplication(uuid).then((status) => { + const app: any = this.applications.results.find((app) => app.uuid === uuid); + app.status = status.status; + return status.status; + }); + }, + + async checkApplicationStatus(uuids: string[]): Promise { + console.log("Checking status for applications:", uuids); + + const response = await applicationService.checkApplicationStatus(uuids); + console.log("Received status updates:", response); + + response.forEach((updatedApp) => { + const appIndex = this.applications.results.findIndex((app) => app.uuid === updatedApp.uuid); + if (appIndex !== -1) { + const app = this.applications.results[appIndex]; + const previousStatus = app.status; + app.status = updatedApp.status; + + if (previousStatus !== "draft" && updatedApp.status === "draft") { + const uiStore = useUIStore(); + uiStore.setSnackbarMessage({ + message: `Application ${app.title} has been unlocked successfully`, + type: SNACKBAR_MESSAGE_TYPES.SUCCESS, + }); + } + + console.log(`Updated application ${updatedApp.uuid} to status ${updatedApp.status}`); + } + }); + }, + + startPolling() { + console.log("Polling started..."); + + const batchSize = 100; + let interval = 10000; //10 sec + //const maxInterval = 60000; + + const pollStatus = async () => { + const deployingApps = this.applications.results.filter( + (app) => app.status === "deploying" || app.status === "undeploying" + ); + + if (deployingApps.length === 0) { + console.log("No applications to poll for."); + return; + } + + console.log(`Polling for ${deployingApps.length} deploying/undeploying applications.`); + + for (let i = 0; i < deployingApps.length; i += batchSize) { + const batch = deployingApps.slice(i, i + batchSize); + await this.checkApplicationStatus(batch.map((app) => app.uuid)); + } + + const stillDeploying = this.applications.results.some( + (app) => app.status === "deploying" || app.status === "undeploying" + ); + + if (stillDeploying) { + console.log(`Some applications are still deploying. Polling again.`); + this.pollingTimerId = window.setTimeout(pollStatus, interval); + } else { + console.log("All applications have completed. Stopping polling."); + this.stopPolling(); + } + }; + + pollStatus(); + }, + + stopPolling() { + if (this.pollingTimerId) { + clearTimeout(this.pollingTimerId); + this.pollingTimerId = undefined; + console.log("Polling stopped."); + } + }, + }, +}); \ No newline at end of file