You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

272 lines
6.9 KiB

<template>
<v-card>
<v-card-title>
{{ $t('dataset.importDataTitle') }}
</v-card-title>
<v-card-text>
<v-overlay :value="isImporting">
<v-progress-circular
indeterminate
size="64"
/>
</v-overlay>
<v-select
v-model="selected"
:items="catalog"
item-text="name"
label="File format"
outlined
/>
<v-form v-model="valid">
<v-text-field
v-for="(item, key) in textFields"
:key="key"
v-model="option[key]"
:label="item.title"
:rules="requiredRules"
outlined
/>
<v-select
v-for="(val, key) in selectFields"
:key="key"
v-model="option[key]"
:items="val.enum"
:label="val.title"
outlined
>
<template #selection="{ item }">
{{ toVisualize(item) }}
</template>
<template #item="{ item }">
{{ toVisualize(item) }}
</template>
</v-select>
</v-form>
<v-sheet
v-if="selected"
:dark="!$vuetify.theme.dark"
:light="$vuetify.theme.dark"
class="mb-5 pa-5"
>
<pre>{{ example }}</pre>
</v-sheet>
<file-pond
v-if="selected && acceptedFileTypes !== '*'"
ref="pond"
chunk-uploads="true"
label-idle="Drop files here..."
:allow-multiple="true"
:accepted-file-types="acceptedFileTypes"
:server="server"
:files="myFiles"
@processfile="handleFilePondProcessfile"
@removefile="handleFilePondRemovefile"
/>
<file-pond
v-if="selected && acceptedFileTypes === '*'"
ref="pond"
chunk-uploads="true"
label-idle="Drop files here..."
:allow-multiple="true"
:server="server"
:files="myFiles"
@processfile="handleFilePondProcessfile"
@removefile="handleFilePondRemovefile"
/>
<v-data-table
v-if="errors.length > 0"
:headers="headers"
:items="errors"
class="elevation-1"
></v-data-table>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
class='text-capitalize me-2 primary'
:disabled="isDisabled"
@click="importDataset"
>
Import
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import Cookies from 'js-cookie'
import vueFilePond from "vue-filepond"
import "filepond/dist/filepond.min.css"
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type"
const FilePond = vueFilePond(
FilePondPluginFileValidateType,
)
export default {
components: {
FilePond,
},
layout: 'project',
data() {
return {
catalog: [],
selected: null,
myFiles: [],
option: {'column_data': '', 'column_label': '', 'delimiter': ''},
taskId: null,
polling: null,
errors: [],
headers: [
{ text: 'Filename', value: 'filename' },
{ text: 'Line', value: 'line' },
{ text: 'Message', value: 'message' }
],
requiredRules: [
v => !!v || 'Field value is required'
],
server: {
url: '/v1/fp',
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
},
process: {
url: '/process/',
method: 'POST',
},
patch: '/patch/',
revert: '/revert/',
restore: '/restore/',
load: '/load/',
fetch: '/fetch/'
},
uploadedFiles: [],
valid: false,
isImporting: false,
}
},
computed: {
isDisabled() {
return this.uploadedFiles.length === 0 || this.taskId !== null || !this.valid
},
properties() {
const item = this.catalog.find(item => item.name === this.selected)
if (item) {
return item.properties
} else {
return {}
}
},
textFields() {
const asArray = Object.entries(this.properties)
const textFields = asArray.filter(([key, value]) => !('enum' in value))
return Object.fromEntries(textFields)
},
selectFields() {
const asArray = Object.entries(this.properties)
const textFields = asArray.filter(([key, value]) => 'enum' in value)
return Object.fromEntries(textFields)
},
acceptedFileTypes() {
const item = this.catalog.find(item => item.name === this.selected)
if (item) {
return item.acceptTypes
} else {
return ''
}
},
example() {
const item = this.catalog.find(item => item.name === this.selected)
if (item) {
const column_data = 'column_data'
const column_label = 'column_label'
if (column_data in this.option && column_label in this.option) {
return item.example.replaceAll(column_data, this.option[column_data])
.replaceAll(column_label, this.option[column_label])
.trim()
} else {
return item.example.trim()
}
} else {
return ''
}
}
},
watch: {
selected() {
const item = this.catalog.find(item => item.name === this.selected)
for (const [key, value] of Object.entries(item.properties)) {
this.option[key] = value.default
}
this.myFiles = []
for (const file of this.uploadedFiles) {
this.$services.parse.revert(file.serverId)
}
this.uploadedFiles = []
this.errors = []
}
},
async created() {
this.catalog = await this.$services.catalog.list(this.$route.params.id)
this.pollData()
},
beforeDestroy() {
clearInterval(this.polling)
},
methods: {
handleFilePondProcessfile(error, file) {
console.log(error)
this.uploadedFiles.push(file)
this.$nextTick()
},
handleFilePondRemovefile(error, file) {
console.log(error)
const index = this.uploadedFiles.findIndex(item => item.id === file.id)
if (index > -1) {
this.uploadedFiles.splice(index, 1)
this.$nextTick()
}
},
async importDataset() {
this.isImporting = true
this.taskId = await this.$services.parse.analyze(
this.$route.params.id,
this.selected,
this.uploadedFiles.map(item => item.serverId),
this.option
)
},
pollData() {
this.polling = setInterval(async() => {
if (this.taskId) {
const res = await this.$services.taskStatus.get(this.taskId)
if (res.ready) {
this.taskId = null
this.errors = res.result.error
this.myFiles = []
this.uploadedFiles = []
this.isImporting = false
}
}
}, 3000)
},
toVisualize(text) {
if (text === '\t') {
return 'Tab'
} else if (text === ' ') {
return 'Space'
} else if (text === '') {
return 'None'
} else {
return text
}
}
},
};
</script>