diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ApiCalls.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ApiCalls.elm index fa5a8890533..b21f6228bb7 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ApiCalls.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ApiCalls.elm @@ -120,7 +120,7 @@ getRulesCompliance model = in send GetRulesComplianceResult req -saveRuleDetails : Rule -> Bool -> Model -> Cmd Msg +saveRuleDetails : Rule -> Bool -> Model -> Cmd Msg saveRuleDetails ruleDetails creation model = let (method, url) = if creation then ("PUT","/rules") else ("POST", ("/rules/"++ruleDetails.id.value)) @@ -137,6 +137,23 @@ saveRuleDetails ruleDetails creation model = in send SaveRuleDetails req +saveCategoryDetails : (Category Rule) -> Bool -> Model -> Cmd Msg +saveCategoryDetails category creation model = + let + (method, url) = if creation then ("PUT","/rules/categories") else ("POST", ("/rules/categories/"++category.id)) + req = + request + { method = method + , headers = [] + , url = getUrl model url + , body = encodeCategoryDetails category |> jsonBody + , expect = expectJson decodeGetCategoryDetails + , timeout = Nothing + , withCredentials = False + } + in + send SaveCategoryResult req + deleteRule : Rule -> Model -> Cmd Msg deleteRule rule model = let diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/DataTypes.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/DataTypes.elm index f41286fd45b..a9f100d0fea 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/DataTypes.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/DataTypes.elm @@ -57,10 +57,11 @@ type alias Technique = } type alias Category a = - { id : String - , name : String - , subElems : SubCategories a - , elems : List a + { id : String + , name : String + , description : String + , subElems : SubCategories a + , elems : List a } type SubCategories a = SubCategories (List (Category a)) @@ -145,7 +146,9 @@ type alias ComplianceDetails = type alias EditRuleDetails = { originRule : Rule, rule : Rule, tab : TabMenu, editDirectives: Bool, editGroups : Bool, newTag : Tag } -type Mode = Loading | RuleTable | EditRule EditRuleDetails | CreateRule EditRuleDetails +type alias EditCategoryDetails = { originCategory : Category Rule, category : Category Rule, tab : TabMenu} + +type Mode = Loading | RuleTable | EditRule EditRuleDetails | CreateRule EditRuleDetails | EditCategory EditCategoryDetails type alias Model = { contextPath : String @@ -166,15 +169,18 @@ type Msg | EditGroups Bool | GetRuleDetailsResult (Result Error Rule) | OpenRuleDetails RuleId - | CloseRuleDetails + | OpenCategoryDetails (Category Rule) + | CloseDetails | SelectGroup RuleTarget Bool | UpdateRule Rule + | UpdateCategory (Category Rule) | NewRule RuleId | UpdateNewTag Tag | CallApi (Model -> Cmd Msg) | GetPolicyModeResult (Result Error String) | GetRulesComplianceResult (Result Error (List RuleCompliance)) | SaveRuleDetails (Result Error Rule) + | SaveCategoryResult (Result Error (Category Rule)) | GetRulesResult (Result Error (Category Rule)) | GetGroupsTreeResult (Result Error (Category Group)) | GetTechniquesTreeResult (Result Error ((Category Technique, List Technique))) diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Init.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Init.elm index ae2e30212a2..39246dba944 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Init.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Init.elm @@ -12,7 +12,7 @@ init : { contextPath : String } -> ( Model, Cmd Msg ) init flags = let - initCategory = Category "" "" (SubCategories []) [] + initCategory = Category "" "" "" (SubCategories []) [] initModel = Model flags.contextPath Loading "" initCategory initCategory initCategory [] [] Nothing listInitActions = diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonDecoder.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonDecoder.elm index 2a6b43e84a2..a514c5b974b 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonDecoder.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonDecoder.elm @@ -13,23 +13,32 @@ decodeGetPolicyMode = decodeCategoryWithLeaves : String -> String -> String -> Decoder a -> Decoder ((Category a), List a) decodeCategoryWithLeaves idIdentifier categoryIdentifier elemIdentifier elemDecoder = - map4 (\id name subCats elems -> (Category id name (SubCategories (List.map Tuple.first subCats)) elems, List.concat [ elems, List.concatMap Tuple.second subCats ] )) + D.map5 (\id name description subCats elems -> (Category id name description (SubCategories (List.map Tuple.first subCats)) elems, List.concat [ elems, List.concatMap Tuple.second subCats ] )) (field idIdentifier D.string) (field "name" D.string) + (field "description" D.string) (field categoryIdentifier (D.list (D.lazy (\_ -> (decodeCategoryWithLeaves idIdentifier categoryIdentifier elemIdentifier elemDecoder))))) (field elemIdentifier (D.list elemDecoder)) - - decodeCategory : String -> String -> String -> Decoder a -> Decoder (Category a) decodeCategory idIdentifier categoryIdentifier elemIdentifier elemDecoder = succeed Category |> required idIdentifier D.string |> required "name" D.string + |> required "description" D.string |> required categoryIdentifier (D.map SubCategories (D.list (D.lazy (\_ -> (decodeCategory idIdentifier categoryIdentifier elemIdentifier elemDecoder))))) |> required elemIdentifier (D.list elemDecoder) +decodeCategoryDetails : Decoder (Category Rule) +decodeCategoryDetails = + succeed Category + |> required "id" D.string + |> required "name" D.string + |> required "description" D.string + |> hardcoded (SubCategories []) + |> hardcoded [] + decodeGetRulesTree = D.at [ "data" , "ruleCategories" ] (decodeCategory "id" "categories" "rules" decodeRule) @@ -37,6 +46,10 @@ decodeGetRuleDetails : Decoder Rule decodeGetRuleDetails = D.at [ "data" , "rules" ] (index 0 decodeRule) +decodeGetCategoryDetails : Decoder (Category Rule) +decodeGetCategoryDetails = + D.at [ "data" , "ruleCategories" ] decodeCategoryDetails + decodeRule : Decoder Rule decodeRule = D.succeed Rule diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonEncoder.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonEncoder.elm index 359f7dd9b93..8c1c15b7ca2 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonEncoder.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/JsonEncoder.elm @@ -21,6 +21,13 @@ encodeRuleDetails ruleDetails = , ("tags" , list encodeTags ruleDetails.tags ) ] +encodeCategoryDetails: (Category Rule) -> Value +encodeCategoryDetails category = + object [ + ("name" , string category.name ) + , ("description" , string category.description ) + ] + encodeDirectives: Directive -> Value encodeDirectives directive= object [ diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Rules.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Rules.elm index 2eb8c861d2c..41244225efd 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Rules.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/Rules.elm @@ -115,7 +115,10 @@ update msg model = OpenRuleDetails rId -> (model, (getRuleDetails model rId)) - CloseRuleDetails -> + OpenCategoryDetails category -> + ({model | mode = EditCategory (EditCategoryDetails category category Information )}, Cmd.none) + + CloseDetails -> ( { model | mode = RuleTable } , Cmd.none ) GetRulesComplianceResult res -> @@ -160,6 +163,14 @@ update msg model = ({model | mode = CreateRule {details | rule = rule}}, Cmd.none) _ -> (model, Cmd.none) + UpdateCategory category -> + case model.mode of + EditCategory details -> + ({model | mode = EditCategory {details | category = category}}, Cmd.none) + --CreateRule details -> + --({model | mode = CreateRule {details | rule = rule}}, Cmd.none) + _ -> (model, Cmd.none) + NewRule id -> let rule = Rule id "" "rootRuleCategory" "" "" True False [] [] [] @@ -187,6 +198,22 @@ update msg model = SaveRuleDetails (Err err) -> processApiError "Saving Rule" err model + SaveCategoryResult (Ok category) -> + -- TODO // Update Rules List + case model.mode of + EditCategory details -> + let + oldCategory = details.category + newCategory = {category | subElems = oldCategory.subElems, elems = oldCategory.elems} + in + ({model | mode = EditCategory {details | originCategory = newCategory, category = newCategory}}, successNotification ("Category '"++ category.name ++"' successfully saved")) + --CreateRule details -> + -- ({model | mode = EditRule {details | originRule = ruleDetails, rule = ruleDetails}}, successNotification ("Rule '"++ ruleDetails.name ++"' successfully created")) + _ -> (model, Cmd.none) + + SaveCategoryResult (Err err) -> + processApiError "Saving Category" err model + DeleteRule (Ok (ruleId, ruleName)) -> -- TODO // Update Rules List case model.mode of diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/View.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/View.elm index d9b7b015e79..67e5d91ba83 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/View.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/View.elm @@ -11,6 +11,7 @@ import NaturalOrdering exposing (compareOn) import ApiCalls exposing (..) import ViewRulesTable exposing (..) import ViewRuleDetails exposing (..) +import ViewCategoryDetails exposing (..) view : Model -> Html Msg @@ -35,7 +36,7 @@ view model = in li[class "jstree-node jstree-open"] [ i[class "jstree-icon jstree-ocl"][] - , a[href "#", class "jstree-anchor"] + , a[href "#", class "jstree-anchor", onClick (OpenCategoryDetails item)] [ i [class "jstree-icon jstree-themeicon fa fa-folder jstree-themeicon-custom"][] , span [class "treeGroupCategoryName tooltipable"][text item.name] ] @@ -68,6 +69,9 @@ view model = CreateRule details -> (editionTemplate model details True) + EditCategory details -> + (editionTemplateCat model details False) + modal = case model.modal of Nothing -> text "" Just (DeletionValidation rule) -> diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ViewCategoryDetails.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ViewCategoryDetails.elm new file mode 100644 index 00000000000..de7e6fb3731 --- /dev/null +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ViewCategoryDetails.elm @@ -0,0 +1,106 @@ +module ViewCategoryDetails exposing (..) + +import DataTypes exposing (..) +import Html exposing (Html, button, div, i, span, text, h1, h4, ul, li, input, a, p, form, label, textarea, select, option, table, thead, tbody, tr, th, td, small) +import Html.Attributes exposing (id, class, type_, placeholder, value, for, href, colspan, rowspan, style, selected, disabled, attribute) +import Html.Events exposing (onClick, onInput) +import List.Extra +import List +import String exposing ( fromFloat) +import NaturalOrdering exposing (compareOn) +import ApiCalls exposing (..) +import ViewTabContent exposing (buildListCategories) + +-- +-- This file contains all methods to display the details of the selected rule. +-- + + +editionTemplateCat : Model -> EditCategoryDetails -> Bool -> Html Msg +editionTemplateCat model details isNewCat = + let + originCat = details.originCategory + category = details.category + categoryTitle = if (String.isEmpty originCat.name && isNewCat) then + span[style "opacity" "0.4"][text "New category"] + else + text originCat.name + + topButtons = + let + disableWhileCreating = case model.mode of + EditCategory _ -> "" + _ -> " disabled" + in + [ li [] [ + a [ class ("action-success"++disableWhileCreating) ] --, onClick (GenerateId (\r -> CloneRule originRule (RuleId r)))] + [ i [ class "fa fa-clone"] [] + , text "Clone" + ] + ] + , li [class "divider"][] + , li [] [ + a [ class ("action-danger"++disableWhileCreating) ] --, onClick (OpenDeletionPopup rule)] + [ i [ class "fa fa-times-circle"] [] + , text "Delete" + ] + ] + ] + + in + div [class "main-container"] + [ div [class "main-header "] + [ div [class "header-title"] + [ h1[] + [ i [class "title-icon fa fa-folder"][] + , categoryTitle + ] + , div[class "header-buttons"] + [ div [ class "btn-group" ] + [ button [ class "btn btn-default dropdown-toggle" , attribute "data-toggle" "dropdown" ] [ + text "Actions " + , i [ class "caret" ] [] + ] + , ul [ class "dropdown-menu" ] topButtons + ] + , button [class "btn btn-default", type_ "button", onClick CloseDetails] + [ text "Close", i [ class "fa fa-times"][]] + , button [class "btn btn-success", type_ "button", onClick (CallApi (saveCategoryDetails category isNewCat))] + [ text "Save", i [ class "fa fa-download"][]] + ] + ] + , div [class "header-description"] + [ p[][text ""] ] + ] + , div [class "main-navbar" ] + [ ul[class "ui-tabs-nav "] + [ li[class "ui-tabs-tab ui-tabs-active"] + [ a[][ text "Information" ] + ] + ] + ] + , div [class "main-details"] + [ div[class "row"][ + form[class "col-xs-12 col-sm-6 col-lg-7"] + [ div [class "form-group"] + [ label[for "category-name"][text "Name"] + , div[] + [ input[ id "category-name", type_ "text", value category.name, class "form-control" , onInput (\s -> UpdateCategory {category | name = s} ) ][] ] + ] + , div [class "form-group"] + [ label[for "category-parent"][text "Parent"] + , div[] + [ select[ id "category-parent", class "form-control" ] --, onInput (\s -> UpdateCategory {category | parent = s} ) ] + (buildListCategories "" model.rulesTree) + ] + ] + , div [class "form-group"] + [ label[for "category-description"][text "Description"] + , div[] + [ textarea[ id "category-description", value category.description, placeholder "There is no description", class "form-control" , onInput (\s -> UpdateCategory {category | description = s} ) ][] ] + ] + ] + , div [class "col-xs-12 col-sm-6 col-lg-5"][] -- <== Right column + ] + ] + ] \ No newline at end of file diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ViewRuleDetails.elm b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ViewRuleDetails.elm index 128e3d5afa4..d4c7de70b86 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ViewRuleDetails.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/rules/sources/ViewRuleDetails.elm @@ -97,7 +97,7 @@ editionTemplate model details isNewRule = ] , ul [ class "dropdown-menu" ] topButtons ] - , button [class "btn btn-default", type_ "button", onClick CloseRuleDetails][text "Close", i [ class "fa fa-times"][]] + , button [class "btn btn-default", type_ "button", onClick CloseDetails][text "Close", i [ class "fa fa-times"][]] , button [class "btn btn-success", type_ "button", onClick (CallApi (saveRuleDetails rule isNewRule))][text "Save", i [ class "fa fa-download"] []] ] ] diff --git a/webapp/sources/rudder/rudder-web/src/main/webapp/style/rudder/rudder-template.css b/webapp/sources/rudder/rudder-web/src/main/webapp/style/rudder/rudder-template.css index ba845a836fb..d7ea98dbe85 100644 --- a/webapp/sources/rudder/rudder-web/src/main/webapp/style/rudder/rudder-template.css +++ b/webapp/sources/rudder/rudder-web/src/main/webapp/style/rudder/rudder-template.css @@ -124,7 +124,7 @@ .rudder-template .header-title .title-icon{ opacity: .4; font-size: 0.8em; - margin-right: 2px; + margin-right: 8px; } .rudder-template .header-title h1{ padding: 0;