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 qui contiennent chacun leurs propres dépendances, dossier build, etc. Par exemple, Crew est plugin d’application. Cliquez ici 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

TODO: Create-taack-app turbo explaination here

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) {
    UiMenuSpecifier m = new UiMenuSpecifier()
    m.ui {
        menu 'Action', TurboController.&action as MC
        // MC stands for MethodClosure
        // import org.codehaus.groovy.runtime.MethodClosure as MC
    }
    return m
}

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

menu 'Action', 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 : Documentation.

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 Book, {
    // -- Header --
    header {
        column {
            fieldHeader "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"
boolean isAdmin = (springSecurityService.currentUser as User).authorities*.authority.contains("ROLE_ADMIN")

UiTableSpecifier tableSpecifier = new UiTableSpecifier()
tableSpecifier.ui Book, {
    // -- Header --
    header {
        column {
            fieldHeader "Title"
        }
        // Column only shown to admin
        if (isAdmin) {
            column {
                fieldHeader "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 la fonctionnalité de Grails suivante : Book.list().

Ensuite, nous allons parcourir la liste avec une boucle et définir nos lignes comme ceci :

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

UiTableSpecifier tableSpecifier = new UiTableSpecifier()
tableSpecifier.ui Book, {
    // -- Header --
    header {
        column {
            fieldHeader "Title"
        }
        // Column only shown to admin
        if (isAdmin) {
            column {
                fieldHeader "Delete book"
            }
        }
    }

    //List all Book
    def books = Book.list()
    for (Book book in books) {
        // Define a row for each book
        row {
            // Define a column displaying the title
            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 "Delete book", ActionIcon.DELETE,
                            TurboController.&index as MC, book.id, false
                }
            }
        }
    }
}

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 {
    ajaxBlock 'blockList', {
        table 'Book table', tableSpecifier, BlockSpec.Width.MAX
    }
}, 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 précédemment, 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 {
    ajaxBlock 'blockList', {
        table 'Book table', tableSpecifier, BlockSpec.Width.MAX, {
            //Added Closure here
            if (isAdmin())
                action 'Create book', ActionIcon.CREATE,
                       TurboController.&bookForm as MC,
                       [redirectAction: actionName], true
        }
    }
}, 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) Le titre du bouton. 2) L’icône du bouton (doit être une valeur de l’enum ActionIcon). 3) L’action vers laquelle le bouton va rediriger. 4) Les paramètres à envoyer lors de la redirection (ici, nous indiquons l’action vers laquelle on sera redirigé après avoir enregistré le livre). 5) Un paramètre pour indiquer si nous affichons dans un modal avec ajax.

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() {
    // Get book if we passed an id of the book we want to update
    // Or create new one
    Book book = Book.read(params.long("id")) ?: new Book(params)
}

OR You could simply write

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 'Save', this.&saveBook as MC, book.id,
               [redirectAction: params.get('redirectAction')], true
}

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

UiBlockSpecifier b = new UiBlockSpecifier()
b.ui {
    modal {
        ajaxBlock "bookForm", {
            form "Book 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) {
    MC red = (redirectAction ? this.&"$redirectAction" : this.&index) as MC
    taackSaveService.saveThenRedirectOrRenderErrors(Book, redirectAction == "null" ? null : red)
}

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 showBook(Book book) {
    // Define the show displayed fields
    UiShowSpecifier show = new UiShowSpecifier().ui(book, {
        field "Title", book.title
        field "Author", book.author
    })

    taackUiService.show(new UiBlockSpecifier().ui {
        modal {
            ajaxBlock "showBook", {
                show "${book.title}", show, BlockSpec.Width.MAX
            }
        }
    })
}

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 "Show book", ActionIcon.SHOW * ActionIconStyleModifier.SCALE_DOWN, TurboController.&showBook as MC, book.id, true

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 ActionIconStyleModifier pour modifier la taille de l’icône. Pour plus de détails, consultez le chapitre détaillé : ActionIcon.

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 !