Create document picklist and refactor axios call

This commit is contained in:
2025-11-05 16:34:22 +01:00
parent 738f627f1f
commit b1c70c5fbf
7 changed files with 662 additions and 155 deletions

View File

@@ -148,12 +148,18 @@
</div>
</div>
<div v-else-if="input.type === 'multiselect'" class="mt-4">
<label :for="input.name">
<b>{{ input.label }}</b>
</label>
<div class="input-wrapper">
<MultiSelect v-model="formData[input.name]" :options="videoGroups" optionLabel="name" filter placeholder="Select VideoGroups" class="w-full md:w-80" />
</div>
<DynamicPicker
v-model="formData[input.name]"
:input-name="input.name"
:label="input.label"
:data-source="input.dataSource || 'videoGroups'"
:options="getOptionsForInput(input)"
:disabled="loadingStore.exectuion_loading"
:loading="loadingOptionsFor[input.dataSource] || false"
:show-status="input.dataSource === 'ksDocuments'"
no-margin
@change="onDynamicPickerChange(input.name, $event)"
/>
</div>
<div v-else>
<label :for="input.name"
@@ -276,11 +282,14 @@
<script setup>
import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue';
import ChatClient from '@/components/ChatClient.vue';
import DynamicPicker from '@/components/DynamicPicker.vue';
import { KSDocumentService } from '@/service/KSDocumentService';
import { FileUploadStore } from '@/stores/FileUploadStore';
import { KsVideoGroupStore } from '@/stores/KsVideoGroupStore';
import { LoadingStore } from '@/stores/LoadingStore';
import { ScenarioExecutionStore } from '@/stores/ScenarioExecutionStore';
import { UserPrefStore } from '@/stores/UserPrefStore';
import { useAuth } from '@websanova/vue-auth/src/v3.js';
import axios from 'axios';
import JsonEditorVue from 'json-editor-vue';
import JSZip from 'jszip';
import { marked } from 'marked';
@@ -294,12 +303,14 @@ import Select from 'primevue/select';
import Textarea from 'primevue/textarea';
import { useConfirm } from 'primevue/useconfirm';
import { useToast } from 'primevue/usetoast';
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { JellyfishLoader } from 'vue3-spinner';
import { ScenarioService } from '../../service/ScenarioService';
const loadingStore = LoadingStore();
const scenarioExecutionStore = ScenarioExecutionStore();
const fileUploadStore = FileUploadStore();
const toast = useToast();
const zip = ref(null);
const route = useRoute();
@@ -316,6 +327,8 @@ const formData = ref({});
const exec_id = ref(null);
const exec_scenario = ref({});
const debug_modal = ref(false);
const loadingOptionsFor = reactive({});
const ksDocuments = ref([]);
let pollingInterval = null;
const folderName = ref('');
const fileNamesOutput = ref([]);
@@ -368,13 +381,20 @@ const isInputFilled = computed(() => {
return false;
}
scenario.value.inputs.forEach((input) => {
if (formData.value[input.name] === undefined || formData.value[input.name] === '') {
console.log('Input not filled: ', input.name);
isFilled = false;
} else {
const processedData = { ...formData.value };
if (processedData.input_multiselect) {
processedData.input_multiselect = JSON.stringify(processedData.input_multiselect.map((item) => item.id));
const inputValue = formData.value[input.name];
// Controllo per input multiselect
if (input.type === 'multiselect') {
if (!inputValue || !Array.isArray(inputValue) || inputValue.length === 0) {
console.log('Multiselect input not filled: ', input.name);
isFilled = false;
}
}
// Controllo per altri tipi di input
else {
if (inputValue === undefined || inputValue === '') {
console.log('Input not filled: ', input.name);
isFilled = false;
}
}
});
@@ -388,10 +408,8 @@ onBeforeUnmount(() => {
onMounted(() => {
fetchScenario(route.params.id);
loadVideoGroups();
const timestamp = Date.now(); // Ottiene il timestamp corrente
const randomNumber = Math.floor(Math.random() * 1000);
folderName.value = `${timestamp}_${randomNumber}`;
const newFolderName = fileUploadStore.generateUniqueFolderId();
folderName.value = newFolderName;
uploadUrl.value = uploadUrlBase + '/uploadListFiles/' + folderName.value;
uploadUrlPR.value = uploadUrl.value + '/PR';
uploadUrlOther.value = uploadUrl.value + '/OTHER';
@@ -410,37 +428,38 @@ const loadVideoGroups = async () => {
watch(() => route.params.id, fetchScenario);
//Function to fetch scenarios
function fetchScenario(id) {
async function fetchScenario(id) {
chatDisabled();
scenario.value.inputs = null;
data_loaded.value = false;
formData.value = {};
loading.value = true;
axios
.get(`/scenarios/${id}`)
.then((response) => {
scenario.value = response.data;
console.log('Scenario fetched:', scenario.value);
if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload' || input.name === 'SingleFileUpload')) {
reqMultiFile.value = true;
}
if (scenario.value.inputs.some((input) => input.type === 'singlefile_acceptall')) {
reqMultiFile.value = false;
acceptedFormats.value = '';
//acceptedFormats.value = '.doc,.docx,.pdf,.msg,.txt,.xlx,.xlxs,.logs,.pptx,.json,.odt,.rtf,.xml,.html';
}
if (scenario.value.inputs.some((input) => input.type === 'singlefile')) {
reqMultiFile.value = false;
acceptedFormats.value = '.docx';
}
})
.catch((error) => {
console.error('Error fetching scenario:', error);
})
.finally(() => {
loading.value = false;
});
try {
const response = await scenarioExecutionStore.fetchScenario(id);
scenario.value = response;
console.log('Scenario fetched:', scenario.value);
// Carica le opzioni necessarie basate sui dataSource presenti negli inputs
await loadOptionsForScenario();
if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload' || input.name === 'SingleFileUpload')) {
reqMultiFile.value = true;
}
if (scenario.value.inputs.some((input) => input.type === 'singlefile_acceptall')) {
reqMultiFile.value = false;
acceptedFormats.value = '';
//acceptedFormats.value = '.doc,.docx,.pdf,.msg,.txt,.xlx,.xlxs,.logs,.pptx,.json,.odt,.rtf,.xml,.html';
}
if (scenario.value.inputs.some((input) => input.type === 'singlefile')) {
reqMultiFile.value = false;
acceptedFormats.value = '.docx';
}
} catch (error) {
console.error('Error fetching scenario:', error);
} finally {
loading.value = false;
}
}
const onBeforeSend = (event) => {
@@ -473,7 +492,7 @@ const chatDisabled = () => {
chat_enabled.value = false;
};
const execScenario = () => {
const execScenario = async () => {
if (numberPrFiles.value !== 1 && reqMultiFile.value) {
toast.add({
severity: 'warn', // Tipo di notifica (errore)
@@ -490,10 +509,23 @@ const execScenario = () => {
// Crea una copia dei dati del form
const processedData = { ...formData.value };
if (processedData.input_multiselect) {
processedData.input_multiselect_id = JSON.stringify(processedData.input_multiselect.map((item) => item.id));
processedData.input_multiselect_name = JSON.stringify(processedData.input_multiselect.map((item) => item.name));
delete processedData.input_multiselect;
// Elabora tutti i multiselect dinamici
if (scenario.value.inputs) {
scenario.value.inputs.forEach((input) => {
if (input.type === 'multiselect' && processedData[input.name]) {
const selectedItems = processedData[input.name];
if (Array.isArray(selectedItems) && selectedItems.length > 0) {
// Elaborazione per VideoGroups (backward compatibility)
processedData[`${input.name}_id`] = JSON.stringify(selectedItems.map((item) => item.id || item));
processedData[`${input.name}_name`] = JSON.stringify(selectedItems.map((item) => item.name || item.fileName || item));
// Rimuovi l'array originale
delete processedData[input.name];
}
}
});
}
const data = {
@@ -501,55 +533,58 @@ const execScenario = () => {
inputs: processedData
};
axios
.post('/scenarios/execute-async', data)
.then((response) => {
console.log('Response data exec 1:', response.data);
scenario_response.value = response.data;
scenario_response_message.value = response.data.message;
scenario_output.value = response.data.stringOutput;
exec_id.value = response.data.scenarioExecution_id;
loadingStore.setIdExecLoading(exec_id.value);
startPolling();
})
.catch((error) => {
console.error('Error executing scenario:', error);
loadingStore.exectuion_loading = false;
});
try {
const response = await scenarioExecutionStore.executeScenario(data);
console.log('Response data exec 1:', response);
scenario_response.value = response;
scenario_response_message.value = response.message;
scenario_output.value = response.stringOutput;
exec_id.value = response.scenarioExecution_id;
loadingStore.setIdExecLoading(exec_id.value);
startPolling();
} catch (error) {
console.error('Error executing scenario:', error);
loadingStore.exectuion_loading = false;
}
}
};
const openDebug = () => {
axios.get('/scenarios/execute/' + exec_id.value).then((resp) => {
exec_scenario.value = resp.data;
const openDebug = async () => {
try {
const resp = await scenarioExecutionStore.getScenarioExecution(exec_id.value);
exec_scenario.value = resp;
debug_modal.value = true;
});
} catch (error) {
console.error('Error opening debug:', error);
}
};
const pollBackendAPI = () => {
const pollBackendAPI = async () => {
errored_execution.value = false;
axios.get('/scenarios/getExecutionProgress/' + exec_id.value).then((response) => {
if (response.data.status == 'OK' || response.data.status == 'ERROR') {
try {
const response = await scenarioExecutionStore.getExecutionProgress(exec_id.value);
if (response.status == 'OK' || response.status == 'ERROR') {
console.log('Condition met, stopping polling.');
stopPolling();
stopTimer();
if(response.data.status == 'ERROR') {
if (response.status == 'ERROR') {
errored_execution.value = true;
error_message.value = response.data.message;
error_message.value = response.message;
}
loading_data.value = false;
data_loaded.value = true;
scenario_output.value = response.data.stringOutput;
console.log('Response data exec 2:', response.data);
exec_id.value = response.data.scenarioExecution_id;
scenario_output.value = response.stringOutput;
console.log('Response data exec 2:', response);
exec_id.value = response.scenarioExecution_id;
scenario_response_message.value = null; //if != null, next scenario starts with old message
console.log('Scenario 3:', scenario.value);
// Controlla se l'array `inputs` contiene un elemento con `name = 'MultiFileUpload'`
if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload')) {
if (response.data.status == 'OK') {
if (response.status == 'OK') {
// Accedi al primo step e controlla se esiste l'attributo `codegenie_output_type`
const firstStep = scenario.value.steps[0];
if (firstStep?.attributes?.['codegenie_output_type']) {
@@ -569,10 +604,12 @@ const pollBackendAPI = () => {
}
} else {
console.log('Condition not met, polling continues.');
scenario_response.value = response.data;
scenario_response_message.value = response.data.message;
scenario_response.value = response;
scenario_response_message.value = response.message;
}
});
} catch (error) {
console.error('Error polling backend API:', error);
}
};
const showFileContent = (base64String, type) => {
@@ -691,66 +728,53 @@ function generateUniqueId() {
return Date.now(); // Puoi usare anche UUID.randomUUID() o una libreria simile
}
const onRemove = (event, removeUploadedFileCallback, type) => {
const onRemove = async (event, removeUploadedFileCallback, type) => {
const { file, index } = event;
console.log('Removing file:', folderName.value);
try {
axios
.post(
`/deleteFile`,
{ fileName: file.name, folderName: folderName.value }, // Invio nome del file come payload
{
headers: {
'Content-Type': 'application/json'
}
}
)
.then((response) => {
if (response.status === 200) {
console.log('File removed successfully:', response.data);
const response = await fileUploadStore.deleteFile(file.name, folderName.value);
// Mostra notifica di successo
toast.add({
severity: 'success',
summary: 'Success',
detail: 'File removed successfully!',
life: 3000
});
if (response.status === 200) {
console.log('File removed successfully:', response.data);
if (type === 'SingleFileUpload') {
numberPrFiles.value -= 1;
console.log('Number of PR files: ', numberPrFiles.value);
formData.value['SingleFileUpload'] = ''
}
// Aggiorna lista dei file caricati
removeUploadedFileCallback(index);
} else {
console.error('Failed to remove file:', response.statusText);
// Mostra notifica di errore
toast.add({
severity: 'error',
summary: 'Error',
detail: `Failed to remove file. Status: ${response.statusText}`,
life: 3000
});
}
})
.catch((error) => {
console.error('Error while removing file:', error);
// Mostra notifica di errore
toast.add({
severity: 'error',
summary: 'Error',
detail: `Error while removing file: ${error.message}`,
life: 3000
});
// Mostra notifica di successo
toast.add({
severity: 'success',
summary: 'Success',
detail: 'File removed successfully!',
life: 3000
});
if (type === 'SingleFileUpload') {
numberPrFiles.value -= 1;
console.log('Number of PR files: ', numberPrFiles.value);
formData.value['SingleFileUpload'] = '';
}
// Aggiorna lista dei file caricati
removeUploadedFileCallback(index);
} else {
console.error('Failed to remove file:', response.statusText);
// Mostra notifica di errore
toast.add({
severity: 'error',
summary: 'Error',
detail: `Failed to remove file. Status: ${response.statusText}`,
life: 3000
});
}
} catch (error) {
console.error('Error while removing file:', error);
// Mostra notifica di errore
toast.add({
severity: 'error',
summary: 'Error',
detail: `Error while removing file: ${error.message}`,
life: 3000
});
}
};
@@ -859,6 +883,71 @@ const formatSize = (bytes) => {
return `${truncatedSize} ${sizes[i]}`;
};
// Metodi per la gestione delle picklist dinamiche
const getOptionsForInput = (input) => {
// Basato sul dataSource, restituisce le opzioni appropriate
switch (input.dataSource) {
case 'videoGroups':
return videoGroups.value;
case 'ksDocuments':
return ksDocuments.value;
default:
return [];
}
};
const onDynamicPickerChange = (inputName, value) => {
console.log(`Dynamic picker changed for ${inputName}:`, value);
formData.value[inputName] = value;
};
// Carica le opzioni necessarie basate sui dataSource presenti negli inputs dello scenario
const loadOptionsForScenario = async () => {
if (!scenario.value.inputs) return;
console.log('Loading options for scenario inputs...');
// Trova tutti i dataSource unici negli input multiselect
const dataSources = new Set();
scenario.value.inputs.forEach((input) => {
if (input.type === 'multiselect' && input.dataSource) {
dataSources.add(input.dataSource);
}
});
// Crea le funzioni di caricamento per ogni dataSource
const loadingPromises = Array.from(dataSources).map(async (dataSource) => {
try {
// Imposta lo stato di loading per questo dataSource
loadingOptionsFor[dataSource] = true;
console.log(`Loading options for dataSource: ${dataSource}`);
switch (dataSource) {
case 'videoGroups':
await loadVideoGroups();
break;
case 'ksDocuments':
const docsResponse = await KSDocumentService.getKSDocuments();
ksDocuments.value = docsResponse.data;
console.log(`Loaded ${ksDocuments.value.length} KS documents`);
break;
default:
console.warn(`Unknown dataSource: ${dataSource}`);
}
} catch (error) {
console.error(`Error loading options for ${dataSource}:`, error);
} finally {
// Reset lo stato di loading per questo dataSource
loadingOptionsFor[dataSource] = false;
}
});
// Aspetta che tutti i caricamenti siano completati
await Promise.all(loadingPromises);
};
</script>
<style scoped>