From a94aeff75cb1ee2215751690062b81589862fbaf Mon Sep 17 00:00:00 2001 From: eikek Date: Wed, 8 Sep 2021 00:22:00 +0200 Subject: [PATCH] Add ui for showing data to be deleted for a user --- modules/webapp/src/main/elm/Api.elm | 6 +- modules/webapp/src/main/elm/Comp/Basic.elm | 48 +++++- .../webapp/src/main/elm/Comp/UserManage.elm | 159 ++++++++++++++---- .../src/main/elm/Messages/Comp/UserManage.elm | 3 + modules/webapp/src/main/elm/Styles.elm | 12 +- 5 files changed, 179 insertions(+), 49 deletions(-) diff --git a/modules/webapp/src/main/elm/Api.elm b/modules/webapp/src/main/elm/Api.elm index 325dddf1..e00110e9 100644 --- a/modules/webapp/src/main/elm/Api.elm +++ b/modules/webapp/src/main/elm/Api.elm @@ -43,7 +43,6 @@ module Api exposing , deleteSource , deleteTag , deleteUser - , deleteUserData , disableOtp , fileURL , getAttachmentMeta @@ -52,6 +51,7 @@ module Api exposing , getCollectiveSettings , getContacts , getCustomFields + , getDeleteUserData , getEquipment , getEquipments , getFolderDetail @@ -1469,8 +1469,8 @@ deleteUser flags user receive = } -deleteUserData : Flags -> String -> (Result Http.Error DeleteUserData -> msg) -> Cmd msg -deleteUserData flags username receive = +getDeleteUserData : Flags -> String -> (Result Http.Error DeleteUserData -> msg) -> Cmd msg +getDeleteUserData flags username receive = Http2.authGet { url = flags.config.baseUrl ++ "/api/v1/sec/user/" ++ username ++ "/deleteData" , account = getAccount flags diff --git a/modules/webapp/src/main/elm/Comp/Basic.elm b/modules/webapp/src/main/elm/Comp/Basic.elm index 75f88803..2f20f4af 100644 --- a/modules/webapp/src/main/elm/Comp/Basic.elm +++ b/modules/webapp/src/main/elm/Comp/Basic.elm @@ -6,7 +6,9 @@ module Comp.Basic exposing - ( editLinkLabel + ( contentDimmer + , deleteButton + , editLinkLabel , editLinkTableCell , genericButton , horizontalDivider @@ -89,6 +91,27 @@ secondaryButton model = } +deleteButton : + { x + | label : String + , icon : String + , disabled : Bool + , handler : Attribute msg + , attrs : List (Attribute msg) + } + -> Html msg +deleteButton model = + genericButton + { label = model.label + , icon = model.icon + , handler = model.handler + , disabled = model.disabled + , attrs = model.attrs + , baseStyle = S.deleteButtonMain + , activeStyle = S.deleteButtonHover + } + + secondaryBasicButton : { x | label : String @@ -182,18 +205,27 @@ linkLabel model = loadingDimmer : { label : String, active : Bool } -> Html msg loadingDimmer cfg = + let + content = + div [ class "text-gray-200" ] + [ i [ class "fa fa-circle-notch animate-spin" ] [] + , span [ class "ml-2" ] + [ text cfg.label + ] + ] + in + contentDimmer cfg.active content + + +contentDimmer : Bool -> Html msg -> Html msg +contentDimmer active content = div [ classList - [ ( "hidden", not cfg.active ) + [ ( "hidden", not active ) ] , class S.dimmer ] - [ div [ class "text-gray-200" ] - [ i [ class "fa fa-circle-notch animate-spin" ] [] - , span [ class "ml-2" ] - [ text cfg.label - ] - ] + [ content ] diff --git a/modules/webapp/src/main/elm/Comp/UserManage.elm b/modules/webapp/src/main/elm/Comp/UserManage.elm index e894612a..0c601476 100644 --- a/modules/webapp/src/main/elm/Comp/UserManage.elm +++ b/modules/webapp/src/main/elm/Comp/UserManage.elm @@ -15,18 +15,18 @@ module Comp.UserManage exposing import Api import Api.Model.BasicResult exposing (BasicResult) +import Api.Model.DeleteUserData exposing (DeleteUserData) import Api.Model.User import Api.Model.UserList exposing (UserList) import Comp.Basic as B import Comp.MenuBar as MB import Comp.UserForm import Comp.UserTable -import Comp.YesNoDimmer import Data.Flags exposing (Flags) import Data.UiSettings exposing (UiSettings) import Html exposing (..) import Html.Attributes exposing (..) -import Html.Events exposing (onSubmit) +import Html.Events exposing (onClick, onSubmit) import Http import Messages.Comp.UserManage exposing (Texts) import Styles as S @@ -39,10 +39,16 @@ type alias Model = , viewMode : ViewMode , formError : FormError , loading : Bool - , deleteConfirm : Comp.YesNoDimmer.Model + , deleteConfirm : DimmerMode } +type DimmerMode + = DimmerOff + | DimmerLoading + | DimmerUserData DeleteUserData + + type ViewMode = Table | Form @@ -53,6 +59,7 @@ type FormError | FormErrorSubmit String | FormErrorHttp Http.Error | FormErrorInvalid + | FormErrorCurrentUser emptyModel : Model @@ -62,7 +69,7 @@ emptyModel = , viewMode = Table , formError = FormErrorNone , loading = False - , deleteConfirm = Comp.YesNoDimmer.emptyModel + , deleteConfirm = DimmerOff } @@ -75,8 +82,10 @@ type Msg | InitNewUser | Submit | SubmitResp (Result Http.Error BasicResult) - | YesNoMsg Comp.YesNoDimmer.Msg | RequestDelete + | GetDeleteDataResp (Result Http.Error DeleteUserData) + | DeleteUserNow String + | CancelDelete update : Flags -> Msg -> Model -> ( Model, Cmd Msg ) @@ -183,12 +192,44 @@ update flags msg model = ( m3, c3 ) = update flags LoadUsers m2 in - ( { m3 | loading = False }, Cmd.batch [ c2, c3 ] ) + ( { m3 | loading = False, deleteConfirm = DimmerOff }, Cmd.batch [ c2, c3 ] ) else - ( { model | formError = FormErrorSubmit res.message, loading = False }, Cmd.none ) + ( { model + | formError = FormErrorSubmit res.message + , loading = False + , deleteConfirm = DimmerOff + } + , Cmd.none + ) SubmitResp (Err err) -> + ( { model + | formError = FormErrorHttp err + , loading = False + , deleteConfirm = DimmerOff + } + , Cmd.none + ) + + RequestDelete -> + let + login = + Maybe.map .user flags.account + |> Maybe.withDefault "" + in + if model.formModel.user.login == login then + ( { model | formError = FormErrorCurrentUser }, Cmd.none ) + + else + ( { model | deleteConfirm = DimmerLoading } + , Api.getDeleteUserData flags model.formModel.user.login GetDeleteDataResp + ) + + GetDeleteDataResp (Ok data) -> + ( { model | deleteConfirm = DimmerUserData data }, Cmd.none ) + + GetDeleteDataResp (Err err) -> ( { model | formError = FormErrorHttp err , loading = False @@ -196,29 +237,15 @@ update flags msg model = , Cmd.none ) - RequestDelete -> - update flags (YesNoMsg Comp.YesNoDimmer.activate) model + CancelDelete -> + ( { model | deleteConfirm = DimmerOff }, Cmd.none ) - YesNoMsg m -> - let - ( cm, confirmed ) = - Comp.YesNoDimmer.update m model.deleteConfirm - - user = - Comp.UserForm.getUser model.formModel - - cmd = - if confirmed then - Api.deleteUser flags user.login SubmitResp - - else - Cmd.none - in - ( { model | deleteConfirm = cm }, cmd ) + DeleteUserNow login -> + ( { model | deleteConfirm = DimmerLoading }, Api.deleteUser flags login SubmitResp ) ---- View2 +--- View view2 : Texts -> UiSettings -> Model -> Html Msg @@ -253,27 +280,82 @@ viewTable2 texts model = ] +renderDeleteConfirm : Texts -> UiSettings -> Model -> Html Msg +renderDeleteConfirm texts settings model = + case model.deleteConfirm of + DimmerOff -> + span [ class "hidden" ] [] + + DimmerLoading -> + B.loadingDimmer + { label = "Loading..." + , active = True + } + + DimmerUserData data -> + let + empty = + List.isEmpty data.folders && data.sentMails == 0 + + folderNames = + String.join ", " data.folders + in + B.contentDimmer True <| + div [ class "flex flex-col" ] <| + (if empty then + [ div [] + [ text texts.reallyDeleteUser + ] + ] + + else + [ div [] + [ text texts.reallyDeleteUser + , text " " + , text "The following data will be deleted:" + ] + , ul [ class "list-inside list-disc" ] + [ li [ classList [ ( "hidden", List.isEmpty data.folders ) ] ] + [ text "Folders: " + , text folderNames + ] + , li [ classList [ ( "hidden", data.sentMails == 0 ) ] ] + [ text (String.fromInt data.sentMails) + , text " sent mails" + ] + ] + ] + ) + ++ [ div [ class "mt-4 flex flex-row items-center" ] + [ B.deleteButton + { label = texts.basics.yes + , icon = "fa fa-check" + , disabled = False + , handler = onClick (DeleteUserNow model.formModel.user.login) + , attrs = [ href "#" ] + } + , B.secondaryButton + { label = texts.basics.no + , icon = "fa fa-times" + , disabled = False + , handler = onClick CancelDelete + , attrs = [ href "#", class "ml-2" ] + } + ] + ] + + viewForm2 : Texts -> UiSettings -> Model -> Html Msg viewForm2 texts settings model = let newUser = Comp.UserForm.isNewUser model.formModel - - dimmerSettings : Comp.YesNoDimmer.Settings - dimmerSettings = - Comp.YesNoDimmer.defaultSettings texts.reallyDeleteUser - texts.basics.yes - texts.basics.no in Html.form [ class "flex flex-col md:relative" , onSubmit Submit ] - [ Html.map YesNoMsg - (Comp.YesNoDimmer.viewN True - dimmerSettings - model.deleteConfirm - ) + [ renderDeleteConfirm texts settings model , if newUser then h3 [ class S.header2 ] [ text texts.createNewUser @@ -331,6 +413,9 @@ viewForm2 texts settings model = FormErrorInvalid -> text texts.pleaseCorrectErrors + + FormErrorCurrentUser -> + text texts.notDeleteCurrentUser ] , B.loadingDimmer { active = model.loading diff --git a/modules/webapp/src/main/elm/Messages/Comp/UserManage.elm b/modules/webapp/src/main/elm/Messages/Comp/UserManage.elm index 60d5f054..83e73eef 100644 --- a/modules/webapp/src/main/elm/Messages/Comp/UserManage.elm +++ b/modules/webapp/src/main/elm/Messages/Comp/UserManage.elm @@ -30,6 +30,7 @@ type alias Texts = , basics : Messages.Basics.Texts , deleteThisUser : String , pleaseCorrectErrors : String + , notDeleteCurrentUser : String } @@ -46,6 +47,7 @@ gb = , createNewUser = "Create new user" , deleteThisUser = "Delete this user" , pleaseCorrectErrors = "Please correct the errors in the form." + , notDeleteCurrentUser = "You can't delete the user you are currently logged in with." } @@ -62,4 +64,5 @@ de = , createNewUser = "Neuen Benutzer erstellen" , deleteThisUser = "Benutzer löschen" , pleaseCorrectErrors = "Bitte korrigiere die Fehler im Formular." + , notDeleteCurrentUser = "Der aktuelle Benutzer kann nicht gelöscht werden." } diff --git a/modules/webapp/src/main/elm/Styles.elm b/modules/webapp/src/main/elm/Styles.elm index c73865fa..3bb87ebb 100644 --- a/modules/webapp/src/main/elm/Styles.elm +++ b/modules/webapp/src/main/elm/Styles.elm @@ -197,7 +197,17 @@ secondaryBasicButtonHover = deleteButton : String deleteButton = - " rounded my-auto whitespace-nowrap border border-red-500 dark:border-lightred-500 text-red-500 dark:text-orange-500 text-center px-4 py-2 shadow-none focus:outline-none focus:ring focus:ring-opacity-75 hover:bg-red-600 hover:text-white dark:hover:text-white dark:hover:bg-orange-500 dark:hover:text-bluegray-900 " + deleteButtonMain ++ deleteButtonHover + + +deleteButtonMain : String +deleteButtonMain = + " rounded my-auto whitespace-nowrap border border-red-500 dark:border-lightred-500 text-red-500 dark:text-orange-500 text-center px-4 py-2 shadow-none focus:outline-none focus:ring focus:ring-opacity-75 " + + +deleteButtonHover : String +deleteButtonHover = + " hover:bg-red-600 hover:text-white dark:hover:bg-orange-500 dark:hover:text-bluegray-900 " undeleteButton : String