Skip to content
Snippets Groups Projects
Commit c1043d54 authored by gltron's avatar gltron
Browse files

Model edition: markdown & tags editor

parent 24814a59
No related branches found
No related tags found
No related merge requests found
Showing
with 306 additions and 56 deletions
VUE_APP_SERVER_URL = http://localhost:8181/v1/
\ No newline at end of file
VUE_APP_SERVER_URL = /api/v1/
\ No newline at end of file
......@@ -9783,6 +9783,11 @@
"object-visit": "^1.0.0"
}
},
"marked": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.0.0.tgz",
"integrity": "sha512-Wo+L1pWTVibfrSr+TTtMuiMfNzmZWiOPeO7rZsQUY5bgsxpHesBEcIWJloWVTFnrMXnf/TL30eTFSGJddmQAng=="
},
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
......
......@@ -11,6 +11,7 @@
"dependencies": {
"buefy": "^0.8.17",
"core-js": "^3.6.4",
"marked": "^1.0.0",
"node-sass": "^4.14.0",
"sass-loader": "^8.0.2",
"vue": "^2.6.11",
......
<template>
<div class="comments" v-if="comments">
<h1 class="title is-5">{{comments.length}} commentaires</h1>
<h1 class="title is-5">{{comments.length}} comments</h1>
<article class="media" v-for="comment in comments" v-bind:key="comment.id">
<div class="media-content">
<div class="content">
<p>
<strong>{{comment.author}}</strong> - <small>{{comment.date}}</small>
<strong>{{comment.author}}</strong> - <small>{{new Date(comment.date).toLocaleDateString()}}</small>
<br>
{{comment.content}}
</p>
......
<template>
<b-menu>
<div>
<b-menu-list label="Performance">
<b-menu-list label="minimum performance">
<b-slider v-model="perfValue" lazy @change="changeTag"></b-slider>
</b-menu-list>
<b-menu-list v-for="tag in tags" v-bind:key="tag.name" :label="tag.name">
......
<template>
<div class="layersEditor">
</div>
</template>
<script>
export default {
name: 'LayersEditor'
}
</script>
<style>
</style>
......@@ -2,22 +2,22 @@
<form action="">
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">Se connecter</p>
<p class="modal-card-title">Login</p>
</header>
<section class="modal-card-body">
<b-field label="Email">
<b-input type="email" v-model="email" placeholder="email" required/>
</b-field>
<b-field label="Mot de passe">
<b-input type="password" v-model="password" password-reveal placeholder="mot de passe" required/>
<b-field label="Password">
<b-input type="password" v-model="password" password-reveal placeholder="password" required/>
</b-field>
<b-button class="is-text is-small">mot de passe oublié ?</b-button >
<b-button class="is-text is-small">forgot password ?</b-button >
</section>
<footer class="modal-card-foot">
<button class="button is-primary" @click="onLogin">Connexion</button>
<button class="button is-primary" @click="onLogin">Login</button>
</footer>
</div>
</form>
......
<template>
<div class="markdownEditor container">
<b-tabs>
<b-tab-item label="Editor" class="edit">
<b-input type="textarea" v-model="input"/>
</b-tab-item>
<b-tab-item label="Preview">
<div class="content" v-html="compiledMarkdown"></div>
</b-tab-item>
</b-tabs>
</div>
</template>
<script>
import marked from 'marked'
export default {
name: 'MarkdownEditor',
props: {
input: {
type: String,
default: '# Readme'
}
},
computed: {
compiledMarkdown: function () {
return marked(this.input)
}
}
}
</script>
<style scoped>
.edit textarea {
min-height: 800px;
}
</style>
......@@ -8,7 +8,7 @@
<p>
<strong>{{model.name}}</strong>
<br>
<small>{{model.author}}</small> - <small>{{model.modificationDate}}</small>
<small>{{model.author}}</small> - <small>{{new Date(model.modificationDate).toLocaleDateString()}}</small>
<br>
{{model.shortDescription}}
</p>
......
<template>
<b-table :data="models" :loading="isLoading" striped hoverable>
<template slot-scope="props">
<b-table-column field="name" label="Nom du modèle" searchable sortable>
<b-table-column field="name" label="Model name" searchable sortable>
{{ props.row.name }}
</b-table-column>
......@@ -9,11 +9,11 @@
{{ props.row.vote }}
</b-table-column>
<b-table-column field="date" label="Date de modification" centered sortable>
<b-table-column field="date" label="Last modification" centered sortable>
{{ new Date(props.row.modificationDate).toLocaleDateString() }}
</b-table-column>
<b-table-column field="date" label="Date d'ajout" centered sortable>
<b-table-column field="date" label="Added" centered sortable>
{{ new Date(props.row.addedDate).toLocaleDateString() }}
</b-table-column>
......@@ -55,9 +55,9 @@ export default {
removePrompt (id) {
const name = this.models[id].name
this.$buefy.dialog.confirm({
message: 'Supprimer ' + name + ' ?',
cancelText: 'Annuler',
confirmText: 'Supprimer',
message: 'Delete ' + name + ' ?',
cancelText: 'Abort',
confirmText: 'Delete',
type: 'is-danger',
hasIcon: true,
onConfirm: () => this.remove(id)
......@@ -73,10 +73,10 @@ export default {
Authorization: 'Bearer ' + this.token
}
})
this.$buefy.toast.open(name + ' supprimé')
this.$buefy.toast.open(name + ' deleted')
this.getData()
} catch (error) {
this.$buefy.toast.open('Erreur supprimer')
this.$buefy.toast.open('Delete error')
}
}
}
......
......@@ -12,7 +12,7 @@
<template slot="start">
<b-navbar-item tag="div">
<b-field>
<b-input placeholder="Rechercher..."
<b-input placeholder="Search..."
type="search"
icon="magnify"
v-model="search"
......@@ -27,10 +27,10 @@
Home
</b-navbar-item>
<b-navbar-item tag="router-link" :to="{ name: 'Search' }">
Rechercher
Search
</b-navbar-item>
<b-navbar-item tag="router-link" :to="{ name: 'Docs' }">
Documentation
Docs
</b-navbar-item>
<b-navbar-item tag="router-link" :to="{ name: 'About' }">
<b-icon icon="help-circle-outline"/>
......@@ -38,18 +38,18 @@
<b-navbar-item tag="div">
<div v-if="isLogged" class="buttons">
<b-button tag="router-link" :to="{ name: 'Account' }" type="is-light">
<strong>Mon compte</strong>
<strong>Account</strong>
</b-button>
<b-button @click="logout" type="is-warning">
Déconnexion
Logout
</b-button>
</div>
<div v-else class="buttons">
<b-button @click="openRegisterPrompt" type="is-primary">
<strong>S'inscrire</strong>
<strong>Sign up</strong>
</b-button>
<b-button @click="openLoginPrompt" type="is-light">
Se connecter
Login
</b-button>
</div>
</b-navbar-item>
......
......@@ -2,28 +2,28 @@
<form action="">
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">S'inscrire</p>
<p class="modal-card-title">Sign up</p>
</header>
<section class="modal-card-body">
<b-field label="Email">
<b-input type="email" v-model="email" placeholder="email" required/>
</b-field>
<b-field label="Nom d'utilisateur">
<b-input v-model="username" placeholder="nom d'utilisateur" required/>
<b-field label="Username">
<b-input v-model="username" placeholder="username" required/>
</b-field>
<b-field label="Mot de passe">
<b-input type="password" v-model="password" password-reveal placeholder="mot de passe" required/>
<b-field label="Password">
<b-input type="password" v-model="password" password-reveal placeholder="password" required/>
</b-field>
<b-field label="Confirmer le mot de passe">
<b-input type="password" v-model="passwordConfirm" password-reveal placeholder="mot de passe" required/>
<b-field label="Confirm password">
<b-input type="password" v-model="passwordConfirm" password-reveal placeholder="password" required/>
</b-field>
</section>
<footer class="modal-card-foot">
<button class="button is-primary">Créer un compte</button>
<button class="button is-primary">Make account</button>
</footer>
</div>
</form>
......
<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" @click="addTagToModel">Add</b-button>
</p>
</b-field>
<b-taglist>
<b-tag
v-for="tag in tags"
v-bind:key="tag.type"
type="is-info"
@close="removeTagFromModel(tag)"
closable>
{{tag.type}}
</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 []
console.log('SELECT ' + this.selectedCategory)
var category = this.tagList.filter((tag) => {
return tag.name === this.selectedCategory
})
console.log('SELECT ' + category)
return category[0].types.filter((type) => {
return type
.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 = ''
},
removeTagFromModel (tag) {
console.log('REMOVE TAG ' + tag)
const index = this.tags.indexOf(tag)
if (index > -1) {
this.tags.splice(index, 1)
}
}
}
}
</script>
<style>
</style>
......@@ -8,8 +8,8 @@ import './assets/style.scss'
Vue.use(Buefy)
Vue.config.productionTip = false
Vue.prototype.$serverurl = 'http://localhost:8181/api/v1/'
Vue.prototype.$isLogged = false
// Vue.prototype.$serverurl = process.env.VUE_APP_SERVER_URL
Vue.prototype.$serverurl = 'http://localhost:8181/v1/'
new Vue({
router,
......
......@@ -34,12 +34,18 @@ const routes = [
path: '/modeledit',
name: 'ModelEdit',
component: () => import('../views/ModelEdit.vue'),
props: true
props: true,
meta: {
requiresAuth: true
}
},
{
path: '/account',
name: 'Account',
component: () => import('../views/Account.vue')
component: () => import('../views/Account.vue'),
meta: {
requiresAuth: true
}
}
]
......@@ -47,4 +53,14 @@ const router = new VueRouter({
routes
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (localStorage.getItem('token') == null) {
next({ path: '/' })
} else next()
} else {
next()
}
})
export default router
<template>
<div class="account container">
<div class="box">
<h1 class="title">Bienvenue {{account.username}}</h1>
<h1 class="title">Welcome {{account.username}}</h1>
<div class="buttons">
<b-button>Ajouter un modèle</b-button>
<b-button>Modifier le compte</b-button>
<b-button>Add new model</b-button>
<b-button>Change account details</b-button>
</div>
</div>
<div class="box">
<h1 class="title is-4">Mes modèles</h1>
<h1 class="title is-4">My models</h1>
<ModelTable/>
</div>
</div>
......
......@@ -16,15 +16,15 @@
</div>
<div class="column">
<h1 class="title is-4">{{model.vote}} votes <b-button size="is-small" icon-left="heart-outline" style="top:-2px"/></h1>
<small>Auteur: </small><strong>{{model.author}}</strong>
<small>Author: </small><strong>{{model.author}}</strong>
<br>
<small>Date d'ajout: </small><strong>{{model.addedDate}}</strong>
<small>Added: </small><strong>{{new Date(model.addedDate).toLocaleDateString()}}</strong>
<br>
<small>Dernière modification: </small><strong>{{model.modificationDate}}</strong>
<small>Last modification: </small><strong>{{new Date(model.modificationDate).toLocaleDateString()}}</strong>
<br>
<br>
<b-button type="is-primary" size="is-medium" icon-left="download">
Télécharger
Download
</b-button>
</div>
</div>
......
<template>
<div class="modelEdit container">
<div class="box">
<b-field label="Nom du modèle">
<b-input maxlength="30" :value="model.name"/>
<b-field label="Model name">
<b-input maxlength="30" :v-model="model.name"/>
</b-field>
<b-field label="Description courte">
<b-input maxlength="200" type="textarea" :value="model.shortDescription"/>
<h1 class="title">Description</h1>
<b-field label="Short description">
<b-input maxlength="200" type="textarea" :v-model="model.shortDescription"/>
</b-field>
<b-field label="Description longue">
<b-input type="textarea" :value="model.longDescription"/>
<b-field label="Long description">
<markdownEditor v-bind:input="model.longDescription"/>
</b-field>
<h1 class="title">Tags</h1>
<tagEditor v-bind:input="model.tags"/>
<h1 class="title">Files</h1>
<h2 class="title is-6">Model</h2>
<b-field position="is-centered">
<b-upload v-model="dropFiles" multiple drag-drop>
<section class="section">
<div class="content has-text-centered">
<p><b-icon icon="upload" size="is-large"/></p>
<p>Drop your files here or click to upload</p>
</div>
</section>
</b-upload>
</b-field>
<h2 class="title is-6">Custom layers</h2>
<layersEditor/>
</div>
<div class="box">
<b-button type="is-warning">Annuler</b-button>
<b-button type="is-danger">Supprimer</b-button>
<b-button type="is-success">Enregistrer</b-button>
<b-button type="is-warning">Abort</b-button>
<b-button type="is-success">Save</b-button>
</div>
</div>
</template>
<script>
import markdownEditor from '@/components/MarkdownEditor.vue'
import tagEditor from '@/components/TagEditor.vue'
import layersEditor from '@/components/LayersEditor.vue'
export default {
name: 'ModelEdit',
props: ['model'],
components: {
markdownEditor,
tagEditor,
layersEditor
},
data () {
return {
model: '',
name: '',
shortDesc: '',
longDesc: '',
......
......@@ -6,7 +6,7 @@
<Filters v-bind:tags="tags" v-on:setTags="setTags"/>
</div>
<div v-if="result" class="column is-four-fifths">
<h1 class="title is-6">{{result.total}} résultats - page {{result.page}}</h1>
<h1 class="title is-6">{{result.total}} result - page {{result.page}}</h1>
<div v-for="model in result.models" v-bind:key="model.name">
<ModelCard v-bind:model="model"/>
</div>
......@@ -58,7 +58,7 @@ export default {
this.result = await this.getResult()
},
async getTags () {
const url = this.$serverurl + 'tags'
const url = this.$serverurl + 'models/tags'
const response = await fetch(url)
try {
return await response.json()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment