This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit e6e2712f4f944568bc1d2335d1e05b1673501b17 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Wed Jun 21 17:45:02 2017 +0200 UI des des liste de votants (ref #77) --- .../pollen/services/bean/FavoriteListBean.java | 20 +- .../services/service/FavoriteListService.java | 36 +- pollen-ui-riot-js/src/main/web/css/main.css | 50 ++ pollen-ui-riot-js/src/main/web/i18n.json | 36 +- pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html | 1 + .../src/main/web/tag/PollenHeader.tag.html | 30 -- .../src/main/web/tag/components/Card.tag.html | 94 ++++ .../web/tag/components/ContextualMenu.tag.html | 68 +++ .../main/web/tag/components/LetterAvatar.tag.html | 10 +- .../src/main/web/tag/components/Search.tag.html | 41 ++ .../web/tag/favoriteList/ChildListCard.tag.html | 146 ++---- .../tag/favoriteList/ChildListEditModal.tag.html | 105 +++++ .../web/tag/favoriteList/FavoriteList.tag.html | 517 ++++----------------- .../web/tag/favoriteList/FavoriteListCard.tag.html | 58 ++- .../favoriteList/FavoriteListEditModal.tag.html | 65 +++ .../web/tag/favoriteList/FavoriteLists.tag.html | 168 +++---- .../web/tag/favoriteList/ImportCsvModal.tag.html | 67 +++ .../web/tag/favoriteList/ImportLdapModal.tag.html | 70 +++ .../main/web/tag/favoriteList/MemberCard.tag.html | 127 ++--- .../web/tag/favoriteList/MemberEditModal.tag.html | 96 ++++ 20 files changed, 985 insertions(+), 820 deletions(-) diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/FavoriteListBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/FavoriteListBean.java index 9d34b339..200ee182 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/FavoriteListBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/FavoriteListBean.java @@ -34,6 +34,10 @@ public class FavoriteListBean extends PollenBean<FavoriteList> { protected String name; + protected long countChildren; + + protected long countMembers; + public FavoriteListBean() { super(FavoriteList.class); } @@ -61,9 +65,23 @@ public class FavoriteListBean extends PollenBean<FavoriteList> { return name; } - public void setName(String name) { this.name = name; } + public long getCountChildren() { + return countChildren; + } + + public void setCountChildren(long countChildren) { + this.countChildren = countChildren; + } + + public long getCountMembers() { + return countMembers; + } + + public void setCountMembers(long countMembers) { + this.countMembers = countMembers; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java index 90ff4f7d..f80d7a7d 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/FavoriteListService.java @@ -71,6 +71,30 @@ import static org.nuiton.i18n.I18n.l; */ public class FavoriteListService extends PollenServiceSupport { + public FavoriteListBean favoriteListBeanFunction(FavoriteListBean input) { + + + long countChildren = getChildFavoriteListDao() + .forProperties(ChildFavoriteList.PROPERTY_PARENT + "." + FavoriteList.PROPERTY_TOPIA_ID, input.getEntityId()) + .count(); + + input.setCountChildren(countChildren); + + long countMembers = getFavoriteListMemberDao() + .forProperties(FavoriteListMember.PROPERTY_FAVORITE_LIST + "." + FavoriteList.PROPERTY_TOPIA_ID, input.getEntityId()) + .count(); + + input.setCountMembers(countMembers); + + return input; + } + + public ChildFavoriteListBean childFavoriteListBeanFunction(ChildFavoriteListBean input) { + input.setChild(favoriteListBeanFunction(input.getChild())); + + return input; + } + public PaginationResultBean<FavoriteListBean> getFavoriteLists(PaginationParameterBean paginationParameter) { checkIsConnected(); @@ -80,7 +104,7 @@ public class FavoriteListService extends PollenServiceSupport { PaginationParameter page = getFavoriteListPaginationParameter(paginationParameter); PaginationResult<FavoriteList> favoriteLists = getFavoriteListDao().forPollenUserEquals(user).findPage(page); - return toPaginationListBean(FavoriteListBean.class, favoriteLists); + return toPaginationListBean(FavoriteListBean.class, favoriteLists, this::favoriteListBeanFunction); } @@ -92,7 +116,7 @@ public class FavoriteListService extends PollenServiceSupport { PollenUser user = getConnectedUser(); FavoriteList favoriteList = getFavoriteList0(user, favoriteListId); - return toBean(FavoriteListBean.class, favoriteList); + return toBean(FavoriteListBean.class, favoriteList, this::favoriteListBeanFunction); } @@ -137,7 +161,7 @@ public class FavoriteListService extends PollenServiceSupport { getNotificationService().onFavoriteListEdited(user, result); - return toBean(FavoriteListBean.class, result); + return toBean(FavoriteListBean.class, result, this::favoriteListBeanFunction); } @@ -605,7 +629,7 @@ public class FavoriteListService extends PollenServiceSupport { PaginationParameter page = getFavoriteListPaginationParameter(paginationParameter); PaginationResult<ChildFavoriteList> children = getChildFavoriteListDao().forParentEquals(favoriteList).findPage(page); - return toPaginationListBean(ChildFavoriteListBean.class, children); + return toPaginationListBean(ChildFavoriteListBean.class, children, this::childFavoriteListBeanFunction); } @@ -620,7 +644,7 @@ public class FavoriteListService extends PollenServiceSupport { FavoriteList favoriteList = getFavoriteList0(user, favoriteListId); ChildFavoriteList child = getChildList0(favoriteList, childListId); - return toBean(ChildFavoriteListBean.class, child); + return toBean(ChildFavoriteListBean.class, child, this::childFavoriteListBeanFunction); } @@ -665,7 +689,7 @@ public class FavoriteListService extends PollenServiceSupport { ChildFavoriteList result = saveChildFavoriteList(favoriteList, childList); commit(); - return toBean(ChildFavoriteListBean.class, result); + return toBean(ChildFavoriteListBean.class, result, this::childFavoriteListBeanFunction); } diff --git a/pollen-ui-riot-js/src/main/web/css/main.css b/pollen-ui-riot-js/src/main/web/css/main.css index d04b499b..701144db 100644 --- a/pollen-ui-riot-js/src/main/web/css/main.css +++ b/pollen-ui-riot-js/src/main/web/css/main.css @@ -262,6 +262,36 @@ time-picker .next:hover { background-color: var(--brand); } +/* The container <div> - needed to position the dropdown content */ +.dropdown { + position: relative; + display: inline-block; +} + +/* Dropdown Content (Hidden by Default) */ +.dropdown-content { + display: none; + position: absolute; + min-width: 188px; +} + +.dropdown-content.right { + right: 10px; +} + +/* Links inside the dropdown */ +.dropdown-content a { + padding: 12px 16px; + text-decoration: none; + display: block; +} + +/* Show the dropdown menu on hover */ +.dropdown:hover .dropdown-content { + display: block; + z-index: 1; +} + .dropdown-content { background-color: var(--dropdown); box-shadow: 0 8px 16px 0 var(--dropdown-shadow); @@ -315,3 +345,23 @@ pollenfooter a { pollenfooter a:hover { color: var(--footer-text-hover); } + +.brand { + color: var(--brand); +} + +.info { + color: var(--info); +} + +.warning { + color: var(--warning); +} + +.success { + color: var(--success); +} + +.error { + color: var(--error); +} diff --git a/pollen-ui-riot-js/src/main/web/i18n.json b/pollen-ui-riot-js/src/main/web/i18n.json index 01f0de84..b256996f 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -372,12 +372,21 @@ "choice_fileSizeMax_title": "Fichier trop lourd", "choice_fileSizeMax_message": "Le fichier « {0} » de taille de {1} ne doit pas dépasser {2}.", "favoriteList_title": "Mes listes de votants", + "favoriteList_one": "liste de votants", + "favoriteList_many": "listes de votants", "favoriteList_addFavoriteList": "Ajouter une nouvelle liste de votants", "favoriteList_export": "Exporter les listes de votants", + "favoriteList_children": "sous-listes", + "favoriteList_child": "sous-liste", + "favoriteList_members": "membres", + "favoriteList_member": "membre", + "favoriteList_noMember": "Aucun membre", + "favoriteList_new": "Nouvelle liste", + "favoriteList_edit": "Modifier cette liste", "favoriteList_name": "Nom", "favoriteList_name_placdeholder": "Renseignez le nom de la nouvelle liste", "favoriteList_add": "Ajouter", - "favoriteList_sort": "trier par", + "search_label": "Rechercher", "favoriteList_createDate": "Date de création", "favoriteList_name": "Nom", "favoriteList_email": "Courriel", @@ -388,16 +397,14 @@ "favoriteList_edit": "Modifier la liste de votants", "favoriteList_delete": "Supprimer", "favoriteList_deleteMessage": "Supprimer la liste de votants ?", - "favoriteList_noMember": "Aucun membre dans cette liste", - "favoriteList_members": "Membres de la liste", "favoriteList_member_new": "Nouveau membre", "favoriteList_member_import": "Importer", - "favoriteList_member_importCsv": "Importer des membres à partir d'un fichier", + "favoriteList_member_importCsv": "Importer un fichier CSV", "favoriteList_member_csvFile": "Fichier des membres", "favoriteList_member_csvFile_exemple": "# Courriel;Nom;Poids\ndupond@domaine.fr;Jean Dupond;1.00\npseudo@bleu.fr;Arnaud Lemaitre;4.50\nmiller@courriel.com;Benjamin Miller;3.00", "favoriteList_member_csvFile_exemple_label": "Exemple de fichier", "favoriteList_member_csvFile_exemple_detail": "Si le poids est omis, sa valeur par défaut est 1", - "favoriteList_member_importLdap": "Importer des membres à partir d'un annuaire LDAP", + "favoriteList_member_importLdap": "Importer un annuaire LDAP", "favoriteList_member_ldap": "Adresse de l'annuaire LDAP", "favoriteList_member_ldap_exemple": "ldap://ldap.domaine.org/ou=companies,o=entreprise?cn,mail?sub?(objectclass=people)\nldaps://login:password@ldap.domaine.org/ou=companies,o=libre-entreprise?cn,mail?sub?(objectclass=people)", "favoriteList_member_ldap_exemple_label": "Exemple d'adresse LDAP", @@ -424,6 +431,7 @@ "favoriteList_childList_cancel": "Annuler", "favoriteList_childList_save": "Enregistrer", "favoriteList_childList_add": "Ajouter", + "favoriteList_childList_edit": "Modifier la sous-liste", "favoriteList_childList_delete": "Retirer la sous-liste", "favoriteList_childList_deleteMessage": "Retirer la sou-liste ?", "favoriteList_importFavoriteLists": "Importer des listes de votants", @@ -838,11 +846,21 @@ "choice_fileSizeMax_title": "File to big", "choice_fileSizeMax_message": "File \"{0}\" for size {1} can't be over {2}.", "favoriteList_title": "My favorite lists", + "favoriteList_one": "favorite list", + "favoriteList_many": "favorite lists", "favoriteList_addFavoriteList": "Add new favorite list", "favoriteList_export": "Export favorite lists", + "favoriteList_children": "sub-lists", + "favoriteList_child": "sub-list", + "favoriteList_members": "members", + "favoriteList_member": "member", + "favoriteList_noMember": "No membre", + "favoriteList_new": "New list", + "favoriteList_edit": "Edit this list", "favoriteList_name": "Name", "favoriteList_name_placdeholder": "Enter new list name", "favoriteList_add": "Add", + "search_label": "Search", "favoriteList_sort": "Sort by", "favoriteList_createDate": "Creation Date", "favoriteList_email": "Email", @@ -850,19 +868,16 @@ "favoriteList_cancel": "Cancel", "favoriteList_back": "Back", "favoriteList_save": "Save", - "favoriteList_edit": "edit favorite list", "favoriteList_delete": "Delete", "favoriteList_deleteMessage": "Delete favorite list ?", - "favoriteList_noMember": "no member in this list", - "favoriteList_members": "list members", "favoriteList_member_new": "New member", "favoriteList_member_import": "Import", - "favoriteList_member_importCsv": "Import members from filer", + "favoriteList_member_importCsv": "Import from CSV file", "favoriteList_member_csvFile": "members file", "favoriteList_member_csvFile_exemple": "# Email Name\nsmith@domain.uk John Smith \npseudo@yellow.uk Mathieu Anderson \nmiller@courriel.com William Miller ", "favoriteList_member_csvFile_exemple_label": "file example", "favoriteList_member_csvFile_exemple_detail": "If weight is mising, default value is 1", - "favoriteList_member_importLdap": "Import members from LDAP repository", + "favoriteList_member_importLdap": "Import from LDAP repository", "favoriteList_member_ldap": "LDAP repository address", "favoriteList_member_ldap_exemple": "ldap://ldap.domaine.org/ou=companies,o=entreprise?cn,mail?sub?(objectclass=people)\nldaps://login:password@ldap.domaine.org/ou=companies,o=libre-entreprise?cn,mail?sub?(objectclass=people)", "favoriteList_member_ldap_exemple_label": "LDAP example", @@ -889,6 +904,7 @@ "favoriteList_childList_cancel": "Cancel", "favoriteList_childList_save": "Save", "favoriteList_childList_add": "Ajouter", + "favoriteList_childList_edit": "Edit sub-list", "favoriteList_childList_delete": "Remove sub-list", "favoriteList_childList_deleteMessage": "Remove sub-list ?", "favoriteList_importFavoriteLists": "Import favorite lists", diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html index 8bf594ed..56c85f3d 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag.html @@ -239,6 +239,7 @@ require("./popup/InformationPopup.tag.html"); position: fixed; bottom: 20px; right: 0px; + z-index: 2; } </style> diff --git a/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html b/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html index dda1dc12..f91e4474 100644 --- a/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/PollenHeader.tag.html @@ -120,36 +120,6 @@ require("./HeaderI18n.tag.html"); cursor: pointer; } - /* The container <div> - needed to position the dropdown content */ - .dropdown { - position: relative; - display: inline-block; - } - - /* Dropdown Content (Hidden by Default) */ - .dropdown-content { - display: none; - position: absolute; - min-width: 188px; - } - - .dropdown-content.right { - right: 10px; - } - - /* Links inside the dropdown */ - .dropdown-content a { - padding: 12px 16px; - text-decoration: none; - display: block; - } - - /* Show the dropdown menu on hover */ - .dropdown:hover .dropdown-content { - display: block; - z-index: 1; - } - @media (max-width: 640px) { .user-name { display: none; diff --git a/pollen-ui-riot-js/src/main/web/tag/components/Card.tag.html b/pollen-ui-riot-js/src/main/web/tag/components/Card.tag.html new file mode 100644 index 00000000..4f825b02 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/components/Card.tag.html @@ -0,0 +1,94 @@ +require("./LetterAvatar.tag.html"); +<Card> + + <div class="card-actions"> + <a class="info" + title={parent.__.edit} + onclick={opts.onedit}> + <i class="fa fa-pencil"></i> + </a> + <a class="error" + title={parent.__.delete} + onclick={opts.ondelete}> + <i class="fa fa-times"></i> + </a> + </div> + + <div class="card-content"> + + <div if={!opts.href} class="card-avatar"> + <LetterAvatar name={opts.name} rounded="true"/> + </div> + + <a if={opts.href} href={opts.href} class="card-avatar"> + <LetterAvatar name={opts.name} rounded="true"/> + </a> + + <div class="card-name" title={opts.name}> + {opts.name} + </div> + + <div class="card-detail"> + <yield/> + + </div> + + <div class="card-weight" if={opts.weight}> + <i class="fa fa-balance-scale" aria-hidden="true"></i> + {opts.weight} + </div> + </div> + + <style> + card { + position: relative; + display: block; + padding: 10px 0; + margin: 5px; + box-shadow: 0 0 10px hsla(0,0%,7%,.6); + width: 180px; + overflow: hidden; + } + + .card-actions { + position: absolute; + top: 0; + right: 0; + transform: translate3d(32px, 0px, 0px); + transition: transform 0.6s; + } + + card:hover .card-actions { + transform: translate3d(0px, 0px, 0px); + } + + .card-content { + display: flex; + flex-direction: column; + align-items: center; + } + + .card-avatar { + margin: 5px 0; + font-size: 3em; + } + + .card-name { + width: 100%; + font-size: 1.5em; + white-space: nowrap; + overflow: hidden; + text-align: center; + text-overflow: ellipsis; + } + + .card-detail { + width: 100%; + } + + .card-weight { + + } + + </style> +</Card> diff --git a/pollen-ui-riot-js/src/main/web/tag/components/ContextualMenu.tag.html b/pollen-ui-riot-js/src/main/web/tag/components/ContextualMenu.tag.html new file mode 100644 index 00000000..e6458f6f --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/components/ContextualMenu.tag.html @@ -0,0 +1,68 @@ +<ContextualMenu> + <i class="icon fa fa-plus"></i> + + <div class="links"> + <yield/> + </div> + + <style> + contextualmenu { + position: fixed; + right: 4em; + bottom: 4em; + display: block; + border-radius: 1.5em; + overflow: hidden; + background-color: var(--success); + color:var(--background); + } + + contextualmenu:hover { + width: inherit; + height: inherit; + } + + .icon { + font-size: 1.5em; + padding: 0.5em; + width: 2em; + height: 2em; + text-align: center; + } + + .links { + max-width: 0; + max-height: 0; + transition: max-width 1s, max-height 1s; + + } + + contextualmenu:hover .links { + max-width: 500px; + max-height: 500px; + transition: max-width 1s, max-height 1s; + } + + .links a { + padding: 0.75em 1em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + color:var(--background); + } + + .links a:hover { + background-color: var(--success-hover) + } + + @media (max-width: 640px) { + contextualmenu { + right: 1em; + bottom: 1em; + } + } + + </style> + +</ContextualMenu> diff --git a/pollen-ui-riot-js/src/main/web/tag/components/LetterAvatar.tag.html b/pollen-ui-riot-js/src/main/web/tag/components/LetterAvatar.tag.html index 9a17d9a9..2edbe438 100644 --- a/pollen-ui-riot-js/src/main/web/tag/components/LetterAvatar.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/components/LetterAvatar.tag.html @@ -8,14 +8,19 @@ <script type="es6"> this.redraw = () => { - this.avatarLetter = this.opts.name[0].toUpperCase(); + let nameSplit = this.opts.name.split(); + this.avatarLetter = nameSplit[0][0].toUpperCase(); + let secondLetter = (nameSplit.length > 1 ? nameSplit[1][0] : nameSplit[0][1]).toUpperCase(); let letterIndex = this.avatarLetter.charCodeAt() - 64; - let hue = (360 / 26) * letterIndex; + let secondIndex = secondLetter.charCodeAt() - 64; + let hue = (360 / (26 * 26)) * (secondIndex * 26 + letterIndex); this.backgroundColor = "hsl(" + hue + ", 68%, 48%)"; }; this.on("update", this.redraw); + this.redraw(); + </script> <style> @@ -36,7 +41,6 @@ fontSize: 1.70em; } - </style> </LetterAvatar> diff --git a/pollen-ui-riot-js/src/main/web/tag/components/Search.tag.html b/pollen-ui-riot-js/src/main/web/tag/components/Search.tag.html new file mode 100644 index 00000000..7865099e --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/components/Search.tag.html @@ -0,0 +1,41 @@ +<Search> + <div class="o-form-element search"> + <div class="o-field o-field--icon-left o-field--icon-right"> + <i class="fa fa-fw fa-search c-icon"></i> + <input class="c-field" + id="search" + name="search" + ref="search" + oninput={search} + placeholder={__.label} + type="text"> + <i class="fa fa-fw fa-times c-icon" + if={refs && refs.search.value} + onclick={deleteSearch}></i> + </div> + </div> + + <script type="es6"> + + let session = require("../../js/Session"); + this.installBundle(session, "search"); + + this.search = () => { + if (this.searchTimeoutId) { + window.clearTimeout(this.searchTimeoutId); + } + this.searchTimeoutId = window.setTimeout(() => { + delete this.searchTimeoutId; + if (this.opts.onsearch) { + this.opts.onsearch(); + } + }, 300); + }; + + this.deleteSearch = () => { + this.refs.search.value = ""; + this.search(); + }; + + </script> +</Search> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/ChildListCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ChildListCard.tag.html index 43f9bd55..c5001534 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/ChildListCard.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ChildListCard.tag.html @@ -1,77 +1,40 @@ -<ChildListCard class="card"> - - <div class="child-list-card-view" if={!editing}> - <div class="info"> - <a href="#favoriteLists/{opts.childList.child.id}"> - <i class="fa fa-users" aria-hidden="true"></i> - {opts.childList.child.name} - </a> - - {opts.childList.weight} - </div> - - <div class="member-actions u-xsmall"> - <button class="c-button c-button--info" - title={__.edit} - onclick={startEdition}> - <i class="fa fa-pencil"></i> - </button> - <button class="c-button c-button--error" - title={__.delete} - onclick={delete}> - <i class="fa fa-times"></i> - </button> - </div> - - </div> - - <form class="childList-card-edit" if={editing} onsubmit={save}> - <div class="o-form-element"> - <label class="c-label" for="child">{__.child}</label> - <input type="text" - id="child" - ref="child" - class="c-field" - value={opts.childList.child.name} - disabled> - </div> - <div class="o-form-element"> - <label class="c-label" for="weight">{__.weight}</label> - <input type="number" - id="weight" - ref="weight" - required - value={opts.childList.weight} - step="0.01" - class="c-field {c-field--error : errors.weight}"> - </div> - <div class="actions"> - <button type="button" - class="c-button c-button--ghost-info" - onclick={cancelEdition}> - <i class="fa fa-undo" aria-hidden="true"></i> - {__.cancel} - </button> - <button type="submit" - class="c-button c-button--info"> - <i class="fa fa-check" aria-hidden="true"></i> - {__.save} - </button> - </div> - </form> +require("../components/Card.tag.html"); +require("./ChildListEditModal.tag.html"); + +<ChildListCard> + + <Card name={opts.childList.child.name} + weight={opts.childList.weight} + ondelete={delete} + onedit={edit}> + <div> + {parent.opts.childList.child.countChildren} <i class="fa fa-users"></i> + </div> + <div> + {parent.opts.childList.child.countMembers} <i class="fa fa-user"></i> + </div> + </card> + + <ChildListEditModal ref="editModal" + child-list={opts.childList} + favorite-list={opts.favoriteList}/> <script type="es6"> let session = require("../../js/Session"); this.installBundle(session, "favoriteList_childList"); let favoriteListService = require("../../js/FavoriteListService"); - this.editing = false; - this.errors = {}; - this.startEdition = () => { - this.editing = true; - }; - - this.cancelEdition = () => { - this.editing = false; + this.edit = () => { + this.refs.editModal.open().then(() => { + if (this.opts.onChildListChange) { + this.opts.onChildListChange(); + } else { + this.update(); + } + }, () => { + this.update(); + }); + this.update(); }; this.delete = () => { @@ -86,56 +49,13 @@ }); }; - this.save = e => { - e.preventDefault(); - e.stopPropagation(); - this.opts.childList.weight = this.refs.weight.value; - - favoriteListService.saveChildList(this.opts.favoriteList.id, this.opts.childList).then(() => { - this.errors = {}; - this.cancelEdition(); - this.update(); - }, errors => { - this.errors = errors; - this.update(); - }); - }; - </script> <style> - .child-list-card-view { + .card-detail { display: flex; - justify-content: space-between; - } - - .child-list-actions { - display: flex; - align-items: flex-start; - } - - .child-list-actions button { - margin-left: 3px; - } - - .child-list-card-edit .o-form-element .c-label:first-child { - width: 25%; - display: inline-block; - text-align: right; - float: left; - padding-top: 0.5em; - padding-right: 5px; - } - - .child-list-card-edit .o-form-element .c-field { - width: 75%; - display: inline-block; - } - - .child-list-card-edit .o-form-element .c-toggle, - .child-list-card-edit .o-form-element .c-hint { - margin-left: 25%; + justify-content: space-around; } </style> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/ChildListEditModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ChildListEditModal.tag.html new file mode 100644 index 00000000..8c569d6d --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ChildListEditModal.tag.html @@ -0,0 +1,105 @@ +require("../popup/Modal.tag.html"); + +<ChildListEditModal> + <Modal ref="modal" + header={opts.childList.id ? __.edit : __.new} + label={opts.childList.id ? __.save : __.add} + type="success" + onsubmit={save}> + <div class="o-form-element"> + <label class="c-label" for="childList">{parent.__.child}</label> + <select if={!parent.opts.childList.id} + id="childList" + ref="childList" + placeholder={parent.__.member_name_placeholder} + required + disabled={parent.opts.childList.id} + class="c-field {c-field--error : parent.errors.child}"> + <option each={list, index in parent.favoriteLists} value={index}>{list.name}</option> + </select> + <input if={parent.opts.childList.id} + type="text" + id="childList" + ref="childList" + class="c-field" + value={parent.opts.childList.child.name} + disabled> + </div> + <div class="o-form-element"> + <label class="c-label" for="childListWeight">{parent.__.weight}</label> + <input type="number" + id="childListWeight" + ref="childListWeight" + required + value={parent.opts.childList.weight || 1} + step="0.01" + class="c-field {c-field--error : parent.errors.weight}"> + </div> + </Modal> + + <script type="es6"> + let session = require("../../js/Session"); + let Message = require("../../js/Message"); + this.installBundle(session, "favoriteList_childList"); + let favoriteListService = require("../../js/FavoriteListService"); + + this.favoriteLists = []; + + if (!this.opts.childList) { + this.opts.childList = {}; + } + + this.errors = {}; + + this.open = () => { + if (!this.opts.childList.id) { + this.refs.modal.refs.childList.value = 0; + this.refs.modal.refs.childListWeight.value = "1.00"; + favoriteListService.favoriteLists({ + order: "name", + desc: false, + pageSize: -1, + pageNumber: 0 + }).then(result => { + this.favoriteLists = result.elements; + this.update(); + }); + } + return this.refs.modal.open(); + }; + + this.save = () => { + + let childList = {}; + Object.assign(childList, this.opts.childList); + childList.weight = this.refs.modal.refs.childListWeight.value; + + let promise; + if (childList.id) { + promise = favoriteListService.saveChildList(this.opts.favoriteList.id, childList).then(() => { + this.errors = {}; + }, errors => { + this.errors = errors; + this.bus.trigger("message", new Message(errors, "error")); + this.update(); + return Promise.reject(); + }); + } else { + childList.child = this.favoriteLists[this.refs.modal.refs.childList.value]; + + promise = favoriteListService.addChildList(this.opts.favoriteList.id, childList).then(() => { + this.errors = {}; + }, errors => { + this.errors = errors; + this.bus.trigger("message", new Message(errors, "error")); + this.update(); + return Promise.reject(); + }); + } + + return promise; + }; + + </script> + +</ChildListEditModal> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteList.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteList.tag.html index f038cb97..6705e976 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteList.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteList.tag.html @@ -1,255 +1,60 @@ -require("../Pagination.tag.html"); require("./MemberCard.tag.html"); require("./ChildListCard.tag.html"); +require("./MemberEditModal.tag.html"); +require("./ImportCsvModal.tag.html"); +require("./ImportLdapModal.tag.html"); +require("./ChildListEditModal.tag.html"); <FavoriteList> <div class="container" > <div show="{loaded}"> - <h1 class="c-heading">{favoriteList.name || __.title}</h1> - <form onsubmit={save}> - <div class="o-form-element"> - <label class="c-label" for="name">{__.name}</label> - <input type="text" - id="name" - ref="name" - class="c-field" - placeholder={__.name_placeholder} - value={favoriteList.name}> + <h1 class="c-heading">{favoriteList.name} + <div class="c-heading__sub"> + <span if={favoriteList.countChildren > 0}> + {favoriteList.countChildren} {favoriteList.countChildren > 1 ? __.children : __.child} + </span> + <span if={favoriteList.countChildren === 0 && favoriteList.countMembers == 0}> + {__.noMember} + </span> + <span if={favoriteList.countMembers > 0}> + {favoriteList.countMembers} {favoriteList.countMembers > 1 ? __.members : __.member} + </span> </div> - <div class="actions"> - <a class="c-button c-button--ghost-info" - if={!favoriteList.id} - href="#/favoriteLists"> - <i class="fa fa-undo" aria-hidden="true"></i> - {__.cancel} - </a> - <a class="c-button c-button--ghost-info" - href="#/favoriteLists" - if={favoriteList.id}> - <i class="fa fa-chevron-left" aria-hidden="true"></i> - {__.back} - </a> - <div class="actions-right"> - <button class="c-button c-button--error" - type="button" - if={favoriteList.id} - onclick={delete}> - <i class="fa fa-times" aria-hidden="true"></i> - {__.delete} - </button> - <button class="c-button c-button--success" - type="submit"> - <i class="fa fa-check" aria-hidden="true"></i> - {__.save} - </button> - </div> - </div> - </form> - <virtual if={favoriteList.id}> - <hr/> - <h3 class="c-heading">{__.members}</h3> - <div show={members.length > 0} > - <div class="o-form-element sort"> - <label class="c-label" for="sort">{__.sort}</label> - <div class="c-input-group"> - <div class="o-field"> - <select class="c-field" - onchange={selectSort}> - <option value="topiaCreateDate">{__.createDate}</option> - <option value="name">{__.name}</option> - <option value="email">{__.email}</option> - </select> - </div> - <button class="c-button c-button--brand" - onclick={toggleSort}> - <i class="fa {pagination.desc ? 'fa-sort-amount-desc' : 'fa-sort-amount-asc'}"></i> - </button> - </div> - </div> - - <Pagination pagination={pagination} onchange="{refresh}"/> - - <MemberCard each={member in members} member={member} favorite-list={parent.favoriteList} on-member-change={parent.refresh}/> - - <Pagination pagination={pagination} onchange="{refresh}"/> - </div> - <div show={members.length === 0} class="c-alert c-alert--info"> - {__.noMember} - </div> - <hr/> - <h3 class="c-heading">{__.childrenLists}</h3> - <div show={childrenLists.length > 0} > - <div class="o-form-element sort"> - <label class="c-label" for="sort">{__.sort}</label> - <div class="c-input-group"> - <div class="o-field"> - <select class="c-field" - onchange={selectSortChildrenLists}> - <option value="topiaCreateDate">{__.createDate}</option> - <option value="name">{__.name}</option> - <option value="weight">{__.weight}</option> - </select> - </div> - <button class="c-button c-button--brand" - onclick={toggleSortChildrenLists}> - <i class="fa {paginationChildrenLists.desc ? 'fa-sort-amount-desc' : 'fa-sort-amount-asc'}"></i> - </button> - </div> - </div> - - <Pagination pagination={paginationChildrenLists} onchange="{refresh}"/> + </h1> + <div show={members.length > 0} > + <Search onsearch={refresh}/> + <div class="elements"> <ChildListCard each={childList in childrenLists} child-list={childList} favorite-list={parent.favoriteList} on-child-list-change={parent.refresh}/> - - <Pagination pagination={paginationChildrenLists} onchange="{refresh}"/> - </div> - <div show={childrenLists.length === 0} class="c-alert c-alert--info"> - {__.noChildList} + <MemberCard each={member in members} member={member} favorite-list={parent.favoriteList} on-member-change={parent.refresh}/> </div> - <hr/> - <form class="form-add" onsubmit={addMember}> - <h3 class="c-heading">{__.member_new}</h3> - <div class="o-form-element"> - <label class="c-label" for="nameMember">{__.member_name}</label> - <input type="text" - id="nameMember" - ref="nameMember" - placeholder={__.member_name_placeholder} - required - class="c-field {c-field--error : addMemberErrors.name}"> - </div> - <div class="o-form-element"> - <label class="c-label" for="email">{__.member_email}</label> - <input type="email" - id="email" - ref="email" - required - placeholder={__.member_email_placeholder} - class="c-field {c-field--error : addMemberErrors.email}"> - </div> - <div class="o-form-element"> - <label class="c-label" for="email">{__.member_weight}</label> - <input type="number" - id="weight" - ref="weight" - required - value="1.00" - step="0.01" - class="c-field {c-field--error : addMemberErrors.weight}"> - </div> - <div class="actions"> - <a class="c-button c-button--ghost-info" - href="#/favoriteLists" - if={favoriteList.id}> - <i class="fa fa-chevron-left" aria-hidden="true"></i> - {__.back} - </a> - <button class="c-button c-button--success" - type="submit"> - <i class="fa fa-user-plus" aria-hidden="true"></i> - {__.member_add} - </button> - </div> - </form> - <hr/> - <form class="form-add" onsubmit={importCsv}> - <h3 class="c-heading">{__.member_importCsv}</h3> - <div class="o-form-element"> - <label class="c-label" for="csvFile">{__.member_csvFile}</label> - <input type="file" - id="csvFile" - ref="csvFile" - required - class="c-field {c-field--error : csvErrors.error}"> - <div class="exemple"> - {__.member_csvFile_exemple_label} - <code class="c-code c-code--multiline">{__.member_csvFile_exemple}</code> - {__.member_csvFile_exemple_detail} - </div> - </div> - <div class="actions"> - <a class="c-button c-button--ghost-info" - href="#/favoriteLists" - if={favoriteList.id}> - <i class="fa fa-chevron-left" aria-hidden="true"></i> - {__.back} - </a> - <button class="c-button c-button--success" - type="submit"> - <i class="fa fa-upload" aria-hidden="true"></i> - {__.member_import} - </button> - </div> - </form> - <hr/> - <form class="form-add" onsubmit={importLdap}> - <h3 class="c-heading">{__.member_importLdap}</h3> - <div class="o-form-element"> - <label class="c-label" for="csvFile">{__.member_ldap}</label> - <input type="text" - id="ldapUrl" - ref="ldapUrl" - required - placeholder={__.member_ldap_placeholder} - class="c-field {c-field--error : ldapErrors.error}"> - <div class="exemple"> - {__.member_ldap_exemple_label} - <code class="c-code c-code--multiline">{__.member_ldap_exemple}</code> - {__.member_ldap_exemple_detail} - </div> - </div> - <div class="actions"> - <a class="c-button c-button--ghost-info" - href="#/favoriteLists" - if={favoriteList.id}> - <i class="fa fa-chevron-left" aria-hidden="true"></i> - {__.back} - </a> - <button class="c-button c-button--success" - type="submit"> - <i class="fa fa-upload" aria-hidden="true"></i> - {__.member_import} - </button> - </div> - </form> - <hr/> - <form class="form-add" onsubmit={addChildList}> - <h3 class="c-heading">{__.childList_new}</h3> - <div class="o-form-element"> - <label class="c-label" for="childList">{__.childList_child}</label> - <select type="text" - id="childList" - ref="childList" - placeholder={__.member_name_placeholder} - required - class="c-field {c-field--error : childListErrors.child}"> - <option each={list, index in favoriteLists} value={index}>{list.name}</option> - </select> - </div> - <div class="o-form-element"> - <label class="c-label" for="childListWeight">{__.childList_weight}</label> - <input type="number" - id="childListWeight" - ref="childListWeight" - required - value="1.00" - step="0.01" - class="c-field {c-field--error : childListErrors.weight}"> - </div> - <div class="actions"> - <a class="c-button c-button--ghost-info" - href="#/favoriteLists" - if={favoriteList.id}> - <i class="fa fa-chevron-left" aria-hidden="true"></i> - {__.back} - </a> - <button class="c-button c-button--success" - type="submit"> - <i class="fa fa-users" aria-hidden="true"></i> - {__.childList_add} - </button> - </div> - </form> - </virtual> + </div> + + <ContextualMenu> + <a onclick={parent.addMember} > + {parent.__.member_new} + </a> + <a onclick={parent.importCsv} > + {parent.__.member_importCsv} + </a> + <a onclick={parent.importLdap} > + {parent.__.member_importLdap} + </a> + <a onclick={parent.createChildList} > + {parent.__.childList_new} + </a> + </ContextualMenu> + + <MemberEditModal ref="createMemberModal" + favorite-list={favoriteList} /> + + <ImportCsvModal ref="importCsvModal" + favorite-list={favoriteList}/> + + <ImportLdapModal ref="importLdapModal" + favorite-list={favoriteList}/> + + <ChildListEditModal ref="createChildListModal" + favorite-list={favoriteList}/> </div> </div> @@ -258,22 +63,16 @@ require("./ChildListCard.tag.html"); let route = require("riot-route"); this.installBundle(session, "favoriteList"); let favoriteListService = require("../../js/FavoriteListService"); - this.addType = "member"; - this.errors = {}; - this.addMemberErrors = {}; - this.csvErrors = {}; - this.ldapErrors = {}; - this.childListErrors = {}; this.pagination = { - order: "topiaCreateDate", - desc: true, - pageSize: 5, + order: "name", + desc: false, + pageSize: -1, pageNumber: 0 }; this.paginationChildrenLists = { - order: "topiaCreateDate", - desc: true, - pageSize: 5, + order: "child.name", + desc: false, + pageSize: -1, pageNumber: 0 }; this.favoriteList = { @@ -281,7 +80,6 @@ require("./ChildListCard.tag.html"); }; this.members = []; this.childrenLists = []; - this.favoriteLists = []; this.delete = () => { if (this.favoriteList.id) { @@ -295,33 +93,35 @@ require("./ChildListCard.tag.html"); } }; - this.save = e => { - e.preventDefault(); - e.stopPropagation(); - this.favoriteList.name = this.refs.name.value; + this.addMember = () => { + this.refs.createMemberModal.open().then(() => { + this.update(); + this.refresh(); + }, () => {}); + this.update(); + }; - if (this.favoriteList.id) { - favoriteListService.saveFavoriteList(this.favoriteList).then(() => { - this.errors = {}; - this.refresh(); - }, errors => { - this.errors = errors; - this.bus.trigger("message", errors); - this.update(); - }); - } else { - favoriteListService.createFavoriteList(this.favoriteList).then((result) => { - route("/favoriteLists/" + result.id); - }, errors => { - this.errors = errors; - this.bus.trigger("message", errors); - this.update(); - }); - } + this.importCsv = () => { + this.refs.importCsvModal.open().then(() => { + this.update(); + this.refresh(); + }, () => {}); + this.update(); }; - this.onAddTypeChange = () => { - this.addType = this.refs.addType.value; + this.importLdap = () => { + this.refs.importLdapModal.open().then(() => { + this.update(); + this.refresh(); + }, () => {}); + this.update(); + }; + + this.createChildList = () => { + this.refs.createChildListModal.open().then(() => { + this.refresh(); + }, () => {}); + this.update(); }; @@ -330,20 +130,13 @@ require("./ChildListCard.tag.html"); Promise.all([ favoriteListService.favoriteList(this.favoriteList.id), favoriteListService.members(this.favoriteList.id, this.pagination), - favoriteListService.childrenLists(this.favoriteList.id, this.paginationChildrenLists), - favoriteListService.favoriteLists({ - order: "name", - desc: false, - pageSize: -1, - pageNumber: 0 - }) + favoriteListService.childrenLists(this.favoriteList.id, this.paginationChildrenLists) ]).then((results) => { this.favoriteList = results[0]; this.members = results[1].elements; Object.assign(this.pagination, results[1].pagination); this.childrenLists = results[2].elements; Object.assign(this.paginationChildrenLists, results[2].pagination); - this.favoriteLists = results[3].elements; this.loaded = true; this.update(); return this.favoriteList; @@ -353,156 +146,22 @@ require("./ChildListCard.tag.html"); } }; - this.addMember = (e) => { - e.preventDefault(); - e.stopPropagation(); - let member = { - name: this.refs.nameMember.value, - email: this.refs.email.value, - weight: this.refs.weight.value - }; - - favoriteListService.addMember(this.favoriteList.id, member).then(() => { - this.addMemeberErrors = {}; - this.refs.nameMember.value = ""; - this.refs.email.value = ""; - this.refs.weight.value = "1.00"; - this.refresh(); - }, errors => { - this.addMemberErrors = errors; - this.bus.trigger("message", errors); - this.update(); - }); - }; - - this.importCsv = (e) => { - e.preventDefault(); - e.stopPropagation(); - let csvFile = this.refs.csvFile.files[0]; - favoriteListService.importCsv(this.favoriteList.id, csvFile).then(() => { - this.csvErrors = {}; - this.refs.csvFile.value = ""; - this.refresh(); - }, errors => { - this.csvErrors = errors; - this.bus.trigger("message", errors); - this.update(); - }); - }; - - this.importLdap = (e) => { - e.preventDefault(); - e.stopPropagation(); - let ldap = this.refs.ldapUrl.value; - - favoriteListService.importLdap(this.favoriteList.id, ldap).then(() => { - this.ldapErrors = {}; - this.refs.nameMember.value = ""; - this.refs.email.value = ""; - this.refresh(); - }, errors => { - this.ldapErrors = errors; - this.bus.trigger("message", errors); - this.update(); - }); - }; - - this.addChildList = (e) => { - e.preventDefault(); - e.stopPropagation(); - let childList = { - child: this.favoriteLists[this.refs.childList.value], - weight: this.refs.childListWeight.value - }; - - favoriteListService.addChildList(this.favoriteList.id, childList).then(() => { - this.childListErrors = {}; - this.refs.childList.value = ""; - this.refs.childListWeight.value = "1.00"; - this.refresh(); - }, errors => { - this.childListErrors = errors; - this.bus.trigger("message", errors); - this.update(); - }); - }; - - this.toggleSort = () => { - this.pagination.desc = !this.pagination.desc; - this.refresh(); - }; - - this.selectSort = (e) => { - this.pagination.order = e.target.value; - this.refresh(); - }; - - this.toggleSortChildrenLists = () => { - this.paginationChildrenLists.desc = !this.paginationChildrenLists.desc; - this.refresh(); - }; - - this.selectSortChildrenLists = (e) => { - this.paginationChildrenLists.order = e.target.value; - this.refresh(); - }; - this.refresh(); </script> <style> - h1.c-heading { + .c-heading, + .c-heading .c-heading__sub { text-align: center; } - .o-form-element.sort .c-label:first-child { - width: 70px; - display: inline-block; - text-align: right; - float: left; - padding-top: 0.5em; - padding-right: 5px; - } - - .o-form-element.sort .c-input-group { - width: 200px; - } - - .o-form-element.sort .c-input-group .c-field { - width: 100%; - } - - .exemple { - font-size: 0.9em; - padding-left: 25%; - padding-top: 0.5em; - width: 100%; + .elements { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } - - .exemple code.c-code { - -webkit-user-select: text; /* Chrome all / Safari all */ - -moz-user-select: text; /* Firefox all */ - -ms-user-select: text; /* IE 10+ */ - user-select: text; - } - - @media (min-width: 640px) { - .o-form-element .c-label:first-child { - width: 25%; - display: inline-block; - text-align: right; - float: left; - padding-top: 0.5em; - padding-right: 5px; - } - - .o-form-element .c-field { - width: 75%; - display: inline-block; - } - } - + </style> </FavoriteList> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteListCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteListCard.tag.html index 6292dd8d..52d3ac0d 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteListCard.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteListCard.tag.html @@ -1,20 +1,21 @@ -require("../Pagination.tag.html"); -require("./MemberCard.tag.html"); -<FavoriteListCard class="card"> - <div class="favoriteList-card-view"> - <div class="name"> - <a href="#favoriteLists/{opts.favoriteList.id}"> - {opts.favoriteList.name} - </a> - </div> - - <div class="card-actions"> - <a title={__.delete} - onclick={delete}> - <i class="fa fa-times"></i> - </a> - </div> - </div> +require("../components/Card.tag.html"); +require("./FavoriteListEditModal.tag.html"); +<FavoriteListCard> + + <Card name={opts.favoriteList.name} + href="#favoriteLists/{opts.favoriteList.id}" + ondelete={delete} + onedit={edit}> + <div> + {parent.opts.favoriteList.countChildren} <i class="fa fa-users"></i> + </div> + <div> + {parent.opts.favoriteList.countMembers} <i class="fa fa-user"></i> + </div> + </Card> + + <FavoriteListEditModal ref="editModal" + favorite-list={opts.favoriteList}/> <script type="es6"> @@ -22,23 +23,36 @@ require("./MemberCard.tag.html"); this.installBundle(session, "favoriteList"); let favoriteListService = require("../../js/FavoriteListService"); + this.edit = () => { + this.refs.editModal.open().then(() => { + if (this.opts.onFavoriteListChange) { + this.opts.onFavoriteListChange(); + } else { + this.update(); + } + }, () => {this.update();}); + this.update(); + }; + this.delete = () => { this.confirm(this.__.deleteMessage).then((confirm) => { if (confirm) { favoriteListService.deleteFavoriteList(this.opts.favoriteList.id).then(() => { - this.opts.onFavoriteListChange(); + if (this.opts.onFavoriteListChange) { + this.opts.onFavoriteListChange(); + } }); } }); }; + </script> <style> - - .favoriteList-card-view { + .card-detail { display: flex; - justify-content: space-between; + justify-content: space-around; } - </style> + </FavoriteListCard> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteListEditModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteListEditModal.tag.html new file mode 100644 index 00000000..c122f388 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteListEditModal.tag.html @@ -0,0 +1,65 @@ +require("../popup/Modal.tag.html"); + +<FavoriteListEditModal> + <Modal ref="modal" + header={opts.favoriteList ? __.edit : __.new} + label={__.save} + type="success" + onsubmit={save}> + <div class="o-form-element"> + <label class="c-label" for="name">{parent.__.name}</label> + <input type="text" + id="name" + ref="name" + class="c-field" + placeholder={parent.__.name_placeholder} + value={parent.opts.favoriteList.name}> + </div> + </Modal> + + <script type="es6"> + let session = require("../../js/Session"); + let route = require("riot-route"); + let Message = require("../../js/Message"); + this.installBundle(session, "favoriteList"); + let favoriteListService = require("../../js/FavoriteListService"); + + if (!this.opts.favoriteList) { + this.opts.favoriteList = {}; + } + + this.errors = {}; + + this.open = () => { + return this.refs.modal.open(); + }; + + this.save = () => { + let favoriteList = {}; + Object.assign(favoriteList, this.opts.favoriteList); + favoriteList.name = this.refs.modal.refs.name.value; + + let promise; + if (favoriteList.id) { + promise = favoriteListService.saveFavoriteList(favoriteList).then(() => { + this.errors = {}; + }, errors => { + this.errors = errors; + this.bus.trigger("message", new Message(errors, "error")); + this.update(); + }); + } else { + promise = favoriteListService.createFavoriteList(favoriteList).then((result) => { + route("/favoriteLists/" + result.id); + }, errors => { + this.errors = errors; + this.bus.trigger("message", new Message(errors, "error")); + this.update(); + }); + } + return promise; + }; + + </script> + +</FavoriteListEditModal> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html index 3060fafd..37495a23 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/FavoriteLists.tag.html @@ -1,74 +1,54 @@ -require("../Pagination.tag.html"); +require("../components/Search.tag.html"); +require("../components/ContextualMenu.tag.html"); require("./FavoriteListCard.tag.html"); +require("./FavoriteListEditModal.tag.html"); <FavoriteLists> <div class="container" > <div show="{loaded}"> - <h1 class="c-heading">{__.title}</h1> - - <div show={favoriteLists.length > 0} > - <div class="o-form-element sort"> - <label class="c-label" for="sort">{__.sort}</label> - <div class="c-input-group"> - <div class="o-field"> - <select class="c-field" - onchange={selectSort}> - <option value="topiaCreateDate">{__.createDate}</option> - <option value="name">{__.name}</option> - </select> - </div> - <button class="c-button c-button--brand" - onclick={toggleSort}> - <i class="fa {pagination.desc ? 'fa-sort-amount-desc' : 'fa-sort-amount-asc'}"></i> - </button> - </div> + <h1 class="c-heading">{__.title} + <div class="c-heading__sub"> + {pagination.count === 0 ? __.noFavoriteList : (pagination.count + " " + (pagination.count === 1 ? __.one : __.many))} + <a class="c-button c-button--info" + if={pagination.count > 0} + href="{session.configuration.endPoint}/v1/favoriteLists/exports" + target="_blank" + title={__.export}> + <i class="fa fa-download"></i> + </a> </div> + </h1> - <Pagination pagination={pagination} onchange="{refresh}"/> - - <FavoriteListCard each={favoriteList in favoriteLists} favorite-list={favoriteList} on-favorite-list-change={parent.refresh}/> - - <Pagination pagination={pagination} onchange="{refresh}"/> - </div> - <div show={favoriteLists.length === 0} class="c-alert c-alert--info"> - {__.noFavoriteList} + <div show={pagination.count > 0} > + <Search onsearch={refresh}/> + <div class="elements"> + <FavoriteListCard each={favoriteList in favoriteLists} favorite-list={favoriteList} on-favorite-list-change={parent.refresh}/> + </div> </div> - <div class="actions-right"> - <a class="c-button c-button--info" - if={pagination.count > 0} - href="{session.configuration.endPoint}/v1/favoriteLists/exports" - target="_blank"> - <i class="fa fa-download"></i> - {__.export} - </a> - <a class="c-button c-button--success" - href="#/favoriteLists/new"> - {__.addFavoriteList} - <i class="fa fa-plus"></i> - </a> - </div> - <hr/> - <form class="form-add" onsubmit={import}> - <h3 class="c-heading">{__.importFavoriteLists}</h3> + <ContextualMenu> + <a onclick={parent.addFavoriteList}> + {parent.__.addFavoriteList} + </a> + <a onclick={parent.openImportModal} > + {parent.__.importFavoriteLists} + </a> + </ContextualMenu> + + <Modal ref="importModal" onsubmit={import} header={__.importFavoriteLists} label={__.import} type="success"> <div class="o-form-element"> - <label class="c-label" for="importFile">{__.import_file}</label> + <label class="c-label" for="importFile">{parent.__.import_file}</label> <input type="file" id="importFile" ref="importFile" required - class="c-field {c-field--error : importErrors.error}"> + class="c-field {c-field--error : parent.importErrors.error}"> <div class="exemple"> - {__.import_file_detail} + {parent.__.import_file_detail} </div> </div> - <div class="actions-right"> - <button class="c-button c-button--success" - type="submit"> - <i class="fa fa-upload" aria-hidden="true"></i> - {__.import} - </button> - </div> - </form> + </Modal> + + <FavoriteListEditModal ref="createFavoriteListModal"> </div> </div> @@ -79,16 +59,17 @@ require("./FavoriteListCard.tag.html"); this.installBundle(this.session, "favoriteList"); this.pagination = { - order: "topiaCreateDate", - desc: true, - pageSize: 5, + order: "name", + desc: false, + pageSize: -1, pageNumber: 0 }; this.favoriteLists = []; this.importErrors = {}; this.refresh = () => { - return favoriteListsService.favoriteLists(this.pagination).then((result) => { + let search = this.refs.search && this.refs.search.value; + return favoriteListsService.favoriteLists(this.pagination, search).then((result) => { this.favoriteLists = result.elements; Object.assign(this.pagination, result.pagination); this.loaded = true; @@ -97,33 +78,18 @@ require("./FavoriteListCard.tag.html"); }); }; - this.addFavoriteList = (e) => { - e.preventDefault(); - e.stopPropagation(); - let favoriteList = { - name: this.refs.name.value - }; - - favoriteListsService.createFavoriteList(favoriteList).then(() => { - this.errors = {}; - this.refs.name.value = ""; + this.addFavoriteList = () => { + this.refs.createFavoriteListModal.open().then(() => { this.refresh(); - }, errors => { - this.errors = errors; - this.update(); - }); + }, () => {}); + this.update(); }; this.refresh(); - this.toggleSort = () => { - this.pagination.desc = !this.pagination.desc; - this.refresh(); - }; - - this.selectSort = (e) => { - this.pagination.order = e.target.value; - this.refresh(); + this.openImportModal = () => { + this.refs.importModal.open(); + this.update(); }; this.import = (e) => { @@ -144,48 +110,26 @@ require("./FavoriteListCard.tag.html"); </script> <style> - h1.c-heading { + .c-heading, + .c-heading .c-heading__sub { text-align: center; } - .o-form-element.sort .c-label:first-child { - width: 70px; - display: inline-block; - text-align: right; - float: left; - padding-top: 0.5em; - padding-right: 5px; - } - - .o-form-element.sort .c-input-group { - width: 200px; - } - - .o-form-element.sort .c-input-group .c-field { - width: 100%; + .c-heading .c-heading__sub .c-button { + opacity: inherit; + font-size: 1rem; } .exemple { font-size: 0.9em; - padding-left: 25%; padding-top: 0.5em; width: 100%; } - @media (min-width: 640px) { - .o-form-element .c-label:first-child { - width: 25%; - display: inline-block; - text-align: right; - float: left; - padding-top: 0.5em; - padding-right: 5px; - } - - .o-form-element .c-field { - width: 75%; - display: inline-block; - } + .elements { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } </style> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/ImportCsvModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ImportCsvModal.tag.html new file mode 100644 index 00000000..7707ac58 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ImportCsvModal.tag.html @@ -0,0 +1,67 @@ +require("../popup/Modal.tag.html"); + +<ImportCsvModal> + <Modal ref="modal" + header={__.member_importCsv} + label={__.member_import} + type="success" + onsubmit={importCsv}> + <div class="o-form-element"> + <label class="c-label" for="csvFile">{parent.__.member_csvFile}</label> + <input type="file" + id="csvFile" + ref="csvFile" + required + class="c-field {c-field--error : parent.errors.error}"> + <div class="exemple"> + {parent.__.member_csvFile_exemple_label} + <code class="c-code c-code--multiline">{parent.__.member_csvFile_exemple}</code> + {parent.__.member_csvFile_exemple_detail} + </div> + </div> + </Modal> + + <script type="es6"> + let session = require("../../js/Session"); + let route = require("riot-route"); + this.installBundle(session, "favoriteList"); + let favoriteListService = require("../../js/FavoriteListService"); + + this.errors = {}; + + this.open = () => { + return this.refs.modal.open(); + }; + + this.importCsv = () => { + let csvFile = this.refs.modal.refs.csvFile.files[0]; + return favoriteListService.importCsv(this.opts.favoriteList.id, csvFile).then(() => { + this.errors = {}; + this.refs.modal.refs.csvFile.value = ""; + this.update(); + }, errors => { + this.errors = errors; + this.bus.trigger("message", errors); + this.update(); + }); + }; + + </script> + + <style> + .exemple { + font-size: 0.9em; + padding-top: 0.5em; + width: 100%; + } + + .exemple code.c-code { + -webkit-user-select: text; /* Chrome all / Safari all */ + -moz-user-select: text; /* Firefox all */ + -ms-user-select: text; /* IE 10+ */ + user-select: text; + } + + </style> + +</ImportCsvModal> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/ImportLdapModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ImportLdapModal.tag.html new file mode 100644 index 00000000..b2269d5b --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/ImportLdapModal.tag.html @@ -0,0 +1,70 @@ +require("../popup/Modal.tag.html"); + +<ImportLdapModal> + <Modal ref="modal" + header={__.member_importLdap} + label={__.member_import} + type="success" + onsubmit={importLdap}> + <div class="o-form-element"> + <label class="c-label" for="ldapUrl">{parent.__.member_ldap}</label> + <input type="text" + id="ldapUrl" + ref="ldapUrl" + required + placeholder={parent.__.member_ldap_placeholder} + class="c-field {c-field--error :parent.errors.error}"> + <div class="exemple"> + {parent.__.member_ldap_exemple_label} + <code class="c-code c-code--multiline">{parent.__.member_ldap_exemple}</code> + {parent.__.member_ldap_exemple_detail} + </div> + </div> + </Modal> + + + <script type="es6"> + let session = require("../../js/Session"); + let route = require("riot-route"); + this.installBundle(session, "favoriteList"); + let favoriteListService = require("../../js/FavoriteListService"); + + this.errors = {}; + + this.open = () => { + return this.refs.modal.open(); + }; + + this.importLdap = () => { + let ldap = this.refs.modal.refs.ldapUrl.value; + + return favoriteListService.importLdap(this.opts.favoriteList.id, ldap).then(() => { + this.errors = {}; + this.refs.modal.refs.ldapUrl.value = ""; + this.update(); + }, errors => { + this.errors = errors; + this.bus.trigger("message", errors); + this.update(); + }); + }; + + </script> + + <style> + .exemple { + font-size: 0.9em; + padding-top: 0.5em; + width: 100%; + } + + .exemple code.c-code { + -webkit-user-select: text; /* Chrome all / Safari all */ + -moz-user-select: text; /* Firefox all */ + -ms-user-select: text; /* IE 10+ */ + user-select: text; + } + + </style> + +</ImportLdapModal> diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html index 9306d2de..0f3881b8 100644 --- a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberCard.tag.html @@ -1,86 +1,34 @@ -<MemberCard class="card"> - - <div class="member-card-view" if={!editing}> - <div class="info"> - <i class="fa fa-user" aria-hidden="true"></i> - <span if={opts.member.name !== opts.member.email}> - {opts.member.name} - - </span> - {opts.member.email} - {opts.member.weight} - </div> - - <div class="member-actions u-xsmall"> - <button class="c-button c-button--info" - title={__.edit} - onclick={startEdition}> - <i class="fa fa-pencil"></i> - </button> - <button class="c-button c-button--error" - title={__.delete} - onclick={delete}> - <i class="fa fa-times"></i> - </button> - </div> - - </div> - - <form class="member-card-edit" if={editing} onsubmit={save}> - <div class="o-form-element"> - <label class="c-label" for="name">{__.name}</label> - <input type="text" - id="name" - ref="name" - class="c-field" - value={opts.member.name}> - </div> - <div class="o-form-element"> - <label class="c-label" for="name">{__.email}</label> - <input type="email" - id="email" - ref="email" - required - class="c-field {c-field--error: errors.email}" - value={opts.member.email}> - <div class="c-hint c-hint--static c-hint--error" each={error in errors.email}>{error}</div> - </div> - <div class="o-form-element"> - <label class="c-label" for="email">{__.weight}</label> - <input type="number" - id="weight" - ref="weight" - required - value={opts.member.weight} - step="0.01" - class="c-field {c-field--error : errors.weight}"> - </div> - <div class="actions"> - <button type="button" - class="c-button c-button--ghost-info" - onclick={cancelEdition}> - <i class="fa fa-undo" aria-hidden="true"></i> - {__.cancel} - </button> - <button type="submit" - class="c-button c-button--info"> - <i class="fa fa-check" aria-hidden="true"></i> - {__.save} - </button> - </div> - </form> +require("../components/Card.tag.html"); +require("./MemberEditModal.tag.html"); +<MemberCard> + + <Card name={opts.member.name} + weight={opts.member.weight} + ondelete={delete} + onEdit={edit}> + <span title={parent.opts.member.email}> + {parent.opts.member.email} + </span> + </Card> + + <MemberEditModal ref="editModal" + favorite-list={opts.favoriteList} + member={opts.member}/> <script type="es6"> let session = require("../../js/Session"); this.installBundle(session, "favoriteList_member"); let favoriteListService = require("../../js/FavoriteListService"); - this.editing = false; - this.errors = {}; - this.startEdition = () => { - this.editing = true; - }; - - this.cancelEdition = () => { - this.editing = false; + this.edit = () => { + this.refs.editModal.open().then(() => { + if (this.opts.onMemberChange) { + this.opts.onMemberChange(); + } else { + this.update(); + } + }, () => {this.update();}); + this.update(); }; this.delete = () => { @@ -95,27 +43,18 @@ }); }; - this.save = e => { - e.preventDefault(); - e.stopPropagation(); - this.opts.member.name = this.refs.name.value; - this.opts.member.email = this.refs.email.value; - this.opts.member.weight = this.refs.weight.value; - - favoriteListService.saveMember(this.opts.favoriteList.id, this.opts.member).then(() => { - this.errors = {}; - this.cancelEdition(); - this.update(); - }, errors => { - this.errors = errors; - this.update(); - }); - }; - </script> <style> + .card-detail { + font-size: 0.8em; + white-space: nowrap; + overflow: hidden; + text-align: center; + text-overflow: ellipsis; + } + .member-card-view { display: flex; justify-content: space-between; diff --git a/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html new file mode 100644 index 00000000..f6d5a5b5 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/favoriteList/MemberEditModal.tag.html @@ -0,0 +1,96 @@ +require("../popup/Modal.tag.html"); + +<MemberEditModal> + <Modal ref="modal" + header={opts.member ? __.edit : __.new} + label={__.save} + type="success" + onsubmit={save}> + <div class="o-form-element"> + <label class="c-label" for="name">{parent.__.name}</label> + <input type="text" + id="name" + ref="name" + required + class="c-field" + placeholder={parent.__.name_placeholder} + value={parent.opts.member.name}> + </div> + <div class="o-form-element"> + <label class="c-label" for="name">{parent.__.email}</label> + <input type="email" + id="email" + ref="email" + required + class="c-field {c-field--error: parent.errors.email}" + placeholder={parent.__.email_placeholder} + value={parent.opts.member.email}> + <div class="c-hint c-hint--static c-hint--error" each={error in parent.errors.email}>{error}</div> + </div> + <div class="o-form-element"> + <label class="c-label" for="email">{parent.__.weight}</label> + <input type="number" + id="weight" + ref="weight" + required + value={parent.opts.member.weight || 1} + step="0.01" + class="c-field {c-field--error : parent.errors.weight}"> + </div> + </Modal> + + <script type="es6"> + let session = require("../../js/Session"); + let Message = require("../../js/Message"); + this.installBundle(session, "favoriteList_member"); + let favoriteListService = require("../../js/FavoriteListService"); + + if (!this.opts.member) { + this.opts.member = {}; + } + + this.errors = {}; + + this.open = () => { + if (!this.opts.member.id) { + this.refs.modal.refs.name.value = ""; + this.refs.modal.refs.email.value = ""; + this.refs.modal.refs.weight.value = 1; + } + return this.refs.modal.open(); + }; + + this.save = () => { + let member = {}; + Object.assign(member, this.opts.member); + member.name = this.refs.modal.refs.name.value; + member.email = this.refs.modal.refs.email.value; + member.weight = this.refs.modal.refs.weight.value; + + let promise; + if (member.id) { + promise = favoriteListService.saveMember(this.opts.favoriteList.id, member).then(() => { + this.errors = {}; + }, errors => { + this.errors = errors; + this.bus.trigger("message", new Message(errors, "error")); + this.update(); + return Promise.reject(); + }); + } else { + promise = favoriteListService.addMember(this.opts.favoriteList.id, member).then(() => { + this.errors = {}; + this.update(); + }, errors => { + this.errors = errors; + this.bus.trigger("message", new Message(errors, "error")); + this.update(); + return Promise.reject(); + }); + } + return promise; + }; + + </script> + +</MemberEditModal> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.