Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphaelGauthier committed Oct 26, 2023
1 parent 9c0d9e2 commit fb49da9
Show file tree
Hide file tree
Showing 9 changed files with 915 additions and 1 deletion.
@@ -0,0 +1,64 @@
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

getDirectiveCompliance : Model -> Cmd Msg
getDirectiveCompliance model =
let
req =
request
{ method = "GET"
, headers = []
, url = getUrl model [ "compliance", "nodes", model.nodeId.value ] []
, body = emptyBody
, expect = expectJson GetDirectiveComplianceResult decodeGetDirectiveCompliance
, timeout = Nothing
, tracker = Nothing
}
in
req

getCSVExport : Model -> Cmd Msg
getCSVExport model =
let
req =
request
{ method = "GET"
, headers = []
, url = getUrl model [ "compliance", "directives", model.nodeId.value ] [ Url.Builder.string "format" "csv"]
, body = emptyBody
, expect = expectString Export
, timeout = Nothing
, tracker = Nothing
}
in
req
@@ -0,0 +1,84 @@
module NodeCompliance.DataTypes exposing (..)

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

import Compliance.DataTypes exposing (..)
import Rules.DataTypes exposing (RuleCompliance)
--
-- All our data types
--

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

type alias DirectiveCompliance =
{ compliance : Float
, policyMode : String
, complianceDetails : ComplianceDetails
, rules : List (RuleCompliance NodeValueCompliance)
, nodes : List NodeCompliance
}

type alias RuleCompliance value =
{ ruleId : RuleId
, name : String
, compliance : Float
, complianceDetails : ComplianceDetails
, components : List (ComponentCompliance value)
}

type alias NodeValueCompliance =
{ nodeId : NodeId
, name : String
, policyMode : String
, compliance : Float
, complianceDetails : ComplianceDetails
, values : List ValueCompliance
}

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


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
, directiveCompliance : Maybe DirectiveCompliance
}

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

@@ -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
, getDirectiveCompliance initModel
]
in
( initModel
, Cmd.batch listInitActions
)
@@ -0,0 +1,109 @@
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


decodeGetDirectiveCompliance : Decoder DirectiveCompliance
decodeGetDirectiveCompliance =
at ["data", "directiveCompliance" ] decodeDirectiveCompliance

decodeDirectiveCompliance : Decoder DirectiveCompliance
decodeDirectiveCompliance =
succeed DirectiveCompliance
|> required "compliance" float
|> required "policyMode" string
|> required "complianceDetails" decodeComplianceDetails
|> required "rules" (list (decodeRuleCompliance "nodes" decodeNodeCompliance) )
|> required "nodes" (list decodeRuleComplianceByNode )

decodeRuleComplianceByNode : Decoder NodeCompliance
decodeRuleComplianceByNode =
succeed NodeCompliance
|> required "id" (map NodeId string)
|> required "name" string
|> required "compliance" float
|> required "policyMode" string
|> required "complianceDetails" decodeComplianceDetails
|> required "rules" (list (decodeRuleCompliance "values" decodeValueCompliance ))

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

decodeNodeCompliance : Decoder NodeValueCompliance
decodeNodeCompliance =
succeed NodeValueCompliance
|> required "id" (map NodeId string)
|> required "name" string
|> required "policyMode" string
|> required "compliance" float
|> required "complianceDetails" decodeComplianceDetails
|> required "values" (list decodeValueCompliance)

decodeValueCompliance : Decoder ValueCompliance
decodeValueCompliance =
succeed ValueCompliance
|> required "value" string
|> required "reports" (list decodeReport)

decodeRuleCompliance : String -> Decoder a -> Decoder (RuleCompliance a)
decodeRuleCompliance elem decoder =
succeed RuleCompliance
|> required "id" (map RuleId 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 } )
@@ -0,0 +1,16 @@
module NodeCompliance.View exposing (..)

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import List
import Html.Lazy

import NodeCompliance.DataTypes exposing (..)
import NodeCompliance.ViewUtils exposing (..)
import NodeCompliance.ViewCompliance exposing (..)


view : Model -> Html Msg
view model =
div [class "tab-table-content"][Html.Lazy.lazy displayComplianceTable model]
@@ -0,0 +1,78 @@
module NodeCompliance.ViewCompliance exposing (..)

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

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


displayComplianceTable : Model -> Html Msg
displayComplianceTable model =
let
filters = model.ui.tableFilters
complianceFilters = model.ui.complianceFilters
fun = byNodeCompliance model complianceFilters
col = "Node"
childs = case model.directiveCompliance of
Just dc -> dc.nodes
Nothing -> []
childrenSort = childs
|> List.filter (\n -> (filterSearch filters.filter (searchFieldNodeCompliance n)))
|> 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 model i1) (fun.data model i2))
Nothing -> (\_ _ -> EQ)
in
( if model.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"))][]
]
]
, 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 model) children
)
]
]
])

0 comments on commit fb49da9

Please sign in to comment.