Merged PR 165: Update dashboard
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,20 +28,30 @@ 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) {
|
||||
message.value = 'Logging in to the application...';
|
||||
console.log('[Callback] AccessToken presente:', 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...';
|
||||
|
||||
// Token exchange function with retry
|
||||
const tryTokenExchange = async (retry = false) => {
|
||||
try {
|
||||
console.log('[Callback] Chiamata a /msauth/exchange con accessToken...');
|
||||
console.log(`[Callback] Call to /msauth/exchange (retry=${retry})...`);
|
||||
const res = await axios.post(
|
||||
'/msauth/exchange',
|
||||
{},
|
||||
@@ -48,45 +59,64 @@ onMounted(async () => {
|
||||
headers: { Authorization: `Bearer ${response.accessToken}` }
|
||||
}
|
||||
);
|
||||
console.log('[Callback] Risposta da /msauth/exchange:', res);
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (res.data.token) {
|
||||
console.log('[Callback] Token backend ricevuto:', res.data.token);
|
||||
auth.token(null, res.data.token, false);
|
||||
let exchangeResponse;
|
||||
try {
|
||||
console.log('[Callback] Chiamata a 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);
|
||||
exchangeResponse = await tryTokenExchange();
|
||||
console.log('[Callback] Response from /msauth/exchange:', exchangeResponse);
|
||||
|
||||
if (!userResponse.data.data.selectedProject) {
|
||||
console.log('[Callback] Nessun progetto selezionato, redirect a projects-list');
|
||||
if (exchangeResponse.data.token) {
|
||||
console.log('[Callback] Backend token received:', exchangeResponse.data.token);
|
||||
auth.token(null, exchangeResponse.data.token, false);
|
||||
|
||||
try {
|
||||
console.log('[Callback] Calling auth.fetch()...');
|
||||
const userResponse = await auth.fetch();
|
||||
console.log('[Callback] User fetch response:', userResponse);
|
||||
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user