Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphaelGauthier committed Dec 8, 2023
1 parent 79fd607 commit c4e796e
Show file tree
Hide file tree
Showing 13 changed files with 729 additions and 717 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,6 @@ function refuseEnter(event)
}
}

/* portlet */

$(function() {

$(".portlet").addClass("ui-widget ui-widget-content ui-helper-clearfix arrondis")
.find(".portlet-header")
.addClass("ui-widget-header")
.end()
.find(".portlet-content");

$(".portlet-header .ui-icon").click(function() {
$(this).toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
$(this).parents(".portlet:first").find(".portlet-content").toggle();
});

});


/**
* Check all checkbox named name according to the status of the checkbox with id id
* @param id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,29 +43,41 @@ import com.normation.eventlog.ModificationId
import com.normation.inventory.domain.AcceptedInventory
import com.normation.inventory.domain.FullInventory
import com.normation.inventory.domain.NodeId
import com.normation.inventory.domain.NodeSummary
import com.normation.plugins.DefaultExtendableSnippet
import com.normation.rudder.batch.AutomaticStartDeployment
import com.normation.rudder.domain.Constants
import com.normation.rudder.domain.logger.NodeLoggerPure
import com.normation.rudder.domain.nodes.NodeInfo
import com.normation.rudder.domain.nodes.NodeState
import com.normation.rudder.domain.policies.GlobalPolicyMode
import com.normation.rudder.facts.nodes.ChangeContext
import com.normation.rudder.hooks.HookReturnCode
import com.normation.rudder.reports.AgentRunInterval
import com.normation.rudder.reports.GlobalComplianceMode
import com.normation.rudder.reports.HeartbeatConfiguration
import com.normation.rudder.reports.NodeComplianceMode
import com.normation.rudder.repository.FullNodeGroupCategory
import com.normation.rudder.services.servers.DeleteMode
import com.normation.rudder.web.ChooseTemplate
import com.normation.rudder.web.model.JsNodeId
import com.normation.rudder.web.services.CurrentUser
import com.normation.rudder.web.services.DisplayNode
import com.normation.rudder.web.services.DisplayNode.displayMachineType
import com.normation.rudder.web.services.DisplayNode.getNodeState
import com.normation.rudder.web.services.DisplayNodeGroupTree
import com.normation.rudder.web.snippet.RegisterToasts
import com.normation.rudder.web.snippet.ToastNotification
import net.liftweb.common._
import net.liftweb.http.DispatchSnippet
import net.liftweb.http.S
import net.liftweb.http.SHtml
import net.liftweb.http.js.JE.JsRaw
import net.liftweb.http.js.JsCmd
import net.liftweb.http.js.JsCmds._
import net.liftweb.http.js.JsExp
import net.liftweb.util.Helpers._
import org.joda.time.DateTime
import scala.xml.NodeSeq

object ShowNodeDetailsFromNode {
Expand Down Expand Up @@ -261,12 +273,12 @@ class ShowNodeDetailsFromNode(
val jsId = JsNodeId(nodeId, "")
def htmlId(jsId: JsNodeId, prefix: String): String = prefix + jsId.toString
val detailsId = htmlId(jsId, "details_")

configService.rudder_global_policy_mode().toBox match {
case Full(globalMode) =>
bindNode(node, sm, withinPopup, globalMode) ++ Script(
DisplayNode.jsInit(node.id, sm.node.softwareIds, "") &
JsRaw(s"""
$$('#nodeHostname').html("${xml.Utility.escape(sm.node.main.hostname)}");
$$( "#${detailsId}" ).tabs({ active : ${tab} } );
$$('#nodeInventory .ui-tabs-vertical .ui-tabs-nav li a').on('click',function(){
var tab = $$(this).attr('href');
Expand All @@ -275,6 +287,7 @@ class ShowNodeDetailsFromNode(
$$('#nodeInventory > .sInventory > .sInventory').hide();
$$(tab).show();
});
new ClipboardJS('[data-clipboard-text]');
""") &
buildJsTree(groupTreeId)
)
Expand All @@ -299,9 +312,155 @@ class ShowNodeDetailsFromNode(
* Show the content of a node in the portlet
* @return
*/
private[this] def removeNode(node: NodeSummary): JsCmd = {
implicit val cc: ChangeContext = ChangeContext(
ModificationId(uuidGen.newUuid),
CurrentUser.actor,
DateTime.now(),
None,
S.request.map(_.remoteAddr).toOption
)

// only erase for Rudder 8.0
RudderConfig.removeNodeService.removeNodePure(node.id, DeleteMode.Erase).toBox match {
case Full(_) =>
asyncDeploymentAgent ! AutomaticStartDeployment(cc.modId, cc.actor)
onSuccess(node)
case eb: EmptyBox =>
val message = s"There was an error while deleting node '${node.hostname}' [${node.id.value}]"
val e = eb ?~! message
NodeLoggerPure.Delete.logEffect.error(e.messageChain)
onFailure(node, message, e.messageChain, None)
}
}

private[this] def onFailure(
node: NodeSummary,
message: String,
details: String,
hookError: Option[HookReturnCode.Error]
): JsCmd = {
RegisterToasts.register(
ToastNotification.Error(
s"An error happened when trying to delete node '${node.hostname}' [${node.id.value}]. " +
"Please contact your server admin to resolve the problem. " +
s"Error was: '${message}'"
)
)
RedirectTo("/secure/nodeManager/nodes")
}

private[this] def onSuccess(node: NodeSummary): JsCmd = {
RegisterToasts.register(ToastNotification.Success(s"Node '${node.hostname}' [${node.id.value}] was correctly deleted"))
RedirectTo("/secure/nodeManager/nodes")
}

private[this] def isRootNode(n: NodeId): Boolean = {
n.value.equals("root");
}

private def bindNode(node: NodeInfo, inventory: FullInventory, withinPopup: Boolean, globalMode: GlobalPolicyMode): NodeSeq = {
val id = JsNodeId(node.id)
("#node_groupTree" #>

val machineTooltip: String = {
s"""
|<h4>Machine details</h4>
|<div class='tooltip-content'>
| <ul>
| <li><b>Type:</b> ${displayMachineType(inventory.machine)}</li>
| <li><b>Total physical memory (RAM):</b> ${xml.Utility.escape(
node.ram.map(_.toStringMo).getOrElse("-")
)}</li>
| <li><b>Manufacturer:</b> ${xml.Utility.escape(
inventory.machine.flatMap(x => x.manufacturer).map(x => x.name).getOrElse("-")
)}</li>
| <li><b>Total swap space:</b> ${xml.Utility.escape(inventory.node.swap.map(_.toStringMo).getOrElse("-"))}</li>
| <li><b>System serial number:</b> ${xml.Utility.escape(
inventory.machine.flatMap(x => x.systemSerialNumber).getOrElse("-")
)}</li>
| <li><b>Time zone:</b> ${xml.Utility.escape(
inventory.node.timezone
.map(x => if (x.name.toLowerCase == "utc") "UTC" else s"${x.name} (UTC ${x.offset})")
.getOrElse("unknown")
)}</li>
| <li>${inventory.machine
.map(_.id.value)
.map(machineId => "<b>Machine ID:</b> " ++ { xml.Utility.escape(machineId) })
.getOrElse("<span class='error'>Machine Information are missing for that node</span>")}</li>
| </ul>
|</div>
|""".stripMargin.replaceAll("\n", " ")
}

val headerInfo = {
<div id="nodeHeaderInfo">
<span class={"node-state " ++ getNodeState(node.state).toLowerCase} title={getNodeState(node.state)}></span>
<span>{node.hostname}</span>
<span class="machine-os-info">
<span class="machine-info">{node.osDetails.fullName}</span>
<span class="machine-info ram">{node.ram.map(_.toStringMo).getOrElse("-")}</span>
<span class="fa fa-info-circle icon-info" data-bs-toggle="tooltip" data-bs-placement="bottom" title={
machineTooltip
}></span>
</span>
</div>
}

val headerSubtitle = {
<div class="header-subtitle">
<a class="clipboard" title="Copy to clipboard" data-clipboard-text={inventory.node.main.id.value}>
<span id="nodeHeaderId">{inventory.node.main.id.value}</span>
<i class="ion ion-clipboard"></i>
</a>
</div>
}

val deleteBtn = {
inventory.node.main.status match {
case AcceptedInventory =>
<lift:authz role="node_write">
{
if (!isRootNode(inventory.node.main.id)) {
<button type="button" class="btn btn-danger btn-icon" data-bs-toggle="modal" data-bs-target="#nodeDeleteModal">
Delete
<i class="fa fa-times-circle"></i>
</button>
} else { NodeSeq.Empty }
}
</lift:authz>
case _ => NodeSeq.Empty
}
}
<lift:authz role="node_write">

</lift:authz>

val osTooltip: String = {
s"""
|<h4>Operating system details</h4>
|<div class='tooltip-content'>
| <ul>
| <li><b>Type:</b> ${xml.Utility.escape(inventory.node.main.osDetails.os.kernelName)}</li>
| <li><b>Name:</b> ${xml.Utility.escape(S.?("os.name." + inventory.node.main.osDetails.os.name))}</li>
| <li><b>Version:</b> ${xml.Utility.escape(inventory.node.main.osDetails.version.value)}</li>
| <li><b>Service pack:</b> ${xml.Utility.escape(inventory.node.main.osDetails.servicePack.getOrElse("None"))}</li>
| <li><b>Architecture:</b> ${xml.Utility.escape(inventory.node.archDescription.getOrElse("None"))}</li>
| <li><b>Kernel version:</b> ${xml.Utility.escape(inventory.node.main.osDetails.kernelVersion.value)}</li>
| </ul>
|</div>""".stripMargin.replaceAll("\n", " ")
}
("#nodeHeaderInfo" #> headerInfo &
"#nodeHeaderSubtitle" #> headerSubtitle &
"#nodeHeaderLogo" #> <div class={
"os-logo " ++ inventory.node.main.osDetails.os.name.toLowerCase()
} data-bs-toggle="tooltip" title={osTooltip}></div> &
"#nodeDeleteBtn" #> deleteBtn &
"#confirmNodeDeletion" #> SHtml.ajaxButton(
"Confirm",
() => { removeNode(inventory.node.main) },
("class", "btn btn-danger")
) &
"#node_groupTree" #>
<div id={groupTreeId}>
<ul>{DisplayNodeGroupTree.buildTreeKeepingGroupWithNode(groupLib, node, None, None, Map(("info", _ => Noop)))}</ul>
</div> &
Expand Down
Loading

0 comments on commit c4e796e

Please sign in to comment.