mirror of
https://github.com/valitydev/wazuh-kibana-app.git
synced 2024-11-06 18:05:20 +00:00
New directive to edit xml files
This commit is contained in:
parent
a2f1cb9fbc
commit
635af9d7fa
@ -11,7 +11,6 @@
|
||||
*/
|
||||
import beautifier from '../../utils/json-beautifier';
|
||||
import * as FileSaver from '../../services/file-saver';
|
||||
import CodeMirror from '../../utils/codemirror/lib/codemirror';
|
||||
|
||||
export function GroupsController(
|
||||
$scope,
|
||||
@ -22,8 +21,7 @@ export function GroupsController(
|
||||
appState,
|
||||
shareAgent,
|
||||
$document,
|
||||
wzTableFilter,
|
||||
$timeout
|
||||
wzTableFilter
|
||||
) {
|
||||
$scope.$on('groupsIsReloaded', () => {
|
||||
$scope.currentGroup = false;
|
||||
@ -61,19 +59,6 @@ export function GroupsController(
|
||||
const globalAgent = shareAgent.getAgent();
|
||||
|
||||
const load = async () => {
|
||||
$scope.xmlCodeBox = CodeMirror.fromTextArea(
|
||||
$document[0].getElementById('xml_box'),
|
||||
{
|
||||
lineNumbers: true,
|
||||
matchClosing: true,
|
||||
matchBrackets: true,
|
||||
mode: 'text/xml',
|
||||
theme: 'ttcn',
|
||||
foldGutter: true,
|
||||
styleSelectedText: true,
|
||||
gutters: ['CodeMirror-foldgutter']
|
||||
}
|
||||
);
|
||||
try {
|
||||
// If come from agents
|
||||
if (globalAgent) {
|
||||
@ -197,33 +182,10 @@ export function GroupsController(
|
||||
return;
|
||||
};
|
||||
|
||||
const autoFormat = () => {
|
||||
var totalLines = $scope.xmlCodeBox.lineCount();
|
||||
var totalChars = $scope.xmlCodeBox.getTextArea().value.length;
|
||||
$scope.xmlCodeBox.autoFormatRange({ line: 0, ch: 0 }, { line: totalLines, ch: totalChars });
|
||||
}
|
||||
|
||||
$scope.editGroupAgentConfig = (group, params) => {
|
||||
$timeout(function () { $scope.xmlCodeBox.refresh() });
|
||||
$scope.editingGroupAgentConfig = true;
|
||||
$scope.editingGroupAgentConfigItem = params.group;
|
||||
try {
|
||||
const xml = "<bookstore>\n<book>\n" +
|
||||
"<title>Everyday Italian</title>\n" +
|
||||
"<author>Giada De Laurentiis</author>\n" +
|
||||
"<year>2005</year>\n" +
|
||||
"</book>\n</bookstore>";
|
||||
$scope.xmlCodeBox.setValue(xml);
|
||||
autoFormat();
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
$scope.$on('editGroupAgentConfig', (group, params) => $scope.editGroupAgentConfig(group, params));
|
||||
// Resetting the factory configuration
|
||||
$scope.$on('$destroy', () => { });
|
||||
|
||||
$scope.$watch('lookingGroup', value => {
|
||||
$scope.$watch('lookingGroup', value => {
|
||||
if (!value) {
|
||||
$scope.file = false;
|
||||
$scope.filename = false;
|
||||
|
@ -22,3 +22,5 @@ import './wz-config-item/wz-config-item.less';
|
||||
import './wz-tag-filter/wz-tag-filter';
|
||||
import './wz-tag-filter/wz-tag-filter.less';
|
||||
import './wz-config-viewer/wz-config-viewer';
|
||||
import './wz-xml-file-editor/wz-xml-file-editor';
|
||||
import './wz-xml-file-editor/wz-xml-file-editor.less';
|
||||
|
@ -38,6 +38,7 @@ app.directive('wzTable', function () {
|
||||
extraLimit: '=extraLimit'
|
||||
},
|
||||
controller(
|
||||
$rootScope,
|
||||
$scope,
|
||||
apiReq,
|
||||
$timeout,
|
||||
@ -255,7 +256,7 @@ app.directive('wzTable', function () {
|
||||
};
|
||||
|
||||
$scope.editGroupAgentConfig = (ev, group) => {
|
||||
$scope.$emit('editGroupAgentConfig', { group });
|
||||
$rootScope.$emit('editXmlFile', { 'target' : group });
|
||||
};
|
||||
|
||||
$scope.showConfirm = function (ev, agent) {
|
||||
|
15
public/directives/wz-xml-file-editor/wz-xml-file-editor.html
Normal file
15
public/directives/wz-xml-file-editor/wz-xml-file-editor.html
Normal file
@ -0,0 +1,15 @@
|
||||
<div class='wzEmbedDialog' ng-show='!lookingGroup && editingFile'>
|
||||
<div class='wzEmbedDialogHeader'>
|
||||
<span>Edit <b>{{fileName}}</b> of <b>{{targetName}}</b></span>
|
||||
<i aria-hidden='true' class='fa fa-fw fa-times cursor-pointer' ng-click='editingFile = false'></i>
|
||||
</div>
|
||||
<div ng-show='!loadingFile'>
|
||||
<textarea id='xml_box'></textarea>
|
||||
</div>
|
||||
<div class='wzEmbedDialogFooter'>
|
||||
<span ng-disabled='xmlHasErrors' ng-click='saveFile()' class='btn btn-primary'><i aria-hidden='true' class='fa fa-fw fa-save'></i>
|
||||
Save file</span>
|
||||
<span ng-show='xmlHasErrors' class='btn-danger'><i aria-hidden='true' class='fa fa-fw fa-exclamation-triangle'></i>
|
||||
XML format error</span>
|
||||
</div>
|
||||
</div>
|
128
public/directives/wz-xml-file-editor/wz-xml-file-editor.js
Normal file
128
public/directives/wz-xml-file-editor/wz-xml-file-editor.js
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Wazuh app - Wazuh XML file editor
|
||||
* Copyright (C) 2018 Wazuh, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Find more information about this on the LICENSE file.
|
||||
*/
|
||||
|
||||
import template from './wz-xml-file-editor.html';
|
||||
import CodeMirror from '../../utils/codemirror/lib/codemirror';
|
||||
import { uiModules } from 'ui/modules';
|
||||
|
||||
const app = uiModules.get('app/wazuh', []);
|
||||
|
||||
app.directive('wzXmlFileEditor', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
loadPath: '=loadPath',
|
||||
updatePath: '=updatePath',
|
||||
fileName: '@fileName'
|
||||
},
|
||||
controller(
|
||||
$rootScope,
|
||||
$scope,
|
||||
$timeout,
|
||||
apiReq,
|
||||
$document,
|
||||
errorHandler
|
||||
) {
|
||||
$(document).ready(function () {
|
||||
$scope.xmlCodeBox = CodeMirror.fromTextArea(
|
||||
$document[0].getElementById('xml_box'),
|
||||
{
|
||||
lineNumbers: true,
|
||||
matchClosing: true,
|
||||
matchBrackets: true,
|
||||
mode: 'text/xml',
|
||||
theme: 'ttcn',
|
||||
foldGutter: true,
|
||||
styleSelectedText: true,
|
||||
gutters: ['CodeMirror-foldgutter']
|
||||
}
|
||||
);
|
||||
$scope.xmlHasErrors = false;
|
||||
$scope.xmlCodeBox.on('change', () => {
|
||||
checkXmlParseError();
|
||||
});
|
||||
const checkXmlParseError = () => {
|
||||
try {
|
||||
var parser = new DOMParser();
|
||||
var xml = $scope.xmlCodeBox.getValue();
|
||||
var xmlDoc = parser.parseFromString(xml, "text/xml");
|
||||
$timeout(function () {
|
||||
$scope.xmlHasErrors = xmlDoc.getElementsByTagName("parsererror").length > 0 ? true : false
|
||||
}, 50);
|
||||
} catch (error) {
|
||||
errorHandler.handle(error, 'Error validating XML');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const autoFormat = () => {
|
||||
var totalLines = $scope.xmlCodeBox.lineCount();
|
||||
$scope.xmlCodeBox.autoFormatRange({ 'line': 0, 'ch': 0 }, { line: totalLines - 1 });
|
||||
$scope.xmlCodeBox.setCursor(0);
|
||||
}
|
||||
|
||||
const updateFile = async () => {
|
||||
try {
|
||||
/*const response = await this.apiReq.request(
|
||||
'PUT',
|
||||
$scope.updatePath,
|
||||
{}
|
||||
);*/
|
||||
const response = "";
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.apiInputBox.model = [];
|
||||
}
|
||||
}
|
||||
|
||||
$scope.saveFile = async () => {
|
||||
const response = await updateFile();
|
||||
console.log(response);
|
||||
}
|
||||
|
||||
const fetchFile = async () => {
|
||||
try {
|
||||
/*const xml = = await this.apiReq.request(
|
||||
'GET',
|
||||
$scope.loadPath,
|
||||
{}
|
||||
);*/
|
||||
const xml = "<agent_config>" +
|
||||
"\n" +
|
||||
"<!-- Shared agent configuration here -->\n" +
|
||||
"\n" +
|
||||
"</agent_config>";
|
||||
return xml;
|
||||
} catch (error) {
|
||||
errorHandler.handle(error, 'Fetch file error');
|
||||
}
|
||||
}
|
||||
|
||||
$scope.editXmlFile = async (item, params) => {
|
||||
$scope.editingFile = true;
|
||||
$scope.loadingFile = true;
|
||||
$scope.targetName = params.target.name;
|
||||
try {
|
||||
const xml = await fetchFile();
|
||||
$scope.xmlCodeBox.setValue(xml);
|
||||
autoFormat();
|
||||
$scope.loadingFile = false;
|
||||
$timeout(function () { $scope.xmlCodeBox.refresh() }, 100);
|
||||
} catch (error) {
|
||||
errorHandler.handle(error, 'Fetch file error');
|
||||
}
|
||||
};
|
||||
$rootScope.$on('editXmlFile', (item, params) => $scope.editXmlFile(item, params));
|
||||
},
|
||||
template
|
||||
};
|
||||
});
|
45
public/directives/wz-xml-file-editor/wz-xml-file-editor.less
Normal file
45
public/directives/wz-xml-file-editor/wz-xml-file-editor.less
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Wazuh app - Wazuh XML file editor stylesheet
|
||||
* Copyright (C) 2018 Wazuh, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Find more information about this on the LICENSE file.
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* ------------------ Wazuh XML file editor stylesheet ---------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
.wzEmbedDialog{
|
||||
width: 50vw;
|
||||
height: 400px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
border: 1px solid #e0e0e0;
|
||||
min-width: 500px;
|
||||
margin: 5px;
|
||||
border-radius: 3px;
|
||||
right: 0;
|
||||
box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
.wzEmbedDialogHeader{
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.wzEmbedDialogHeader b{
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wzEmbedDialogHeader i{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.wzEmbedDialogFooter{
|
||||
padding: 10px;
|
||||
border-top: 1px solid #dddddd;
|
||||
}
|
@ -507,29 +507,4 @@ md-sidenav {
|
||||
|
||||
.visualization {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.wzEmbedDialog{
|
||||
width: 50vw;
|
||||
height: 400px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
border: 1px solid #e0e0e0;
|
||||
min-width: 500px;
|
||||
margin: 5px;
|
||||
border-radius: 3px;
|
||||
right: 0;
|
||||
box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
.wzEmbedDialogHeader{
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.wzEmbedDialogHeader i{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.wzEmbedDialogFooter{
|
||||
padding: 10px;
|
||||
border-top: 1px solid #dddddd;
|
||||
}
|
@ -90,18 +90,10 @@
|
||||
<!-- End CSV Download button section for groups -->
|
||||
|
||||
<!-- XML editor for group agents -->
|
||||
<div class="wzEmbedDialog" ng-show="!lookingGroup && editingGroupAgentConfig" >
|
||||
<div class="wzEmbedDialogHeader">
|
||||
<span>Edit <b>agent.conf</b> of {{editingGroupAgentConfigItem.name}}</span>
|
||||
<i aria-hidden="true" class="fa fa-fw fa-times cursor-pointer" ng-click="editingGroupAgentConfig = false"></i>
|
||||
</div>
|
||||
<textarea id="xml_box"></textarea>
|
||||
<div class="wzEmbedDialogFooter">
|
||||
<span ng-click="saveGroupAgentConfig()" class="btn btn-primary"><i aria-hidden="true" class="fa fa-fw fa-save"></i> Save file</span>
|
||||
</div>
|
||||
</div>
|
||||
<wz-xml-file-editor file-name='agents.conf' load-path='hola' update-path='adios'>
|
||||
</wz-xml-file-editor>
|
||||
<!-- XML editor for group agents -->
|
||||
|
||||
|
||||
<!-- Group agents table -->
|
||||
<div layout="row" ng-if="lookingGroup && groupsSelectedTab==='agents' && currentGroup" class="md-padding">
|
||||
<wz-table flex path="'/agents/groups/' + currentGroup.name" keys="['id','name','ip','status','os.name','os.version','version']"
|
||||
|
118
public/utils/codemirror/formatting.js
Normal file
118
public/utils/codemirror/formatting.js
Normal file
@ -0,0 +1,118 @@
|
||||
(function(mod) {
|
||||
if (typeof exports == 'object' && typeof module == 'object')
|
||||
// CommonJS
|
||||
mod(require('./lib/codemirror'), require('./foldcode'));
|
||||
else if (typeof define == 'function' && define.amd)
|
||||
// AMD
|
||||
define(['./lib/codemirror', './foldcode'], mod);
|
||||
// Plain browser env
|
||||
else mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
'use strict';
|
||||
|
||||
CodeMirror.extendMode("css", {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
newlineAfterToken: function(type, content) {
|
||||
return /^[;{}]$/.test(content);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.extendMode("javascript", {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
// FIXME semicolons inside of for
|
||||
newlineAfterToken: function(type, content, textAfter, state) {
|
||||
if (this.jsonMode) {
|
||||
return /^[\[,{]$/.test(content) || /^}/.test(textAfter);
|
||||
} else {
|
||||
if (content == ";" && state.lexical && state.lexical.type == ")") return false;
|
||||
return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.extendMode("xml", {
|
||||
commentStart: "<!--",
|
||||
commentEnd: "-->",
|
||||
newlineAfterToken: function(type, content, textAfter) {
|
||||
return type == "tag" && />$/.test(content) || /^</.test(textAfter);
|
||||
}
|
||||
});
|
||||
|
||||
// Comment/uncomment the specified range
|
||||
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
|
||||
var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
|
||||
cm.operation(function() {
|
||||
if (isComment) { // Comment range
|
||||
cm.replaceRange(curMode.commentEnd, to);
|
||||
cm.replaceRange(curMode.commentStart, from);
|
||||
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
|
||||
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
|
||||
} else { // Uncomment range
|
||||
var selText = cm.getRange(from, to);
|
||||
var startIndex = selText.indexOf(curMode.commentStart);
|
||||
var endIndex = selText.lastIndexOf(curMode.commentEnd);
|
||||
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
|
||||
// Take string till comment start
|
||||
selText = selText.substr(0, startIndex)
|
||||
// From comment start till comment end
|
||||
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
|
||||
// From comment end till string end
|
||||
+ selText.substr(endIndex + curMode.commentEnd.length);
|
||||
}
|
||||
cm.replaceRange(selText, from, to);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Applies automatic mode-aware indentation to the specified range
|
||||
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
|
||||
var cmInstance = this;
|
||||
this.operation(function () {
|
||||
for (var i = from.line; i <= to.line; i++) {
|
||||
cmInstance.indentLine(i, "smart");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Applies automatic formatting to the specified range
|
||||
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
|
||||
var cm = this;
|
||||
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
|
||||
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
|
||||
var tabSize = cm.getOption("tabSize");
|
||||
|
||||
var out = "", lines = 0, atSol = from.ch == 0;
|
||||
function newline() {
|
||||
out += "\n";
|
||||
atSol = true;
|
||||
++lines;
|
||||
}
|
||||
|
||||
for (var i = 0; i < text.length; ++i) {
|
||||
var stream = new CodeMirror.StringStream(text[i], tabSize);
|
||||
while (!stream.eol()) {
|
||||
var inner = CodeMirror.innerMode(outer, state);
|
||||
var style = outer.token(stream, state), cur = stream.current();
|
||||
stream.start = stream.pos;
|
||||
if (!atSol || /\S/.test(cur)) {
|
||||
out += cur;
|
||||
atSol = false;
|
||||
}
|
||||
if (!atSol && inner.mode.newlineAfterToken &&
|
||||
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state))
|
||||
newline();
|
||||
}
|
||||
if (!stream.pos && outer.blankLine) outer.blankLine(state);
|
||||
if (!atSol) newline();
|
||||
}
|
||||
|
||||
cm.operation(function () {
|
||||
cm.replaceRange(out, from, to);
|
||||
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
|
||||
cm.indentLine(cur, "smart");
|
||||
cm.setSelection(from, cm.getCursor(false));
|
||||
});
|
||||
});
|
||||
});
|
@ -6,6 +6,7 @@ import './foldgutter.css';
|
||||
import './ttcn.css';
|
||||
import './javascript.js';
|
||||
import './xml.js';
|
||||
import './formatting.js';
|
||||
import './brace-fold.js';
|
||||
import './foldcode.js';
|
||||
import './foldgutter.js';
|
||||
|
Loading…
Reference in New Issue
Block a user