From ce1ea0b5b749d4ca4842093a22620a3c5b3db6d7 Mon Sep 17 00:00:00 2001 From: "thomas.blanc.2@etu.univ-amu.fr" <gltron3000@gmail.com> Date: Tue, 12 May 2020 14:50:26 +0200 Subject: [PATCH] Added account edit & model add/edit improvement --- src/components/LayersEditor.vue | 4 +- src/components/LoginForm.vue | 7 +- src/components/ModelUpload.vue | 166 ++++++++++++++++++++++++++++++++ src/components/RegisterForm.vue | 52 ++++++++-- src/router/index.js | 5 + src/views/About.vue | 2 +- src/views/Account.vue | 22 ++++- src/views/Docs.vue | 2 +- src/views/Model.vue | 9 +- src/views/ModelAdd.vue | 31 ++++-- src/views/ModelEdit.vue | 26 +++-- src/views/UserEdit.vue | 40 ++++++++ 12 files changed, 335 insertions(+), 31 deletions(-) create mode 100644 src/components/ModelUpload.vue create mode 100644 src/views/UserEdit.vue diff --git a/src/components/LayersEditor.vue b/src/components/LayersEditor.vue index 3d4d3ee..c3b86da 100644 --- a/src/components/LayersEditor.vue +++ b/src/components/LayersEditor.vue @@ -15,13 +15,13 @@ <b-input :placeholder="'Layer ' + index + ' name'" v-model="layer.name"/> <p class="control"> - <b-upload v-model="file" accept=".py"> + <b-upload v-model="layer.file" accept=".py"> <a class="button is-primary"> <b-icon icon="upload"></b-icon> <span>Upload layer file</span> </a> </b-upload> - <span class="file-name" v-if="file">{{ file.name }}</span> + <span class="file-name" v-if="layer.file">{{ layer.file.name }}</span> </p> </b-field> diff --git a/src/components/LoginForm.vue b/src/components/LoginForm.vue index 44afa98..8c90933 100644 --- a/src/components/LoginForm.vue +++ b/src/components/LoginForm.vue @@ -5,6 +5,8 @@ <p class="modal-card-title">Login</p> </header> <section class="modal-card-body"> + <h2 class="subtitle has-text-danger">{{errorMessage}}</h2> + <b-field label="Email"> <b-input type="email" v-model="email" placeholder="email" required/> </b-field> @@ -29,7 +31,8 @@ export default { data () { return { email: '', - password: '' + password: '', + errorMessage: null } }, methods: { @@ -40,7 +43,7 @@ export default { this.$parent.close() this.$router.go() } else { - this.$buefy.toast.open('Email ou mot de passe incorect') + this.errorMessage = 'Email or password incorect' } }, async login (email, password) { diff --git a/src/components/ModelUpload.vue b/src/components/ModelUpload.vue new file mode 100644 index 0000000..f5e52b6 --- /dev/null +++ b/src/components/ModelUpload.vue @@ -0,0 +1,166 @@ +<template> + <div class="modal-card"> + <b-progress :value="progress" size="is-large" show-value :type="status"> + {{message}} + </b-progress> + </div> +</template> + +<script> +export default { + name: 'ModelUpload', + props: { + model: { + type: Object, + default: function () { + return {} + } + } + }, + data () { + return { + message: '', + progress: 0, + status: 'is-primary', + stausMessage: '', + modelId: null + } + }, + mounted () { + this.saveModel() + }, + methods: { + setProgress (step) { + switch (step) { + case 0: + this.message = 'Sending description' + this.progress = 25 + break + case 1: + this.message = 'Sending model file' + this.progress = 50 + break + case 2: + this.message = 'Sending custom layers model' + this.progress = 75 + break + case 3: + this.message = 'Upload completed !' + this.progress = 100 + this.status = 'is-success' + break + } + }, + setError (message) { + this.message = message + this.status = 'is-danger' + }, + async saveModel () { + this.setProgress(0) + var response = await this.uploadModel() + if (response.error) { + this.setError(response.message) + return + } else { + this.modelId = response.id + } + + if (this.model.file !== undefined) { + console.log('Upload model ' + this.model.file) + this.setProgress(1) + if (!await this.uploadModelFile()) { + this.setError('Model upload error') + return + } + } + + if (this.model.customLayers !== undefined) { + console.log('Upload layers ' + this.model.customLayers) + this.setProgress(2) + if (!await this.uploadLayers()) { + this.setError('Custom layer upload error') + return + } + } + + this.setProgress(3) + }, + async uploadModel () { + const url = this.$serverurl + 'models' + const token = await localStorage.getItem('token') + try { + const response = await fetch(url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + token + }, + body: JSON.stringify({ + name: this.model.name, + shortDescription: this.model.shortDescription, + longDescription: this.model.longDescription, + performance: this.model.performance, + tags: this.model.tags, + customLayers: this.model.customLayers + }) + }) + return await response.json() + } catch (error) { + return null + } + }, + async uploadModelFile () { + const data = new FormData() + const url = this.$serverurl + 'models?id=' + this.modelId + '/upload' + const token = await localStorage.getItem('token') + + data.append('model', this.model.file) + + try { + const response = await fetch(url, { + method: 'POST', + headers: { + Authorization: 'Bearer ' + token + }, + body: data + }) + return response !== 200 + } catch (error) { + return null + } + }, + async uploadLayers () { + const token = await localStorage.getItem('token') + for (var i = 0; i < this.model.customLayers.length; i++) { + const layer = this.model.customLayers[i] + const data = new FormData() + const url = this.$serverurl + 'models?id=' + this.modelId + '/layer?id=' + i + + console.log('Upload layers ' + i + ' | ' + layer.file) + if (layer.file === undefined) continue + + data.append('layer', layer.file) + + try { + const response = await fetch(url, { + method: 'POST', + headers: { + Authorization: 'Bearer ' + token + }, + body: data + }) + if (response !== 200) return false + } catch (error) { + return false + } + } + return true + } + } +} +</script> + +<style> + +</style> diff --git a/src/components/RegisterForm.vue b/src/components/RegisterForm.vue index 7151ed2..ddf9554 100644 --- a/src/components/RegisterForm.vue +++ b/src/components/RegisterForm.vue @@ -5,25 +5,26 @@ <p class="modal-card-title">Sign up</p> </header> <section class="modal-card-body"> + <h2 class="subtitle has-text-danger">{{errorMessage}}</h2> <b-field label="Email"> - <b-input type="email" v-model="email" placeholder="email" required/> + <b-input type="email" v-model="email" placeholder="email" required maxlength="50"/> </b-field> <b-field label="Username"> - <b-input v-model="username" placeholder="username" required/> + <b-input v-model="username" placeholder="username" required maxlength="30"/> </b-field> <b-field label="Password"> - <b-input type="password" v-model="password" password-reveal placeholder="password" required/> + <b-input type="password" v-model="password" password-reveal placeholder="password" required maxlength="50"/> </b-field> <b-field label="Confirm password"> - <b-input type="password" v-model="passwordConfirm" password-reveal placeholder="password" required/> + <b-input type="password" v-model="passwordConfirm" password-reveal placeholder="password" required maxlength="50"/> </b-field> </section> <footer class="modal-card-foot"> - <button class="button is-primary">Make account</button> + <button class="button is-primary" @click="onRegister">Make account</button> </footer> </div> </form> @@ -37,7 +38,46 @@ export default { email: '', username: '', password: '', - passwordConfirm: '' + passwordConfirm: '', + errorMessage: null + } + }, + methods: { + async onRegister () { + if (this.password !== this.passwordConfirm) { + this.errorMessage = 'Passwords are different' + return + } + const response = await this.register(this.username, this.email, this.password) + if (response.error) { + this.errorMessage = response.message + } else { + await localStorage.setItem('token', response.token) + this.$parent.close() + this.$router.go() + } + }, + async register (username, email, password) { + const url = this.$serverurl + 'user' + try { + const response = await fetch( + url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: email, + username: username, + password: password + }) + } + ) + return await response.json() + } catch (error) { + return null + } } } } diff --git a/src/router/index.js b/src/router/index.js index 0792ffa..0e97d71 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -25,6 +25,11 @@ const routes = [ name: 'Search', component: () => import('../views/Search.vue') }, + { + path: '/useredit', + name: 'UserEdit', + component: () => import('../views/UserEdit.vue') + }, { path: '/model', name: 'Model', diff --git a/src/views/About.vue b/src/views/About.vue index 77a63ab..8a780a3 100644 --- a/src/views/About.vue +++ b/src/views/About.vue @@ -1,5 +1,5 @@ <template> - <div class="about"> + <div class="about container"> <h1>About page</h1> </div> </template> diff --git a/src/views/Account.vue b/src/views/Account.vue index 925ec11..dd88602 100644 --- a/src/views/Account.vue +++ b/src/views/Account.vue @@ -3,8 +3,22 @@ <div class="box"> <h1 class="title">Welcome {{account.username}}</h1> <div class="buttons"> - <b-button tag="router-link" :to="{ name: 'ModelAdd' }">Add new model</b-button> - <b-button>Change account details</b-button> + <b-button + icon-left="plus" + type="is-info" + tag="router-link" + :to="{ name: 'ModelAdd' }" + > + Add new model + </b-button> + <b-button + icon-left="pencil" + type="is-info" + tag="router-link" + :to="{ name: 'UserEdit' }" + > + Change account details + </b-button> </div> </div> <div class="box"> @@ -46,5 +60,7 @@ export default { </script> <style scoped> - +.account{ + margin-top: 20px; +} </style> diff --git a/src/views/Docs.vue b/src/views/Docs.vue index 609fdb4..6a2b47d 100644 --- a/src/views/Docs.vue +++ b/src/views/Docs.vue @@ -1,5 +1,5 @@ <template> - <div class="docs"> + <div class="docs container"> <h1>Documentation page</h1> </div> </template> diff --git a/src/views/Model.vue b/src/views/Model.vue index 440874f..17e0c51 100644 --- a/src/views/Model.vue +++ b/src/views/Model.vue @@ -38,7 +38,14 @@ </div> </div> <div class="box"> - <div class="content" v-html="compiledLongDescription"></div> + <b-tabs> + <b-tab-item label="Read me"> + <div class="content" v-html="compiledLongDescription"></div> + </b-tab-item> + + <b-tab-item label="Layers"> + </b-tab-item> + </b-tabs> </div> <div class="box"> <Comments v-bind:comments="model.comments"/> diff --git a/src/views/ModelAdd.vue b/src/views/ModelAdd.vue index 51c3502..46f7b29 100644 --- a/src/views/ModelAdd.vue +++ b/src/views/ModelAdd.vue @@ -3,25 +3,25 @@ <b-steps v-model="activeStep"> <b-step-item step="1" label="Description" clickable> <b-field label="Model name"> - <b-input maxlength="30" size="is-large"/> + <b-input maxlength="30" size="is-large" v-model="model.name"/> </b-field> <b-field label="Short description"> - <b-input maxlength="200" type="textarea"/> + <b-input maxlength="200" type="textarea" v-model="model.shortDescription"/> </b-field> <b-field label="Long description"> - <markdownEditor/> + <markdownEditor v-bind:input="model.longDescription"/> </b-field> </b-step-item> <b-step-item step="2" label="Tags" clickable> - <tagEditor/> + <tagEditor v-bind:tags="model.tags"/> </b-step-item> <b-step-item step="3" label="Files" clickable> <b-field label="Model"> - <b-upload v-model="dropFiles" drag-drop expanded> + <b-upload v-model="model.file" drag-drop expanded> <section class="section"> <div class="content has-text-centered"> <p> @@ -35,14 +35,18 @@ </b-step-item> <b-step-item step="4" label="Custom layers" clickable> - <layersEditor/> + <layersEditor v-bind:layers="model.customLayers"/> </b-step-item> <b-step-item step="5" label="Finish" clickable> - <b-button expanded size="is-large" type="is-success">Confirm and upload</b-button> + <b-button expanded size="is-large" type="is-success" @click="openUploadModal">Confirm and upload</b-button> </b-step-item> </b-steps> + + <b-modal :active.sync="isUploadModalActive" has-modal-card trap-focus aria-role="dialog" aria-modal> + <ModelUpload v-bind:model="model"/> + </b-modal> </div> </template> @@ -50,17 +54,26 @@ import markdownEditor from '@/components/MarkdownEditor.vue' import tagEditor from '@/components/TagEditor.vue' import layersEditor from '@/components/LayersEditor.vue' +import ModelUpload from '@/components/ModelUpload.vue' export default { name: 'ModelAdd', components: { markdownEditor, tagEditor, - layersEditor + layersEditor, + ModelUpload }, data () { return { - activeStep: 0 + model: {}, + activeStep: 0, + isUploadModalActive: false + } + }, + methods: { + openUploadModal () { + this.isUploadModalActive = true } } } diff --git a/src/views/ModelEdit.vue b/src/views/ModelEdit.vue index 69f30ac..d088c26 100644 --- a/src/views/ModelEdit.vue +++ b/src/views/ModelEdit.vue @@ -25,7 +25,7 @@ <div class="columns"> <div class="column"> <b-field label="Model"> - <b-upload v-model="dropFiles" drag-drop expanded> + <b-upload v-model="model.file" drag-drop expanded> <section class="section"> <div class="content has-text-centered"> <p> @@ -45,9 +45,13 @@ </div> <div class="box"> - <b-button >Cancel</b-button> - <b-button type="is-success">Save</b-button> + <b-button tag="router-link" :to="{ name: 'Account' }">Cancel</b-button> + <b-button type="is-success" @click="openUploadModal">Save</b-button> </div> + + <b-modal :active.sync="isUploadModalActive" has-modal-card trap-focus aria-role="dialog" aria-modal> + <ModelUpload v-bind:model="model"/> + </b-modal> </div> </template> @@ -55,13 +59,15 @@ import markdownEditor from '@/components/MarkdownEditor.vue' import tagEditor from '@/components/TagEditor.vue' import layersEditor from '@/components/LayersEditor.vue' +import ModelUpload from '@/components/ModelUpload.vue' export default { name: 'ModelEdit', components: { markdownEditor, tagEditor, - layersEditor + layersEditor, + ModelUpload }, props: { model: { @@ -71,15 +77,23 @@ export default { } } }, + data () { + return { + isUploadModalActive: false + } + }, methods: { - async saveModel () { - + openUploadModal () { + this.isUploadModalActive = true } } } </script> <style scoped> +.modelEdit{ + margin-top: 20px; +} .rightColumn { border-left: 2px solid whitesmoke; } diff --git a/src/views/UserEdit.vue b/src/views/UserEdit.vue new file mode 100644 index 0000000..65f1cf6 --- /dev/null +++ b/src/views/UserEdit.vue @@ -0,0 +1,40 @@ +<template> + <div class="userEdit container"> + <h1 class="title">Account details</h1> + + <b-field label="Email"> + <b-input v-model="user.email" type="email" maxlength="50"/> + </b-field> + + <b-field label="Username"> + <b-input v-model="user.username" maxlength="30"/> + </b-field> + + <b-field label="Password"> + <b-input type="password" v-model="user.password" password-reveal maxlength="50"/> + </b-field> + </div> +</template> + +<script> +export default { + name: 'UserEdit', + props: { + user: { + type: Object, + default: function () { + return {} + } + } + }, + methods: { + saveUser () { + + } + } +} +</script> + +<style> + +</style> -- GitLab