From d66cf51241d391ccd17f80767e4056f0b786c0e0 Mon Sep 17 00:00:00 2001 From: Kirill Stytsenko <kirill@styts.com> Date: Tue, 1 Mar 2022 18:01:10 +0100 Subject: [PATCH] Various improvements in csv import. Closes #131 Former-commit-id: ee99e9141359abe2678a3cd1284092ff8a0f6098 --- fda-ui/components/dialogs/CreateDB.vue | 6 +-- .../_database_id/table/_table_id/import.vue | 19 +++++++-- .../database/_database_id/table/import.vue | 41 +++++++++++-------- fda-ui/utils/index.js | 32 +++++++++++++++ 4 files changed, 74 insertions(+), 24 deletions(-) create mode 100644 fda-ui/utils/index.js diff --git a/fda-ui/components/dialogs/CreateDB.vue b/fda-ui/components/dialogs/CreateDB.vue index ee59c65cbf..ee5bcf87c8 100644 --- a/fda-ui/components/dialogs/CreateDB.vue +++ b/fda-ui/components/dialogs/CreateDB.vue @@ -68,6 +68,8 @@ </template> <script> +const { notEmpty } = require('@/utils') + export default { data () { return { @@ -120,9 +122,7 @@ export default { setTimeout(resolve, ms) }) }, - notEmpty (str) { - return typeof str === 'string' && str.trim().length > 0 - }, + notEmpty, async createDB () { let res // create a container diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/import.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/import.vue index 08b02651cd..7fd8e3bb71 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/import.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/import.vue @@ -73,11 +73,14 @@ </v-row> </v-card-text> <v-card-actions> - <v-col> - <v-btn :disabled="!file" :loading="loading" color="primary" @click="upload">Next</v-btn> - </v-col> + <v-btn :disabled="!file" :loading="loading" color="primary" @click="upload">Upload</v-btn> + <v-btn :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}`" outlined> + <v-icon>mdi-table</v-icon> + View + </v-btn> </v-card-actions> </v-card> + <v-breadcrumbs :items="items" class="pa-0 mt-2" /> </div> </template> <script> @@ -107,7 +110,15 @@ export default { false_element: null }, file: null, - fileLocation: null + fileLocation: null, + items: [ + { text: 'Databases', to: '/container', activeClass: '' }, + { + text: `${this.$route.params.database_id}`, + to: `/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/info`, + activeClass: '' + } + ] } }, computed: { diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue index f9b0e65e51..881a42b638 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/table/import.vue @@ -14,7 +14,7 @@ <v-col cols="8"> <v-text-field v-model="tableCreate.name" - required + :rules="[v => notEmpty(v) || $t('Required')]" autocomplete="off" label="Name *" /> </v-col> @@ -23,14 +23,14 @@ <v-col cols="8"> <v-text-field v-model="tableCreate.description" - required + :rules="[v => notEmpty(v) || $t('Required')]" autocomplete="off" label="Description *" /> </v-col> </v-row> <v-row dense> <v-col cols="8"> - <v-btn :disabled="!step1Valid" color="primary" type="submit" @click="step = 2"> + <v-btn :disabled="!validStep1" color="primary" type="submit" @click="step = 2"> Continue </v-btn> </v-col> @@ -48,7 +48,7 @@ <v-col cols="8"> <v-select v-model="tableCreate.separator" - :rules="[rules.required]" + :rules="[v => notEmpty(v) || $t('Required')]" :items="separators" required hint="Character separating the values" @@ -59,10 +59,12 @@ <v-col cols="8"> <v-text-field v-model="tableCreate.skip_lines" - :rules="[rules.required, rules.positive]" + :rules="[ + v => notEmpty(v) || $t('Required'), + v => isNonNegativeInteger(v) || $t('Number of lines to skip')]" type="number" required - hint="Skip n lines from the top" + hint="Skip n lines from the top. These may include comments or the header of column names." label="Skip Lines *" placeholder="e.g. 0" /> </v-col> @@ -96,7 +98,7 @@ </v-row> <v-row dense> <v-col cols="6"> - <v-btn :disabled="!tableCreate.separator || !tableCreate.skip_lines" :loading="loading" color="primary" type="submit" @click="step = 3">Next</v-btn> + <v-btn :disabled="!validStep2 || !tableCreate.separator || !tableCreate.skip_lines" :loading="loading" color="primary" type="submit" @click="step = 3">Next</v-btn> </v-col> </v-row> </v-form> @@ -216,6 +218,8 @@ </div> </template> <script> +const { notEmpty, isNonNegativeInteger } = require('@/utils') + export default { name: 'TableFromCSV', components: { @@ -245,8 +249,7 @@ export default { } ], rules: { - required: value => !!value || 'Required', - positive: value => value >= 0 || 'Positive number' + required: value => !!value || 'Required' }, dateFormats: [], tableCreate: { @@ -257,7 +260,7 @@ export default { true_element: null, null_element: null, separator: ',', - skip_lines: 0 + skip_lines: '1' }, loading: false, file: null, @@ -277,9 +280,6 @@ export default { } }, computed: { - step1Valid () { - return this.tableCreate.name !== null && this.tableCreate.name.length > 0 && this.tableCreate.description !== null && this.tableCreate.description.length > 0 - }, token () { return this.$store.state.token } @@ -288,6 +288,8 @@ export default { this.loadDateFormats() }, methods: { + notEmpty, + isNonNegativeInteger, submit () { this.$refs.form.validate() }, @@ -343,19 +345,24 @@ export default { }, async createTable () { /* make enum values to array */ - this.tableCreate.columns.forEach((column) => { + const validColumns = this.tableCreate.columns.map((column) => { // validate `id` column: must be a PK if (column.name === 'id' && (!column.primary_key)) { this.$toast.error('Column `id` has to be a Primary Key') - return + return false } - if (column.enum_values == null) { - return + if (column.enum_values === null) { + return false } if (column.enum_values.length > 0) { column.enum_values = column.enum_values.split(',') } + return true }) + + // bail out if there is a problem with one of the columns + if (!validColumns.every(Boolean)) { return } + const createUrl = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table` let createResult try { diff --git a/fda-ui/utils/index.js b/fda-ui/utils/index.js new file mode 100644 index 0000000000..58c28e61d3 --- /dev/null +++ b/fda-ui/utils/index.js @@ -0,0 +1,32 @@ +function notEmpty (str) { + return typeof str === 'string' && str.trim().length > 0 +} + +/** + * From https://stackoverflow.com/questions/10834796/validate-that-a-string-is-a-positive-integer + + Tests: + + "0" : true + "23" : true + "-10" : false + "10.30" : false + "-40.1" : false + "string" : false + "1234567890" : true + "129000098131766699.1" : false + "-1e7" : false + "1e7" : true + "1e10" : false + "1edf" : false + " " : false + "" : false + */ +function isNonNegativeInteger (str) { + return str >>> 0 === parseFloat(str) +} + +module.exports = { + notEmpty, + isNonNegativeInteger +} -- GitLab