diff --git a/source/app/blueprints/pages/alerts/alerts_routes.py b/source/app/blueprints/pages/alerts/alerts_routes.py index 00d7e1005..3324b5bc7 100644 --- a/source/app/blueprints/pages/alerts/alerts_routes.py +++ b/source/app/blueprints/pages/alerts/alerts_routes.py @@ -31,6 +31,16 @@ from app.blueprints.responses import response_error from app.blueprints.access_controls import ac_requires + +from app.datamgmt.client.client_db import get_clients_sla +from app.blueprints.responses import response_success + +from app.blueprints.access_controls import ac_api_requires + +from app.datamgmt.alerts.alerts_db import get_elapsed_sla + +from app.datamgmt.alerts.alerts_db import set_elapsed_sla + alerts_blueprint = Blueprint( 'alerts', __name__, @@ -57,6 +67,39 @@ def alerts_list_view_route(caseid, url_redir) -> Union[str, Response]: return render_template('alerts.html', caseid=caseid, form=form) +#later move this to source/app/blueprints/rest/alerts_routes.py +@alerts_blueprint.route('/alerts/api/set_elapsed_sla_api//', methods=['GET']) +@ac_api_requires(Permissions.alerts_write) +def set_elapsed_sla_api(alert_id: int, new_elapsed_sla: int): + updated_alert = set_elapsed_sla(alert_id, new_elapsed_sla) + return response_success(data=updated_alert) + + +@alerts_blueprint.route('/alerts/api/get_clients_sla_api', methods=['GET']) +@ac_api_requires() +def get_clients_sla_api(): + rows= get_clients_sla() + customers = [dict(row._mapping) for row in rows] + output = { + "customers_sla": customers + } + + return response_success(data=output) + +#later move this to source/app/blueprints/rest/alerts_routes.py +@alerts_blueprint.route('/alerts/api/get_elapsed_sla_api/', methods=['GET']) +@ac_api_requires() +def get_elapsed_sla_api(alert_id: int): + elapsed_sla = get_elapsed_sla(alert_id) + #output = { + # "elapsed_sla": elapsed_sla + #} + + return response_success(data=elapsed_sla) + + + + @alerts_blueprint.route('/alerts//comments/modal', methods=['GET']) @ac_requires(Permissions.alerts_read, no_cid_required=True) diff --git a/source/app/blueprints/pages/alerts/templates/alerts.html b/source/app/blueprints/pages/alerts/templates/alerts.html index b2532cf7c..ecb135872 100644 --- a/source/app/blueprints/pages/alerts/templates/alerts.html +++ b/source/app/blueprints/pages/alerts/templates/alerts.html @@ -368,6 +368,7 @@ + {% endblock javascripts %} diff --git a/source/app/datamgmt/alerts/alerts_db.py b/source/app/datamgmt/alerts/alerts_db.py index d78792409..0d4e27a4f 100644 --- a/source/app/datamgmt/alerts/alerts_db.py +++ b/source/app/datamgmt/alerts/alerts_db.py @@ -1566,3 +1566,20 @@ def get_alert_status_by_name(name: str) -> AlertStatus: """ return AlertStatus.query.filter(AlertStatus.status_name == name).first() + +def get_elapsed_sla(alert_id: int) -> Alert: + elapsed_sla = Alert.query.filter(Alert.alert_id == alert_id).first() + return elapsed_sla + +def set_elapsed_sla(alert_id: int, new_elapsed_sla: int): + alert = Alert.query.filter(Alert.alert_id == alert_id).first() + if alert: + # Update the column with the new value + alert.alert_elapsed_sla = new_elapsed_sla + # Commit the changes to the database + db.session.commit() + return alert + else: + # Optionally handle the case where no alert is found + return None + diff --git a/source/app/datamgmt/client/client_db.py b/source/app/datamgmt/client/client_db.py index 42437dbc5..ed9ca8627 100644 --- a/source/app/datamgmt/client/client_db.py +++ b/source/app/datamgmt/client/client_db.py @@ -55,6 +55,10 @@ def get_client_list(current_user_id: int = None, return output +def get_clients_sla(): + client_data = Client.query.with_entities(Client.sla, Client.client_id).all() + return client_data + def get_client(client_id: int) -> Client: client = Client.query.filter(Client.client_id == client_id).first() diff --git a/source/app/models/alerts.py b/source/app/models/alerts.py index 884e56467..859252b0f 100644 --- a/source/app/models/alerts.py +++ b/source/app/models/alerts.py @@ -67,6 +67,7 @@ class Alert(db.Model): alert_customer_id = Column(ForeignKey('client.client_id'), nullable=False) alert_classification_id = Column(ForeignKey('case_classification.id')) alert_resolution_status_id = Column(ForeignKey('alert_resolution_status.resolution_status_id'), nullable=True) + alert_elapsed_sla = Column(Integer, default=-1) owner = relationship('User', foreign_keys=[alert_owner_id]) severity = relationship('Severity') diff --git a/ui/src/pages/ProgressBar.svelte b/ui/src/pages/ProgressBar.svelte new file mode 100644 index 000000000..e1949ec77 --- /dev/null +++ b/ui/src/pages/ProgressBar.svelte @@ -0,0 +1,247 @@ + + +
+
+
+
+

{startDateTime} - {endDateTime}

+
+ +
+ Elapsed time: +
+ + + +
+

{elapsed.toFixed(1)}s

+
+
+
+ + {#if duration === elapsed} +

SLA breached!

+ {/if} +
+ + + \ No newline at end of file diff --git a/ui/src/pages/SLA.js b/ui/src/pages/SLA.js new file mode 100644 index 000000000..0eadaadd1 --- /dev/null +++ b/ui/src/pages/SLA.js @@ -0,0 +1,33 @@ +import App from './SLAcontainer.svelte'; + +export let app; // Declare at the top level + +document.addEventListener('alertRendered', (event) => { + const containers = document.querySelectorAll('.SLAcontainer'); + if (containers) { + containers.forEach((container) => { + // Check if the container already has the "mounted" class + if (container.classList.contains("mounted")) { + console.log('SLA component already mounted on this container'); + return; + } + app = new App({ + target: container, + props: { + IRIStime: event.detail.IRIStime, + alertStatusID: event.detail.alertStatusID, + alertSevID: event.detail.alertSevID, + alertCustomerID: event.detail.alertCustomerID, + SLA: event.detail.SLA, + alertID: event.detail.alertID + } + }); + console.log('Svelte component mounted:', app); + // Mark the container by adding a "mounted" class so we don't mount again. + container.classList.add("mounted"); + }); + } +}); + + + diff --git a/ui/src/pages/SLAbar.svelte b/ui/src/pages/SLAbar.svelte new file mode 100644 index 000000000..095a0ac9d --- /dev/null +++ b/ui/src/pages/SLAbar.svelte @@ -0,0 +1,256 @@ + + +
+ {#if result === true} + + {:else} + + {/if} +
\ No newline at end of file diff --git a/ui/src/pages/SLAcontainer.svelte b/ui/src/pages/SLAcontainer.svelte new file mode 100644 index 000000000..e818437a7 --- /dev/null +++ b/ui/src/pages/SLAcontainer.svelte @@ -0,0 +1,18 @@ + + +
+
+ +
+
\ No newline at end of file diff --git a/ui/src/pages/alerts.js b/ui/src/pages/alerts.js index e7f7c7926..7db61c7b8 100644 --- a/ui/src/pages/alerts.js +++ b/ui/src/pages/alerts.js @@ -1037,6 +1037,14 @@ function renderAlert(alert, expanded=false, modulesOptionsAlertReq, ` : ''}
+ +

SLA

+
+
+
+ +
+

Alert note

${alert.alert_note}
@@ -1307,6 +1315,7 @@ async function refreshAlert(alertId, alertData, expanded=false) { } alertData = alertDataReq.data; } + const SLAdata = await fetchSLAdata(); if (modulesOptionsAlertReq === null) { modulesOptionsAlertReq = await fetchModulesOptionsAlert(); @@ -1324,8 +1333,47 @@ async function refreshAlert(alertId, alertData, expanded=false) { const alertElement = $(`#alertCard-${alertId}`); const alertHtml = renderAlert(alertData, expanded, modulesOptionsAlertReq.data, modulesOptionsIocReq.data); alertElement.replaceWith(alertHtml); + + //const SLAelement = $(`#SLAelement`).text(); + console.log("SLA ELEMENT IS HERE! "); + console.log(alertData.alert_customer_id); + //document.dispatchEvent(new CustomEvent('alertRendered', { detail: { IRIStime: alertData.alert_creation_time, alertStatusID: alertData.alert_status_id }})); + + document.dispatchEvent(new CustomEvent('alertRendered', { + detail: { + IRIStime: alertData.alert_creation_time, + alertStatusID: alertData.alert_status_id, + alertSevID: alertData.severity.severity_id, + alertCustomerID: alertData.alert_customer_id, + SLA: SLAdata, + alertID: alertData.alert_id + } + })); } +async function fetchSLAdata() { + + try { + const response = await fetch('alerts/api/get_clients_sla_api'); + const data = await response.json(); + + // Declare the variable properly + const customersSla = data.data.customers_sla; + console.log('Customers SLA:', customersSla); + + // Convert the entire array to a single JSON string + const jsonString = JSON.stringify(customersSla); + console.log("JSON string:", jsonString); + + return jsonString; + } catch (error) { + console.error('Error fetching data:', error); + throw error; // Optionally re-throw the error after logging it + } + + } + + async function fetchModulesOptionsAlert() { const response = get_request_api('/dim/hooks/options/alert/list'); @@ -1379,6 +1427,10 @@ async function updateAlerts(page, per_page, filters = {}, paging=false){ } } + + const SLAdata = await fetchSLAdata(); + + // Check if the selection mode is active const selectionModeActive = $('body').hasClass('selection-mode'); selectionModeActive ? $('body').removeClass('selection-mode') : ''; @@ -1405,6 +1457,19 @@ async function updateAlerts(page, per_page, filters = {}, paging=false){ modulesOptionsIocReq.data); alertElement.html(alertHtml); alertsContainer.append(alertElement); + console.log(alert); + const jsonString = ""; + + document.dispatchEvent(new CustomEvent('alertRendered', { + detail: { + IRIStime: alert.alert_creation_time, + alertStatusID: alert.alert_status_id, + alertSevID: alert.severity.severity_id, + alertCustomerID: alert.alert_customer_id, + SLA: SLAdata, + alertID: alert.alert_id + } + })); }); } diff --git a/ui/src/pages/persistentStore.js b/ui/src/pages/persistentStore.js new file mode 100644 index 000000000..41c85483d --- /dev/null +++ b/ui/src/pages/persistentStore.js @@ -0,0 +1,15 @@ +import { writable } from 'svelte/store'; + +export function createPersistentStore(key, initialValue) { + // Try to read from localStorage; if none exists, use the initial value + const storedValue = localStorage.getItem(key); + const data = storedValue ? JSON.parse(storedValue) : initialValue; + const store = writable(data); + + // Subscribe to store changes and write to localStorage + store.subscribe(value => { + localStorage.setItem(key, JSON.stringify(value)); + }); + + return store; +}