Installer

Prérequis

Pour commencer, vous aurez besoin des éléments suivants :

  • Java (JDK-17 or JDK-19)

  • git

En option, vous pouvez aussi installer :

  • Solr-9.6.x (Used for intranet-wide search bar)

  • Postgresql

Version de Java

Commande affichant la version:

java -fullversion
openjdk full version "17.0.5+1"

Sur Mac, on peut utiliser brew pour l’installation du Jdk :

brew install openjdk@17

Clonez le projet Intranet clé en main

git clone https://github.com/Taack/intranet.git

Ce dépôt contient une version simplifiée d’un Intranet dans lequel vous pourrez ajouter d’autres applications. Il contient "Crew", qui est le système de gestion des utilisateurs, ainsi que sa dépendance de sécurité : Spring Security Plugin.

Lancez votre futur Intranet

Allez dans le répertoire intranet nouvellement cloné et démarrez le serveur en exécutant cette commande :

./gradlew server:bootRun

Si vous souhaitez que Gradle observe les modifications des fichiers pour recharger à chaud les modifications, lancer avec l’option -Dgrails.run.active=true :

./gradlew -Dgrails.run.active=true server:bootRun

Après un certain temps, vous devriez voir dans la console le message suivant :

Grails application running at http://localhost:9442...

Vous pouvez maintenant accéder à l’Intranet en allant à cette adresse depuis votre navigateur. Vous pouvez aussi vous identifier avec les identifiants par défaut (identifiant : admin, mot de passe : ChangeIt). Le mot de passe peut être remplacé dans le fichier server/grails-app/conf/application.yml.

Base de données persistante

Éditer le fichier server/grails-app/conf/application.yml, la section dataSource. Les base de données relationnelle et non relationnelle sont supportées.

Pour que les données de H2 soit persistante en mode développement :

environments:
    development:
        dataSource:
            dbCreate: update        (1)
            url: jdbc:h2:./prodDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE (2)
1 Mode de création des schémas (voir Grails GORM documentation)
2 prodDb : la racine du nom du fichier utilisé

Tâche Gradle pour création de binaire Tomcat

À la place de bootRun, utiliser la tâche assemble :

./gradlew server:assemble

Le binaire se trouvera dans le répertoire server/build/libs. Pour l’importer ensuite dans Tomcat :

cd server/build/libs
java -jar server-[version].jar

L’exécution sera plus rapide, les fichiers statiques seront compressés et concaténés.

Soyez sûr de ne pas avoir une instance déjà en train de fonctionner

Configurez votre IDE

Nous recommandons fortement d’utiliser la dernière version d'IntelliJ Ultimate Edition, pour son support étendu de Groovy et Grails. Nous étudions actuellement le support d’autres IDE (Eclipse, Visual Studio Code), ainsi que le support des autres versions d’IntelliJ.

IntelliJ Ultimate Edition

Nous vous recommandons d’installer les plugins Taack pour IntelliJ que vous pouvez trouver dans le store Intellij TaackUiASTAutocomplete ou en compilant les sources ici.

Pour ouvrir le projet, sélectionnez "Open projet" et sélectionnez intranet/settings.gradle.

Visual Studio Code

Si vous voulez vraiment utiliser Visual Studio Code, nous vous recommandons les extensions suivantes pour utiliser ce framework :

Gardez à l’esprit que la plupart des fonctionnalités de Grails et de Taack Framework ne seront pas reconnues par VSCode mais celui-ci peut toujours être utilisé. De plus, VSCode ne vous proposera pas d’aide avec les importations, la navigation dans le code ainsi que de nombreuses autres fonctionnalités pratiques puisque le support de Groovy n’est pas aussi avancé que sur IntelliJ.

Première application

Comment une application fonctionne avec Taack Framework ?

Votre projet Intranet possède deux parties :

  • Les plugins d’applications, qui sont regroupés dans le répertoire app : ce sont des micro-projets Gradle qui contiennent chacun leurs propres dépendances, dossier build, etc. Par exemple, Crew est plugin d’application.

Enregistrer une application pour en savoir plus sur la façon dont les plugins d’application sont implémentés sur le serveur. * Le serveur principal, qui va gérer tous les plugins d’applications définis dans build.gradle et les ajouter sur la page principale de l’Intranet.

Créer une nouvelle application

Pour créer une nouvelle appliquette (un plugin Grails ou module Gradle), assurez-vous d’avoir la dernière version Github de l’Intranet (voir installation).

Ceci fait, exécuter la commande suivante :

./gradlew -DmodName=myToto server:generateTaackAppTask

Une nouvelle appliquette apparaîtra dans le répertoire app. Pensez à recharger Gradle pour détecter sa présence dans Intellij.

Reload
Figure 1. Recharger Gradle

Mot sur la maintenance

La plupart du temps, mettre à jour votre Intranet ne devrait impliquer que de mettre à jour le répertoire buildSrc, et le fichier gradle.properties.

Ne soyez pas effrayé par ce genre de procedure. Il n’y a pas vraiment de méthode parfaite.

Créer un menu

Avant toute chose, penchons-nous sur la navigation de votre nouvelle application. La première chose à faire est de définir comment le menu va être construit. Nous pouvons commencer à partir du modèle de base suivant :

static private UiMenuSpecifier buildMenu(String q = null) {
    new UiMenuSpecifier().ui {
        menu SomeController.&action as MC
        menu this.&anotherAction as MC
        // import org.codehaus.groovy.runtime.MethodClosure as MC
    }
}

Nous créons tout d’abord un objet UiMenuSpecifier, puis nous définissons le contenu du menu :

menu TurboController.&action as MC

Ici, menu crée un simple lien dans notre bar de navigation. 'Action' est le nom du lien affiché et TurboController.&action as MethodClosure définie l’action vers laquelle le lien va rediriger.

Vous pouvez consulter la liste complète des éléments que vous pouvez ajouter dans votre menu ici : Menu DSL.

Créer un tableau

Maintenant, affichons un tableau dans votre page index. Commençons avec ce modèle de base :

UiTableSpecifier tableSpecifier = new UiTableSpecifier()
tableSpecifier.ui Book, {
    //Add table content inside the closure here
}

Ici, nous avons défini un nouveau tableau qui va lister des instances de Book. Nous pouvons ensuite définir l’en-tête du tableau en ajoutant dans la closure le code suivant :

UiTableSpecifier tableSpecifier = new UiTableSpecifier()
tableSpecifier.ui {
    // -- Header --
    header {
        column {
            fieldHeader object.title_
        }
    }
}

Puisque nous avons défini notre tableau dans une closure, nous pouvons ajouter des conditions, des boucles, etc.

Ajoutons maintenant une colonne qui va être affichée uniquement si l’utilisateur possède le rôle ROLE_ADMIN :

// Look if the current user has the Role "ROLE_ADMIN"
User cu = springSecurityService.currentUser as User
boolean isAdmin = cu.authorities*.authority.contains("ROLE_ADMIN")

new UiTableSpecifier().ui {
    header {
        column {
            label object.title_
        }
        // Column only shown to admin
        if (isAdmin) {
            column {
                label "Delete book"
            }
        }
    }
}

La colonne avec l’en-tête "Delete book" sera affichée seulement si l’utilisateur courant est un admin.

Maintenant, nous allons remplir notre tableau. Nous allons lister toutes les instances de Book dans la base de données en utilisant l’instruction iterate du DSL des tables.

User cu = springSecurityService.currentUser as User
boolean isAdmin = cu.authorities*.authority.contains("ROLE_ADMIN")

new UiTableSpecifier().ui {
    header {
        column {
            label object.title_
        }
        // Column only shown to admin
        if (isAdmin) {
            column {
                label "Delete book"
            }
        }
    }

    iterate(taackFilterService.getBuilder(Book)
            .setMaxNumberOfLine(8)
            .setSortOrder(TaackFilter.Order.DESC, object.title_)
            .build()) { Book book ->
        rowColumn {
            rowField book.title_ //The underscore is needed here
        }
        // If the user is an admin display a column with a button link
        // to redirect towards the book deletion action
        if (isAdmin) {
            rowColumn {
                rowAction ActionIcon.DELETE,
                        this.&deleteBook as MC, book.id
            }
        }
    }
}

Pour chaque livre dans notre liste, nous créons une nouvelle ligne avec son titre dans la première colonne et un bouton "supprimer" dans la seconde colonne si l’utilisateur est un admin (pour le moment, nous sommes redirigés vers index puisque nous n’avons pas encore créé de méthode de suppression).

Votre tableau est désormais complet. Nous devons maintenant simplement l’afficher sur la page. Pour afficher les UiSpecifiers que nous avons précédemment construits, nous devons utiliser taackUiService. Il devrait être déjà importé dans le contrôleur créé par la commande create-taack-app.

Ajoutez le code suivant sous le code de votre tableau :

taackUiService.show(new UiBlockSpecifier().ui {
    table tableSpecifier
}, buildMenu())

taackUiService.show(UiBlockSpecifier block, UiMenuSpecifier menu) sera en charge d’afficher la spécification que nous lui avons donnée. Dans ce cas, nous voulons afficher un ajaxBlock qui contient une table nommée "Book table". Nous passons notre tableSpecifier précédemment créé en tant qu’argument et nous réglons la largeur du tableau à MAX afin qu’il occupe toute la largeur de la page. Nous utilisons également notre méthode statique buildMenu() créée auparavant, et nous la passons en tant que second argument de show() pour afficher notre menu avec la page.

Vous pouvez maintenant lancer le serveur et accéder à votre nouvelle application. Votre tableau devrait fonctionner, mais pour le moment, vous ne devriez voir que les en-têtes, car vous n’avez pas encore de livres dans votre base de données. Continuons donc avec la création du formulaire et la sauvegarde de l’objet dans la base de données.

Ajouter des boutons dans le tableau

Nous allons ajouter un bouton dans notre tableau Book qui va ouvrir un modal en ajax pour créer un nouveau livre. Pour cela, nous devons ajouter une closure dans le tableau comme ceci :

taackUiService.show(new UiBlockSpecifier().ui {
    table 'Book table', tableSpecifier, BlockSpec.Width.MAX, {
        //Added Closure here
        if (isAdmin())
            action ActionIcon.CREATE, this.&bookForm as MC
    }
}, buildMenu())

Maintenant un admin pourra voir un bouton "Créer" en haut à droite du tableau.

La méthode action est composée des paramètres suivants :

  1. L’icône du bouton ;

  2. L’action vers laquelle le bouton va rediriger ;

  3. Le libellé sera composé et traduit en utilisant le nom de l’action.

Créer un formulaire et sauvegarder des objets

Nous allons maintenant créer le formulaire qui sera utilisé à la fois pour la création et la mise à jour des livres. Pour gérer les deux cas, nous allons d’abord définir notre action bookForm et ensuite initialiser soit un nouveau livre, soit regarder si l’identifiant d’une instance de livre a été passé en paramètre de la requête.

def bookForm(Book book) {
    book ?= new Book(params)
}

Maintenant, nous allons créer un FormSpecifier pour définir notre formulaire et son contenu :

UiFormSpecifier form = new UiFormSpecifier()
form.ui book, {
    //Section of fields
    section "Book details", {
        field book.title_
        field book.author_
    }
    //Save button
    formAction this.&saveBook as MC
}

Maintenant que votre formulaire est défini, affichons-le en utilisant taackUiService.show().

UiBlockSpecifier b = new UiBlockSpecifier()
b.ui {
    modal {
        form form, BlockSpec.Width.MAX
    }
}
taackUiService.show(b)

Cette fois, nous n’allons pas spécifier buildMenu dans notre show, car nous ne voulons pas que le menu soit affiché dans le modal !

N’oubliez pas de créer l’action saveBook :

@Secured("ROLE_ADMIN")
@Transactional
def saveBook(String redirectAction) {
    taackSaveService.saveThenReloadOrRenderErrors(Book)
}

Puisque nous voulons autoriser seulement les administrateurs à créer des livres, l’annotation @Secured a été ajoutée au niveau de la méthode saveBook. Pour plus d’informations, nous vous invitons à consulter le chapitre détaillé sur les annotations de sécurité : grails-spring-security-core.

Afficher un objet

Maintenant que nous pouvons créer des livres et les lister dans un tableau, affichons leurs détails dans un modal. Encore une fois, nous allons définir le Specifier et l’afficher dans un bloc via taackUiService.show() :

def showUser(Book book) {
    // Define the show displayed fields
    UiShowSpecifier showSpec = new UiShowSpecifier().ui(book, {
        fieldLabeled book.title_
        fieldLabeled book.author_
    })

    taackUiService.show(new UiBlockSpecifier().ui {
        modal {
            show showSpec
        }
    })
}

Nous devons également ajouter un lien vers cette page dans le tableau. Pour ajouter un lien dans le tableau, ajoutez la ligne suivante dans la même rowColumn (sous le champ title du livre par exemple) que celle où vous voulez que le bouton apparaisse :

rowAction
        ActionIcon.SHOW * StyleModifier.SCALE_DOWN, (1)
        TurboController.&showBook as MC, book.id
1 Cela créera un petit bouton dans la cellule du tableau qui ouvrira un modal avec les détails du livre correspondant.

Notez qu’ici, ActionIcon a été multiplié avec un IconStyle pour modifier la taille de l’icône.

Supprimer un objet

Vous souvenez-vous du bouton de suppression que nous avons placé dans notre tableau ? Nous allons maintenant le faire fonctionner. Pour cela, remplacez le nom de l’action dans le tableau par "&deleteBook", puis créez une nouvelle action avec le même nom dans le contrôleur :

@Transactional
@Secured(['ROLE_ADMIN'])
def deleteBook(Book book) {
    book.delete()
    redirect action: 'index'
}

C’est tout ! Nous utilisons la méthode delete pour supprimer le livre de la base de données, puis on redirige vers l’action index afin de revenir au tableau.

Vous disposez maintenant d’un CRUD entièrement fonctionnel pour votre classe Book sans avoir touché aux fichiers HTML/GSP !

Vous êtes maintenant prêt à vous plonger dans les fonctionnalités plus complexes de Taack Ui Framework.

Bienvenue !