Merged PR 165: Update dashboard

This commit is contained in:
2025-06-12 15:58:32 +00:00
2 changed files with 89 additions and 83 deletions

View File

@@ -12,18 +12,18 @@
<div class="filter-section flex justify-start gap-4 items-end">
<div class="filter-item">
<label class="filter-label">Date Range:</label>
<Calendar v-model="dateRange" selectionMode="range" placeholder="Date Range" />
<Calendar v-model="dateRange" selectionMode="range" placeholder="Select a Date Range" />
</div>
<!-- Dropdown account -->
<div class="filter-item">
<label class="filter-label">Account:</label>
<Dropdown v-model="selectedAccount" :options="uniqueAccounts" optionLabel="name" optionValue="id" placeholder="All Accounts" class="w-full md:w-20rem" />
<Dropdown v-model="selectedAccount" :options="uniqueAccounts" optionLabel="name" optionValue="id" placeholder="Select an Account" class="w-full md:w-20rem" />
</div>
<!-- MultiSelect progetti -->
<div class="filter-item">
<label class="filter-label">Project:</label>
<MultiSelect v-model="selectedProjects" :options="filteredProjects" optionLabel="fe_name" optionValue="id" display="chip" placeholder="All Projects" :maxSelectedLabels="3" class="w-full" style="min-width: 100px" />
<MultiSelect v-model="selectedProjects" :options="filteredProjects" optionLabel="fe_name" optionValue="id" display="chip" placeholder="Select Projects" :maxSelectedLabels="3" class="w-full" style="min-width: 100px" />
</div>
<!-- MultiSelect applicazione -->
@@ -65,7 +65,7 @@
<!-- MultiSelect scenarios -->
<div class="filter-item">
<label class="filter-label">Scenario:</label>
<MultiSelect v-model="selectedScenarios" :options="scenarioOptions" optionLabel="name" optionValue="id" display="chip" placeholder="All Scenarios" :maxSelectedLabels="3" class="w-full" style="min-width: 100px" />
<MultiSelect v-model="selectedScenarios" :options="scenarioOptions" optionLabel="name" optionValue="id" display="chip" placeholder="Select Scenarios" :maxSelectedLabels="3" class="w-full" style="min-width: 100px" />
</div>
<!-- <div class=" apply-button-container">
@@ -443,17 +443,6 @@ const uniqueAccounts = computed(() => {
return accounts.map((acc) => ({ name: acc, id: acc })); // usa anche `id` se serve per la picklist
});
// Filter progetti per account selezionato
// const filteredProjects = computed(() => {
// if (!projectOptions.value) return []
// let filteredList = projectOptions.value
// if (selectedAccount.value) {
// filteredList = filteredList.filter(p => p.account === selectedAccount.value.name)
// }
// return filteredList;
// })
const onPage = (event) => {
currentPageExecutions.value = event.page + 1;
@@ -533,9 +522,20 @@ const exportAggregations = () => {
document.body.removeChild(link);
};
// const exportChats = () => {
// if (chatTable.value) chatTable.value.exportCSV()
// }
const formatLocalDate = (date) => {
if (!date) return null;
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
const formatLocalDateTo = (date) => {
if (!date) return null;
const nextDay = new Date(date);
nextDay.setDate(nextDay.getDate() + 1);
return formatLocalDate(nextDay);
};
// Caricamento dati con filtri
const loadData = async () => {
@@ -543,8 +543,8 @@ const loadData = async () => {
try {
const filterParams = {
// Date
dateFrom: dateRange.value?.[0] ? dateRange.value[0].toISOString().split('T')[0] : null,
dateTo: dateRange.value?.[1] ? dateRange.value[1].toISOString().split('T')[0] : null,
dateFrom: formatLocalDate(dateRange.value?.[0]),
dateTo: null ? formatLocalDateTo(dateRange.value?.[0]):formatLocalDateTo(dateRange.value?.[1]),
account: selectedAccount.value || null,
@@ -554,37 +554,10 @@ const loadData = async () => {
? selectedProjects.value
.map((id) => {
const project = projectOptions.value.find((p) => p.id === id);
return project ? project.fe_name : null;
return project ? project.internal_name : null;
})
.filter(Boolean)
: [],
// // Applicazioni
// applicationIds: selectedApplications.value.length
// ? selectedApplications.value.map(id => String(id))
// : [],
// applicationNames: selectedApplications.value.length
// ? selectedApplications.value
// .map(id => {
// const app = appOptions.value.find(a => a.id === id)
// return app ? app.fe_name : null
// })
// .filter(Boolean)
// : [],
// // Utenti
// userIds: selectedUsers.value.length
// ? selectedUsers.value.map(id => String(id))
// : [],
// userNames: selectedUsers.value.length
// ? selectedUsers.value
// .map(id => {
// const user = userOptions.value.find(u => u.id === id)
// return user ? user.username : null
// })
// .filter(Boolean)
// : [],
// Scenari
scenarioIds: selectedScenarios.value.length ? selectedScenarios.value.map((id) => String(id)) : [],
scenarioNames: selectedScenarios.value.length
@@ -600,14 +573,14 @@ const loadData = async () => {
console.log('Filter parameters:', filterParams);
const chatParams = {
dateFrom: dateRange.value?.[0] ? dateRange.value[0].toISOString().split('T')[0] : null,
dateTo: dateRange.value?.[1] ? dateRange.value[1].toISOString().split('T')[0] : null,
dateFrom: formatLocalDate(dateRange.value?.[0]),
dateTo: null ? formatLocalDateTo(dateRange.value?.[0]):formatLocalDateTo(dateRange.value?.[1]),
projectIds: selectedProjects.value.length ? selectedProjects.value.map((id) => String(id)) : [],
projectNames: selectedProjects.value.length
? selectedProjects.value
.map((id) => {
const project = projectOptions.value.find((p) => p.id === id);
return project ? project.fe_name : null;
return project ? project.internal_name : null;
})
.filter(Boolean)
: [],
@@ -681,7 +654,10 @@ const onApplyFilters = async () => {
// Funzione per cancellare filtri
const onClearFilters = () => {
dateRange.value = null;
const today = new Date();
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(today.getDate() - 7);
dateRange.value = [sevenDaysAgo, today];
selectedAccount.value = null;
selectedProjects.value = [];
selectedApplications.value = [];
@@ -703,7 +679,7 @@ onMounted(async () => {
const lstProjects = userPrefStore.user?.lstProjects || [];
console.log('Projects loaded:', lstProjects);
projectOptions.value = lstProjects.filter((p) => p.fe_name).map((p) => ({ ...p }));
projectOptions.value = lstProjects.filter((p) => p.fe_name || p.internal_name).map((p) => ({ ...p, internal_name: p.internal_name || p.fe_name }));
selectedProjects.value = [];
// Popola appOptions in base alle applicazioni nei progetti

View File

@@ -12,12 +12,13 @@ const visible = ref(false);
onMounted(async () => {
console.log('[Callback] Mounted on callback');
try {
await msalInstance.initialize();
console.log('[Callback] After initialize on callback');
} catch (e) {
console.error('[Callback] Errore durante initialize MSAL:', e);
message.value = "Errore durante l'inizializzazione di MSAL.";
console.error('[Callback] Error during MSAL initialization:', e);
message.value = "Error during MSAL initialization.";
visible.value = true;
return;
}
@@ -27,66 +28,95 @@ onMounted(async () => {
response = await msalInstance.handleRedirectPromise();
console.log('[Callback] handleRedirectPromise response:', response);
} catch (e) {
console.error('[Callback] Errore in handleRedirectPromise:', e);
message.value = 'Errore durante la gestione del redirect.';
console.error('[Callback] Error in handleRedirectPromise:', e);
message.value = 'Error handling the redirect.';
visible.value = true;
return;
}
if (response && response.accessToken) {
console.log('[Callback] Access token present:', response.accessToken);
if (!response.account) {
console.warn('[Callback] No account present in the response. Possible MSAL anomaly.');
} else {
console.log('[Callback] Account info:', response.account);
localStorage.setItem('msalUser', JSON.stringify(response.account));
}
// Wait 1 second to avoid race condition
await new Promise(resolve => setTimeout(resolve, 1000));
message.value = 'Logging in to the application...';
console.log('[Callback] AccessToken presente:', response.accessToken);
console.log('[Callback] Account info:', response.account);
localStorage.setItem('msalUser', JSON.stringify(response.account));
try {
console.log('[Callback] Chiamata a /msauth/exchange con accessToken...');
const res = await axios.post(
'/msauth/exchange',
{},
{
headers: { Authorization: `Bearer ${response.accessToken}` }
// Token exchange function with retry
const tryTokenExchange = async (retry = false) => {
try {
console.log(`[Callback] Call to /msauth/exchange (retry=${retry})...`);
const res = await axios.post(
'/msauth/exchange',
{},
{
headers: { Authorization: `Bearer ${response.accessToken}` }
}
);
return res;
} catch (err) {
if (!retry) {
console.warn('[Callback] First attempt failed, waiting 1500ms and retrying...');
await new Promise(resolve => setTimeout(resolve, 1500));
return tryTokenExchange(true);
} else {
throw err;
}
);
console.log('[Callback] Risposta da /msauth/exchange:', res);
}
};
let exchangeResponse;
try {
exchangeResponse = await tryTokenExchange();
console.log('[Callback] Response from /msauth/exchange:', exchangeResponse);
if (exchangeResponse.data.token) {
console.log('[Callback] Backend token received:', exchangeResponse.data.token);
auth.token(null, exchangeResponse.data.token, false);
if (res.data.token) {
console.log('[Callback] Token backend ricevuto:', res.data.token);
auth.token(null, res.data.token, false);
try {
console.log('[Callback] Chiamata a auth.fetch()...');
console.log('[Callback] Calling auth.fetch()...');
const userResponse = await auth.fetch();
console.log('[Callback] Risposta user fetch:', userResponse);
console.log('[Callback] userResponse.data:', userResponse.data);
console.log('[Callback] userResponse.data.data:', userResponse.data.data);
console.log('[Callback] User fetch response:', userResponse);
if (!userResponse.data.data.selectedProject) {
console.log('[Callback] Nessun progetto selezionato, redirect a projects-list');
const userData = userResponse.data?.data;
console.log('[Callback] userResponse.data.data:', userData);
if (!userData || !userData.selectedProject) {
console.log('[Callback] No project selected, redirecting to projects-list');
router.push({ name: 'projects-list' });
} else {
console.log('[Callback] Progetto selezionato, redirect a scenario-list');
console.log('[Callback] Project selected, redirecting to scenario-list');
router.push({ name: 'scenario-list' });
}
} catch (fetchErr) {
console.error('[Callback] Errore su fetch user dopo token exchange:', fetchErr);
console.error('[Callback] Error fetching user after token exchange:', fetchErr);
message.value = 'User not configured for this application. Contact the administrator for details.';
visible.value = true;
}
} else {
console.error('[Callback] No token received from backend:', exchangeResponse.data);
message.value = 'User not configured for this application. Contact the administrator for details.';
console.error('[Callback] Nessun token ricevuto dal backend:', res.data);
visible.value = true;
}
} catch (error) {
console.error('[Callback] Error on token exchange:', error.response ? error.response.data : error);
console.error('[Callback] Error on token exchange (after retry):', error.response ? error.response.data : error);
message.value = 'An error occurred during the token exchange. Please try again.';
visible.value = true;
}
} else {
console.error('[Callback] Invalid response o access token mancante:', response);
console.error('[Callback] Invalid response or missing access token:', response);
message.value = 'Authentication failed. Please log in again.';
visible.value = true;
}
});
</script>
<template>