Appli de gestion de mot de passe en Symfony et Vue.js (Partie 2)

Suite de notre développement !

Dans le chapitre précédent on a pu mettre en place tout notre environnement ainsi que notre première page.

Cet article est écrit en 3 parties :

Vous pouvez retrouver le projet complet ici : https://github.com/gponty/gespassvuejs

Comme convenu on va maintenant configurer vue.js en créant un fichier webpack.config.js à la racine :

let Encore = require('@symfony/webpack-encore');

Encore
// the project directory where compiled assets will be stored
    .setOutputPath('public/build/')
    // the public path used by the web server to access the previous directory
    .setPublicPath('/build')
    .cleanupOutputBeforeBuild()
    .enableSourceMaps(!Encore.isProduction())
    // uncomment to create hashed filenames (e.g. app.abc123.css)
    // .enableVersioning(Encore.isProduction())

    // uncomment to define the assets of the project
    .addEntry('js/app', './assets/js/app.js')
    .addStyleEntry('css/app', './assets/css/app.scss')

    // uncomment if you use Sass/SCSS files
    .enableSassLoader()

    // uncomment for legacy applications that require $/jQuery as a global variable
    // .autoProvidejQuery()

    // Enable Vue Loader
    .enableVueLoader()
;

module.exports = Encore.getWebpackConfig();

Il faut aussi créer quelques répertoires où stocker nos fichiers css et js :

/assets/css
/assets/js

On va créer notre fichier scss, qui va juste se contenter d’appeler la librairie Bootstrap :

/* /assets/css/app.scss
@import '~bootstrap-sass/assets/stylesheets/bootstrap';

On va faire un peu de joli et remplacer le fichier par défaut de notre « base » html (« /templates/base.html.twig ») :

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{% block title %} Gestion de mot de passe{% endblock %}</title>
    {% block stylesheets %}
        <link rel="stylesheet" href="{{ asset('build/css/app.css') }}">
    {% endblock %}
</head>
<body>

<div id="app">
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand" href="{{ path('default') }}"> Gestion de mot de passe </a>
            </div>
        </div>
    </nav>


    {% block body %}{% endblock %}
</div>

{% block javascripts %}
    <script src="{{ asset('build/js/app.js') }}"></script>
{% endblock %}
</body>
</html>

Si vous relancez la page vous allez voir quelque chose de pas beau du tout :

C’est que tout simplement on a pas compilé le fichier scss, pour ça rien de plus simple il suffit de lancer :

yarn run encore dev --watch

Vous devriez avoir une erreur qui dit que le fichier app.js n’existe pas, c’est normal on le créera plus tard.

La page est un peu plus belle :

On va maintenant créer nos fichiers vue.js, d’abord le fichier /assets/js/app.js :

global.jQuery = require('jquery');
global.axios = require('axios');

require('bootstrap-sass');

import Vue from 'vue';
import motdepasse from './components/motdepasseComponent'

new Vue({
    el: '#app',
    components: {motdepasse}
});

Puis le fichier default/index.html.twig :

{% extends 'base.html.twig' %}

{% block title %}Gestion de mot de passe {% endblock %}

{% block body %}

    <div class="container">
        <div class="row">
            <motdepasse></motdepasse>
        </div>
    </div>

{% endblock %}

Si vous relancez

yarn run encore dev --watch

A ce stade du développement plus rien ne fonctionne car il manque encore pas mal de fichiers à développer.

Comme par exemple le fichier component vue.js : (/assets/js/components/motdepasseComponent.vue)

<template>
    <div class="col-md-11 col-md-offset-1">

        <div class="row">
            <div class="col-sm-12">
                <h2 class="pull-left project-title">Liste des mots de passe</h2>
            </div>
        </div>

        <hr>

        <div v-if="passwords.length > 0">
            <div class="panel panel-default">
                <table class="table table-condensed ">
                    <thead>
                    <tr>
                        <th class="text-center">#</th>
                        <th class="text-center">Titre</th>
                        <th class="text-center">Url</th>
                        <th class="text-center">Username</th>
                        <th class="text-center">Password</th>
                        <th class="text-center">DernModif</th>
                        <th class="text-center">Update</th>
                        <th class="text-center">Delete</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="pass in passwords" :key="pass.id">
                        <td class="text-right col-md-1">{{ pass.id }}</td>
                        <td class="col-md-2">{{ pass.titre }}</td>
                        <td class="col-md-2">{{ pass.url }}</td>
                        <td class="col-md-2">{{ pass.username }}</td>
                        <td class="col-md-2">{{ pass.password }}</td>
                        <td class="text-center col-md-1"><span class="label" v-bind:class="[isExpired(pass.updatedAt) ? 'label-danger' : 'label-success']">{{ calculInterval(pass.updatedAt) }} jours</span></td>
                        <td class="text-center col-md-1"></td>
                        <td class="text-center col-md-1"></td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </div>
        <div v-else>
            <h3 align="center">Aucun mot de passe enregistré</h3>
        </div>
    </div>
</template>

<script>
    import moment from 'moment'

    export default {
        data: function () {
            return {
                passwords: {}
            }
        },
        created() {
            axios.get('/passwords').then(res => {
                this.passwords = res.data;
            })
        },
        computed: {
            isDisabled() {
                return this.passwords.titre === '';
            }
        },
        methods: {
            calculInterval: function (value) {
                if (!value) return '';
                let todaysDate = moment(new Date());
                let oDate = moment(new Date(value.timestamp * 1000));
                return todaysDate.diff(oDate, 'days');

            },
            isExpired(value) {
                if (this.calculInterval(value) > 300) {
                    return true;
                } else {
                    return false;
                }
                ;
            },
        },
    }
</script>

Il ne faut pas oublier de relancer la compilation des assets, et à partir de maintenant vous pouvez le laisser tourner en tâche de fond, à chaque modif dans un fichier scss ou js, ça se recompilera automatiquement sans que vous n’ayez rien à faire.

Pour tester que tout notre process fonctionne il suffit d’ajouter un mot de passe à la main dans la base de données, et voici ce que ça nous donne :

Pas mal n’est ce pas ? Dans le prochain chapitre on traitera l’ajout et la modif des mots de passe.

4 commentaires

  1. Salut,
    Je commente plusieurs mois plus tard !
    Cependant j’ai une question assez technique.
    La ici cette appliweb n’est pas seo frendly.
    Du coup si je souhaite la rendre seo frendly quelles sont mes possibilités ?

    Utilisez v8js ( c’est pas très stable et il faut en plus bidouiller le serveur)

    Ou je pensez à utiliser symfony comme API et découplé vueJs pour l’utiliser avec nuxt.js et faire du SSR.

    Par comment déployer ça sur serveur de prod?
    Car ici ce n’est pas du statique donc il faut forcément un serveur node pour la partie vue?

    Je suis assez perdu sur cette partie et je ne trouve que des cas de sites statiques avec nuxt donc pas beaucoup d’infos sur Google

    Peux être as tu une réponse?

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.