Merged PR 116: Create videoGroup picklist for KT scenario

Create videoGroup picklist for KT scenario
This commit is contained in:
2025-05-12 14:49:38 +00:00
3 changed files with 147 additions and 62 deletions

View File

@@ -0,0 +1,20 @@
import axios from 'axios';
export const KsVideoGroupService = {
getKsVideoGroups(projectId) {
return axios.get(`/project`, {
params: {
projectId: projectId
}
});
},
findByProjectId(projectId) {
return axios.get(`/project/${projectId}`);
},
getVideoGroupById(id) {
return axios.get(`/${id}`);
}
};

View File

@@ -0,0 +1,40 @@
import { defineStore } from 'pinia';
import { computed, ref } from 'vue';
import { KsVideoGroupService } from '../service/KsVideoGroupService';
export const KsVideoGroupStore = defineStore('ksvideogroup_store', () => {
const lstKsVideoGroup = ref([]);
const selectedKsVideoGroup = ref(null);
async function fetchKsVideoGroup(projectId) {
try {
const response = await KsVideoGroupService.getKsVideoGroups(projectId);
lstKsVideoGroup.value = response.data;
} catch (error) {
console.error('Error fetching video groups:', error);
} finally {
}
}
const ksVideoGroup = computed(() => {
return lstKsVideoGroup.value;
});
const getSelectedKsVideoGroup = computed(() => {
return selectedKsVideoGroup.value;
});
async function setSelectedKsVideoGroup(group) {
selectedKsVideoGroup.value = group;
console.log('selectedVideoGroup', selectedKsVideoGroup.value);
}
return {
fetchKsVideoGroup,
selectedKsVideoGroup,
lstKsVideoGroup,
ksVideoGroup,
getSelectedKsVideoGroup,
setSelectedKsVideoGroup
};
});

View File

@@ -17,7 +17,6 @@
<div v-else class="flex mt-2"> <div v-else class="flex mt-2">
<div class="card flex flex-col w-full"> <div class="card flex flex-col w-full">
<MdPreview :class="['markdown-content', 'ml-[-20px]']" v-model="scenario.hint" language="en-US" /> <MdPreview :class="['markdown-content', 'ml-[-20px]']" v-model="scenario.hint" language="en-US" />
<template v-if="scenario.inputs"> <template v-if="scenario.inputs">
<div class="grid grid-cols-2 md:grid-cols-1"> <div class="grid grid-cols-2 md:grid-cols-1">
<div v-for="input in scenario.inputs" :key="input.name"> <div v-for="input in scenario.inputs" :key="input.name">
@@ -82,7 +81,6 @@
<p class="mt-2 mb-2 text-m">Drag and drop files here to upload.</p> <p class="mt-2 mb-2 text-m">Drag and drop files here to upload.</p>
</div> </div>
</template> </template>
</FileUpload> </FileUpload>
</div> </div>
</div> </div>
@@ -151,6 +149,14 @@
</FileUpload> </FileUpload>
</div> </div>
</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>
</div>
<div v-else> <div v-else>
<label :for="input.name" <label :for="input.name"
><b>{{ input.label }}</b></label ><b>{{ input.label }}</b></label
@@ -278,7 +284,9 @@
<script setup> <script setup>
import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue'; import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue';
import ChatClient from '@/components/ChatClient.vue'; import ChatClient from '@/components/ChatClient.vue';
import { KsVideoGroupStore } from '@/stores/KsVideoGroupStore';
import { LoadingStore } from '@/stores/LoadingStore'; import { LoadingStore } from '@/stores/LoadingStore';
import { UserPrefStore } from '@/stores/UserPrefStore';
import { useAuth } from '@websanova/vue-auth/src/v3.js'; import { useAuth } from '@websanova/vue-auth/src/v3.js';
import axios from 'axios'; import axios from 'axios';
import JsonEditorVue from 'json-editor-vue'; import JsonEditorVue from 'json-editor-vue';
@@ -289,6 +297,7 @@ import 'md-editor-v3/lib/style.css';
import moment from 'moment'; import moment from 'moment';
import { usePrimeVue } from 'primevue/config'; import { usePrimeVue } from 'primevue/config';
import InputText from 'primevue/inputtext'; import InputText from 'primevue/inputtext';
import MultiSelect from 'primevue/multiselect';
import Select from 'primevue/select'; import Select from 'primevue/select';
import Textarea from 'primevue/textarea'; import Textarea from 'primevue/textarea';
import { useConfirm } from 'primevue/useconfirm'; import { useConfirm } from 'primevue/useconfirm';
@@ -317,6 +326,9 @@ const debug_modal = ref(false);
let pollingInterval = null; let pollingInterval = null;
const folderName = ref(''); const folderName = ref('');
const fileNamesOutput = ref([]); const fileNamesOutput = ref([]);
const ksVideoGroupStore = KsVideoGroupStore();
const userPrefStore = UserPrefStore();
const videoGroups = ref([]);
// URL di upload // URL di upload
const uploadUrlBase = import.meta.env.VITE_BACKEND_URL; const uploadUrlBase = import.meta.env.VITE_BACKEND_URL;
const uploadUrl = ref(''); const uploadUrl = ref('');
@@ -365,6 +377,14 @@ const isInputFilled = computed(() => {
if (formData.value[input.name] === undefined || formData.value[input.name] === '') { if (formData.value[input.name] === undefined || formData.value[input.name] === '') {
console.log('Input not filled: ', input.name); console.log('Input not filled: ', input.name);
isFilled = false; isFilled = false;
} else {
const processedData = { ...formData.value };
if (processedData.video_group) {
processedData.video_group = JSON.stringify(
processedData.video_group.map((item) => item.id)
);
}
} }
}); });
return isFilled; return isFilled;
@@ -372,6 +392,7 @@ const isInputFilled = computed(() => {
onMounted(() => { onMounted(() => {
fetchScenario(route.params.id); fetchScenario(route.params.id);
loadVideoGroups();
const timestamp = Date.now(); // Ottiene il timestamp corrente const timestamp = Date.now(); // Ottiene il timestamp corrente
const randomNumber = Math.floor(Math.random() * 1000); const randomNumber = Math.floor(Math.random() * 1000);
folderName.value = `${timestamp}_${randomNumber}`; folderName.value = `${timestamp}_${randomNumber}`;
@@ -381,6 +402,14 @@ onMounted(() => {
console.log('Upload URL:', uploadUrl); console.log('Upload URL:', uploadUrl);
}); });
const loadVideoGroups = async () => {
await ksVideoGroupStore.fetchKsVideoGroup(userPrefStore.selectedProject.id).then(async () => {
videoGroups.value = [...(ksVideoGroupStore.ksVideoGroup || [])];
//Wait for all video counts to be fetched
videoGroups.value = await Promise.all(videoGroups.value);
});
};
// Ricarica i dati quando cambia il parametro `id` // Ricarica i dati quando cambia il parametro `id`
watch(() => route.params.id, fetchScenario); watch(() => route.params.id, fetchScenario);
@@ -402,7 +431,7 @@ function fetchScenario(id) {
} }
if (scenario.value.inputs.some((input) => input.type === 'singlefile_acceptall')) { if (scenario.value.inputs.some((input) => input.type === 'singlefile_acceptall')) {
reqMultiFile.value = false; reqMultiFile.value = false;
acceptedFormats.value = ""; acceptedFormats.value = '';
//acceptedFormats.value = '.doc,.docx,.pdf,.msg,.txt,.xlx,.xlxs,.logs,.pptx,.json,.odt,.rtf,.xml,.html'; //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')) { if (scenario.value.inputs.some((input) => input.type === 'singlefile')) {
@@ -433,6 +462,8 @@ const getInputComponent = (type) => {
return Textarea; return Textarea;
case 'select': case 'select':
return Select; return Select;
case 'multiselect':
return MultiSelect;
default: default:
return InputText; return InputText;
} }
@@ -440,11 +471,11 @@ const getInputComponent = (type) => {
const chatEnabled = () => { const chatEnabled = () => {
chat_enabled.value = true; chat_enabled.value = true;
} };
const chatDisabled = () => { const chatDisabled = () => {
chat_enabled.value = false; chat_enabled.value = false;
} };
const execScenario = () => { const execScenario = () => {
if (numberPrFiles.value !== 1 && reqMultiFile.value) { if (numberPrFiles.value !== 1 && reqMultiFile.value) {
@@ -461,9 +492,17 @@ const execScenario = () => {
loadingStore.exectuion_loading = true; loadingStore.exectuion_loading = true;
// Crea una copia dei dati del form
const processedData = { ...formData.value };
if (processedData.video_group) {
processedData.video_group = JSON.stringify(
processedData.video_group.map((item) => item.id)
);
}
const data = { const data = {
scenario_id: scenario.value.id, scenario_id: scenario.value.id,
inputs: { ...formData.value } inputs: processedData
}; };
axios axios
@@ -475,7 +514,6 @@ const execScenario = () => {
scenario_output.value = response.data.stringOutput; scenario_output.value = response.data.stringOutput;
exec_id.value = response.data.scenarioExecution_id; exec_id.value = response.data.scenarioExecution_id;
loadingStore.setIdExecLoading(exec_id.value); loadingStore.setIdExecLoading(exec_id.value);
// Start polling
startPolling(); startPolling();
}) })
.catch((error) => { .catch((error) => {
@@ -508,7 +546,6 @@ const pollBackendAPI = () => {
// Controlla se l'array `inputs` contiene un elemento con `name = 'MultiFileUpload'` // Controlla se l'array `inputs` contiene un elemento con `name = 'MultiFileUpload'`
if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload')) { if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload')) {
if (response.data.status == 'OK') { if (response.data.status == 'OK') {
// Accedi al primo step e controlla se esiste l'attributo `codegenie_output_type` // Accedi al primo step e controlla se esiste l'attributo `codegenie_output_type`
const firstStep = scenario.value.steps[0]; const firstStep = scenario.value.steps[0];
@@ -523,33 +560,26 @@ if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload')) {
if (firstStep.attributes['codegenie_output_type'] == 'FILE') { if (firstStep.attributes['codegenie_output_type'] == 'FILE') {
//console.log('base64 ', scenario_output.value) //console.log('base64 ', scenario_output.value)
//extractFiles(scenario_output.value, 'output', zipOutput) //extractFiles(scenario_output.value, 'output', zipOutput)
fileType.value = 'FILE' fileType.value = 'FILE';
} else if (firstStep.attributes['codegenie_output_type'] == 'MARKDOWN') {
} fileType.value = 'MARKDOWN';
else if(firstStep.attributes['codegenie_output_type'] == 'MARKDOWN'){ showFileContent(scenario_output.value, 'MARKDOWN');
fileType.value = 'MARKDOWN' } else if (firstStep.attributes['codegenie_output_type'] == 'JSON') {
showFileContent(scenario_output.value, 'MARKDOWN') fileType.value = 'JSON';
} showFileContent(scenario_output.value, 'JSON');
else if(firstStep.attributes['codegenie_output_type'] == 'JSON'){
fileType.value = 'JSON'
showFileContent(scenario_output.value, 'JSON')
} }
} }
} else { } else {
console.log("Error in execution"); console.log('Error in execution');
} }
} }
} else { } else {
console.log("Condition not met, polling continues."); console.log('Condition not met, polling continues.');
scenario_response.value = response.data; scenario_response.value = response.data;
scenario_response_message.value = response.data.message; scenario_response_message.value = response.data.message;
} }
}); });
} };
const showFileContent = (base64String, type) => { const showFileContent = (base64String, type) => {
try { try {
@@ -648,7 +678,7 @@ async function updateRating(newRating) {
life: 3000 // Durata della notifica in millisecondi life: 3000 // Durata della notifica in millisecondi
}); });
} else { } else {
console.error("Errore during rating update", response.data); console.error('Errore during rating update', response.data);
toast.add({ toast.add({
severity: 'error', // Tipo di notifica (errore) severity: 'error', // Tipo di notifica (errore)
summary: 'Error', // Titolo della notifica summary: 'Error', // Titolo della notifica
@@ -735,7 +765,6 @@ const onUpload = (event, uploadType) => {
const { xhr } = event; // Estraggo l'oggetto XMLHttpRequest const { xhr } = event; // Estraggo l'oggetto XMLHttpRequest
if (xhr.status === 200) { if (xhr.status === 200) {
if (uploadType === 'SingleFileUpload') { if (uploadType === 'SingleFileUpload') {
//formData.value['SingleFileUpload'] = "OK"; //formData.value['SingleFileUpload'] = "OK";
if (event.files && event.files.length > 0) { if (event.files && event.files.length > 0) {
@@ -744,7 +773,7 @@ const onUpload = (event, uploadType) => {
} else { } else {
formData.value['SingleFileUpload'] = 'UnknownFile'; formData.value['SingleFileUpload'] = 'UnknownFile';
} }
console.log("Length of uploaded files", event.files.length); console.log('Length of uploaded files', event.files.length);
numberPrFiles.value += 1; numberPrFiles.value += 1;
console.log('Number of PR files: ', numberPrFiles.value); console.log('Number of PR files: ', numberPrFiles.value);
} }
@@ -760,10 +789,10 @@ const onUpload = (event, uploadType) => {
detail: 'File uploaded successfully!', detail: 'File uploaded successfully!',
life: 3000 life: 3000
}); });
console.log("Length of uploaded files", uploadedFiles.value.length); console.log('Length of uploaded files', uploadedFiles.value.length);
} else { } else {
// Errore durante l'upload // Errore durante l'upload
console.error("Error during upload. Status:", xhr.status, 'Response:', xhr.response); console.error('Error during upload. Status:', xhr.status, 'Response:', xhr.response);
toast.add({ toast.add({
severity: 'error', severity: 'error',
@@ -835,11 +864,9 @@ const formatSize = (bytes) => {
return `${truncatedSize} ${sizes[i]}`; return `${truncatedSize} ${sizes[i]}`;
}; };
</script> </script>
<style scoped> <style scoped>
.input-container { .input-container {
margin-bottom: 1em; margin-bottom: 1em;
} }
@@ -863,7 +890,6 @@ const formatSize = (bytes) => {
list-style-type: disc !important; list-style-type: disc !important;
} }
pre { pre {
white-space: pre-wrap; /* Fa andare a capo il contenuto automaticamente */ white-space: pre-wrap; /* Fa andare a capo il contenuto automaticamente */
word-wrap: break-word; /* Interrompe le parole troppo lunghe */ word-wrap: break-word; /* Interrompe le parole troppo lunghe */
@@ -883,6 +909,5 @@ pre {
max-width: 100%; /* Adatta il contenuto alla larghezza del contenitore */ max-width: 100%; /* Adatta il contenuto alla larghezza del contenitore */
overflow-x: auto; /* Aggiunge scorrimento orizzontale solo se necessario */ overflow-x: auto; /* Aggiunge scorrimento orizzontale solo se necessario */
background-color: #f5f5f5; /* Sfondo per distinguere il contenuto */ background-color: #f5f5f5; /* Sfondo per distinguere il contenuto */
} }
</style> </style>