Revision 2dbc5942
1er jet pour représenter les groupes d'éléments supervisés sous forme d'arbre dans VigiBoard (formulaire de recherche).
Améliorations possibles : icônes plus jolies/pertinentes, chargement dynamique des sous-groupes.
Légères modifications dans la manière dont le formulaire de recherche est généré, afin de propager automatiquement les anciennes
valeur de recherche dans le formulaire lorsqu'il est réaffiché.
git-svn-id: https://vigilo-dev.si.c-s.fr/svn@3600 b22e2e97-25c9-44ff-b637-2e5ceca36478
vigiboard/controllers/root.py | ||
---|---|---|
32 | 32 |
|
33 | 33 |
from vigiboard.controllers.vigiboardrequest import VigiboardRequest |
34 | 34 |
from vigiboard.controllers.vigiboard_controller import VigiboardRootController |
35 |
|
|
35 | 36 |
from vigiboard.widgets.edit_event import edit_event_status_options |
37 |
from vigiboard.widgets.search_form import create_search_form, get_calendar_lang |
|
36 | 38 |
|
37 | 39 |
__all__ = ('RootController', 'get_last_modification_timestamp', |
38 | 40 |
'date_to_timestamp') |
... | ... | |
74 | 76 |
class DefaultSchema(schema.Schema): |
75 | 77 |
"""Schéma de validation de la méthode default.""" |
76 | 78 |
page = validators.Int(min=1, if_missing=1, if_invalid=1) |
77 |
supitemgroup = validators.String(if_missing=None)
|
|
79 |
supitemgroup = validators.Int(if_missing=None, if_invalid=None)
|
|
78 | 80 |
host = validators.String(if_missing=None) |
79 | 81 |
service = validators.String(if_missing=None) |
80 | 82 |
output = validators.String(if_missing=None) |
... | ... | |
120 | 122 |
Event.idsupitem == aggregates.items.c.idsupitem)) |
121 | 123 |
aggregates.add_order_by(asc(aggregates.items.c.hostname)) |
122 | 124 |
|
123 |
search = { |
|
124 |
'host': '', |
|
125 |
'service': '', |
|
126 |
'output': '', |
|
127 |
'tt': '', |
|
128 |
'from_date': '', |
|
129 |
'to_date': '', |
|
130 |
'supitemgroup': '', |
|
131 |
} |
|
125 |
search = {} |
|
132 | 126 |
|
133 | 127 |
# Application des filtres si nécessaire |
134 | 128 |
if supitemgroup: |
135 | 129 |
search['supitemgroup'] = supitemgroup |
136 |
supitemgroup = sql_escape_like(supitemgroup) |
|
137 |
aggregates.add_join((SupItemGroup, SupItemGroup.idgroup == \ |
|
138 |
aggregates.items.c.idsupitemgroup)) |
|
139 |
aggregates.add_filter( |
|
140 |
SupItemGroup.name.ilike('%s' % supitemgroup)) |
|
130 |
aggregates.add_filter(aggregates.items.c.idsupitemgroup == \ |
|
131 |
supitemgroup) |
|
141 | 132 |
|
142 | 133 |
if host: |
143 | 134 |
search['host'] = host |
... | ... | |
224 | 215 |
nb_pages = nb_pages, |
225 | 216 |
page = page, |
226 | 217 |
event_edit_status_options = edit_event_status_options, |
218 |
search_form = create_search_form, |
|
227 | 219 |
search = search, |
220 |
get_calendar_lang = get_calendar_lang, |
|
228 | 221 |
refresh_times = config['vigiboard_refresh_times'], |
229 | 222 |
) |
230 | 223 |
|
... | ... | |
324 | 317 |
}, |
325 | 318 |
nb_pages = nb_pages, |
326 | 319 |
page = page, |
327 |
search = { |
|
328 |
'host': '', |
|
329 |
'service': '', |
|
330 |
'output': '', |
|
331 |
'tt': '', |
|
332 |
'from_date': '', |
|
333 |
'to_date': '', |
|
334 |
'supitemgroup': '', |
|
335 |
}, |
|
336 |
refresh_times=config['vigiboard_refresh_times'], |
|
320 |
search_form = create_search_form, |
|
321 |
search = {}, |
|
322 |
get_calendar_lang = get_calendar_lang, |
|
323 |
refresh_times=config['vigiboard_refresh_times'], |
|
337 | 324 |
) |
338 | 325 |
|
339 | 326 |
|
... | ... | |
412 | 399 |
nb_pages = nb_pages, |
413 | 400 |
page = page, |
414 | 401 |
history = history_entries, |
415 |
search = { |
|
416 |
'host': '', |
|
417 |
'service': '', |
|
418 |
'output': '', |
|
419 |
'tt': '', |
|
420 |
'from_date': '', |
|
421 |
'to_date': '', |
|
422 |
'supitemgroup': '', |
|
423 |
}, |
|
424 |
refresh_times=config['vigiboard_refresh_times'], |
|
402 |
search_form = create_search_form, |
|
403 |
search = {}, |
|
404 |
get_calendar_lang = get_calendar_lang, |
|
405 |
refresh_times=config['vigiboard_refresh_times'], |
|
425 | 406 |
) |
426 | 407 |
|
427 | 408 |
|
... | ... | |
496 | 477 |
nb_pages = nb_pages, |
497 | 478 |
page = page, |
498 | 479 |
event_edit_status_options = edit_event_status_options, |
499 |
search = { |
|
500 |
'host': '', |
|
501 |
'service': '', |
|
502 |
'output': '', |
|
503 |
'tt': '', |
|
504 |
'from_date': '', |
|
505 |
'to_date': '', |
|
506 |
'supitemgroup': '', |
|
507 |
}, |
|
480 |
search_form = create_search_form, |
|
481 |
search = {}, |
|
482 |
get_calendar_lang = get_calendar_lang, |
|
508 | 483 |
refresh_times=config['vigiboard_refresh_times'], |
509 | 484 |
) |
510 | 485 |
|
... | ... | |
742 | 717 |
|
743 | 718 |
@require(access_restriction) |
744 | 719 |
@expose('json') |
745 |
def get_groups(self, idgroup=None):
|
|
720 |
def get_groups(self): |
|
746 | 721 |
user = get_current_user() |
747 | 722 |
groups = DBSession.query( |
748 | 723 |
SupItemGroup.idgroup, |
749 | 724 |
SupItemGroup.name, |
725 |
GroupHierarchy.idparent, |
|
750 | 726 |
).join( |
751 | 727 |
(GroupHierarchy, GroupHierarchy.idchild == \ |
752 | 728 |
SupItemGroup.idgroup), |
753 |
) |
|
729 |
).filter(GroupHierarchy.hops <= 1 |
|
730 |
).order_by(GroupHierarchy.hops.asc()) |
|
754 | 731 |
|
755 | 732 |
is_manager = in_group('managers').is_met(request.environ) |
756 | 733 |
if not is_manager: |
... | ... | |
758 | 735 |
groups = groups.filter(SupItemGroup.idgroup.in_(user_groups)) |
759 | 736 |
|
760 | 737 |
# Cas des groupes racines (parents les plus élevés dans l'arbre). |
761 |
if idgroup: |
|
762 |
groups = groups.filter(GroupHierarchy.idparent == idgroup) |
|
763 |
else: |
|
764 |
groups = groups |
|
738 |
# if idgroup: |
|
739 |
# groups = groups.filter(GroupHierarchy.idparent == idgroup) |
|
740 |
|
|
741 |
hierarchy = {} |
|
742 |
|
|
743 |
def find_parent(idgroup): |
|
744 |
def __find_parent(hier, idgroup): |
|
745 |
if idgroup in hier: |
|
746 |
return hier[idgroup]['children'] |
|
747 |
for g in hier: |
|
748 |
res = __find_parent(hier[g]['children'], idgroup) |
|
749 |
if res: |
|
750 |
return res |
|
751 |
return None |
|
752 |
parent = __find_parent(hierarchy, idgroup) |
|
753 |
if parent is None: |
|
754 |
return hierarchy |
|
755 |
return parent |
|
756 |
|
|
757 |
for g in groups.all(): |
|
758 |
parent = find_parent(g.idparent) |
|
759 |
if g.idgroup in hierarchy: |
|
760 |
parent[g.idgroup] = hierarchy[g.idgroup] |
|
761 |
del hierarchy[g.idgroup] |
|
762 |
else: |
|
763 |
parent[g.idgroup] = { |
|
764 |
'name': g.name, |
|
765 |
'children': {}, |
|
766 |
} |
|
765 | 767 |
|
766 |
groups = [(g.idgroup, g.name) for g in groups.all()] |
|
767 |
return dict(groups=groups) |
|
768 |
return dict(groups=hierarchy) |
|
768 | 769 |
|
769 | 770 |
def get_last_modification_timestamp(event_id_list, |
770 | 771 |
value_if_none=datetime.now()): |
vigiboard/controllers/vigiboardrequest.py | ||
---|---|---|
6 | 6 |
from logging import getLogger |
7 | 7 |
|
8 | 8 |
from tg import config, tmpl_context, request, url |
9 |
from tg.i18n import get_lang |
|
10 | 9 |
from pylons.i18n import ugettext as _ |
11 | 10 |
from paste.deploy.converters import asbool |
12 | 11 |
from repoze.what.predicates import in_group |
... | ... | |
19 | 18 |
Host, LowLevelService, StateName |
20 | 19 |
from vigilo.models.tables.secondary_tables import SUPITEM_GROUP_TABLE |
21 | 20 |
from vigiboard.widgets.edit_event import EditEventForm |
22 |
from vigiboard.widgets.search_form import SearchForm |
|
23 | 21 |
from vigiboard.controllers.plugins import VigiboardRequestPlugin |
24 | 22 |
|
25 | 23 |
LOGGER = getLogger(__name__) |
... | ... | |
44 | 42 |
l'utilisateur sur les données manipulées. |
45 | 43 |
""" |
46 | 44 |
|
47 |
# TODO: Utiliser le champ "language" du modèle pour cet utilisateur ? |
|
48 |
# On récupère la langue du navigateur de l'utilisateur |
|
49 |
lang = get_lang() |
|
50 |
if not lang: |
|
51 |
lang = config['lang'] |
|
52 |
else: |
|
53 |
lang = lang[0] |
|
54 |
|
|
55 |
# TODO: Il faudrait gérer les cas où tout nous intéresse dans "lang". |
|
56 |
# Si l'identifiant de langage est composé (ex: "fr_FR"), |
|
57 |
# on ne récupère que la 1ère partie. |
|
58 |
lang = lang.replace('_', '-') |
|
59 |
lang = lang.split('-')[0] |
|
60 |
|
|
61 | 45 |
self.user_groups = [ug[0] for ug in user.supitemgroups() if ug[1]] |
62 |
self.lang = lang |
|
63 | 46 |
self.generaterq = False |
64 | 47 |
|
65 | 48 |
is_manager = in_group('managers').is_met(request.environ) |
... | ... | |
418 | 401 |
tmpl_context.last_modification = \ |
419 | 402 |
mktime(get_last_modification_timestamp(ids).timetuple()) |
420 | 403 |
|
421 |
tmpl_context.calendar_lang = self.lang |
|
422 |
# TRANSLATORS: Format de date et heure compatible Python/JavaScript. |
|
423 |
tmpl_context.calendar_date_format = _('%Y-%m-%d %I:%M:%S %p') |
|
424 |
|
|
425 | 404 |
tmpl_context.edit_event_form = EditEventForm("edit_event_form", |
426 | 405 |
submit_text=_('Apply'), action=url('/update')) |
427 |
tmpl_context.search_form = SearchForm("search_form", |
|
428 |
submit_text=_('Search'), action=url('/')) |
|
429 | 406 |
|
vigiboard/widgets/search_form.py | ||
---|---|---|
4 | 4 |
|
5 | 5 |
from pylons.i18n import lazy_ugettext as l_ |
6 | 6 |
from tw.api import WidgetsList |
7 |
from tw.forms import TableForm, TextField, CalendarDateTimePicker |
|
7 |
import tw.forms as twf |
|
8 |
from tg.i18n import get_lang |
|
9 |
import tg |
|
10 |
|
|
11 |
from vigilo.models.session import DBSession |
|
12 |
from vigilo.models.tables.group import Group |
|
8 | 13 |
|
9 | 14 |
__all__ = ( |
10 | 15 |
'SearchForm', |
16 |
'create_search_form', |
|
11 | 17 |
) |
12 | 18 |
|
13 |
class SearchForm(TableForm): |
|
19 |
class GroupSelector(twf.InputField): |
|
20 |
params = ["choose_text", "text_value", "clear_text"] |
|
21 |
choose_text = l_('Choose') |
|
22 |
clear_text = l_('Clear') |
|
23 |
text_value = '' |
|
24 |
|
|
25 |
template = """ |
|
26 |
<div xmlns="http://www.w3.org/1999/xhtml" |
|
27 |
xmlns:py="http://genshi.edgewall.org/" py:strip=""> |
|
28 |
<input type="hidden" name="${name}" class="${css_class}" |
|
29 |
id="${id}.value" value="${value}" py:attrs="attrs" /> |
|
30 |
<input type="text" class="${css_class}" id="${id}.ui" |
|
31 |
value="${text_value}" readonly="readonly" py:attrs="attrs" /> |
|
32 |
<input type="button" class="${css_class}" id="${id}" |
|
33 |
value="${choose_text}" py:attrs="attrs" /> |
|
34 |
<input type="button" class="${css_class}" id="${id}.clear" |
|
35 |
value="${clear_text}" py:attrs="attrs" /> |
|
36 |
</div> |
|
37 |
""" |
|
38 |
|
|
39 |
def update_params(self, d): |
|
40 |
super(GroupSelector, self).update_params(d) |
|
41 |
text_value = DBSession.query(Group.name).filter( |
|
42 |
Group.idgroup == d.value).scalar() |
|
43 |
if not text_value: |
|
44 |
d.value = '' |
|
45 |
else: |
|
46 |
d.text_value = text_value |
|
47 |
|
|
48 |
class SearchForm(twf.TableForm): |
|
14 | 49 |
""" |
15 | 50 |
Formulaire de recherche dans les événements |
16 | 51 |
|
... | ... | |
26 | 61 |
style = 'display: none' |
27 | 62 |
|
28 | 63 |
class fields(WidgetsList): |
29 |
supitemgroup = TextField(label_text=l_('Group'))
|
|
30 |
host = TextField(label_text=l_('Host')) |
|
31 |
service = TextField(label_text=l_('Service')) |
|
32 |
output = TextField(label_text=l_('Output')) |
|
33 |
trouble_ticket = TextField(label_text=l_('Trouble Ticket')) |
|
34 |
from_date = CalendarDateTimePicker( |
|
64 |
supitemgroup = GroupSelector(label_text=l_('Group'))
|
|
65 |
host = twf.TextField(label_text=l_('Host'))
|
|
66 |
service = twf.TextField(label_text=l_('Service'))
|
|
67 |
output = twf.TextField(label_text=l_('Output'))
|
|
68 |
trouble_ticket = twf.TextField(label_text=l_('Trouble Ticket'))
|
|
69 |
from_date = twf.CalendarDateTimePicker(
|
|
35 | 70 |
label_text = l_('From'), |
36 | 71 |
button_text = l_("Choose"), |
37 | 72 |
not_empty = False) |
38 |
to_date = CalendarDateTimePicker( |
|
73 |
to_date = twf.CalendarDateTimePicker(
|
|
39 | 74 |
label_text = l_('To'), |
40 | 75 |
button_text = l_("Choose"), |
41 | 76 |
not_empty = False) |
42 | 77 |
|
78 |
def get_calendar_lang(): |
|
79 |
# TODO: Utiliser le champ "language" du modèle pour cet utilisateur ? |
|
80 |
# On récupère la langue du navigateur de l'utilisateur |
|
81 |
lang = get_lang() |
|
82 |
if not lang: |
|
83 |
lang = config['lang'] |
|
84 |
else: |
|
85 |
lang = lang[0] |
|
86 |
|
|
87 |
# TODO: Il faudrait gérer les cas où tout nous intéresse dans "lang". |
|
88 |
# Si l'identifiant de langage est composé (ex: "fr_FR"), |
|
89 |
# on ne récupère que la 1ère partie. |
|
90 |
lang = lang.replace('_', '-') |
|
91 |
lang = lang.split('-')[0] |
|
92 |
return lang |
|
93 |
|
|
94 |
create_search_form = SearchForm("search_form", |
|
95 |
submit_text=l_('Search'), action=tg.url('/'), |
|
96 |
) |
|
97 |
|
Also available in: Unified diff