Clean Canvas and resolve bug
This commit is contained in:
@@ -6,7 +6,9 @@
|
|||||||
{{ user.name + " " + user.surname }}
|
{{ user.name + " " + user.surname }}
|
||||||
</span>
|
</span>
|
||||||
<!-- <button @click="redirectProject()" class="p-button p-button-outlined">Projects</button> -->
|
<!-- <button @click="redirectProject()" class="p-button p-button-outlined">Projects</button> -->
|
||||||
<button @click="auth.logout()" class="p-button p-button-outlined">Logout</button>
|
<!-- <button @click="auth.logout()" class="p-button p-button-outlined">Logout</button> -->
|
||||||
|
<button @click="logout()" class="p-button p-button-outlined">Logout</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -16,14 +18,26 @@
|
|||||||
import { useAuth } from '@websanova/vue-auth/src/v3.js';
|
import { useAuth } from '@websanova/vue-auth/src/v3.js';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { ScenarioStore } from '@/stores/ScenarioStore';
|
||||||
|
|
||||||
|
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
const user = computed(() => auth.user());
|
const user = computed(() => auth.user());
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const scenario_store = ScenarioStore();
|
||||||
|
|
||||||
|
|
||||||
function redirectProject() {
|
function redirectProject() {
|
||||||
router.push('/projects'); // Specifica il percorso per la pagina "Projects"
|
router.push('/projects'); // Specifica il percorso per la pagina "Projects"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
auth.logout().then(() => {
|
||||||
|
scenario_store.resetStore();
|
||||||
|
router.push('/auth/login');
|
||||||
|
}).catch(err => {
|
||||||
|
console.error("Errore durante il logout:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { UserPrefStore } from './UserPrefStore'
|
|||||||
|
|
||||||
export const ScenarioStore = defineStore('scenario_store', () => {
|
export const ScenarioStore = defineStore('scenario_store', () => {
|
||||||
|
|
||||||
|
|
||||||
const projectScenarios = ref([])
|
const projectScenarios = ref([])
|
||||||
const globalScenarios = ref([])
|
const globalScenarios = ref([])
|
||||||
const applicationScenarios = ref([])
|
const applicationScenarios = ref([])
|
||||||
@@ -18,7 +17,6 @@ export const ScenarioStore = defineStore('scenario_store', () => {
|
|||||||
const userPrefStore = UserPrefStore()
|
const userPrefStore = UserPrefStore()
|
||||||
const loadingStore = LoadingStore()
|
const loadingStore = LoadingStore()
|
||||||
|
|
||||||
|
|
||||||
async function fetchScenarios() {
|
async function fetchScenarios() {
|
||||||
loadingStore.scenario_loading = true;
|
loadingStore.scenario_loading = true;
|
||||||
await ScenarioService.getScenariosProject(userPrefStore.selectedProject).then(resp => {
|
await ScenarioService.getScenariosProject(userPrefStore.selectedProject).then(resp => {
|
||||||
@@ -26,7 +24,6 @@ export const ScenarioStore = defineStore('scenario_store', () => {
|
|||||||
allScenarios.value = [...projectScenarios.value]
|
allScenarios.value = [...projectScenarios.value]
|
||||||
loadingStore.scenario_loading = false;
|
loadingStore.scenario_loading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchScenariosForRE() {
|
async function fetchScenariosForRE() {
|
||||||
@@ -35,7 +32,6 @@ export const ScenarioStore = defineStore('scenario_store', () => {
|
|||||||
scenariosForRE.value = resp.data;
|
scenariosForRE.value = resp.data;
|
||||||
loadingStore.scenario_loading = false;
|
loadingStore.scenario_loading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchScenariosCross() {
|
async function fetchScenariosCross() {
|
||||||
@@ -45,19 +41,16 @@ export const ScenarioStore = defineStore('scenario_store', () => {
|
|||||||
allScenarios.value = [...globalScenarios.value]
|
allScenarios.value = [...globalScenarios.value]
|
||||||
loadingStore.scenario_loading = false;
|
loadingStore.scenario_loading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function fetchApplicationScenarios() {
|
async function fetchApplicationScenarios() {
|
||||||
loadingStore.scenario_loading = true;
|
loadingStore.scenario_loading = true;
|
||||||
console.log("fetchApplicationScenarios >= selectedApp", userPrefStore.selectedApp) ;
|
console.log("fetchApplicationScenarios >= selectedApp", userPrefStore.selectedApp);
|
||||||
await ScenarioService.getScenariosApplication(userPrefStore.selectedApp).then(resp=>{
|
await ScenarioService.getScenariosApplication(userPrefStore.selectedApp).then(resp => {
|
||||||
console.log("response scenari", resp);
|
console.log("response scenari", resp);
|
||||||
applicationScenarios.value = resp.data
|
applicationScenarios.value = resp.data
|
||||||
allScenarios.value = [...projectScenarios.value, ...applicationScenarios.value]
|
allScenarios.value = [...projectScenarios.value, ...applicationScenarios.value]
|
||||||
loadingStore.scenario_loading = false;
|
loadingStore.scenario_loading = false;
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +58,6 @@ export const ScenarioStore = defineStore('scenario_store', () => {
|
|||||||
return allScenarios.value
|
return allScenarios.value
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const filteredScenarios = computed(() => {
|
const filteredScenarios = computed(() => {
|
||||||
console.log("scenarios", allScenarios.value);
|
console.log("scenarios", allScenarios.value);
|
||||||
var filteredScenario = []
|
var filteredScenario = []
|
||||||
@@ -91,12 +83,43 @@ export const ScenarioStore = defineStore('scenario_store', () => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const filteredScenariosCanvas = computed(() => {
|
||||||
|
console.log("scenarios", allScenarios.value);
|
||||||
|
var filteredScenario = []
|
||||||
|
|
||||||
return {filteredScenarios,
|
if(userPrefStore.getSelApp != null) {
|
||||||
|
filteredScenario = [...globalScenarios.value,...projectScenarios.value, ...applicationScenarios.value]
|
||||||
|
} else {
|
||||||
|
filteredScenario = [...globalScenarios.value,...projectScenarios.value]
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredScenario
|
||||||
|
})
|
||||||
|
|
||||||
|
function resetStore() {
|
||||||
|
projectScenarios.value = []
|
||||||
|
globalScenarios.value = []
|
||||||
|
applicationScenarios.value = []
|
||||||
|
filterString.value = ''
|
||||||
|
allScenarios.value = []
|
||||||
|
typeFilter.value = { name: 'All', value: 'all' }
|
||||||
|
scenariosForRE.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
filteredScenarios,
|
||||||
|
filteredScenariosCanvas,
|
||||||
projectScenarios,
|
projectScenarios,
|
||||||
applicationScenarios,
|
applicationScenarios,
|
||||||
fetchScenarios,
|
fetchScenarios,
|
||||||
fetchApplicationScenarios,
|
fetchApplicationScenarios,
|
||||||
scenarios,
|
scenarios,
|
||||||
filterString , typeFilter, fetchScenariosCross, globalScenarios, fetchScenariosForRE, scenariosForRE}
|
filterString,
|
||||||
})
|
typeFilter,
|
||||||
|
fetchScenariosCross,
|
||||||
|
globalScenarios,
|
||||||
|
fetchScenariosForRE,
|
||||||
|
scenariosForRE,
|
||||||
|
resetStore
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="flex items-center justify-between p-1">
|
<div class="flex items-center justify-between p-1">
|
||||||
<h1>
|
<h1>
|
||||||
{{ scenario.name }}
|
{{ scenario.name }}
|
||||||
@@ -12,24 +11,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex mt-6">
|
<div class="flex mt-6">
|
||||||
<div class="card flex flex-col gap-4 w-full">
|
<div class="card flex flex-col gap-4 w-full">
|
||||||
<h3>
|
<MdPreview :class="['markdown-content', 'ml-[-20px]']" v-model="scenario.hint" language="en-US" />
|
||||||
{{ scenario.hint }}
|
|
||||||
</h3>
|
|
||||||
<template v-if="scenario.inputs">
|
<template v-if="scenario.inputs">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<div v-for="input in scenario.inputs" :key="input.name"
|
<div v-for="input in scenario.inputs" :key="input.name" :class="['input-container', input.type === 'textarea' ? 'col-span-12' : '']">
|
||||||
:class="['input-container', input.type === 'textarea' ? 'col-span-12' : '']">
|
|
||||||
|
|
||||||
<div v-if="input.type === 'singlefile' || input.type === 'singlefile_acceptall'">
|
<div v-if="input.type === 'singlefile' || input.type === 'singlefile_acceptall'">
|
||||||
<label :for="input.name">
|
<label :for="input.name">
|
||||||
<b>{{ input.label }}</b>
|
<b>{{ input.label }}</b>
|
||||||
<i
|
<i class="pi pi-info-circle text-violet-600 cursor-pointer" v-tooltip="'Upload one document from the suggested types. Mandatory if you want to execute scenario.'"></i>
|
||||||
class="pi pi-info-circle text-violet-600 cursor-pointer"
|
|
||||||
v-tooltip="'Upload one document from the suggested types. Mandatory if you want to execute scenario.'"
|
|
||||||
></i>
|
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<FileUpload
|
<FileUpload
|
||||||
:name="'MultiFileUpload'"
|
:name="'MultiFileUpload'"
|
||||||
:customUpload="false"
|
:customUpload="false"
|
||||||
@@ -42,14 +34,11 @@
|
|||||||
:showCancelButton="false"
|
:showCancelButton="false"
|
||||||
:maxFileSize="10000000"
|
:maxFileSize="10000000"
|
||||||
v-model:files="uploadedFiles"
|
v-model:files="uploadedFiles"
|
||||||
|
|
||||||
|
|
||||||
>
|
>
|
||||||
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<!-- Tabella per file in caricamento -->
|
<!-- Tabella per file in caricamento -->
|
||||||
<div v-if="uploadedFiles.length > 0">
|
<div v-if="uploadedFiles.length > 0">
|
||||||
|
|
||||||
<table class="table-auto w-full border-collapse border border-gray-200">
|
<table class="table-auto w-full border-collapse border border-gray-200">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -60,24 +49,14 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr v-for="(file, index) in uploadedFiles" :key="file.name + file.size" class="hover:bg-gray-50">
|
||||||
v-for="(file, index) in uploadedFiles"
|
|
||||||
:key="file.name + file.size"
|
|
||||||
class="hover:bg-gray-50"
|
|
||||||
>
|
|
||||||
<td class="border border-gray-300 p-2">{{ file.name }}</td>
|
<td class="border border-gray-300 p-2">{{ file.name }}</td>
|
||||||
<td class="border border-gray-300 p-2">{{ formatSize(file.size) }}</td>
|
<td class="border border-gray-300 p-2">{{ formatSize(file.size) }}</td>
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
<Badge value="UPLOADED" severity="success" />
|
<Badge value="UPLOADED" severity="success" />
|
||||||
</td>
|
</td>
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
<Button
|
<Button label="Remove" @click="onRemove({ file, index }, removeUploadedFileCallback, 'SingleFileUpload')" />
|
||||||
label="Remove"
|
|
||||||
@click="onRemove({ file, index }, removeUploadedFileCallback, 'SingleFileUpload')"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -93,21 +72,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</FileUpload>
|
</FileUpload>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="input.type === 'multifile'">
|
<div v-else-if="input.type === 'multifile'">
|
||||||
<label :for="input.name">
|
<label :for="input.name">
|
||||||
<b>{{ input.label }}
|
<b>{{ input.label }} </b>
|
||||||
</b>
|
<i class="pi pi-info-circle text-violet-600 cursor-pointer" v-tooltip="'Upload others documents of .docx, .msg, .text type. Optional.'"></i>
|
||||||
<i
|
|
||||||
class="pi pi-info-circle text-violet-600 cursor-pointer"
|
|
||||||
v-tooltip="'Upload others documents of .docx, .msg, .text type. Optional.'"
|
|
||||||
></i>
|
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<FileUpload
|
<FileUpload
|
||||||
:name="'MultiFileUpload'"
|
:name="'MultiFileUpload'"
|
||||||
:customUpload="false"
|
:customUpload="false"
|
||||||
@@ -120,14 +93,11 @@
|
|||||||
:showCancelButton="false"
|
:showCancelButton="false"
|
||||||
:maxFileSize="10000000"
|
:maxFileSize="10000000"
|
||||||
v-model:files="uploadedFiles"
|
v-model:files="uploadedFiles"
|
||||||
|
|
||||||
|
|
||||||
>
|
>
|
||||||
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<!-- Tabella per file in caricamento -->
|
<!-- Tabella per file in caricamento -->
|
||||||
<div v-if="uploadedFiles.length > 0">
|
<div v-if="uploadedFiles.length > 0">
|
||||||
|
|
||||||
<table class="table-auto w-full border-collapse border border-gray-200">
|
<table class="table-auto w-full border-collapse border border-gray-200">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -138,24 +108,14 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr v-for="(file, index) in uploadedFiles" :key="file.name + file.size" class="hover:bg-gray-50">
|
||||||
v-for="(file, index) in uploadedFiles"
|
|
||||||
:key="file.name + file.size"
|
|
||||||
class="hover:bg-gray-50"
|
|
||||||
>
|
|
||||||
<td class="border border-gray-300 p-2">{{ file.name }}</td>
|
<td class="border border-gray-300 p-2">{{ file.name }}</td>
|
||||||
<td class="border border-gray-300 p-2">{{ formatSize(file.size) }}</td>
|
<td class="border border-gray-300 p-2">{{ formatSize(file.size) }}</td>
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
<Badge value="UPLOADED" severity="success" />
|
<Badge value="UPLOADED" severity="success" />
|
||||||
</td>
|
</td>
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
<Button
|
<Button label="Remove" @click="onRemove({ file, index }, removeUploadedFileCallback, 'MultiFileUpload')" />
|
||||||
label="Remove"
|
|
||||||
@click="onRemove({ file, index }, removeUploadedFileCallback, 'MultiFileUpload')"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -171,32 +131,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</FileUpload>
|
</FileUpload>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<label :for="input.name"><b>{{ input.label }}</b></label>
|
<label :for="input.name"
|
||||||
|
><b>{{ input.label }}</b></label
|
||||||
|
>
|
||||||
<div class="input-wrapper">
|
<div class="input-wrapper">
|
||||||
<component
|
<component :is="getInputComponent(input.type)" :id="input.name" v-model="formData[input.name]" :options="input.options" class="full-width-input" :disabled="loadingStore.exectuion_loading" />
|
||||||
:is="getInputComponent(input.type)"
|
|
||||||
:id="input.name"
|
|
||||||
v-model="formData[input.name]"
|
|
||||||
:options="input.options"
|
|
||||||
class="full-width-input"
|
|
||||||
:disabled="loadingStore.exectuion_loading"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<Button :disabled="loadingStore.exectuion_loading || !isInputFilled " label="Execute" @click="execScenario" size="large" iconPos="right" icon="pi pi-cog"></Button>
|
<Button :disabled="loadingStore.exectuion_loading || !isInputFilled" label="Execute" @click="execScenario" size="large" iconPos="right" icon="pi pi-cog"></Button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -207,10 +157,8 @@
|
|||||||
<div v-if="scenario_response_message && scenario_response_message.includes('/')">
|
<div v-if="scenario_response_message && scenario_response_message.includes('/')">
|
||||||
<span>{{ scenario_response_message }}</span>
|
<span>{{ scenario_response_message }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>Starting execution...</div>
|
||||||
Starting execution...
|
<div class="flex justify-center" style="margin-bottom: 30px">
|
||||||
</div>
|
|
||||||
<div class="flex justify-center" style="margin-bottom: 30px;">
|
|
||||||
<p>Time elapsed: </p>
|
<p>Time elapsed: </p>
|
||||||
<div id="timer" class="timer">00:00</div>
|
<div id="timer" class="timer">00:00</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -221,18 +169,12 @@
|
|||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="font-bold">Workflow Response</span>
|
<span class="font-bold">Workflow Response</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #icons>
|
<template #icons>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Rating
|
<Rating :modelValue="rating" :stars="5" @change="updateRating($event)" />
|
||||||
|
|
||||||
:modelValue="rating"
|
|
||||||
:stars="5"
|
|
||||||
@change="updateRating($event)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -248,12 +190,7 @@
|
|||||||
<ChangeImpactOutputViewer :scenario_output="scenario_output" />
|
<ChangeImpactOutputViewer :scenario_output="scenario_output" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="scenario.outputType == 'file'">
|
<div v-if="scenario.outputType == 'file'">
|
||||||
<Button
|
<Button icon="pi pi-download" label="Download File" class="p-button-primary" @click="downloadFile" />
|
||||||
icon="pi pi-download"
|
|
||||||
label="Download File"
|
|
||||||
class="p-button-primary"
|
|
||||||
@click="downloadFile"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<!-- <div v-if="fileNamesOutput.length">
|
<!-- <div v-if="fileNamesOutput.length">
|
||||||
@@ -272,13 +209,8 @@
|
|||||||
<div v-if="fileType == 'FILE'">
|
<div v-if="fileType == 'FILE'">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="file-item">
|
<li class="file-item">
|
||||||
sf_document-{{exec_id}}
|
sf_document-{{ exec_id }}
|
||||||
<Button
|
<Button icon="pi pi-download" class="p-button-text p-button-sm" label="Download" @click="downloadFile()" />
|
||||||
icon="pi pi-download"
|
|
||||||
class="p-button-text p-button-sm"
|
|
||||||
label="Download"
|
|
||||||
@click="downloadFile()"
|
|
||||||
/>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -295,21 +227,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
<Dialog v-model:visible="debug_modal" maximizable modal :header="scenario.name" :style="{ width: '75%' }" :breakpoints="{ '1199px': '75vw', '575px': '90vw' }">
|
<Dialog v-model:visible="debug_modal" maximizable modal :header="scenario.name" :style="{ width: '75%' }" :breakpoints="{ '1199px': '75vw', '575px': '90vw' }">
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="card flex flex-col gap-4 w-full">
|
<div class="card flex flex-col gap-4 w-full">
|
||||||
<JsonEditorVue
|
<JsonEditorVue v-model="exec_scenario" />
|
||||||
v-model="exec_scenario"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue';
|
import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue';
|
||||||
import { LoadingStore } from '@/stores/LoadingStore';
|
import { LoadingStore } from '@/stores/LoadingStore';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
@@ -327,10 +254,9 @@ import { useConfirm } from 'primevue/useconfirm';
|
|||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { JellyfishLoader } from "vue3-spinner";
|
import { JellyfishLoader } from 'vue3-spinner';
|
||||||
import { ScenarioService } from '../../service/ScenarioService';
|
import { ScenarioService } from '../../service/ScenarioService';
|
||||||
|
|
||||||
|
|
||||||
const loadingStore = LoadingStore();
|
const loadingStore = LoadingStore();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const zip = ref(null);
|
const zip = ref(null);
|
||||||
@@ -350,17 +276,17 @@ const exec_id = ref(null);
|
|||||||
const exec_scenario = ref({});
|
const exec_scenario = ref({});
|
||||||
const debug_modal = ref(false);
|
const debug_modal = ref(false);
|
||||||
let pollingInterval = null;
|
let pollingInterval = null;
|
||||||
const folderName = ref("");
|
const folderName = ref('');
|
||||||
const fileNamesOutput = ref([]);
|
const fileNamesOutput = 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('');
|
||||||
const uploadUrlPR = ref("");
|
const uploadUrlPR = ref('');
|
||||||
const uploadUrlOther = ref("");
|
const uploadUrlOther = ref('');
|
||||||
// File che l'utente ha selezionato
|
// File che l'utente ha selezionato
|
||||||
const uploadedFiles = ref([]);
|
const uploadedFiles = ref([]);
|
||||||
const numberPrFiles = ref(0);
|
const numberPrFiles = ref(0);
|
||||||
const acceptedFormats = ref(".docx");
|
const acceptedFormats = ref('.docx');
|
||||||
// :url="`http://localhost:8081/uploadListFiles/${folderName}`"
|
// :url="`http://localhost:8081/uploadListFiles/${folderName}`"
|
||||||
|
|
||||||
// Stato per l'ID univoco della cartella
|
// Stato per l'ID univoco della cartella
|
||||||
@@ -380,7 +306,7 @@ function startTimer() {
|
|||||||
startTime = Date.now();
|
startTime = Date.now();
|
||||||
timerInterval = setInterval(() => {
|
timerInterval = setInterval(() => {
|
||||||
const elapsedTime = moment.duration(Date.now() - startTime);
|
const elapsedTime = moment.duration(Date.now() - startTime);
|
||||||
document.getElementById("timer").textContent = moment.utc(elapsedTime.asMilliseconds()).format("mm:ss");
|
document.getElementById('timer').textContent = moment.utc(elapsedTime.asMilliseconds()).format('mm:ss');
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,67 +314,65 @@ function stopTimer() {
|
|||||||
clearInterval(timerInterval);
|
clearInterval(timerInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const isInputFilled = computed(() => {
|
const isInputFilled = computed(() => {
|
||||||
var isFilled = true;
|
var isFilled = true;
|
||||||
if(scenario.value.inputs === undefined) {
|
if (scenario.value.inputs === undefined) {
|
||||||
console.log("No inputs found");
|
console.log('No inputs found');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
scenario.value.inputs.forEach(input => {
|
scenario.value.inputs.forEach((input) => {
|
||||||
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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return isFilled;
|
return isFilled;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchScenario(route.params.id);
|
fetchScenario(route.params.id);
|
||||||
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}`;
|
||||||
uploadUrl.value = uploadUrlBase + '/uploadListFiles/' + folderName.value;
|
uploadUrl.value = uploadUrlBase + '/uploadListFiles/' + folderName.value;
|
||||||
uploadUrlPR.value = uploadUrl.value + '/PR';
|
uploadUrlPR.value = uploadUrl.value + '/PR';
|
||||||
uploadUrlOther.value = uploadUrl.value + '/OTHER';
|
uploadUrlOther.value = uploadUrl.value + '/OTHER';
|
||||||
console.log("Upload URL:", uploadUrl);
|
console.log('Upload URL:', uploadUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
|
//Function to fetch scenarios
|
||||||
//Function to fetch scenarios
|
function fetchScenario(id) {
|
||||||
function fetchScenario(id) {
|
|
||||||
data_loaded.value = false;
|
data_loaded.value = false;
|
||||||
formData.value = {};
|
formData.value = {};
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
axios.get(`/scenarios/${id}`)
|
axios
|
||||||
.then(response => {
|
.get(`/scenarios/${id}`)
|
||||||
|
.then((response) => {
|
||||||
scenario.value = response.data;
|
scenario.value = response.data;
|
||||||
console.log("Scenario fetched:", scenario.value);
|
console.log('Scenario fetched:', scenario.value);
|
||||||
|
|
||||||
if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload' || input.name === 'SingleFileUpload')) {
|
if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload' || input.name === 'SingleFileUpload')) {
|
||||||
reqMultiFile.value = true;
|
reqMultiFile.value = true;
|
||||||
}
|
}
|
||||||
if(scenario.value.inputs.some((input) => input.type === 'singlefile_acceptall')){
|
if (scenario.value.inputs.some((input) => input.type === 'singlefile_acceptall')) {
|
||||||
acceptedFormats.value = ".docx, .pdf, .doc, .txt, .msg";
|
acceptedFormats.value = '.docx, .pdf, .doc, .txt, .msg';
|
||||||
}
|
}
|
||||||
if(scenario.value.inputs.some((input) => input.type === 'singlefile')){
|
if (scenario.value.inputs.some((input) => input.type === 'singlefile')) {
|
||||||
acceptedFormats.value = ".docx";
|
acceptedFormats.value = '.docx';
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
console.error("Error fetching scenario:", error);
|
console.error('Error fetching scenario:', error);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInputComponent = (type) => {
|
const getInputComponent = (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
return InputText;
|
return InputText;
|
||||||
@@ -459,19 +383,16 @@ watch(() => route.params.id, fetchScenario);
|
|||||||
default:
|
default:
|
||||||
return InputText;
|
return InputText;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const execScenario = () => {
|
const execScenario = () => {
|
||||||
|
if (numberPrFiles.value !== 1 && reqMultiFile.value) {
|
||||||
if(numberPrFiles.value!==1 && reqMultiFile.value){
|
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: 'warn', // Tipo di notifica (errore)
|
severity: 'warn', // Tipo di notifica (errore)
|
||||||
summary: 'Attention', // Titolo della notifica
|
summary: 'Attention', // Titolo della notifica
|
||||||
detail: 'You can upload only 1 PR file. Please remove others.' // Messaggio dettagliato
|
detail: 'You can upload only 1 PR file. Please remove others.' // Messaggio dettagliato
|
||||||
});
|
});
|
||||||
}else{
|
} else {
|
||||||
|
|
||||||
|
|
||||||
loading_data.value = true;
|
loading_data.value = true;
|
||||||
data_loaded.value = false;
|
data_loaded.value = false;
|
||||||
rating.value = 0;
|
rating.value = 0;
|
||||||
@@ -484,49 +405,45 @@ watch(() => route.params.id, fetchScenario);
|
|||||||
inputs: { ...formData.value }
|
inputs: { ...formData.value }
|
||||||
};
|
};
|
||||||
|
|
||||||
axios.post('/scenarios/execute-async', data)
|
axios
|
||||||
.then(response => {
|
.post('/scenarios/execute-async', data)
|
||||||
console.log("Response data exec 1:", response.data);
|
.then((response) => {
|
||||||
|
console.log('Response data exec 1:', response.data);
|
||||||
scenario_response.value = response.data;
|
scenario_response.value = response.data;
|
||||||
scenario_response_message.value = response.data.message;
|
scenario_response_message.value = response.data.message;
|
||||||
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
|
// Start polling
|
||||||
startPolling();
|
startPolling();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
console.error('Error executing scenario:', error);
|
console.error('Error executing scenario:', error);
|
||||||
loadingStore.exectuion_loading = false;
|
loadingStore.exectuion_loading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const openDebug = () => {
|
const openDebug = () => {
|
||||||
|
axios.get('/scenarios/execute/' + exec_id.value).then((resp) => {
|
||||||
|
exec_scenario.value = resp.data;
|
||||||
|
debug_modal.value = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
axios.get('/scenarios/execute/'+ exec_id.value).then(resp =>{
|
const pollBackendAPI = () => {
|
||||||
exec_scenario.value = resp.data
|
axios.get('/scenarios/getExecutionProgress/' + exec_id.value).then((response) => {
|
||||||
debug_modal.value = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const pollBackendAPI = () => {
|
|
||||||
|
|
||||||
axios.get('/scenarios/getExecutionProgress/'+exec_id.value).then(response => {
|
|
||||||
if (response.data.status == 'OK' || response.data.status == 'ERROR') {
|
if (response.data.status == 'OK' || response.data.status == 'ERROR') {
|
||||||
console.log("Condition met, stopping polling.");
|
console.log('Condition met, stopping polling.');
|
||||||
stopPolling();
|
stopPolling();
|
||||||
|
|
||||||
stopTimer();
|
stopTimer();
|
||||||
loading_data.value = false;
|
loading_data.value = false;
|
||||||
data_loaded.value = true;
|
data_loaded.value = true;
|
||||||
scenario_output.value = response.data.stringOutput;
|
scenario_output.value = response.data.stringOutput;
|
||||||
console.log("Response data exec 2:", response.data);
|
console.log('Response data exec 2:', response.data);
|
||||||
exec_id.value = response.data.scenarioExecution_id
|
exec_id.value = response.data.scenarioExecution_id;
|
||||||
scenario_response_message.value = null //if != null, next scenario starts with old message
|
scenario_response_message.value = null; //if != null, next scenario starts with old message
|
||||||
console.log("Scenario 3:", scenario.value);
|
console.log('Scenario 3:', scenario.value);
|
||||||
|
|
||||||
// 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')) {
|
||||||
@@ -573,7 +490,7 @@ if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload')) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const showFileContent = (base64String, type) => {
|
const showFileContent = (base64String, type) => {
|
||||||
try {
|
try {
|
||||||
// Decodifica la stringa Base64
|
// Decodifica la stringa Base64
|
||||||
const binaryString = atob(base64String);
|
const binaryString = atob(base64String);
|
||||||
@@ -602,29 +519,29 @@ if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload')) {
|
|||||||
fileContent.value = 'Errore durante la decodifica o il parsing del file.';
|
fileContent.value = 'Errore durante la decodifica o il parsing del file.';
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to start polling
|
// Function to start polling
|
||||||
function startPolling() {
|
function startPolling() {
|
||||||
// Set polling interval (every 2.5 seconds in this case)
|
// Set polling interval (every 2.5 seconds in this case)
|
||||||
pollingInterval = setInterval(pollBackendAPI, 2500);
|
pollingInterval = setInterval(pollBackendAPI, 2500);
|
||||||
console.log("Polling started.");
|
console.log('Polling started.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to stop polling
|
// Function to stop polling
|
||||||
function stopPolling() {
|
function stopPolling() {
|
||||||
clearInterval(pollingInterval);
|
clearInterval(pollingInterval);
|
||||||
loadingStore.exectuion_loading = false;
|
loadingStore.exectuion_loading = false;
|
||||||
loadingStore.setIdExecLoading("");
|
loadingStore.setIdExecLoading('');
|
||||||
|
|
||||||
console.log("Polling stopped.");
|
console.log('Polling stopped.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const extractFiles = async (base64String) => {
|
const extractFiles = async (base64String) => {
|
||||||
try {
|
try {
|
||||||
// Decodifica la base64 in un array di byte
|
// Decodifica la base64 in un array di byte
|
||||||
const byteCharacters = atob(base64String);
|
const byteCharacters = atob(base64String);
|
||||||
const byteNumbers = Array.from(byteCharacters, char => char.charCodeAt(0));
|
const byteNumbers = Array.from(byteCharacters, (char) => char.charCodeAt(0));
|
||||||
const byteArray = new Uint8Array(byteNumbers);
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
|
||||||
// Carica il file zip con JSZip
|
// Carica il file zip con JSZip
|
||||||
@@ -634,14 +551,11 @@ if (scenario.value.inputs.some((input) => input.name === 'MultiFileUpload')) {
|
|||||||
// Ottieni tutti i file (compresi quelli nelle sottocartelle)
|
// Ottieni tutti i file (compresi quelli nelle sottocartelle)
|
||||||
|
|
||||||
fileNamesOutput.value = getFileNames(zipData);
|
fileNamesOutput.value = getFileNames(zipData);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error extracting zip:', error);
|
console.error('Error extracting zip:', error);
|
||||||
|
|
||||||
fileNamesOutput.value = [];
|
fileNamesOutput.value = [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Funzione ricorsiva per ottenere tutti i file (anche quelli dentro le cartelle)
|
// Funzione ricorsiva per ottenere tutti i file (anche quelli dentro le cartelle)
|
||||||
@@ -650,7 +564,8 @@ const getFileNames = (zipData) => {
|
|||||||
|
|
||||||
// Esplora tutti i file nel file zip, considerando anche le sottocartelle
|
// Esplora tutti i file nel file zip, considerando anche le sottocartelle
|
||||||
zipData.forEach((relativePath, file) => {
|
zipData.forEach((relativePath, file) => {
|
||||||
if (!file.dir) { // Escludiamo le cartelle
|
if (!file.dir) {
|
||||||
|
// Escludiamo le cartelle
|
||||||
files.push(relativePath); // Aggiungiamo il percorso relativo del file
|
files.push(relativePath); // Aggiungiamo il percorso relativo del file
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -686,12 +601,11 @@ const getFileNames = (zipData) => {
|
|||||||
// console.log('Removing pending file:', file);
|
// console.log('Removing pending file:', file);
|
||||||
// callback(file, index);
|
// callback(file, index);
|
||||||
// };
|
// };
|
||||||
async function updateRating(newRating) {
|
async function updateRating(newRating) {
|
||||||
|
ScenarioService.updateScenarioExecRating(exec_id.value, newRating.value)
|
||||||
ScenarioService.updateScenarioExecRating(exec_id.value,newRating.value).then((response) => {
|
.then((response) => {
|
||||||
|
|
||||||
console.log('response:', response);
|
console.log('response:', response);
|
||||||
if (response.data === "OK") {
|
if (response.data === 'OK') {
|
||||||
rating.value = newRating.value;
|
rating.value = newRating.value;
|
||||||
console.log('Rating aggiornato con successo:', response.data);
|
console.log('Rating aggiornato con successo:', response.data);
|
||||||
toast.add({
|
toast.add({
|
||||||
@@ -701,7 +615,7 @@ const getFileNames = (zipData) => {
|
|||||||
life: 3000 // Durata della notifica in millisecondi
|
life: 3000 // Durata della notifica in millisecondi
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.error('Errore nell\'aggiornamento del rating', response.data);
|
console.error("Errore nell'aggiornamento del rating", 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
|
||||||
@@ -709,10 +623,10 @@ const getFileNames = (zipData) => {
|
|||||||
life: 3000 // Durata della notifica in millisecondi
|
life: 3000 // Durata della notifica in millisecondi
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).catch((error) => {
|
|
||||||
console.error('Errore durante la chiamata al backend:', error);
|
|
||||||
})
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Errore durante la chiamata al backend:', error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funzione per generare un ID univoco
|
// Funzione per generare un ID univoco
|
||||||
@@ -725,29 +639,31 @@ const onRemove = (event, removeUploadedFileCallback, type) => {
|
|||||||
console.log('Removing file:', folderName.value);
|
console.log('Removing file:', folderName.value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
axios.post(
|
axios
|
||||||
|
.post(
|
||||||
`/deleteFile`,
|
`/deleteFile`,
|
||||||
{ fileName: file.name, folderName: folderName.value }, // Invio nome del file come payload
|
{ fileName: file.name, folderName: folderName.value }, // Invio nome del file come payload
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json'
|
||||||
},
|
|
||||||
}
|
}
|
||||||
).then(response => {
|
}
|
||||||
|
)
|
||||||
|
.then((response) => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log('File removed successfully:', response.data);
|
console.log('File removed successfully:', response.data);
|
||||||
|
|
||||||
// Mostra notifica di successo
|
// Mostra notifica di successo
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: "success",
|
severity: 'success',
|
||||||
summary: "Success",
|
summary: 'Success',
|
||||||
detail: "File removed successfully!",
|
detail: 'File removed successfully!',
|
||||||
life: 3000,
|
life: 3000
|
||||||
});
|
});
|
||||||
|
|
||||||
if(type === 'SingleFileUpload'){
|
if (type === 'SingleFileUpload') {
|
||||||
numberPrFiles.value -= 1;
|
numberPrFiles.value -= 1;
|
||||||
console.log("Number of PR files: ", numberPrFiles.value);
|
console.log('Number of PR files: ', numberPrFiles.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggiorna lista dei file caricati
|
// Aggiorna lista dei file caricati
|
||||||
@@ -757,24 +673,24 @@ const onRemove = (event, removeUploadedFileCallback, type) => {
|
|||||||
|
|
||||||
// Mostra notifica di errore
|
// Mostra notifica di errore
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: "error",
|
severity: 'error',
|
||||||
summary: "Error",
|
summary: 'Error',
|
||||||
detail: `Failed to remove file. Status: ${response.statusText}`,
|
detail: `Failed to remove file. Status: ${response.statusText}`,
|
||||||
life: 3000,
|
life: 3000
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
})
|
||||||
|
.catch((error) => {
|
||||||
console.error('Error while removing file:', error);
|
console.error('Error while removing file:', error);
|
||||||
|
|
||||||
// Mostra notifica di errore
|
// Mostra notifica di errore
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: "error",
|
severity: 'error',
|
||||||
summary: "Error",
|
summary: 'Error',
|
||||||
detail: `Error while removing file: ${error.message}`,
|
detail: `Error while removing file: ${error.message}`,
|
||||||
life: 3000,
|
life: 3000
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error while removing file:', error);
|
console.error('Error while removing file:', error);
|
||||||
}
|
}
|
||||||
@@ -784,7 +700,6 @@ const onRemove = (event, removeUploadedFileCallback, type) => {
|
|||||||
// // Metodo per gestire la rimozione dei file
|
// // Metodo per gestire la rimozione dei file
|
||||||
// console.log('Removing file:', folderName.value);
|
// console.log('Removing file:', folderName.value);
|
||||||
|
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// axios.post(
|
// axios.post(
|
||||||
// `http://localhost:8081/deleteFile`,
|
// `http://localhost:8081/deleteFile`,
|
||||||
@@ -823,50 +738,48 @@ const onRemove = (event, removeUploadedFileCallback, type) => {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
const onUpload = (event, uploadType) => {
|
const onUpload = (event, uploadType) => {
|
||||||
console.log("response upload ",event.xhr.response);
|
console.log('response upload ', event.xhr.response);
|
||||||
|
|
||||||
const { xhr } = event; // Estraggo l'oggetto XMLHttpRequest
|
const { xhr } = event; // Estraggo l'oggetto XMLHttpRequest
|
||||||
|
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
// Risposta OK
|
// Risposta OK
|
||||||
|
|
||||||
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) {
|
||||||
console.log("File uploaded:", event.files);
|
console.log('File uploaded:', event.files);
|
||||||
formData.value['SingleFileUpload'] = event.files[0].name; // Nome del primo file
|
formData.value['SingleFileUpload'] = event.files[0].name; // Nome del primo file
|
||||||
} else {
|
} else {
|
||||||
formData.value['SingleFileUpload'] = "UnknownFile";
|
formData.value['SingleFileUpload'] = 'UnknownFile';
|
||||||
}
|
}
|
||||||
numberPrFiles.value += 1;
|
numberPrFiles.value += 1;
|
||||||
console.log("Number of PR files: ", numberPrFiles.value);
|
console.log('Number of PR files: ', numberPrFiles.value);
|
||||||
}
|
}
|
||||||
formData.value['MultiFileUpload'] = xhr.response;
|
formData.value['MultiFileUpload'] = xhr.response;
|
||||||
|
|
||||||
console.log("Form value upload ",formData.value['MultiFileUpload']);
|
console.log('Form value upload ', formData.value['MultiFileUpload']);
|
||||||
|
|
||||||
console.log("Upload completato con successo. Risposta:", xhr.response);
|
console.log('Upload completato con successo. Risposta:', xhr.response);
|
||||||
|
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: "success",
|
severity: 'success',
|
||||||
summary: "Success",
|
summary: 'Success',
|
||||||
detail: "File uploaded successfully!",
|
detail: 'File uploaded successfully!',
|
||||||
life: 3000,
|
life: 3000
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
} else {
|
|
||||||
// Errore durante l'upload
|
// Errore durante l'upload
|
||||||
console.error("Errore durante l'upload. Stato:", xhr.status, "Risposta:", xhr.response);
|
console.error("Errore durante l'upload. Stato:", xhr.status, 'Risposta:', xhr.response);
|
||||||
|
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: "error",
|
severity: 'error',
|
||||||
summary: "Error",
|
summary: 'Error',
|
||||||
detail: `Failed to upload file. Stato: ${xhr.status}`,
|
detail: `Failed to upload file. Stato: ${xhr.status}`,
|
||||||
life: 3000,
|
life: 3000
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Funzione per scaricare il file
|
// Funzione per scaricare il file
|
||||||
const downloadZipFile = async (fileName) => {
|
const downloadZipFile = async (fileName) => {
|
||||||
@@ -896,7 +809,7 @@ function downloadFile() {
|
|||||||
// Converti la stringa base64 in un blob
|
// Converti la stringa base64 in un blob
|
||||||
const base64String = this.scenario_output.value;
|
const base64String = this.scenario_output.value;
|
||||||
const byteCharacters = atob(base64String);
|
const byteCharacters = atob(base64String);
|
||||||
const byteNumbers = Array.from(byteCharacters, char => char.charCodeAt(0));
|
const byteNumbers = Array.from(byteCharacters, (char) => char.charCodeAt(0));
|
||||||
const byteArray = new Uint8Array(byteNumbers);
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
const blob = new Blob([byteArray]);
|
const blob = new Blob([byteArray]);
|
||||||
|
|
||||||
@@ -904,7 +817,7 @@ function downloadFile() {
|
|||||||
const url = window.URL.createObjectURL(blob);
|
const url = window.URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = 'sf_document-'+exec_id.value+'.docx';// Specifica il nome del file
|
a.download = 'sf_document-' + exec_id.value + '.docx'; // Specifica il nome del file
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
|
|
||||||
@@ -914,9 +827,7 @@ function downloadFile() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Errore durante il download del file:', error);
|
console.error('Errore durante il download del file:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const formatSize = (bytes) => {
|
const formatSize = (bytes) => {
|
||||||
const k = 1024;
|
const k = 1024;
|
||||||
@@ -931,25 +842,23 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-wrapper {
|
.input-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-width-input {
|
.full-width-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.editor ol {
|
.editor ol {
|
||||||
list-style-type: decimal !important;
|
list-style-type: decimal !important;
|
||||||
@@ -959,6 +868,7 @@ 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 */
|
||||||
@@ -973,18 +883,11 @@ pre {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content {
|
.markdown-content {
|
||||||
white-space: pre-wrap; /* Gestisce correttamente gli spazi e i ritorni a capo */
|
|
||||||
word-wrap: break-word; /* Spezza le parole lunghe */
|
word-wrap: break-word; /* Spezza le parole lunghe */
|
||||||
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
||||||
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 */
|
||||||
padding: 10px; /* Margini interni */
|
|
||||||
border-radius: 5px; /* Bordo arrotondato */
|
|
||||||
font-family: Arial, sans-serif; /* Puoi scegliere un font leggibile */
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Effetto estetico di ombra */
|
|
||||||
line-height: 1.5; /* Aumenta la leggibilità */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -102,10 +102,8 @@ const scenarioTypeOp = ref([
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
userPrefStore.fetchUserData().then(() => {
|
userPrefStore.fetchUserData().then(() => {
|
||||||
|
|
||||||
|
|
||||||
scenario_store.fetchScenarios();
|
|
||||||
scenario_store.fetchScenariosCross();
|
scenario_store.fetchScenariosCross();
|
||||||
|
scenario_store.fetchScenarios();
|
||||||
if(userPrefStore.getSelApp != null){
|
if(userPrefStore.getSelApp != null){
|
||||||
scenario_store.fetchApplicationScenarios();
|
scenario_store.fetchApplicationScenarios();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<Dialog v-model:visible="execHermioneDialogVisible" modal :header="modalTitle" :style="{ width: '70rem' }">
|
<Dialog v-model:visible="execHermioneDialogVisible" modal :header="modalTitle" :style="{ width: '70rem' }">
|
||||||
<div v-if="askDialog" class="card flex flex-col gap-4 p-1">
|
<div v-if="askDialog" class="card flex flex-col gap-4 p-1">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<InputText id="question" type="text" placeholder="Write a Question" v-model="userQuestion" />
|
<Textarea id="question" type="text" placeholder="Write a Question" v-model="userQuestion" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<Button label="Submit" @click="askHermione()" class=""/>
|
<Button label="Submit" @click="askHermione()" class=""/>
|
||||||
@@ -24,7 +24,8 @@
|
|||||||
<button class="p-button p-button-primary" @click="addFromDialog(response)">Add to Canvas</button>
|
<button class="p-button p-button-primary" @click="addFromDialog(response)">Add to Canvas</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mt-2">
|
<div class="flex mt-2">
|
||||||
<Editor v-model="response" editorStyle="height: 320px; width: 930px" />
|
<!-- <Editor v-model="response" editorStyle="height: 320px; width: 930px" /> -->
|
||||||
|
<MdPreview class="editor" v-model="response" language="en-US" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -46,12 +47,16 @@ import MdScenarioExctuotionDialog from '@/views/pages/canvas/MdScenarioExecution
|
|||||||
import { Emoji, ExportPDF, Mark } from '@vavt/v3-extension';
|
import { Emoji, ExportPDF, Mark } from '@vavt/v3-extension';
|
||||||
import '@vavt/v3-extension/lib/asset/style.css';
|
import '@vavt/v3-extension/lib/asset/style.css';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { MdEditor } from 'md-editor-v3';
|
import { MdEditor, MdPreview } from 'md-editor-v3';
|
||||||
import 'md-editor-v3/lib/style.css';
|
import 'md-editor-v3/lib/style.css';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref} from 'vue';
|
||||||
|
import { ScenarioStore } from '@/stores/ScenarioStore';
|
||||||
|
import { UserPrefStore } from '@/stores/UserPrefStore';
|
||||||
|
|
||||||
const menu = ref();
|
const menu = ref();
|
||||||
const content = ref('# Welcome to WizardAI Canvas....');
|
const content = ref('# Welcome to WizardAI Canvas.... \n- Right-click to execute one of the available scenarios or ask general questions to Workflow.\n- Select text and right-click to summarize or rewrite it.');
|
||||||
|
const scenario_store = ScenarioStore();
|
||||||
|
const userPrefStore = UserPrefStore();
|
||||||
const scenarios = ref([]);
|
const scenarios = ref([]);
|
||||||
const items = ref([]);
|
const items = ref([]);
|
||||||
const execScenarioDialogVisible = ref(false);
|
const execScenarioDialogVisible = ref(false);
|
||||||
@@ -81,7 +86,7 @@ import { computed, onMounted, ref } from 'vue';
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const onRightClick = (event) => {
|
const onRightClick = async (event) => {
|
||||||
if(editor.value.getSelectedText().length > 0) {
|
if(editor.value.getSelectedText().length > 0) {
|
||||||
items.value=[
|
items.value=[
|
||||||
{label: 'Summarize',icon: 'pi pi-language', command:()=>openEditorAssistant(editor.value.getSelectedText(), "summarize")},
|
{label: 'Summarize',icon: 'pi pi-language', command:()=>openEditorAssistant(editor.value.getSelectedText(), "summarize")},
|
||||||
@@ -89,28 +94,34 @@ import { computed, onMounted, ref } from 'vue';
|
|||||||
]
|
]
|
||||||
}else {
|
}else {
|
||||||
items.value=[
|
items.value=[
|
||||||
{ label: 'Ask Workflow', icon: 'pi pi-language', command:()=>openAskDialog()},
|
{label: 'Ask Workflow', icon: 'pi pi-language', command:()=>openAskDialog()},
|
||||||
{ separator: true},
|
{separator: true}
|
||||||
{ label: 'Execute Scenario', icon: 'pi pi-volume-up',items: scenarioMenuItems}
|
|
||||||
]
|
]
|
||||||
|
if (scenarioMenuItems().length > 0) {
|
||||||
|
items.value.push({label: 'Execute Scenario', icon: 'pi pi-volume-up', items: scenarioMenuItems()})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
menu.value.show(event);
|
menu.value.show(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function scenarioMenuItems() {
|
||||||
const scenarioMenuItems = computed(() => {
|
|
||||||
const scenario_items = [];
|
const scenario_items = [];
|
||||||
for (let i = 0; i < scenarios.value.length; i++) {
|
scenario_store.filteredScenariosCanvas.forEach(scenario => {
|
||||||
|
if (scenario.canvasEnabled) {
|
||||||
scenario_items.push({
|
scenario_items.push({
|
||||||
label: scenarios.value[i].name,
|
label: scenario.name,
|
||||||
icon: 'pi pi-file',
|
icon: 'pi pi-wrench',
|
||||||
command: () => {
|
command: () => {
|
||||||
executeScenario(scenarios.value[i]);
|
executeScenario(scenario);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return scenario_items;
|
return scenario_items;
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const executeScenario = (scenario) => {
|
const executeScenario = (scenario) => {
|
||||||
@@ -197,10 +208,18 @@ import { computed, onMounted, ref } from 'vue';
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
ScenarioService.getScenarios().then(resp=>{
|
userPrefStore.fetchUserData().then(() => {
|
||||||
scenarios.value = resp.data
|
scenario_store.fetchScenariosCross();
|
||||||
})
|
scenario_store.fetchScenarios();
|
||||||
|
if(userPrefStore.getSelApp != null){
|
||||||
|
scenario_store.fetchApplicationScenarios();
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
scenarioMenuItems();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const toolbars = ref([
|
const toolbars = ref([
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
<div v-if="!data_loaded && !loading_data" class="card flex flex-col gap-4 p-1">
|
<div v-if="!data_loaded && !loading_data" class="card flex flex-col gap-4 p-1">
|
||||||
<div v-for="input in scenario.inputs" :key="input.name" class="flex flex-col gap-2" >
|
<!-- <div v-for="input in scenario.inputs" :key="input.name" class="flex flex-col gap-2" >
|
||||||
<label :for="input.name">{{ input.label }}</label>
|
<label :for="input.name">{{ input.label }}</label>
|
||||||
<component
|
<component
|
||||||
:is="getInputComponent(input.type)"
|
:is="getInputComponent(input.type)"
|
||||||
@@ -9,51 +8,304 @@
|
|||||||
v-model="inputData[input.name]"
|
v-model="inputData[input.name]"
|
||||||
class="full-width-input"
|
class="full-width-input"
|
||||||
/>
|
/>
|
||||||
|
</div> -->
|
||||||
|
<div v-for="input in scenario.inputs" :key="input.name" :class="['input-container', input.type === 'textarea' ? 'col-span-12' : '']">
|
||||||
|
<div v-if="input.type === 'singlefile' || input.type === 'singlefile_acceptall'">
|
||||||
|
<label :for="input.name">
|
||||||
|
<b>{{ input.label }}</b>
|
||||||
|
<i class="pi pi-info-circle text-violet-600 cursor-pointer" v-tooltip="'Upload one document from the suggested types. Mandatory if you want to execute scenario.'"></i>
|
||||||
|
</label>
|
||||||
|
<div>
|
||||||
|
<FileUpload
|
||||||
|
:name="'MultiFileUpload'"
|
||||||
|
:customUpload="false"
|
||||||
|
:url="uploadUrlPR"
|
||||||
|
@upload="(event) => onUpload(event, 'SingleFileUpload')"
|
||||||
|
:multiple="false"
|
||||||
|
:accept="acceptedFormats"
|
||||||
|
auto
|
||||||
|
:showUploadButton="false"
|
||||||
|
:showCancelButton="false"
|
||||||
|
:maxFileSize="10000000"
|
||||||
|
v-model:files="uploadedFiles"
|
||||||
|
>
|
||||||
|
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
||||||
|
<div class="pt-4">
|
||||||
|
<!-- Tabella per file in caricamento -->
|
||||||
|
<div v-if="uploadedFiles.length > 0">
|
||||||
|
<table class="table-auto w-full border-collapse border border-gray-200">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="border border-gray-300 p-2">Name</th>
|
||||||
|
<th class="border border-gray-300 p-2">Dimension</th>
|
||||||
|
<th class="border border-gray-300 p-2">Status</th>
|
||||||
|
<th class="border border-gray-300 p-2">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(file, index) in uploadedFiles" :key="file.name + file.size" class="hover:bg-gray-50">
|
||||||
|
<td class="border border-gray-300 p-2">{{ file.name }}</td>
|
||||||
|
<td class="border border-gray-300 p-2">{{ formatSize(file.size) }}</td>
|
||||||
|
<td class="border border-gray-300 p-2">
|
||||||
|
<Badge value="UPLOADED" severity="success" />
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-2">
|
||||||
|
<Button label="Remove" @click="onRemove({ file, index }, removeUploadedFileCallback, 'SingleFileUpload')" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #empty>
|
||||||
|
<div class="flex items-center justify-center flex-col">
|
||||||
|
<i class="pi pi-cloud-upload !border-2 !rounded-full !p-8 !text-4xl !text-muted-color" />
|
||||||
|
<p class="mt-6 mb-0">Drag and drop files to here to upload.</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</FileUpload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="input.type === 'multifile'">
|
||||||
|
<label :for="input.name">
|
||||||
|
<b>{{ input.label }} </b>
|
||||||
|
<i class="pi pi-info-circle text-violet-600 cursor-pointer" v-tooltip="'Upload others documents of .docx, .msg, .text type. Optional.'"></i>
|
||||||
|
</label>
|
||||||
|
<div>
|
||||||
|
<FileUpload
|
||||||
|
:name="'MultiFileUpload'"
|
||||||
|
:customUpload="false"
|
||||||
|
:url="uploadUrlOther"
|
||||||
|
@upload="(event) => onUpload(event, 'MultiFileUpload')"
|
||||||
|
:multiple="true"
|
||||||
|
accept=".msg,.txt,.docx"
|
||||||
|
auto
|
||||||
|
:showUploadButton="false"
|
||||||
|
:showCancelButton="false"
|
||||||
|
:maxFileSize="10000000"
|
||||||
|
v-model:files="uploadedFiles"
|
||||||
|
>
|
||||||
|
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
||||||
|
<div class="pt-4">
|
||||||
|
<!-- Tabella per file in caricamento -->
|
||||||
|
<div v-if="uploadedFiles.length > 0">
|
||||||
|
<table class="table-auto w-full border-collapse border border-gray-200">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="border border-gray-300 p-2">Name</th>
|
||||||
|
<th class="border border-gray-300 p-2">Dimension</th>
|
||||||
|
<th class="border border-gray-300 p-2">Status</th>
|
||||||
|
<th class="border border-gray-300 p-2">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(file, index) in uploadedFiles" :key="file.name + file.size" class="hover:bg-gray-50">
|
||||||
|
<td class="border border-gray-300 p-2">{{ file.name }}</td>
|
||||||
|
<td class="border border-gray-300 p-2">{{ formatSize(file.size) }}</td>
|
||||||
|
<td class="border border-gray-300 p-2">
|
||||||
|
<Badge value="UPLOADED" severity="success" />
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-2">
|
||||||
|
<Button label="Remove" @click="onRemove({ file, index }, removeUploadedFileCallback, 'MultiFileUpload')" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #empty>
|
||||||
|
<div class="flex items-center justify-center flex-col">
|
||||||
|
<i class="pi pi-cloud-upload !border-2 !rounded-full !p-8 !text-4xl !text-muted-color" />
|
||||||
|
<p class="mt-6 mb-0">Drag and drop files to here to upload.</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</FileUpload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<label :for="input.name"
|
||||||
|
><b>{{ input.label }}</b></label
|
||||||
|
>
|
||||||
|
<div class="input-wrapper">
|
||||||
|
<component :is="getInputComponent(input.type)" :id="input.name" v-model="formData[input.name]" :options="input.options" class="full-width-input" :disabled="loadingStore.exectuion_loading" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<Button label="Submit" @click="execScenario" class=""/>
|
<Button :disabled="loadingStore.exectuion_loading || !isInputFilled" label="Execute" @click="execScenario" size="large" iconPos="right" icon="pi pi-cog"></Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading_data" class="flex flex-col items-center">
|
||||||
|
<div class="flex justify-center mt-4">
|
||||||
|
<jellyfish-loader :loading="loadingStore.exectuion_loading" scale="1" color="#A100FF" />
|
||||||
</div>
|
</div>
|
||||||
<ProgressSpinner v-if="loading_data" style="width: 50px; height: 50px" strokeWidth="8" fill="transparent"
|
<div v-if="scenario_response_message && scenario_response_message.includes('/')">
|
||||||
animationDuration=".5s" aria-label="Custom ProgressSpinner" />
|
<span>{{ scenario_response_message }}</span>
|
||||||
<div v-if="data_loaded" class="card flex flex-col gap-4 p-1">
|
</div>
|
||||||
|
<div v-else>Starting execution...</div>
|
||||||
|
<div class="flex justify-center" style="margin-bottom: 30px">
|
||||||
|
<p>Time elapsed: </p>
|
||||||
|
<div id="timer" class="timer">00:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="data_loaded">
|
||||||
|
<Panel class="mt-6">
|
||||||
|
<template #header>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="font-bold">Workflow Response</span>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="flex items-center gap-2 p-0">
|
||||||
|
<button class="p-button p-button-primary" @click="addToCanvas">Add to Canvas</button>
|
||||||
|
</div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #icons>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<div class="flex">
|
||||||
|
<Rating :modelValue="rating" :stars="5" @change="updateRating($event)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Button severity="secondary" rounded @click="openDebug" v-tooltip.left="'View code'">
|
||||||
|
<i class="pi pi-code"></i>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="card flex flex-col gap-4 w-full">
|
||||||
<div class="flex items-center gap-2 p-0">
|
<div class="flex items-center gap-2 p-0">
|
||||||
<button class="p-button p-button-primary" @click="addToCanvas">Add to Canvas</button>
|
<button class="p-button p-button-primary" @click="addToCanvas">Add to Canvas</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div class="flex mt-2">
|
|
||||||
<MdPreview class="editor" v-model="scenario_output" language="en-US" />
|
<MdPreview class="editor" v-model="scenario_output" language="en-US" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Panel>
|
||||||
|
<Dialog v-model:visible="debug_modal" maximizable modal :header="scenario.name" :style="{ width: '75%' }" :breakpoints="{ '1199px': '75vw', '575px': '90vw' }">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="card flex flex-col gap-4 w-full">
|
||||||
|
<JsonEditorVue v-model="exec_scenario" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref ,defineEmits} from 'vue';
|
import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue';
|
||||||
import InputText from 'primevue/inputtext';
|
import { ScenarioService } from '@/service/ScenarioService';
|
||||||
import ProgressSpinner from 'primevue/progressspinner';
|
import { LoadingStore } from '@/stores/LoadingStore';
|
||||||
import Select from 'primevue/select';
|
import axios from 'axios';
|
||||||
import Textarea from 'primevue/textarea';
|
import JsonEditorVue from 'json-editor-vue';
|
||||||
import axios from 'axios';
|
import JSZip from 'jszip';
|
||||||
import { MdEditor } from 'md-editor-v3';
|
import { marked } from 'marked';
|
||||||
import { MdPreview } from 'md-editor-v3';
|
import { MdPreview } from 'md-editor-v3';
|
||||||
import 'md-editor-v3/lib/style.css';
|
import 'md-editor-v3/lib/style.css';
|
||||||
import ChangeImpactOutputViewer from '@/components/ChangeImpactOutputViewer.vue';
|
import moment from 'moment';
|
||||||
|
import { usePrimeVue } from 'primevue/config';
|
||||||
|
import InputText from 'primevue/inputtext';
|
||||||
|
import Select from 'primevue/select';
|
||||||
|
import Textarea from 'primevue/textarea';
|
||||||
|
import { useConfirm } from 'primevue/useconfirm';
|
||||||
|
import { useToast } from 'primevue/usetoast';
|
||||||
|
import { computed, onMounted, ref, defineEmits} from 'vue';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { JellyfishLoader } from 'vue3-spinner';
|
||||||
|
|
||||||
|
const props = defineProps(['scenario'])
|
||||||
|
const emit = defineEmits(['add'])
|
||||||
|
const loadingStore = LoadingStore();
|
||||||
|
const toast = useToast();
|
||||||
|
const zip = ref(null);
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const value = ref('');
|
||||||
|
const rating = ref(0);
|
||||||
|
const scenario_response = ref(null);
|
||||||
|
const scenario_output = ref(null);
|
||||||
|
const scenario_response_message = 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);
|
||||||
|
let pollingInterval = null;
|
||||||
|
const folderName = ref('');
|
||||||
|
const fileNamesOutput = ref([]);
|
||||||
|
// URL di upload
|
||||||
|
const uploadUrlBase = import.meta.env.VITE_BACKEND_URL;
|
||||||
|
const uploadUrl = ref('');
|
||||||
|
const uploadUrlPR = ref('');
|
||||||
|
const uploadUrlOther = ref('');
|
||||||
|
// File che l'utente ha selezionato
|
||||||
|
const uploadedFiles = ref([]);
|
||||||
|
const numberPrFiles = ref(0);
|
||||||
|
const acceptedFormats = ref('.docx');
|
||||||
|
// :url="`http://localhost:8081/uploadListFiles/${folderName}`"
|
||||||
|
|
||||||
|
// Stato per l'ID univoco della cartella
|
||||||
|
const uniqueFolderId = ref(generateUniqueId());
|
||||||
|
const confirm = useConfirm();
|
||||||
|
|
||||||
|
const $primevue = usePrimeVue();
|
||||||
|
const files = ref([]);
|
||||||
|
const fileContent = ref('');
|
||||||
|
const fileType = ref('');
|
||||||
|
const reqMultiFile = ref(false);
|
||||||
|
|
||||||
|
let startTime = ref(null);
|
||||||
|
let timerInterval = ref(null);
|
||||||
|
|
||||||
|
function startTimer() {
|
||||||
|
startTime = Date.now();
|
||||||
|
timerInterval = setInterval(() => {
|
||||||
|
const elapsedTime = moment.duration(Date.now() - startTime);
|
||||||
|
document.getElementById('timer').textContent = moment.utc(elapsedTime.asMilliseconds()).format('mm:ss');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopTimer() {
|
||||||
|
clearInterval(timerInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInputFilled = computed(() => {
|
||||||
|
var isFilled = true;
|
||||||
|
if (props.scenario.inputs === undefined) {
|
||||||
|
console.log('No inputs found');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
props.scenario.inputs.forEach((input) => {
|
||||||
|
if (formData.value[input.name] === undefined || formData.value[input.name] === '') {
|
||||||
|
console.log('Input not filled: ', input.name);
|
||||||
|
isFilled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return isFilled;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('MdScenarioExecutionDialog montato!');
|
||||||
|
const timestamp = Date.now(); //Ottiene il timestamp corrente
|
||||||
|
const randomNumber = Math.floor(Math.random() * 1000);
|
||||||
|
folderName.value = `${timestamp}_${randomNumber}`;
|
||||||
|
uploadUrl.value = uploadUrlBase + '/uploadListFiles/' + folderName.value;
|
||||||
|
uploadUrlPR.value = uploadUrl.value + '/PR';
|
||||||
|
uploadUrlOther.value = uploadUrl.value + '/OTHER';
|
||||||
|
console.log('Upload URL:', uploadUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const getInputComponent = (type) => {
|
||||||
const loading_data = ref(false);
|
|
||||||
const data_loaded = ref(false);
|
|
||||||
const props = defineProps(['scenario']);
|
|
||||||
const emit = defineEmits(['add'])
|
|
||||||
|
|
||||||
const inputData = ref({});
|
|
||||||
const scenario_output = ref("");
|
|
||||||
|
|
||||||
const getInputComponent = (type) => {
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
return InputText;
|
return InputText;
|
||||||
@@ -64,42 +316,419 @@
|
|||||||
default:
|
default:
|
||||||
return InputText;
|
return InputText;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const execScenario = () => {
|
const execScenario = () => {
|
||||||
|
if (numberPrFiles.value !== 1 && reqMultiFile.value) {
|
||||||
|
toast.add({
|
||||||
|
severity: 'warn', // Tipo di notifica (errore)
|
||||||
|
summary: 'Attention', // Titolo della notifica
|
||||||
|
detail: 'You can upload only 1 PR file. Please remove others.' // Messaggio dettagliato
|
||||||
|
});
|
||||||
|
} else {
|
||||||
loading_data.value = true;
|
loading_data.value = true;
|
||||||
data_loaded.value = false;
|
data_loaded.value = false;
|
||||||
|
rating.value = 0;
|
||||||
|
startTimer();
|
||||||
|
|
||||||
|
loadingStore.exectuion_loading = true;
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
scenario_id: props.scenario.id,
|
scenario_id: props.scenario.id,
|
||||||
inputs: { ...inputData.value }
|
inputs: { ...formData.value }
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(data);
|
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);
|
||||||
|
// Start polling
|
||||||
|
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;
|
||||||
|
debug_modal.value = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
axios.post('/scenarios/execute', data)
|
const pollBackendAPI = () => {
|
||||||
.then(response => {
|
axios.get('/scenarios/getExecutionProgress/' + exec_id.value).then((response) => {
|
||||||
|
if (response.data.status == 'OK' || response.data.status == 'ERROR') {
|
||||||
|
console.log('Condition met, stopping polling.');
|
||||||
|
stopPolling();
|
||||||
|
|
||||||
|
stopTimer();
|
||||||
loading_data.value = false;
|
loading_data.value = false;
|
||||||
data_loaded.value = true;
|
data_loaded.value = true;
|
||||||
console.log(response);
|
|
||||||
scenario_output.value = response.data.stringOutput;
|
scenario_output.value = response.data.stringOutput;
|
||||||
|
console.log('Response data exec 2:', response.data);
|
||||||
|
exec_id.value = response.data.scenarioExecution_id;
|
||||||
|
scenario_response_message.value = null; //if != null, next scenario starts with old message
|
||||||
|
console.log('Scenario 3:', props.scenario);
|
||||||
|
|
||||||
})
|
// Controlla se l'array `inputs` contiene un elemento con `name = 'MultiFileUpload'`
|
||||||
.catch(error => {
|
if (props.scenario.inputs.some((input) => input.name === 'MultiFileUpload')) {
|
||||||
console.error('Error executing scenario:', error);
|
if (response.data.status == 'OK') {
|
||||||
|
// Accedi al primo step e controlla se esiste l'attributo `codegenie_output_type`
|
||||||
|
const firstStep = props.scenario.steps[0];
|
||||||
|
if (firstStep?.attributes?.['codegenie_output_type']) {
|
||||||
|
// Controlla se `codegenie_output_type` è uguale a 'FILE'
|
||||||
|
// if (firstStep.attributes['codegenie_output_type'] === 'FILE') {
|
||||||
|
// console.log('base64 ', scenario_output.value);
|
||||||
|
|
||||||
|
// Chiama la funzione `extractFiles` con il valore di `scenario_output.value`
|
||||||
|
//extractFiles(scenario_output.value);
|
||||||
|
//}
|
||||||
|
if (firstStep.attributes['codegenie_output_type'] == 'FILE') {
|
||||||
|
//console.log('base64 ', scenario_output.value)
|
||||||
|
//extractFiles(scenario_output.value, 'output', zipOutput)
|
||||||
|
fileType.value = 'FILE';
|
||||||
|
} else if (firstStep.attributes['codegenie_output_type'] == 'MARKDOWN') {
|
||||||
|
fileType.value = 'MARKDOWN';
|
||||||
|
showFileContent(scenario_output.value, 'MARKDOWN');
|
||||||
|
} else if (firstStep.attributes['codegenie_output_type'] == 'JSON') {
|
||||||
|
fileType.value = 'JSON';
|
||||||
|
showFileContent(scenario_output.value, 'JSON');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Error in execution');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Condition not met, polling continues.');
|
||||||
|
scenario_response.value = response.data;
|
||||||
|
scenario_response_message.value = response.data.message;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addToCanvas = () => {
|
const showFileContent = (base64String, type) => {
|
||||||
console.log("Aggiunto");
|
try {
|
||||||
emit('add',scenario_output.value)
|
// Decodifica la stringa Base64
|
||||||
|
const binaryString = atob(base64String);
|
||||||
|
const binaryLength = binaryString.length;
|
||||||
|
const bytes = new Uint8Array(binaryLength);
|
||||||
|
|
||||||
|
for (let i = 0; i < binaryLength; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converti i byte in una stringa leggibile
|
||||||
|
const textContent = new TextDecoder().decode(bytes);
|
||||||
|
|
||||||
|
// Gestione del tipo di file
|
||||||
|
if (type === 'MARKDOWN') {
|
||||||
|
//fileType.value = 'markdown';
|
||||||
|
fileContent.value = marked(textContent); // Converte Markdown in HTML
|
||||||
|
} else if (type === 'JSON') {
|
||||||
|
//fileType.value = 'json';
|
||||||
|
const jsonObject = JSON.parse(textContent); // Parse JSON
|
||||||
|
fileContent.value = JSON.stringify(jsonObject, null, 2); // Formatta JSON
|
||||||
|
} else {
|
||||||
|
fileContent.value = 'Tipo di file non supportato.';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
fileContent.value = 'Errore durante la decodifica o il parsing del file.';
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to start polling
|
||||||
|
function startPolling() {
|
||||||
|
// Set polling interval (every 2.5 seconds in this case)
|
||||||
|
pollingInterval = setInterval(pollBackendAPI, 2500);
|
||||||
|
console.log('Polling started.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to stop polling
|
||||||
|
function stopPolling() {
|
||||||
|
clearInterval(pollingInterval);
|
||||||
|
loadingStore.exectuion_loading = false;
|
||||||
|
loadingStore.setIdExecLoading('');
|
||||||
|
|
||||||
|
console.log('Polling stopped.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const extractFiles = async (base64String) => {
|
||||||
|
try {
|
||||||
|
// Decodifica la base64 in un array di byte
|
||||||
|
const byteCharacters = atob(base64String);
|
||||||
|
const byteNumbers = Array.from(byteCharacters, (char) => char.charCodeAt(0));
|
||||||
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
|
||||||
|
// Carica il file zip con JSZip
|
||||||
|
const zipData = await JSZip.loadAsync(byteArray);
|
||||||
|
zip.value = zipData;
|
||||||
|
|
||||||
|
// Ottieni tutti i file (compresi quelli nelle sottocartelle)
|
||||||
|
|
||||||
|
fileNamesOutput.value = getFileNames(zipData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error extracting zip:', error);
|
||||||
|
|
||||||
|
fileNamesOutput.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Funzione ricorsiva per ottenere tutti i file (anche quelli dentro le cartelle)
|
||||||
|
const getFileNames = (zipData) => {
|
||||||
|
const files = [];
|
||||||
|
|
||||||
|
// Esplora tutti i file nel file zip, considerando anche le sottocartelle
|
||||||
|
zipData.forEach((relativePath, file) => {
|
||||||
|
if (!file.dir) {
|
||||||
|
// Escludiamo le cartelle
|
||||||
|
files.push(relativePath); // Aggiungiamo il percorso relativo del file
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return files;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function updateRating(newRating) {
|
||||||
|
ScenarioService.updateScenarioExecRating(exec_id.value, newRating.value)
|
||||||
|
.then((response) => {
|
||||||
|
console.log('response:', response);
|
||||||
|
if (response.data === 'OK') {
|
||||||
|
rating.value = newRating.value;
|
||||||
|
console.log('Rating aggiornato con successo:', response.data);
|
||||||
|
toast.add({
|
||||||
|
severity: 'success', // Tipo di notifica (successo)
|
||||||
|
summary: 'Success', // Titolo della notifica
|
||||||
|
detail: 'Rating updated with success.', // Messaggio dettagliato
|
||||||
|
life: 3000 // Durata della notifica in millisecondi
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Errore nell'aggiornamento del rating", response.data);
|
||||||
|
toast.add({
|
||||||
|
severity: 'error', // Tipo di notifica (errore)
|
||||||
|
summary: 'Error', // Titolo della notifica
|
||||||
|
detail: 'Error updating rating. Try later.', // Messaggio dettagliato
|
||||||
|
life: 3000 // Durata della notifica in millisecondi
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Errore durante la chiamata al backend:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Funzione per generare un ID univoco
|
||||||
|
function generateUniqueId() {
|
||||||
|
return Date.now(); // Puoi usare anche UUID.randomUUID() o una libreria simile
|
||||||
|
}
|
||||||
|
|
||||||
|
const onRemove = (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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error while removing file:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUpload = (event, uploadType) => {
|
||||||
|
console.log('response upload ', event.xhr.response);
|
||||||
|
|
||||||
|
const { xhr } = event; // Estraggo l'oggetto XMLHttpRequest
|
||||||
|
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
// Risposta OK
|
||||||
|
|
||||||
|
if (uploadType === 'SingleFileUpload') {
|
||||||
|
//formData.value['SingleFileUpload'] = "OK";
|
||||||
|
if (event.files && event.files.length > 0) {
|
||||||
|
console.log('File uploaded:', event.files);
|
||||||
|
formData.value['SingleFileUpload'] = event.files[0].name; // Nome del primo file
|
||||||
|
} else {
|
||||||
|
formData.value['SingleFileUpload'] = 'UnknownFile';
|
||||||
|
}
|
||||||
|
numberPrFiles.value += 1;
|
||||||
|
console.log('Number of PR files: ', numberPrFiles.value);
|
||||||
|
}
|
||||||
|
formData.value['MultiFileUpload'] = xhr.response;
|
||||||
|
|
||||||
|
console.log('Form value upload ', formData.value['MultiFileUpload']);
|
||||||
|
|
||||||
|
console.log('Upload completato con successo. Risposta:', xhr.response);
|
||||||
|
|
||||||
|
toast.add({
|
||||||
|
severity: 'success',
|
||||||
|
summary: 'Success',
|
||||||
|
detail: 'File uploaded successfully!',
|
||||||
|
life: 3000
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Errore durante l'upload
|
||||||
|
console.error("Errore durante l'upload. Stato:", xhr.status, 'Risposta:', xhr.response);
|
||||||
|
|
||||||
|
toast.add({
|
||||||
|
severity: 'error',
|
||||||
|
summary: 'Error',
|
||||||
|
detail: `Failed to upload file. Stato: ${xhr.status}`,
|
||||||
|
life: 3000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Funzione per scaricare il file
|
||||||
|
const downloadZipFile = async (fileName) => {
|
||||||
|
if (!zip.value) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Estrai il file dallo zip
|
||||||
|
const fileContent = await zip.value.file(fileName).async('blob');
|
||||||
|
const url = URL.createObjectURL(fileContent);
|
||||||
|
|
||||||
|
// Crea un link per scaricare il file
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = fileName;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error downloading file "${fileName}":`, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function downloadFile() {
|
||||||
|
try {
|
||||||
|
// Converti la stringa base64 in un blob
|
||||||
|
const base64String = this.scenario_output;
|
||||||
|
const byteCharacters = atob(base64String);
|
||||||
|
const byteNumbers = Array.from(byteCharacters, (char) => char.charCodeAt(0));
|
||||||
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
const blob = new Blob([byteArray]);
|
||||||
|
|
||||||
|
// Crea un link temporaneo per il download
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'sf_document-' + exec_id.value + '.docx'; // Specifica il nome del file
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
|
||||||
|
// Rimuovi il link temporaneo
|
||||||
|
document.body.removeChild(a);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Errore durante il download del file:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatSize = (bytes) => {
|
||||||
|
const k = 1024;
|
||||||
|
const sizes = $primevue.config.locale.fileSizeTypes;
|
||||||
|
|
||||||
|
if (bytes === 0) {
|
||||||
|
return `0 ${sizes[0]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
const truncatedSize = Math.trunc(bytes / Math.pow(k, i)); // Troncamento del valore
|
||||||
|
|
||||||
|
return `${truncatedSize} ${sizes[i]}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToCanvas = () => {
|
||||||
|
console.log("Added");
|
||||||
|
emit('add',scenario_output.value)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.editor ol {
|
||||||
|
list-style-type: decimal !important;
|
||||||
|
}
|
||||||
|
|
||||||
<style >
|
.editor ul {
|
||||||
|
list-style-type: disc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 {
|
.editor ol {
|
||||||
list-style-type: decimal !important;
|
list-style-type: decimal !important;
|
||||||
@@ -108,4 +737,25 @@
|
|||||||
.editor ul {
|
.editor ul {
|
||||||
list-style-type: disc !important;
|
list-style-type: disc !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap; /* Fa andare a capo il contenuto automaticamente */
|
||||||
|
word-wrap: break-word; /* Interrompe le parole troppo lunghe */
|
||||||
|
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
||||||
|
max-width: 100%; /* Imposta una larghezza massima pari al contenitore genitore */
|
||||||
|
overflow-x: auto; /* Aggiunge uno scorrimento orizzontale solo se necessario */
|
||||||
|
background-color: #f5f5f5; /* Colore di sfondo opzionale per migliorare leggibilità */
|
||||||
|
padding: 10px; /* Spaziatura interna */
|
||||||
|
border-radius: 5px; /* Bordo arrotondato opzionale */
|
||||||
|
font-family: monospace; /* Font specifico per codice */
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* Ombra per migliorare estetica */
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content {
|
||||||
|
word-wrap: break-word; /* Spezza le parole lunghe */
|
||||||
|
overflow-wrap: break-word; /* Per compatibilità con più browser */
|
||||||
|
max-width: 100%; /* Adatta il contenuto alla larghezza del contenitore */
|
||||||
|
overflow-x: auto; /* Aggiunge scorrimento orizzontale solo se necessario */
|
||||||
|
background-color: #f5f5f5; /* Sfondo per distinguere il contenuto */
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user