361 lines
14 KiB
Vue
361 lines
14 KiB
Vue
<template>
|
|
<div v-if="loading" class="flex justify-center">
|
|
<ProgressSpinner style="width: 50px; height: 50px; margin-top: 50px" strokeWidth="3" fill="transparent"/>
|
|
</div>
|
|
<div v-else >
|
|
|
|
<h2 class="text-xl font-bold mt-6">Executions List</h2>
|
|
|
|
<DataTable v-model:filters="filters" v-model:expandedRows="expandedRows" @rowExpand="onRowExpand"
|
|
@rowCollapse="onRowCollapse" :value="scenario_execution_store.scenariosExecution"
|
|
:loading="loading_data"
|
|
:paginator="true"
|
|
:lazy="true"
|
|
:rows="scenario_execution_store.getPageSize"
|
|
:first="scenario_execution_store.getCurrentPage * scenario_execution_store.getPageSize"
|
|
:totalRecords="scenario_execution_store.getTotalRecords"
|
|
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
|
|
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} records"
|
|
:rowsPerPageOptions="[10, 15, 20, 50, 100]" dataKey="id" :rowHover="true" rowGroupMode="subheader"
|
|
:sortOrder="1" filterDisplay="menu"
|
|
tableStyle="min-width: 70rem"
|
|
@page="onPage"
|
|
@sort="onSort"
|
|
removableSort>
|
|
|
|
|
|
<template #header>
|
|
<div class="flex justify-end">
|
|
|
|
<IconField>
|
|
<Button label="Clear Filters" @click="clearFilters" class="mr-2" />
|
|
<InputIcon>
|
|
<i class="pi pi-search" />
|
|
</InputIcon>
|
|
<InputText v-model="filters['_id'].constraints[0].value" placeholder="ID" />
|
|
<Button label="Apply" @click="fetchData(0, 10)" />
|
|
|
|
|
|
</IconField>
|
|
</div>
|
|
</template>
|
|
|
|
|
|
<Column field="scenario.name" header="Scenario Name" sortable :showFilterOperator="false" :showApplyButton="false" :showAddButton="false" :showClearButton="false"
|
|
style="min-width: 12rem" >
|
|
<template #body="slotProps">
|
|
<div class="flex items-center gap-2">
|
|
{{ slotProps.data.scenario?.name }}
|
|
<i
|
|
class="pi pi-info-circle text-violet-600 cursor-pointer"
|
|
v-tooltip="slotProps.data?.scenario?.description || 'No description available'"
|
|
></i>
|
|
<!-- controllare il tooltip -->
|
|
</div>
|
|
</template>
|
|
<template #filter="{ filterModel, filterCallback }">
|
|
<InputText v-model="filterModel.value" type="text" placeholder="Search by ScenarioName" />
|
|
<Button label="Apply" @click="fetchDataWithFilters(filterCallback)" />
|
|
</template>
|
|
|
|
</Column>
|
|
|
|
<Column field="execSharedMap.user_input.selected_application" header="Application Input" sortable :showFilterOperator="false" :showApplyButton="false" :showAddButton="false" :showClearButton="false"
|
|
style="min-width: 12rem">
|
|
<template #body="slotProps">
|
|
<div class="flex items-center gap-2">
|
|
{{ slotProps.data.execSharedMap?.user_input?.selected_application }}
|
|
</div>
|
|
</template>
|
|
<template #filter="{ filterModel, filterCallback }">
|
|
<InputText v-model="filterModel.value" type="text"
|
|
placeholder="Search by Application" />
|
|
<Button label="Apply" @click="fetchDataWithFilters(filterCallback)" />
|
|
|
|
</template>
|
|
</Column>
|
|
<!-- <Column field="startDate"
|
|
filterField="startDate" header="Start Date" sortable
|
|
style="min-width: 12rem">
|
|
<template #body="slotProps">
|
|
<div class="flex items-center gap-2">
|
|
{{ moment(slotProps.data.startDate).format('DD-MM-YYYY HH:mm:ss') }}
|
|
</div>
|
|
</template>
|
|
<template #filter="{ filterModel, filterCallback }">
|
|
<Calendar
|
|
v-model="filterModel.value"
|
|
@input="(value) => {
|
|
filterModel.value = new Date(value); // Converte in oggetto Date
|
|
filterCallback();
|
|
}"
|
|
dateFormat="yy-mm-dd"
|
|
placeholder="Filter by Date"
|
|
/>
|
|
</template>
|
|
</Column> -->
|
|
<Column field="startDate" header="Start Date" filterField="startDate" dataType="date" style="min-width: 10rem" sortable>
|
|
<template #body="slotProps">
|
|
{{ moment(slotProps.data.startDate).format('DD-MM-YYYY HH:mm:ss') }}
|
|
</template>
|
|
<!-- <template #filter="{ filterModel, filterCallback }">
|
|
<DatePicker v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" />
|
|
<Button label="Apply" @click="fetchDataWithFilters(filterCallback)" />
|
|
</template> -->
|
|
</Column>
|
|
|
|
<Column field="scenario.aiModel.model" header="Model AI"
|
|
style="min-width: 12rem">
|
|
<template #body="slotProps">
|
|
<div class="flex items-center gap-2">
|
|
{{ slotProps.data.scenario?.aiModel?.model }}
|
|
<i
|
|
class="pi pi-info-circle text-violet-600 cursor-pointer"
|
|
v-tooltip="'Provider: ' + slotProps.data?.scenario?.aiModel?.apiProvider + ' Token used: ' + slotProps.data?.usedTokens || 'No description available'"
|
|
></i>
|
|
</div>
|
|
</template>
|
|
<!-- <template #filter="{ filterModel, filterCallback }">
|
|
<InputText v-model="filterModel.value" type="text"
|
|
placeholder="Search by Model" />
|
|
<Button label="Apply" @click="fetchDataWithFilters(filterCallback)" />
|
|
|
|
</template> -->
|
|
</Column>
|
|
<Column field="executedByUsername" header="Executed By" sortable
|
|
style="min-width: 12rem" :showApplyButton="false" :showFilterOperator="false" :showAddButton="false" :showClearButton="false">
|
|
<template #body="slotProps">
|
|
<div class="flex items-center gap-2">
|
|
{{ slotProps.data.executedByUsername || 'N/A' }}
|
|
</div>
|
|
</template>
|
|
<template #filter="{ filterModel, filterCallback }">
|
|
<InputText v-model="filterModel.value" type="text"
|
|
placeholder="Search by Username" />
|
|
<Button label="Apply" @click="fetchDataWithFilters(filterCallback)" />
|
|
|
|
</template>
|
|
</Column>
|
|
<Column field="rating" header="Rating" sortable :showApplyButton="false" :showFilterMatchModes="false" :showFilterOperator="false" :showAddButton="false" :showClearButton="false">
|
|
<template #body="slotProps">
|
|
<Rating :modelValue="slotProps.data.rating" :stars="5" :readonly="true" />
|
|
</template>
|
|
<template #filter="{ filterModel, filterCallback }">
|
|
<InputText v-model="filterModel.value" type="text" placeholder="Search (1,2,3,4,5)" />
|
|
<Button label="Apply" @click="fetchDataWithFilters(filterCallback)" />
|
|
</template>
|
|
</Column>
|
|
<Column field="id" :style="{ position: 'sticky', right: '0', zIndex: '1', background: '#f3f3f3'}">
|
|
<template #body="slotProps">
|
|
<div class="flex justify-center items-center h-full">
|
|
<Button label="View" @click="goToScenarioExec(slotProps.data)" class="mt-0 ml-0" />
|
|
</div>
|
|
</template>
|
|
</Column>
|
|
|
|
<template #empty>
|
|
<tr>
|
|
<td :colspan="9" class="text-center">No execution found</td>
|
|
</tr>
|
|
</template>
|
|
</DataTable>
|
|
</div>
|
|
|
|
<div v-if="loading_data" class="flex justify-center">
|
|
<ProgressSpinner style="width: 30px; height: 30px; margin: 30px" strokeWidth="6" fill="transparent"/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
|
|
import { FilterMatchMode, FilterOperator } from '@primevue/core/api';
|
|
import 'md-editor-v3/lib/style.css';
|
|
import moment from 'moment';
|
|
import ProgressSpinner from 'primevue/progressspinner';
|
|
import { useToast } from 'primevue/usetoast';
|
|
import { onMounted, ref, watch } from 'vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { ScenarioExecutionStore } from '../../stores/ScenarioExecutionStore.js';
|
|
import { UserPrefStore } from '../../stores/UserPrefStore.js';
|
|
|
|
const first = ref(0);
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const value = ref('');
|
|
const scenario = ref({});
|
|
const scenario_output = ref(null);
|
|
const loading = ref(false);
|
|
const data_loaded = ref(false);
|
|
const loading_data = ref(false);
|
|
const formData = ref({});
|
|
const exec_id = ref(null);
|
|
const exec_scenario = ref({});
|
|
const debug_modal = ref(false);
|
|
const execution_id = ref("");
|
|
const listScenarios = ref([]);
|
|
const scenario_execution_store = ScenarioExecutionStore();
|
|
const toast = useToast();
|
|
const userPrefStore = UserPrefStore();
|
|
const records = ref(788);
|
|
const actualPage = ref(0);
|
|
const actualPageSize = ref(10);
|
|
const sortField = ref(null);
|
|
const sortOrder = ref(null);
|
|
|
|
|
|
|
|
|
|
const filters = ref({
|
|
'_id': { operator: FilterOperator.AND,
|
|
constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }]
|
|
},
|
|
'scenario.name': {
|
|
operator: FilterOperator.AND,
|
|
constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }]
|
|
},
|
|
'execSharedMap.user_input.selected_application': {
|
|
operator: FilterOperator.AND,
|
|
constraints: [{
|
|
value: userPrefStore.getSelApp?.fe_name || null, matchMode: FilterMatchMode.CONTAINS
|
|
}]
|
|
},
|
|
'scenario.aiModel.model': {
|
|
operator: FilterOperator.AND,
|
|
constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }]
|
|
},
|
|
|
|
'executedByUsername': {
|
|
operator: FilterOperator.AND,
|
|
constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }]
|
|
},
|
|
|
|
'startDate': {
|
|
operator: FilterOperator.AND,
|
|
constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }]
|
|
},
|
|
|
|
'rating': {
|
|
operator: FilterOperator.AND,
|
|
constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }]
|
|
}
|
|
|
|
});
|
|
|
|
onMounted(() => {
|
|
updateFilters();
|
|
});
|
|
watch(() => route.params.name, updateFilters);
|
|
// watch([() => filters.value], () => {
|
|
// scenario_execution_store.updateFilters(filters.value); // Applica i filtri e carica i dati
|
|
// });
|
|
|
|
// watch([() => filters.value, () => first.value], () => {
|
|
// fetchData(Math.floor(first.value / scenario_execution_store.getPageSize), scenario_execution_store.getPageSize, filters.value);
|
|
// });
|
|
|
|
|
|
|
|
function updateFilters() {
|
|
const selectedScenario = userPrefStore.getSelScenario;
|
|
|
|
if (selectedScenario && route.params.name!=='all') {
|
|
console.log('selectedScenario: im in');
|
|
filters.value['scenario.name'].constraints[0].value = selectedScenario;
|
|
|
|
}else{
|
|
filters.value['scenario.name'].constraints[0].value = null;
|
|
}
|
|
fetchData(0, 10);
|
|
}
|
|
|
|
function fetchDataWithFilters(filterCallback) {
|
|
filterCallback();
|
|
fetchData(0, actualPageSize.value);
|
|
}
|
|
|
|
function onSort(event) {
|
|
console.log('Sorting event:', event);
|
|
|
|
sortField.value = event.sortField;
|
|
sortOrder.value = event.sortOrder;
|
|
|
|
fetchData(0,actualPageSize.value);
|
|
}
|
|
|
|
const fetchData = async (page, size) => {
|
|
loading_data.value = true;
|
|
|
|
try {
|
|
scenario_execution_store.fetchScenariosExecution(page, size, filters.value, sortField.value, sortOrder.value);
|
|
//const response = await ScenarioService.getScenarioExecutionList(page, size, filtersForRequest);
|
|
// aggiorna il store con i risultati della query
|
|
} catch (error) {
|
|
console.error('Error fetching data', error);
|
|
} finally {
|
|
loading_data.value = false;
|
|
}
|
|
};
|
|
|
|
function clearFilters() {
|
|
filters.value = {
|
|
'_id': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }] },
|
|
'scenario.name': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }] },
|
|
'execSharedMap.user_input.selected_application': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }] },
|
|
'scenario.aiModel.model': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }] },
|
|
'executedByUsername': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.CONTAINS }] },
|
|
'startDate': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] }
|
|
};
|
|
fetchData(0, actualPageSize.value);
|
|
}
|
|
|
|
const goToScenarioExec = (execScenarioItem) => {
|
|
console.log(execScenarioItem);
|
|
|
|
router.push({ name: 'scenario-exec-history', query: { id:execScenarioItem.id } });
|
|
|
|
// scenario_execution_store.setSelectedExecScenario(execScenarioItem).then(() => {
|
|
// router.push({ name: 'scenario-exec-history', query: { id:execScenarioItem.id } });
|
|
// });
|
|
};
|
|
|
|
function onPage(event) {
|
|
actualPage.value = event.page;
|
|
actualPageSize.value = event.rows;
|
|
fetchData(event.page, event.rows);
|
|
console.log('event onpage:', event);
|
|
//updateFilters();
|
|
}
|
|
// function onPage(event) {
|
|
// first.value = event.first; // Imposta la pagina corrente
|
|
// fetchData(Math.floor(first.value / scenario_execution_store.getPageSize), scenario_execution_store.getPageSize);
|
|
// }
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
.input-container {
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
.input-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5em;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.full-width-input {
|
|
width: 100%;
|
|
}
|
|
|
|
|
|
.editor ol {
|
|
list-style-type: decimal !important;
|
|
}
|
|
|
|
.editor ul {
|
|
list-style-type: disc !important;
|
|
}
|
|
|
|
|
|
</style> |