diff --git a/src/components/Filters.vue b/src/components/Filters.vue index 76954fa729a82716a00624c0ce1fbec5b1c64426..c9e4c2d040dce593d55c60afe92e523706f576f4 100644 --- a/src/components/Filters.vue +++ b/src/components/Filters.vue @@ -16,12 +16,12 @@ <b-slider-tick :value="3">10000</b-slider-tick> </b-slider> </b-menu-list> - <b-menu-list v-for="tag in tags" v-bind:key="tag.name" :label="tag.name"> - <div v-for="type in tag.types" v-bind:key="type" class="field"> + <b-menu-list v-for="category in tags" v-bind:key="category.name" :label="category.name"> + <div v-for="tag in category.tags" v-bind:key="tag" class="field"> <b-checkbox - :native-value="type" + :native-value="tag.name" v-model="checkboxGroup" - @input="changeTag">{{type}}</b-checkbox> + @input="changeTag">{{tag.name}}</b-checkbox> </div> </b-menu-list> </div> diff --git a/src/components/LoginForm.vue b/src/components/LoginForm.vue index 8c9093325dc76ac32690a1a85a1e6498712d7252..b3dc08df24c9b135bbe1db6b50faaf91205cf5fc 100644 --- a/src/components/LoginForm.vue +++ b/src/components/LoginForm.vue @@ -7,8 +7,8 @@ <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 label="Username"> + <b-input v-model="username" placeholder="username" required/> </b-field> <b-field label="Password"> @@ -30,24 +30,26 @@ export default { name: 'LoginForm', data () { return { - email: '', + username: '', password: '', errorMessage: null } }, methods: { async onLogin () { - var response = await this.login(this.email, this.password) - if (response.token !== null) { - await localStorage.setItem('token', response.token) + var response = await this.login(this.username, this.password) + console.log('LOGIN RESPONSE ' + response) + if (response !== null) { + console.log('LOGIN TOKEN OK') + await localStorage.setItem('token', response.message) this.$parent.close() this.$router.go() } else { - this.errorMessage = 'Email or password incorect' + this.errorMessage = 'Username or password incorect' } }, - async login (email, password) { - const url = this.$serverurl + 'auth' + async login (username, password) { + const url = this.$serverurl + 'login' try { const response = await fetch( url, { @@ -57,7 +59,7 @@ export default { 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email, + username: username, password: password }) } diff --git a/src/components/ModelCard.vue b/src/components/ModelCard.vue index 2c56fec228b7d183d5b75a7187665d2cc65f02af..6202d5a29e8e0b0eab8978a197d0bb51ef2fc9d3 100644 --- a/src/components/ModelCard.vue +++ b/src/components/ModelCard.vue @@ -8,13 +8,12 @@ <p> <strong>{{model.name}}</strong> <br> - <small>{{model.author}}</small> - <small>{{new Date(model.modificationDate).toLocaleDateString()}}</small> + <small>{{model.author.username}}</small> - <small>{{new Date(model.modificationDate).toLocaleDateString()}}</small> <br> {{model.shortDescription}} </p> <b-taglist> - <b-tag v-for="tag in model.tags" v-bind:key="tag.type" type="is-info">{{tag.type}}</b-tag> - <b-tag type="is-info">{{model.performance}}%</b-tag> + <b-tag v-for="tag in model.tags" v-bind:key="tag.name" type="is-info">{{tag.name}}</b-tag> </b-taglist> </div> </div> diff --git a/src/components/ModelUpload.vue b/src/components/ModelUpload.vue index 83a4aa84666ac9a73bfa5fda129b839e69c043eb..e535dc5dd8b15b8c7104c188b2fd1663048ab2b7 100644 --- a/src/components/ModelUpload.vue +++ b/src/components/ModelUpload.vue @@ -77,7 +77,7 @@ export default { this.setError(response.message) return } else { - this.modelId = response.id + this.modelId = response.message } if (this.model.file !== undefined) { diff --git a/src/components/RegisterForm.vue b/src/components/RegisterForm.vue index ddf95544b790aec1898724dd3abcbe87d86f4195..b553034e610834591ceac1ad85a989e58612cd26 100644 --- a/src/components/RegisterForm.vue +++ b/src/components/RegisterForm.vue @@ -52,13 +52,13 @@ export default { if (response.error) { this.errorMessage = response.message } else { - await localStorage.setItem('token', response.token) + await localStorage.setItem('token', response.message) this.$parent.close() this.$router.go() } }, async register (username, email, password) { - const url = this.$serverurl + 'user' + const url = this.$serverurl + 'user/signup' try { const response = await fetch( url, { diff --git a/src/components/TagEditor.vue b/src/components/TagEditor.vue index 7a565b4d6505124e7024ffced9f484128f99bd05..f78f2898426cfcf72950fb0fe858eafaa5222e16 100644 --- a/src/components/TagEditor.vue +++ b/src/components/TagEditor.vue @@ -1,38 +1,59 @@ <template> <div class="tagEditor"> - <b-field position="is-centered" has-addons> - <b-autocomplete - v-model="tagName" - :open-on-focus="true" - :data="filteredTags" - icon-right="close-circle" - icon-right-clickable> - <template slot="header"> - <a @click="addNewTagDialog"> - <span> Add new... </span> - </a> - </template> - </b-autocomplete> - <p class="control"> - <b-select placeholder="Select a category" v-model="selectedCategory"> - <option v-for="tag in tagList" v-bind:key="tag.type" :value="tag.name">{{tag.name}}</option> - </b-select> - </p> - <p class="control"> - <b-button class="control is-primary" @click="addTagToModel">Add</b-button> - </p> - </b-field> - <b-taglist> <b-tag - v-for="tag in tags" - v-bind:key="tag.type" + v-for="tag in modelTags" + v-bind:key="tag" type="is-info" @close="removeTagFromModel(tag)" closable> - {{tag.type}} + + {{tag}} </b-tag> </b-taglist> + + <b-collapse + class="card" + animation="slide" + v-for="(category, index) of aviablesTags" + :key="index" + :open="isOpen == index" + @open="isOpen = index"> + + <div + slot="trigger" + slot-scope="props" + class="card-header" + role="button"> + + <p class="card-header-title"> + {{category.name}} + </p> + <a class="card-header-icon"> + <b-icon :icon="props.open ? 'menu-down' : 'menu-up'"/> + </a> + </div> + + <div class="card-content"> + <div class="buttons"> + <b-button + v-for="tag in category.tags" + v-bind:key="tag.name" + @click="addTagToModel(tag.name)" + type="is-info" + rounded> + + {{tag.name}} + </b-button> + + <b-button + @click="addNewTagDialog(category.id)" + type="is-warning" + icon-right="plus" + rounded/> + </div> + </div> + </b-collapse> </div> </template> @@ -40,7 +61,7 @@ export default { name: 'TagEditor', props: { - tags: { + modelTags: { type: Array, default: function () { return [] @@ -49,27 +70,12 @@ export default { }, data () { return { - tagName: '', - selectedCategory: null, - tagList: [] - } - }, - computed: { - filteredTags () { - if (this.selectedCategory === null) return [] - var category = this.tagList.filter((tag) => { - return tag.name === this.selectedCategory - }) - return category[0].types.filter((type) => { - return type - .toString() - .toLowerCase() - .indexOf(this.tagName.toLowerCase()) >= 0 - }) + aviablesTags: [], + isOpen: 0 } }, async mounted () { - this.tagList = await this.getTags() + this.aviablesTags = await this.getTags() }, methods: { async getTags () { @@ -81,36 +87,34 @@ export default { return null } }, - addNewTagDialog () { + addNewTagDialog (categoryId) { this.$buefy.dialog.prompt({ message: 'Tag', inputAttrs: { - maxlength: 20, - value: this.name + maxlength: 20 }, confirmText: 'Add', - onConfirm: (value) => { - this.addNewTag(value) - var category = this.tagList.filter((tag) => { - return tag.name === this.selectedCategory - }) - category[0].types.push(value) + onConfirm: async (value) => { + await this.addNewTag(value, categoryId) + this.aviablesTags = await this.getTags() } }) }, - async addNewTag (tag) { + async addNewTag (tag, categoryId) { const url = this.$serverurl + 'models/tags' + const token = await localStorage.getItem('token') try { const response = await fetch( url, { method: 'POST', headers: { Accept: 'application/json', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + token }, body: JSON.stringify({ - name: this.selectedCategory, - type: tag + name: tag, + categoryId: categoryId }) } ) @@ -119,23 +123,19 @@ export default { return null } }, - addTagToModel () { - this.tags.push({ - name: this.selectedCategory, - type: this.tagName - }) - this.tagName = '' + addTagToModel (tag) { + this.modelTags.push(tag) this.syncToParent() }, removeTagFromModel (tag) { - const index = this.tags.indexOf(tag) + const index = this.modelTags.indexOf(tag) if (index > -1) { - this.tags.splice(index, 1) + this.modelTags.splice(index, 1) } this.syncToParent() }, syncToParent () { - this.$emit('update-tags', this.tags) + this.$emit('update-tags', this.modelTags) } } } diff --git a/src/components/TagEditorOLD.vue b/src/components/TagEditorOLD.vue new file mode 100644 index 0000000000000000000000000000000000000000..23a212badeca5d3f85c94d47f2a455814a629221 --- /dev/null +++ b/src/components/TagEditorOLD.vue @@ -0,0 +1,146 @@ +<template> + <div class="tagEditor"> + <b-field position="is-centered" has-addons> + <b-autocomplete + v-model="tagName" + :open-on-focus="true" + :data="filteredTags" + icon-right="close-circle" + icon-right-clickable> + <template slot="header"> + <a @click="addNewTagDialog"> + <span> Add new... </span> + </a> + </template> + </b-autocomplete> + <p class="control"> + <b-select placeholder="Select a category" v-model="selectedCategory"> + <option v-for="category in tagList" v-bind:key="category.name" :value="category.name">{{category.name}}</option> + </b-select> + </p> + <p class="control"> + <b-button class="control is-primary" @click="addTagToModel">Add</b-button> + </p> + </b-field> + + <b-taglist> + <b-tag + v-for="tag in tags" + v-bind:key="tag.name" + type="is-info" + @close="removeTagFromModel(tag)" + closable> + {{tag.name}} + </b-tag> + </b-taglist> + </div> +</template> + +<script> +export default { + name: 'TagEditor', + props: { + tags: { + type: Array, + default: function () { + return [] + } + } + }, + data () { + return { + tagName: '', + selectedCategory: null, + tagList: [] + } + }, + computed: { + filteredTags () { + if (this.selectedCategory === null) return [] + var category = this.tagList.filter((tag) => { + return tag.name === this.selectedCategory + }) + return category[0].tags.filter((tag) => { + return tag + .toString() + .toLowerCase() + .indexOf(this.tagName.toLowerCase()) >= 0 + }) + } + }, + async mounted () { + this.tagList = await this.getTags() + }, + methods: { + async getTags () { + const url = this.$serverurl + 'models/tags' + const response = await fetch(url) + try { + return await response.json() + } catch (error) { + return null + } + }, + addNewTagDialog () { + this.$buefy.dialog.prompt({ + message: 'Tag', + inputAttrs: { + maxlength: 20, + value: this.name + }, + confirmText: 'Add', + onConfirm: (value) => { + this.addNewTag(value) + var category = this.tagList.filter((tag) => { + return tag.name === this.selectedCategory + }) + category[0].types.push(value) + } + }) + }, + async addNewTag (tag) { + const url = this.$serverurl + 'models/tags' + try { + const response = await fetch( + url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name: this.selectedCategory, + type: tag + }) + } + ) + return await response.json() + } catch (error) { + return null + } + }, + addTagToModel () { + this.tags.push({ + name: this.selectedCategory, + type: this.tagName + }) + this.tagName = '' + this.syncToParent() + }, + removeTagFromModel (tag) { + const index = this.tags.indexOf(tag) + if (index > -1) { + this.tags.splice(index, 1) + } + this.syncToParent() + }, + syncToParent () { + this.$emit('update-tags', this.tags) + } + } +} +</script> + +<style> + +</style> diff --git a/src/main.js b/src/main.js index ab4d3ec04d2b8173a1d693ac8c9fd4fff6800c14..33ad0b8f8fd649d8c90e9d0e1438fcb487d51707 100644 --- a/src/main.js +++ b/src/main.js @@ -9,7 +9,7 @@ Vue.use(Buefy) Vue.config.productionTip = false // Vue.prototype.$serverurl = process.env.VUE_APP_SERVER_URL -Vue.prototype.$serverurl = 'http://localhost:8181/v1/' +Vue.prototype.$serverurl = 'http://localhost:8181/' new Vue({ router, diff --git a/src/views/Model.vue b/src/views/Model.vue index faa6a63e7f0ec6ac917e752f8f0e4682a3af3091..5687df5c0371c15d8acd9fc44fc2126d002414a4 100644 --- a/src/views/Model.vue +++ b/src/views/Model.vue @@ -10,30 +10,28 @@ <h1 class="title is-1">{{model.name}}</h1> <h2 class="subtitle">{{model.shortDescription}}</h2> <b-taglist> - <b-tag v-for="tag in model.tags" v-bind:key="tag.type" type="is-info">{{tag.type}}</b-tag> - <b-tag type="is-info">{{model.performance}}%</b-tag> + <b-tag v-for="tag in model.tags" v-bind:key="tag.name" type="is-info">{{tag.name}}</b-tag> </b-taglist> </div> <div class="column infoColumn"> <h1 class="title is-4">{{model.vote}} votes <b-button size="is-small" icon-left="heart-outline" style="top:-2px"/></h1> - <small>Author: </small><strong>{{model.author}}</strong> + <small>Author: </small><strong>{{model.author.username}}</strong> <br> <small>Added: </small><strong>{{new Date(model.addedDate).toLocaleDateString()}}</strong> <br> <small>Last modification: </small><strong>{{new Date(model.modificationDate).toLocaleDateString()}}</strong> <br> <br> - <b-button type="is-primary" size="is-medium" icon-left="download"> + <b-button type="is-primary" size="is-medium" icon-left="download" @click="downloadModel(model.id)"> Download model </b-button> <hr> <strong>{{model.customLayers.length}} customs layers</strong> <br> <template v-for="layer in model.customLayers"> - <b-button class="customLayer" type="is-primary" icon-left="download" v-bind:key="layer.name"> + <b-button class="customLayer" type="is-primary" icon-left="download" v-bind:key="layer.name" @click="downloadLayer(layer.id)"> Download {{layer.name}} - </b-button> - <br v-bind:key="layer.name"> + </b-button> </template> </div> </div> @@ -91,6 +89,10 @@ export default { } catch (error) { return null } + }, + downloadModel (id) { + }, + downloadLayer (id) { } } } diff --git a/src/views/Search.vue b/src/views/Search.vue index fde2ef7051ef6c033ca520a2be7642a3b567f451..e547c4f73ac6d1c5c476f3c379ef7ee5fc6decb0 100644 --- a/src/views/Search.vue +++ b/src/views/Search.vue @@ -20,7 +20,7 @@ <option value="date">Most recent</option> </b-select> </b-field> - <h1 class="title is-6">{{result.total}} result - page {{result.page}}</h1> + <h1 class="title is-6">{{result.total}} results - page {{result.page}}</h1> <div v-for="model in result.models" v-bind:key="model.name"> <ModelCard v-bind:model="model"/> </div> @@ -94,9 +94,9 @@ export default { const url = new URL(this.$serverurl + 'search') const params = new URLSearchParams() - if (this.paramSearch != null) params.append('q', this.paramSearch) + if (this.paramSearch != null) params.append('name', this.paramSearch) if (this.paramTags != null) params.append('tag', this.paramTags) - if (this.paramPerf != null) params.append('perf', this.paramPerf) + if (this.paramPerf != null) params.append('param', this.paramPerf) if (this.paramOrder != null) params.append('order', this.paramOrder) params.append('size', this.resultSize)