@@ -4,7 +4,7 @@ | |||
"author": "Guillaume Vincent <guillaume@oslab.fr>", | |||
"private": true, | |||
"scripts": { | |||
"dev": "webpack-dev-server --hot --host 0.0.0.0", | |||
"dev": "webpack-dev-server --inline --hot --host 0.0.0.0", | |||
"build": "NODE_ENV=production webpack --display-error-details --progress --hide-modules", | |||
"test": "ava test --compilers js:babel-register" | |||
}, | |||
@@ -26,6 +26,7 @@ | |||
"file-loader": "^0.9.0", | |||
"font-awesome": "^4.6.3", | |||
"hint.css": "^2.3.2", | |||
"jquery": "^3.1.1", | |||
"json-loader": "^0.5.4", | |||
"jwt-decode": "^2.1.0", | |||
"lesspass": "^4.0.4", | |||
@@ -0,0 +1,35 @@ | |||
<style> | |||
.fa-white { | |||
color: #ffffff; | |||
} | |||
</style> | |||
<template> | |||
<div id="delete-button"> | |||
<button type="button" class="btn btn-danger" v-on:click="confirm"> | |||
<i class="fa-white fa fa-trash"></i> | |||
</button> | |||
</div> | |||
</template> | |||
<script type="text/ecmascript-6"> | |||
export default { | |||
data() { | |||
return { | |||
pending: false | |||
} | |||
}, | |||
props: { | |||
promise: {type: Function, required: true}, | |||
text: {type: String, required: true}, | |||
object: {type: Object, required: true} | |||
}, | |||
methods: { | |||
confirm() { | |||
this.pending = true; | |||
var response = confirm(this.text); | |||
if (response == true) { | |||
this.promise(this.object); | |||
} | |||
} | |||
} | |||
} | |||
</script> |
@@ -25,22 +25,37 @@ | |||
</form> | |||
<div id="passwords" class="row" v-if="!loading"> | |||
<div class="col-xs-12"> | |||
<div class="col-xs-12" v-if="passwords.length === 0"> | |||
You don't have any passwords saved in your database. | |||
<br> | |||
<router-link :to="{ name: 'home'}">Would you like to create one ?</router-link> | |||
</div> | |||
<router-link class="list-group-item list-group-item-action" | |||
:to="{ name: 'password', params: { passwordId: password.id }}" | |||
v-for="password in filteredPasswords"> | |||
<h5 class="list-group-item-heading">{{password.site}}</h5> | |||
<p class="list-group-item-text">{{password.login}}</p> | |||
</router-link> | |||
<table class="table"> | |||
<tbody> | |||
<tr v-if="passwords.length === 0"> | |||
<td> | |||
You don't have any passwords saved in your database. | |||
<br> | |||
<router-link :to="{ name: 'home'}">Would you like to create one ?</router-link> | |||
</td> | |||
</tr> | |||
<tr v-for="password in filteredPasswords"> | |||
<td> | |||
<router-link :to="{ name: 'password', params: { passwordId: password.id }}"> | |||
{{password.site}} | |||
</router-link> | |||
<br> | |||
{{password.login}} | |||
</td> | |||
<td class="text-xs-right"> | |||
<delete-button :promise="deletePassword" :object="password" | |||
text="Are you sure you want to delete this password ?"> | |||
</delete-button> | |||
</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script type="text/ecmascript-6"> | |||
import DeleteButton from './DeleteButton'; | |||
import Storage from '../api/storage'; | |||
import HTTP from '../api/http'; | |||
@@ -55,12 +70,20 @@ | |||
searchQuery: '' | |||
} | |||
}, | |||
components: { | |||
DeleteButton | |||
}, | |||
methods: { | |||
fetchPasswords(){ | |||
Passwords.all().then(response => { | |||
this.passwords = response.data.results; | |||
this.loading = false; | |||
}); | |||
}, | |||
deletePassword(password){ | |||
return Passwords.remove({id: password.id}).then(() => { | |||
this.fetchPasswords(); | |||
}); | |||
} | |||
}, | |||
computed: { | |||
@@ -4,8 +4,8 @@ import 'bootstrap/dist/css/bootstrap.css'; | |||
import 'font-awesome/css/font-awesome.css'; | |||
import 'hint.css/hint.css'; | |||
import App from './App'; | |||
import 'bootstrap/dist/js/bootstrap.min'; | |||
import Store from './store' | |||
import 'bootstrap/dist/js/bootstrap'; | |||
import Store from './store'; | |||
import Storage from './api/storage'; | |||
import router from './routes'; | |||
@@ -1,6 +1,6 @@ | |||
var webpack = require('webpack'); | |||
var path = require('path'); | |||
var ExtractTextPlugin = require("extract-text-webpack-plugin"); | |||
var ExtractTextPlugin = require('extract-text-webpack-plugin'); | |||
module.exports = { | |||
entry: './src/main.js', | |||
@@ -13,7 +13,8 @@ module.exports = { | |||
extensions: ['', '.js', '.vue'], | |||
fallback: [path.join(__dirname, 'node_modules')], | |||
alias: { | |||
src: path.resolve(__dirname, './src') | |||
src: path.resolve(__dirname, './src'), | |||
jquery: 'jquery/src/jquery' | |||
} | |||
}, | |||
resolveLoader: { | |||
@@ -23,26 +24,20 @@ module.exports = { | |||
loaders: [ | |||
{test: /\.vue$/, loader: 'vue-loader'}, | |||
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'}, | |||
{test: /\.json$/, loader: "json-loader"}, | |||
{test: /\.(png|jpg|jpeg|gif)$/, loader: 'url?limit=10000&name=images/[name].[ext]',}, | |||
{test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")}, | |||
{test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader')}, | |||
{test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader'} | |||
] | |||
}, | |||
plugins: [ | |||
new ExtractTextPlugin("styles.css"), | |||
new ExtractTextPlugin('styles.css'), | |||
new webpack.ProvidePlugin({ | |||
$: 'jquery', | |||
jQuery: 'jquery', | |||
'window.jQuery': 'jquery', | |||
'Tether': 'tether', | |||
'window.Tether': 'tether' | |||
}) | |||
], | |||
devServer: { | |||
historyApiFallback: true, | |||
noInfo: true | |||
}, | |||
devtool: '#eval-source-map' | |||
}; | |||
@@ -50,11 +45,6 @@ if (process.env.NODE_ENV === 'production') { | |||
module.exports.devtool = false; | |||
module.exports.output.publicPath = ''; | |||
module.exports.plugins = (module.exports.plugins || []).concat([ | |||
new webpack.DefinePlugin({ | |||
'process.env': { | |||
NODE_ENV: '"production"' | |||
} | |||
}), | |||
new webpack.optimize.DedupePlugin(), | |||
new webpack.optimize.OccurrenceOrderPlugin(), | |||
new webpack.optimize.UglifyJsPlugin({ | |||