Skip to content

Commit

Permalink
Merge branch 'arch_23656/rewrite_nodes_compliance_table_in_elm_pr' in…
Browse files Browse the repository at this point in the history
…to branches/rudder/8.0
  • Loading branch information
Jenkins CI committed Nov 13, 2023
2 parents 72ffd2f + bb35418 commit 143cd53
Show file tree
Hide file tree
Showing 9 changed files with 848 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
module NodeCompliance.ApiCalls exposing (..)

import Http exposing (..)
import Url.Builder exposing (QueryParameter)

import NodeCompliance.DataTypes exposing (..)
import NodeCompliance.JsonDecoder exposing (..)


--
-- This files contains all API calls for the Directive compliance UI
--

getUrl: Model -> List String -> List QueryParameter -> String
getUrl m url p=
Url.Builder.relative (m.contextPath :: "secure" :: "api" :: url) p

getPolicyMode : Model -> Cmd Msg
getPolicyMode model =
let
req =
request
{ method = "GET"
, headers = []
, url = getUrl model [ "settings", "global_policy_mode" ] []
, body = emptyBody
, expect = expectJson GetPolicyModeResult decodeGetPolicyMode
, timeout = Nothing
, tracker = Nothing
}
in
req

getNodeCompliance : Model -> Cmd Msg
getNodeCompliance model =
let
req =
request
{ method = "GET"
, headers = []
, url = getUrl model [ "compliance", "nodes", model.nodeId.value ] []
, body = emptyBody
, expect = expectJson GetNodeComplianceResult decodeGetNodeCompliance
, timeout = Nothing
, tracker = Nothing
}
in
req
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module NodeCompliance.DataTypes exposing (..)

import Dict exposing (Dict)
import Http exposing (Error)

import Compliance.DataTypes exposing (..)

--
-- All our data types
--

type alias RuleId = { value : String }
type alias DirectiveId = { value : String }
type alias NodeId = { value : String }


type alias NodeCompliance =
{ nodeId : NodeId
, name : String
, compliance : Float
, policyMode : String
, complianceDetails : ComplianceDetails
, rules : List RuleCompliance
}

type alias RuleCompliance =
{ ruleId : RuleId
, name : String
, compliance : Float
, complianceDetails : ComplianceDetails
, directives : List (DirectiveCompliance ValueCompliance)
}

type alias DirectiveCompliance value =
{ directiveId : DirectiveId
, name : String
, compliance : Float
, complianceDetails : ComplianceDetails
, components : List (ComponentCompliance value)
}

type alias TableFilters =
{ sortOrder : SortOrder
, filter : String
, openedRows : Dict String (String, SortOrder)
}

type SortOrder = Asc | Desc

type alias UI =
{ tableFilters : TableFilters
, complianceFilters : ComplianceFilters
, loading : Bool
}

type alias Model =
{ nodeId : NodeId
, contextPath : String
, policyMode : String
, ui : UI
, nodeCompliance : Maybe NodeCompliance
}

type Msg
= Ignore
| UpdateFilters TableFilters
| UpdateComplianceFilters ComplianceFilters
| GoTo String
| ToggleRow String String
| ToggleRowSort String String SortOrder
| GetPolicyModeResult (Result Error String)
| GetNodeComplianceResult (Result Error NodeCompliance)
| CallApi (Model -> Cmd Msg)
| Refresh

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module NodeCompliance.Init exposing (..)

import Dict exposing (Dict)

import NodeCompliance.ApiCalls exposing (..)
import NodeCompliance.DataTypes exposing (..)
import Compliance.DataTypes exposing (..)


init : { nodeId : String, contextPath : String } -> ( Model, Cmd Msg )
init flags =
let
initFilters = (TableFilters Asc "" Dict.empty)
initUI = UI initFilters (ComplianceFilters False False []) True
initModel = Model (DirectiveId flags.nodeId) flags.contextPath "" initUI Nothing
listInitActions =
[ getPolicyMode initModel
, getNodeCompliance initModel
]
in
( initModel
, Cmd.batch listInitActions
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
module NodeCompliance.JsonDecoder exposing (..)

import Json.Decode exposing (..)
import Json.Decode.Pipeline exposing (..)
import Json.Decode.Field exposing (require)

import NodeCompliance.DataTypes exposing (..)
import Compliance.DataTypes exposing (..)


decodeGetPolicyMode : Decoder String
decodeGetPolicyMode =
at ["data", "settings", "global_policy_mode" ] string

decodeGetNodeCompliance : Decoder NodeCompliance
decodeGetNodeCompliance =
at ["data", "nodes" ] (index 0 decodeNodeCompliance)

decodeNodeCompliance : Decoder NodeCompliance
decodeNodeCompliance =
succeed NodeCompliance
|> required "id" (map NodeId string)
|> required "name" string
|> required "compliance" float
|> required "mode" string
|> required "complianceDetails" decodeComplianceDetails
|> required "rules" (list decodeRuleCompliance)

decodeRuleCompliance : Decoder RuleCompliance
decodeRuleCompliance =
succeed RuleCompliance
|> required "id" (map NodeId string)
|> required "name" string
|> required "compliance" float
|> required "complianceDetails" decodeComplianceDetails
|> required "directives" (list (decodeDirectiveCompliance "values" decodeValueCompliance ))

decodeDirectiveCompliance : String -> Decoder a -> Decoder (DirectiveCompliance a)
decodeDirectiveCompliance elem decoder =
succeed DirectiveCompliance
|> required "id" (map DirectiveId string)
|> required "name" string
|> required "compliance" float
|> required "complianceDetails" decodeComplianceDetails
|> required "components" (list (decodeComponentCompliance elem decoder ))

decodeComplianceDetails : Decoder ComplianceDetails
decodeComplianceDetails =
succeed ComplianceDetails
|> optional "successNotApplicable" (map Just float) Nothing
|> optional "successAlreadyOK" (map Just float) Nothing
|> optional "successRepaired" (map Just float) Nothing
|> optional "error" (map Just float) Nothing
|> optional "auditCompliant" (map Just float) Nothing
|> optional "auditNonCompliant" (map Just float) Nothing
|> optional "auditError" (map Just float) Nothing
|> optional "auditNotApplicable" (map Just float) Nothing
|> optional "unexpectedUnknownComponent" (map Just float) Nothing
|> optional "unexpectedMissingComponent" (map Just float) Nothing
|> optional "noReport" (map Just float) Nothing
|> optional "reportsDisabled" (map Just float) Nothing
|> optional "applying" (map Just float) Nothing
|> optional "badPolicyMode" (map Just float) Nothing

decodeComponentValueCompliance : String -> Decoder a -> Decoder (ComponentValueCompliance a)
decodeComponentValueCompliance elem decoder =
succeed ComponentValueCompliance
|> required "name" string
|> required "compliance" float
|> required "complianceDetails" decodeComplianceDetails
|> required elem (list decoder)

decodeComponentCompliance : String -> Decoder a -> Decoder (ComponentCompliance a)
decodeComponentCompliance elem decoder =
oneOf [
map (\b -> Block b) <| decodeBlockCompliance elem decoder ()
, map (\v -> Value v) <| decodeComponentValueCompliance elem decoder
]

decodeBlockCompliance : String -> Decoder a -> () -> Decoder (BlockCompliance a)
decodeBlockCompliance elem decoder _ =
require "name" string <| \name ->
require "compliance" float <| \compliance ->
require "complianceDetails" decodeComplianceDetails <| \details ->
require "components" (list (decodeComponentCompliance elem decoder)) <| \components ->
succeed ({ component = name, compliance = compliance, complianceDetails = details, components = components } )

decodeReport : Decoder Report
decodeReport =
succeed Report
|> required "status" string
|> optional "message" (maybe string) Nothing

decodeValueCompliance : Decoder ValueCompliance
decodeValueCompliance =
succeed ValueCompliance
|> required "value" string
|> required "reports" (list decodeReport)
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module NodeCompliance.View exposing (..)

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick, onInput)
import List
import Html.Lazy
import Tuple3
import Dict
import List.Extra

import NodeCompliance.ApiCalls exposing (..)
import NodeCompliance.DataTypes exposing (..)
import NodeCompliance.ViewUtils exposing (..)
import Compliance.Utils exposing (displayComplianceFilters, filterDetailsByCompliance)


view : Model -> Html Msg
view model =
let
ui = model.ui
displayComplianceTable : Model -> Html Msg
displayComplianceTable mod =
let
filters = mod.ui.tableFilters
complianceFilters = mod.ui.complianceFilters
fun = byRuleCompliance mod complianceFilters
col = "Rule"
childs = case mod.nodeCompliance of
Just dc -> dc.rules
Nothing -> []
childrenSort = childs
|> List.filter (\r -> (filterSearch filters.filter (searchFieldRuleCompliance r)))
|> List.filter (filterDetailsByCompliance complianceFilters)
|> List.sortWith sort

(children, order, newOrder) = case sortOrder of
Asc -> (childrenSort, "asc", Desc)
Desc -> (List.reverse childrenSort, "desc", Asc)

rowId = "by" ++ col ++ "s/"
rows = List.map Tuple3.first fun.rows
(sortId, sortOrder) = Dict.get rowId filters.openedRows |> Maybe.withDefault (col, Asc)
sort = case List.Extra.find (Tuple3.first >> (==) sortId) fun.rows of
Just (_,_,sortFun) -> (\i1 i2 -> sortFun (fun.data mod i1) (fun.data mod i2))
Nothing -> (\_ _ -> EQ)
in
( if mod.ui.loading then
generateLoadingTable
else
div[]
[ div [class "table-header extra-filters"]
[ div[class "main-filters"]
[ input [type_ "text", placeholder "Filter", class "input-sm form-control", value filters.filter, onInput (\s -> (UpdateFilters {filters | filter = s} ))][]
, button [class "btn btn-default btn-sm btn-icon", onClick (UpdateComplianceFilters {complianceFilters | showComplianceFilters = not complianceFilters.showComplianceFilters}), style "min-width" "170px"]
[ text ((if complianceFilters.showComplianceFilters then "Hide " else "Show ") ++ "compliance filters")
, i [class ("fa " ++ (if complianceFilters.showComplianceFilters then "fa-minus" else "fa-plus"))][]
]
, button [class "btn btn-default btn-sm btn-refresh", onClick Refresh ]
[ i [ class "fa fa-refresh" ] [] ]
]
, displayComplianceFilters complianceFilters UpdateComplianceFilters
]
, div[class "table-container"]
[ table [class "dataTable compliance-table"]
[ thead []
[ tr [ class "head" ]
( List.map (\row -> th [onClick (ToggleRowSort rowId row (if row == sortId then newOrder else Asc)), class ("sorting" ++ (if row == sortId then "_"++order else ""))] [ text row ]) rows )
]
, tbody []
( if List.length childs <= 0 then
[ tr[]
[ td[class "empty", colspan 2][i [class"fa fa-exclamation-triangle"][], text "There is no compliance for this directive."] ]
]
else if List.length children == 0 then
[ tr[]
[ td[class "empty", colspan 2][i [class"fa fa-exclamation-triangle"][], text "No nodes match your filter."] ]
]
else
List.concatMap (\d -> showComplianceDetails fun d "" filters.openedRows mod) children
)
]
]
])
in
div [class "tab-table-content"][Html.Lazy.lazy displayComplianceTable model]
Loading

0 comments on commit 143cd53

Please sign in to comment.