Commit 70c9b9f1 authored by Andrey Vertiprahov's avatar Andrey Vertiprahov
Browse files

Merge branch 'alarm-tag-tree' into 'master'

tag tree widget

See merge request noc/noc!4154
parents 56ca1a06 20d3797c
......@@ -9,6 +9,7 @@
import datetime
from collections import defaultdict
from functools import reduce
import re
# Third-party modules
from django.http import HttpResponse
......@@ -72,6 +73,8 @@ class ExtModelApplication(ExtApplication):
SECRET_MASK = "********"
file_fields_mask = None
rx_oper_splitter = re.compile(r"^(?P<field>\S+)(?P<f_num>\d+)__in")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.db_table = self.model._meta.db_table
......@@ -259,6 +262,19 @@ class ExtModelApplication(ExtApplication):
def cleaned_query(self, q):
nq = {}
q = q.copy()
# Extract IN
# extjs not working with same parameter name in query
for p in list(q.keys()):
if p.endswith(self.in_param):
match = self.rx_oper_splitter.match(p)
if match:
field = self.rx_oper_splitter.match(p).group("field") + self.in_param
if field not in q:
q[field] = "%s" % (q[p])
else:
q[field] += ",%s" % (q[p])
del q[p]
for p in q:
if p.endswith("__exists"):
v = BooleanParameter().clean(q[p])
......@@ -312,6 +328,8 @@ class ExtModelApplication(ExtApplication):
except self.fk_fields[np].DoesNotExist:
nq[np] = 0 # False search
continue
elif np in self.clean_fields and self.in_param in p:
v = ListOfParameter(self.clean_fields[np]).clean(v)
elif np in self.clean_fields: # @todo: Check for valid lookup types
v = self.clean_fields[np].clean(v)
# Write back
......
......@@ -174,6 +174,10 @@ class AlarmApplication(ExtApplication):
if q["administrative_domain"] != "_root_":
q["adm_path"] = int(q["administrative_domain"])
q.pop("administrative_domain")
if "administrative_domain__in" in q:
if "_root_" not in q["administrative_domain__in"]:
q["adm_path__in"] = q["administrative_domain__in"]
q.pop("administrative_domain__in")
if "segment" in q:
if q["segment"] != "_root_":
q["segment_path"] = bson.ObjectId(q["segment"])
......
......@@ -188,10 +188,6 @@ Ext.define("NOC.core.combotree.ComboTree", {
expanded: true,
children: []
},
// ToDo make variable for theme
bodyStyle: {
background: "#ecf0f1"
},
tbar: [
searchField
],
......@@ -240,18 +236,15 @@ Ext.define("NOC.core.combotree.ComboTree", {
doFilter: function() {
var me = this, parentNode = me.getParentNode();
if(parentNode) {
parentNode.removeAll();
if(me.searchField.getValue()) {
parentNode.appendChild(me.cache.filter(
function(node) {
return node.data[me.displayField].toLowerCase()
.indexOf(me.searchField.getValue().toLowerCase()) !== -1;
}
));
} else {
parentNode.appendChild(me.cache);
parentNode.expand();
}
me.treePicker.getStore().filterBy(function(record) {
if(record.parentNode.id !== me.currentLeaf) {
return true;
}
if(!me.searchField.getValue()) {
return true;
}
return record.get(me.displayField).toLowerCase().indexOf(me.searchField.getValue().toLowerCase()) !== -1;
})
}
},
// event handlers
......
......@@ -440,6 +440,7 @@ TABLE {
.x-fieldset {
overflow: visible;
background: unset;
}
.fas {
......
......@@ -84,13 +84,13 @@
cursor: default;
}
.x-panel-body-default {
background-color: #ecf0f1 !important;
}
/*.x-panel-body-default {*/
/* background-color: #ecf0f1 !important;*/
/*}*/
.x-grid-row {
background-color: #ecf0f1 !important;
}
/*.x-grid-row {*/
/* background-color: #ecf0f1 !important;*/
/*}*/
.x-summary {
color: #7f8c8d;
......
......@@ -237,12 +237,12 @@ Ext.define("NOC.fm.alarm.ApplicationController", {
Ext.each([
"managed_object",
"managedobjectselector",
"segment",
"administrative_domain"
"segment"
], restoreCombo, this);
// restore tag fields
Ext.each([
"alarm_class"
"alarm_class",
"administrative_domain"
], restoreTagField, this);
// don't change, http params is string compare with int, 0 == "0"
if(params.hasOwnProperty("cleared_after") && params.cleared_after != 0) {
......@@ -303,12 +303,12 @@ Ext.define("NOC.fm.alarm.ApplicationController", {
{key: "timestamp__lte"},
// tree
{key: "segment", valueField: "id"},
{key: "administrative_domain", valueField: "id"},
// combo
{key: "managed_object", valueField: "id"},
{key: "managedobjectselector", valueField: "id"},
// tag field
{key: "alarm_class", valueField: "id"}
{key: "alarm_class", valueField: "id"},
{key: "administrative_domain", valueField: "id"}
], setParam);
if(value.hasOwnProperty("profiles")) {
var i, len = value.profiles.length;
......
......@@ -74,7 +74,7 @@ Ext.define("NOC.fm.alarm.view.grids.Lookup", {
initComponent: function() {
this.store.proxy.url = this.url;
// Fix combobox with remote paging
this.pickerId = me.getId() + '_picker';
this.pickerId = this.getId() + '_picker';
// end
this.callParent();
}
......
......@@ -216,12 +216,13 @@ Ext.define("NOC.fm.alarm.view.grids.Sidebar", {
}
},
{
xtype: "noc.core.combotree",
restUrl: "/sa/administrativedomain/",
xtype: "fm.alarm.tagfield",
url: "/sa/administrativedomain/lookup/",
isTree: true,
fieldLabel: __("Adm. Domain"),
name: "administrative_domain",
bind: {
selection: "{activeFilter.administrative_domain}"
selected: "{activeFilter.administrative_domain}"
}
},
{
......
//---------------------------------------------------------------------
// fm.alarm application
// fm.alarm.tagfield widget
//---------------------------------------------------------------------
// Copyright (C) 2007-2019 The NOC Project
// Copyright (C) 2007-2020 The NOC Project
// See LICENSE for details
//---------------------------------------------------------------------
console.debug("Defining NOC.fm.alarm.view.grids.Tagfield");
......@@ -11,6 +11,7 @@ Ext.define("NOC.fm.alarm.view.grids.Tagfield", {
alias: "widget.fm.alarm.tagfield",
controller: "fm.alarm.tagfield",
requires: [
"NOC.fm.alarm.view.grids.TreePicker",
"NOC.fm.alarm.view.grids.TagfieldController"
],
displayField: "label",
......@@ -21,6 +22,7 @@ Ext.define("NOC.fm.alarm.view.grids.Tagfield", {
queryDelay: 200,
minChars: 2,
pageSize: true,
isTree: false,
store: {
fields: ["id", "label"],
pageSize: 25,
......@@ -48,10 +50,21 @@ Ext.define("NOC.fm.alarm.view.grids.Tagfield", {
"selected"
],
listeners: {
change: "onChange"
change: "onChangeTagValue"
},
initComponent: function() {
this.store.proxy.url = this.url;
if(this.isTree) {
// this.treePicker = this.createTreePicker();
this.triggers.picker.cls = "theme-classic fas fa fa-folder-open-o";
this.treePicker = Ext.create({
xtype: "fm.alarm.treepicker",
displayField: this.displayField,
scope: this,
});
}
// Fix combobox when use remote paging
this.pickerId = this.getId() + '-picker';
this.callParent();
},
setSelected: function(value, skip) {
......@@ -62,5 +75,25 @@ Ext.define("NOC.fm.alarm.view.grids.Tagfield", {
},
setWidgetValues: function(data) {
this.setSelection(data);
}
},
onTriggerClick: function(el) {
if(!el) {
return;
}
if(this.isTree) {
var position,
heightAbove = this.getPosition()[1] - Ext.getBody().getScroll().top,
heightBelow = Ext.Element.getViewportHeight() - heightAbove - this.getHeight();
this.treePicker.setWidth(this.getWidth());
this.treePicker.height = Math.max(heightAbove, heightBelow) - 5;
this.setEditable(false);
position = this.getPosition();
if(heightAbove > heightBelow) {
position[1] -= this.treePicker.height - this.getHeight();
}
this.treePicker.showAt(position);
} else {
Ext.form.field.Tag.prototype.onTriggerClick.apply(this, arguments);
}
},
});
//---------------------------------------------------------------------
// fm.alarm application
// Tagfield controller
//---------------------------------------------------------------------
// Copyright (C) 2007-2018 The NOC Project
// Copyright (C) 2007-2020 The NOC Project
// See LICENSE for details
//---------------------------------------------------------------------
console.debug("Defining NOC.fm.alarm.view.grids.TagfieldController");
......@@ -9,8 +9,12 @@ Ext.define("NOC.fm.alarm.view.grids.TagfieldController", {
extend: "Ext.app.ViewController",
alias: "controller.fm.alarm.tagfield",
onChange: function(self) {
var selected = self.getPicker().getSelectionModel().getSelection();
this.getView().setSelected(selected, true);
}
onChangeTagValue: function(self) {
var view = this.getView(),
selected = self.getPicker().getSelectionModel().getSelection();
if(view.isTree) {
view.treePicker.getController().selectNode(selected);
}
view.setSelected(selected, true);
},
});
\ No newline at end of file
//---------------------------------------------------------------------
// fm.alarm.treepicker widget
//---------------------------------------------------------------------
// Copyright (C) 2007-2020 The NOC Project
// See LICENSE for details
//---------------------------------------------------------------------
console.debug("Defining NOC.fm.alarm.view.grids.TreePicker");
Ext.define("NOC.fm.alarm.view.grids.TreePicker", {
extend: "Ext.tree.Panel",
alias: "widget.fm.alarm.treepicker",
controller: "fm.alarm.treepicker",
requires: [
"NOC.fm.alarm.view.grids.TreePickerController"
],
baseCls: Ext.baseCSSPrefix + "boundlist",
shrinkWrap: 2,
shrinkWrapDock: true,
animCollapse: true,
singleExpand: false,
useArrows: true,
scrollable: true,
floating: true,
manageHeight: false,
collapseFirst: false,
currentLeaf: false,
rootVisible: false,
root: {
expanded: true,
children: []
},
selModel: {
mode: "SIMPLE"
},
tbar: [
{
xtype: "searchfield",
width: "90%",
emptyText: __("pattern"),
enableKeyEvents: true,
triggers: {
clear: {
cls: "x-form-clear-trigger",
hidden: true,
handler: "onClearSearchField"
}
},
listeners: {
keyup: "onChangeSearchField"
}
},
{
glyph: NOC.glyph.times_circle,
tooltip: __("Close"),
handler: "onClosePanel"
}
],
listeners: {
itemclick: "onItemClick",
itemkeydown: "onPickerKeyDown",
beforeitemexpand: "onItemBeforeExpand",
itemexpand: "onItemExpand",
focusleave: "onLeaveFocusTreePicker"
},
initComponent: function() {
// tree panel store
this.treeStore = Ext.create("Ext.data.Store",
Ext.merge(
Ext.clone(this.scope.getStore()),
{
autoLoad: true,
proxy: {
extraParams: {parent: ""}
},
listeners: {
scope: this.getController(),
load: this.getController().onLoadTree
}
}, true));
this.callParent();
}
});
\ No newline at end of file
//---------------------------------------------------------------------
// fm.alarm.treepicker controller
//---------------------------------------------------------------------
// Copyright (C) 2007-2020 The NOC Project
// See LICENSE for details
//---------------------------------------------------------------------
console.debug("Defining NOC.fm.alarm.view.grids.TreePickerController");
Ext.define("NOC.fm.alarm.view.grids.TreePickerController", {
extend: "Ext.app.ViewController",
alias: "controller.fm.alarm.treepicker",
requires: [],
// store events
onLoadTree: function(store, records, success) {
var parentNode = this.getParentNode(),
me = this.getView(),
parentField = me.scope;
if(!parentNode.hasChildNodes() && success) {
parentNode.appendChild(records.map(function(item) {
return Ext.merge({
leaf: !item.get("has_children"),
qtip: item.get(parentField.displayField)
}, item.getData());
}));
parentNode.expand();
}
if(!me.cache) { // first run, root elements
me.cache = Ext.clone(parentNode.childNodes);
}
},
// tree panel events
onClosePanel: function() {
this.getView().hide();
},
onItemClick: function(view, record) {
this.selectItem(record);
},
onPickerKeyDown: function(view, record, item, index, e) {
var key = e.getKey();
if(key === e.ENTER) {
this.selectItem(record);
}
},
onItemBeforeExpand: function(self) {
var me = this.getView(), node;
if(me.currentLeaf && (me.currentLeaf !== self.getId())) {
node = me.getStore().getNodeById(me.currentLeaf);
node.appendChild(me.cache);
}
me.currentLeaf = self.getId();
me.cache = Ext.clone(self.childNodes);
if(!self.hasChildNodes()) {
this.loadChildren(me.currentLeaf);
return false;
}
},
onItemExpand: function() {
this.doFilter();
},
onLeaveFocusTreePicker: function() {
this.getView().scope.setEditable(true);
this.getView().hide();
},
// search field events
onClearSearchField: function(self) {
self.setValue();
self.getTrigger("clear").hide();
this.doFilter();
},
onChangeSearchField: function(self) {
if(self.getValue() == null || !self.getValue().length) {
this.onClearSearchField(self);
return;
}
this.doFilter();
self.getTrigger("clear").show();
},
//
getParentNode: function() {
var me = this.getView(), store = me.getStore();
if(!me.currentLeaf) {
return store.getRootNode();
} else {
return store.getById(me.currentLeaf);
}
},
loadChildren: function(id) {
var me = this.getView();
if(!me.hidden) {
me.mask(__("loading ..."));
}
me.treeStore.load({
params: {
parent: id
},
callback: function() {
if(!me.hidden) {
me.unmask();
}
}
});
},
selectItem: function(record) {
var parent = this.getView().scope, value = {}, isExist,
selected = parent.getSelected();
if(selected) {
isExist = Ext.Array.findBy(selected, function(el) {
return el.id === record.id
});
}
if(isExist) {
parent.removeValue(isExist);
} else {
value[parent.valueField] = record.id;
value[parent.displayField] = record.get(parent.displayField);
parent.addValue(Ext.create("Ext.data.Model", value));
}
},
selectNode: function() {
var me = this.getView(), selection = [];
if(me) {
// maping to tree-picker store
Ext.Array.each(me.scope.getPicker().getSelectionModel().getSelection(), function(record) {
var node = me.getStore().getNodeById(record.id);
if(node) {
selection.push(node);
}
});
if(selection.length) {
me.getSelectionModel().select(selection);
}
if(selection.length === 0) {
me.getSelectionModel().deselectAll(selection);
}
}
},
doFilter: function() {
var me = this.getView(), parentNode = this.getParentNode(),
searchField = me.down("[xtype=searchfield]");
if(parentNode) {
me.getStore().filterBy(function(record) {
if(record.parentNode.id !== me.currentLeaf) {
return true;
}
if(!searchField.getValue()) {
return true;
}
return record.get(me.scope.displayField).toLowerCase().indexOf(searchField.getValue().toLowerCase()) !== -1;
})
this.selectNode();
}
},
});
\ No newline at end of file
......@@ -125,9 +125,6 @@ Ext.define("NOC.inv.map.MapPanel", {
xtype: "component",
autoScroll: true,
layout: "fit",
style: {
background: "#ecf0f1"
}
}
]
});
......
......@@ -30,9 +30,6 @@ Ext.define('NOC.inv.map.MiniMap', {
width: w,
model: mapPanel.graph,
gridSize: 1,
background: {
color: '#ecf0f1'
},
interactive: false
});
this.miniPaper.on('blank:pointerdown', function(evt, x, y) {
......
......@@ -11,9 +11,6 @@ Ext.define('NOC.inv.map.inspectors.Inspector', {
title: undefined,
scrollable: 'vertical',
bodyStyle: {
background: '#c0c0c0'
},
defaults: {
padding: 4
},
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment