mirror of
https://github.com/ansible/awx.git
synced 2026-01-18 13:11:19 -03:30
Merge branch 'auditlog'
* auditlog: (38 commits) Move auditlog migration to 0028 for main branch merge Search.js now supports up to 3 search filters on a page. First search widget can be regular or an object selector, which is used on the activity stream widget. Activity stream now has 2 filter widgets allowing a search to combine object and responsible user in a single query. AC-640 Added additional help text explaining why an organization is required on a project. Added 'working' spinner to all save/delete/select actions. This is to compensate for places where activity log is slowing down the API. AC-646 changes Rackspace credentials to show API Key in place of password. Fixed a bug on machine credential that caused username to not be passed to the API when adding and editing. AC-611 Latest activity widget features. Tweaked current filter, but still does not include an object type. Added activty stream to Organization tab. Add a field to the activity stream model that more closely identifies the api object type for aid in api querying Add some initial activity stream tests Improve loading time for some module calls by reducing the number of queries against the activity stream table Implement AC-634 - Additional bits First attempt at accessing /activity_stream. Modified /list/Stream.js to match the API and to start providing some of the translation we'll need. Add job to the list of models that are filtered if a user didn't directly interface with it Make sure we are handling multiple activitystream instances from the middleware Fix a bug passing args to object 2 of the activitystream serializer Found and fixed another bug on the Credentials form. Changing the ssh password value was causing a hidden password field to become invalid. Form definition for ssh password cleared the incorrect associated confirmation field. Add activitystream table migration AC-625 while looking into issue surrounding non-running updates, discoverd that creating credentials from the Users and Teams tabs was not allowing the user to click Save. The Save button refused to become enabled. Turns out that when a user or team is preelected (using route params) form initialization routine needs to run and it was not. Make sure we show relative object information in the api Integrate a simple api list and detail display Use process_response to attach user information later in the middleware request processing Fix up some bugs with signal handling related to association/disassociation ...
This commit is contained in:
commit
002341468d
@ -28,7 +28,7 @@ from awx.main.utils import *
|
||||
|
||||
# FIXME: machinery for auto-adding audit trail logs to all CREATE/EDITS
|
||||
|
||||
__all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'ListCreateAPIView',
|
||||
__all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView', 'ListCreateAPIView',
|
||||
'SubListAPIView', 'SubListCreateAPIView', 'RetrieveAPIView',
|
||||
'RetrieveUpdateAPIView', 'RetrieveUpdateDestroyAPIView']
|
||||
|
||||
@ -172,6 +172,9 @@ class GenericAPIView(generics.GenericAPIView, APIView):
|
||||
ret['search_fields'] = self.search_fields
|
||||
return ret
|
||||
|
||||
class SimpleListAPIView(generics.ListAPIView, GenericAPIView):
|
||||
pass
|
||||
|
||||
class ListAPIView(generics.ListAPIView, GenericAPIView):
|
||||
# Base class for a read-only list view.
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import json
|
||||
import re
|
||||
import socket
|
||||
import urlparse
|
||||
import logging
|
||||
|
||||
# PyYAML
|
||||
import yaml
|
||||
@ -27,7 +28,9 @@ from rest_framework import serializers
|
||||
|
||||
# AWX
|
||||
from awx.main.models import *
|
||||
from awx.main.utils import update_scm_url
|
||||
from awx.main.utils import update_scm_url, camelcase_to_underscore
|
||||
|
||||
logger = logging.getLogger('awx.api.serializers')
|
||||
|
||||
BASE_FIELDS = ('id', 'url', 'related', 'summary_fields', 'created', 'modified',
|
||||
'name', 'description')
|
||||
@ -1032,6 +1035,58 @@ class JobEventSerializer(BaseSerializer):
|
||||
pass
|
||||
return d
|
||||
|
||||
class ActivityStreamSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ActivityStream
|
||||
fields = ('id', 'url', 'related', 'summary_fields', 'timestamp', 'operation', 'changes',
|
||||
'object1_id', 'object1', 'object1_type', 'object2_id', 'object2', 'object2_type', 'object_relationship_type')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
rel = {}
|
||||
if obj.user is not None:
|
||||
rel['user'] = reverse('api:user_detail', args=(obj.user.pk,))
|
||||
obj1_resolution = camelcase_to_underscore(obj.object1_type.split(".")[-1])
|
||||
rel['object1'] = reverse('api:' + obj1_resolution + '_detail', args=(obj.object1_id,))
|
||||
if obj.operation in ('associate', 'disassociate'):
|
||||
obj2_resolution = camelcase_to_underscore(obj.object2_type.split(".")[-1])
|
||||
rel['object2'] = reverse('api:' + obj2_resolution + '_detail', args=(obj.object2_id,))
|
||||
return rel
|
||||
|
||||
def get_summary_fields(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
d = super(ActivityStreamSerializer, self).get_summary_fields(obj)
|
||||
try:
|
||||
short_obj_type = obj.object1_type.split(".")[-1]
|
||||
under_short_obj_type = camelcase_to_underscore(short_obj_type)
|
||||
obj1 = eval(obj.object1_type + ".objects.get(id=" + str(obj.object1_id) + ")")
|
||||
if hasattr(obj1, "name"):
|
||||
d['object1'] = {'name': obj1.name, 'description': obj1.description,
|
||||
'base': under_short_obj_type, 'id': obj.object1_id}
|
||||
else:
|
||||
d['object1'] = {'base': under_short_obj_type, 'id': obj.object1_id}
|
||||
if under_short_obj_type == "host" or under_short_obj_type == "group":
|
||||
d['inventory'] = {'name': obj1.inventory.name, 'id': obj1.inventory.id}
|
||||
except Exception, e:
|
||||
logger.error("Error getting object 1 summary: " + str(e))
|
||||
try:
|
||||
short_obj_type = obj.object2_type.split(".")[-1]
|
||||
under_short_obj_type = camelcase_to_underscore(short_obj_type)
|
||||
if obj.operation in ('associate', 'disassociate'):
|
||||
obj2 = eval(obj.object2_type + ".objects.get(id=" + str(obj.object2_id) + ")")
|
||||
if hasattr(obj2, "name"):
|
||||
d['object2'] = {'name': obj2.name, 'description': obj2.description,
|
||||
'base': under_short_obj_type, 'id': obj.object2_id}
|
||||
else:
|
||||
d['object2'] = {'base': under_short_obj_type, 'id': obj.object2_id}
|
||||
if under_short_obj_type == "host" or under_short_obj_type == "group":
|
||||
d['inventory'] = {'name': obj2.inventory.name, 'id': obj2.inventory.id}
|
||||
except Exception, e:
|
||||
pass
|
||||
return d
|
||||
|
||||
class AuthTokenSerializer(serializers.Serializer):
|
||||
|
||||
|
||||
@ -141,6 +141,11 @@ job_event_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/hosts/$', 'job_event_hosts_list'),
|
||||
)
|
||||
|
||||
activity_stream_urls = patterns('awx.api.views',
|
||||
url(r'^$', 'activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/$', 'activity_stream_detail'),
|
||||
)
|
||||
|
||||
v1_urls = patterns('awx.api.views',
|
||||
url(r'^$', 'api_v1_root_view'),
|
||||
url(r'^config/$', 'api_v1_config_view'),
|
||||
@ -162,6 +167,7 @@ v1_urls = patterns('awx.api.views',
|
||||
url(r'^jobs/', include(job_urls)),
|
||||
url(r'^job_host_summaries/', include(job_host_summary_urls)),
|
||||
url(r'^job_events/', include(job_event_urls)),
|
||||
url(r'^activity_stream/', include(activity_stream_urls)),
|
||||
)
|
||||
|
||||
urlpatterns = patterns('awx.api.views',
|
||||
|
||||
@ -88,6 +88,7 @@ class ApiV1RootView(APIView):
|
||||
data['hosts'] = reverse('api:host_list')
|
||||
data['job_templates'] = reverse('api:job_template_list')
|
||||
data['jobs'] = reverse('api:job_list')
|
||||
data['activity_stream'] = reverse('api:activity_stream_list')
|
||||
return Response(data)
|
||||
|
||||
class ApiV1ConfigView(APIView):
|
||||
@ -1055,6 +1056,15 @@ class JobJobEventsList(BaseJobEventsList):
|
||||
headers=headers)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class ActivityStreamList(SimpleListAPIView):
|
||||
|
||||
model = ActivityStream
|
||||
serializer_class = ActivityStreamSerializer
|
||||
|
||||
class ActivityStreamDetail(RetrieveAPIView):
|
||||
|
||||
model = ActivityStream
|
||||
serializer_class = ActivityStreamSerializer
|
||||
|
||||
# Create view functions for all of the class-based views to simplify inclusion
|
||||
# in URL patterns and reverse URL lookups, converting CamelCase names to
|
||||
|
||||
50
awx/main/middleware.py
Normal file
50
awx/main/middleware.py
Normal file
@ -0,0 +1,50 @@
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models.signals import pre_save, post_save
|
||||
from django.utils.functional import curry
|
||||
from awx.main.models.activity_stream import ActivityStream
|
||||
import json
|
||||
import uuid
|
||||
import urllib2
|
||||
|
||||
class ActivityStreamMiddleware(object):
|
||||
|
||||
def process_request(self, request):
|
||||
self.isActivityStreamEvent = False
|
||||
if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated') and request.user.is_authenticated():
|
||||
user = request.user
|
||||
else:
|
||||
user = None
|
||||
|
||||
self.instances = []
|
||||
set_actor = curry(self.set_actor, user)
|
||||
self.disp_uid = str(uuid.uuid1())
|
||||
self.finished = False
|
||||
post_save.connect(set_actor, sender=ActivityStream, dispatch_uid=self.disp_uid, weak=False)
|
||||
|
||||
def process_response(self, request, response):
|
||||
post_save.disconnect(dispatch_uid=self.disp_uid)
|
||||
self.finished = True
|
||||
if self.isActivityStreamEvent:
|
||||
for instance in self.instances:
|
||||
if "current_user" in request.COOKIES and "id" in request.COOKIES["current_user"]:
|
||||
userInfo = json.loads(urllib2.unquote(request.COOKIES['current_user']).decode('utf8'))
|
||||
userActual = User.objects.get(id=int(userInfo['id']))
|
||||
instance.user = userActual
|
||||
instance.save()
|
||||
else:
|
||||
obj1_type_actual = instance.object1_type.split(".")[-1]
|
||||
if obj1_type_actual in ("InventoryUpdate", "ProjectUpdate", "JobEvent", "Job") and instance.id is not None:
|
||||
instance.delete()
|
||||
return response
|
||||
|
||||
def set_actor(self, user, sender, instance, **kwargs):
|
||||
if not self.finished:
|
||||
if sender == ActivityStream:
|
||||
if isinstance(user, User) and instance.user is None:
|
||||
instance.user = user
|
||||
else:
|
||||
self.isActivityStreamEvent = True
|
||||
self.instances.append(instance)
|
||||
else:
|
||||
self.isActivityStreamEvent = False
|
||||
425
awx/main/migrations/0028_v14_changes.py
Normal file
425
awx/main/migrations/0028_v14_changes.py
Normal file
@ -0,0 +1,425 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'ActivityStream'
|
||||
db.create_table(u'main_activitystream', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='activity_stream', null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||
('operation', self.gf('django.db.models.fields.CharField')(max_length=13)),
|
||||
('timestamp', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('changes', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('object1_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
|
||||
('object1', self.gf('django.db.models.fields.TextField')()),
|
||||
('object1_type', self.gf('django.db.models.fields.TextField')()),
|
||||
('object2_id', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, db_index=True)),
|
||||
('object2', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
|
||||
('object2_type', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
|
||||
('object_relationship_type', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
))
|
||||
db.send_create_signal('main', ['ActivityStream'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'ActivityStream'
|
||||
db.delete_table(u'main_activitystream')
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'main.activitystream': {
|
||||
'Meta': {'object_name': 'ActivityStream'},
|
||||
'changes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'object1': ('django.db.models.fields.TextField', [], {}),
|
||||
'object1_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
|
||||
'object1_type': ('django.db.models.fields.TextField', [], {}),
|
||||
'object2': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'object2_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'db_index': 'True'}),
|
||||
'object2_type': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'object_relationship_type': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'operation': ('django.db.models.fields.CharField', [], {'max_length': '13'}),
|
||||
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_stream'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.authtoken': {
|
||||
'Meta': {'object_name': 'AuthToken'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'request_hash': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '40', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_tokens'", 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.credential': {
|
||||
'Meta': {'unique_together': "[('user', 'team', 'kind', 'name')]", 'object_name': 'Credential'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'cloud': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'credential\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'kind': ('django.db.models.fields.CharField', [], {'default': "'ssh'", 'max_length': '32'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'credential\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'ssh_key_data': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'ssh_key_unlock': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'sudo_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'sudo_username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'team': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'credentials'", 'null': 'True', 'blank': 'True', 'to': "orm['main.Team']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'credentials'", 'null': 'True', 'blank': 'True', 'to': u"orm['auth.User']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'})
|
||||
},
|
||||
'main.group': {
|
||||
'Meta': {'unique_together': "(('name', 'inventory'),)", 'object_name': 'Group'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'group\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'groups_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'groups'", 'blank': 'True', 'to': "orm['main.Host']"}),
|
||||
'hosts_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'groups'", 'to': "orm['main.Inventory']"}),
|
||||
'inventory_sources': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'groups'", 'blank': 'True', 'to': "orm['main.InventorySource']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'group\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'parents': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'children'", 'blank': 'True', 'to': "orm['main.Group']"}),
|
||||
'total_groups': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'total_hosts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
|
||||
},
|
||||
'main.host': {
|
||||
'Meta': {'unique_together': "(('name', 'inventory'),)", 'object_name': 'Host'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'host\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'instance_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts'", 'to': "orm['main.Inventory']"}),
|
||||
'inventory_sources': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hosts'", 'blank': 'True', 'to': "orm['main.InventorySource']"}),
|
||||
'last_job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts_as_last_job+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Job']", 'blank': 'True', 'null': 'True'}),
|
||||
'last_job_host_summary': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts_as_last_job_summary+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobHostSummary']", 'blank': 'True', 'null': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'host\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
|
||||
},
|
||||
'main.inventory': {
|
||||
'Meta': {'unique_together': "[('name', 'organization')]", 'object_name': 'Inventory'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventory\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'groups_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'hosts_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory_sources_with_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventory\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'organization': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventories'", 'to': "orm['main.Organization']"}),
|
||||
'total_groups': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'total_hosts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'total_inventory_sources': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'main.inventorysource': {
|
||||
'Meta': {'object_name': 'InventorySource'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventorysource\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_sources'", 'null': 'True', 'blank': 'True', 'to': "orm['main.Credential']"}),
|
||||
'current_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_source_as_current_update+'", 'null': 'True', 'to': "orm['main.InventoryUpdate']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'group': ('awx.main.fields.AutoOneToOneField', [], {'related_name': "'inventory_source'", 'null': 'True', 'default': 'None', 'to': "orm['main.Group']", 'blank': 'True', 'unique': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_sources'", 'null': 'True', 'to': "orm['main.Inventory']"}),
|
||||
'last_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_source_as_last_update+'", 'null': 'True', 'to': "orm['main.InventoryUpdate']"}),
|
||||
'last_update_failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_updated': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventorysource\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'overwrite_vars': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'source': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
|
||||
'source_path': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'source_regions': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'source_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '32', 'null': 'True'}),
|
||||
'update_interval': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||
},
|
||||
'main.inventoryupdate': {
|
||||
'Meta': {'object_name': 'InventoryUpdate'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'cancel_flag': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'celery_task_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventoryupdate\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory_source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventory_updates'", 'to': "orm['main.InventorySource']"}),
|
||||
'job_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'job_cwd': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_env': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
'license_error': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventoryupdate\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'result_stdout': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'})
|
||||
},
|
||||
'main.job': {
|
||||
'Meta': {'object_name': 'Job'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'cancel_flag': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'celery_task_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'cloud_credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs_as_cloud_credential+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'job\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Credential']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
|
||||
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'jobs'", 'blank': 'True', 'through': "orm['main.JobHostSummary']", 'to': "orm['main.Host']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||
'job_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'job_cwd': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_env': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
'job_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobTemplate']", 'blank': 'True', 'null': 'True'}),
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'launch_type': ('django.db.models.fields.CharField', [], {'default': "'manual'", 'max_length': '20'}),
|
||||
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'job\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'playbook': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
|
||||
'result_stdout': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'}),
|
||||
'verbosity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'})
|
||||
},
|
||||
'main.jobevent': {
|
||||
'Meta': {'ordering': "('pk',)", 'object_name': 'JobEvent'},
|
||||
'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'event': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'event_data': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'host': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_events_as_primary_host'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Host']", 'blank': 'True', 'null': 'True'}),
|
||||
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'job_events'", 'blank': 'True', 'to': "orm['main.Host']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_events'", 'to': "orm['main.Job']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobEvent']", 'blank': 'True', 'null': 'True'}),
|
||||
'play': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'task': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'})
|
||||
},
|
||||
'main.jobhostsummary': {
|
||||
'Meta': {'ordering': "('-pk',)", 'unique_together': "[('job', 'host')]", 'object_name': 'JobHostSummary'},
|
||||
'changed': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'dark': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'host': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_host_summaries'", 'to': "orm['main.Host']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_host_summaries'", 'to': "orm['main.Job']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'ok': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'processed': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'skipped': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
|
||||
},
|
||||
'main.jobtemplate': {
|
||||
'Meta': {'object_name': 'JobTemplate'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'cloud_credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates_as_cloud_credential+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'jobtemplate\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
|
||||
'host_config_key': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||
'job_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'jobtemplate\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'playbook': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
|
||||
'verbosity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'})
|
||||
},
|
||||
'main.organization': {
|
||||
'Meta': {'object_name': 'Organization'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'admins': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'admin_of_organizations'", 'blank': 'True', 'to': u"orm['auth.User']"}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'organization\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'organization\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'projects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organizations'", 'blank': 'True', 'to': "orm['main.Project']"}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organizations'", 'blank': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'permission\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'permission\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'permission_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
|
||||
'team': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Team']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.profile': {
|
||||
'Meta': {'object_name': 'Profile'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ldap_dn': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'user': ('awx.main.fields.AutoOneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.project': {
|
||||
'Meta': {'object_name': 'Project'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'project\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'projects'", 'null': 'True', 'blank': 'True', 'to': "orm['main.Credential']"}),
|
||||
'current_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'project_as_current_update+'", 'null': 'True', 'to': "orm['main.ProjectUpdate']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'project_as_last_update+'", 'null': 'True', 'to': "orm['main.ProjectUpdate']"}),
|
||||
'last_update_failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_updated': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'project\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'scm_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'null': 'True', 'blank': 'True'}),
|
||||
'scm_clean': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_delete_on_next_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_delete_on_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||
'scm_update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_url': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'ok'", 'max_length': '32', 'null': 'True'})
|
||||
},
|
||||
'main.projectupdate': {
|
||||
'Meta': {'object_name': 'ProjectUpdate'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'cancel_flag': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'celery_task_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'projectupdate\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'job_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'job_cwd': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_env': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'projectupdate\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'project_updates'", 'to': "orm['main.Project']"}),
|
||||
'result_stdout': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'})
|
||||
},
|
||||
'main.team': {
|
||||
'Meta': {'unique_together': "[('organization', 'name')]", 'object_name': 'Team'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'team\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'team\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'organization': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'teams'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Organization']"}),
|
||||
'projects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': "orm['main.Project']"}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
u'taggit.tag': {
|
||||
'Meta': {'object_name': 'Tag'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'})
|
||||
},
|
||||
u'taggit.taggeditem': {
|
||||
'Meta': {'object_name': 'TaggedItem'},
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_tagged_items'", 'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
|
||||
'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_items'", 'to': u"orm['taggit.Tag']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
@ -6,6 +6,8 @@ from awx.main.models.organization import *
|
||||
from awx.main.models.projects import *
|
||||
from awx.main.models.inventory import *
|
||||
from awx.main.models.jobs import *
|
||||
from awx.main.models.activity_stream import *
|
||||
from awx.main.registrar import activity_stream_registrar
|
||||
|
||||
# Monkeypatch Django serializer to ignore django-taggit fields (which break
|
||||
# the dumpdata command; see https://github.com/alex/django-taggit/issues/155).
|
||||
@ -27,3 +29,20 @@ User.add_to_class('can_access', check_user_access)
|
||||
|
||||
# Import signal handlers only after models have been defined.
|
||||
import awx.main.signals
|
||||
|
||||
activity_stream_registrar.connect(Organization)
|
||||
activity_stream_registrar.connect(Inventory)
|
||||
activity_stream_registrar.connect(Host)
|
||||
activity_stream_registrar.connect(Group)
|
||||
activity_stream_registrar.connect(InventorySource)
|
||||
activity_stream_registrar.connect(InventoryUpdate)
|
||||
activity_stream_registrar.connect(Credential)
|
||||
activity_stream_registrar.connect(Team)
|
||||
activity_stream_registrar.connect(Project)
|
||||
activity_stream_registrar.connect(ProjectUpdate)
|
||||
activity_stream_registrar.connect(Permission)
|
||||
activity_stream_registrar.connect(JobTemplate)
|
||||
activity_stream_registrar.connect(Job)
|
||||
activity_stream_registrar.connect(JobHostSummary)
|
||||
activity_stream_registrar.connect(JobEvent)
|
||||
#activity_stream_registrar.connect(Profile)
|
||||
|
||||
41
awx/main/models/activity_stream.py
Normal file
41
awx/main/models/activity_stream.py
Normal file
@ -0,0 +1,41 @@
|
||||
# Copyright (c) 2013 AnsibleWorks, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
|
||||
from django.db import models
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
class ActivityStream(models.Model):
|
||||
'''
|
||||
Model used to describe activity stream (audit) events
|
||||
'''
|
||||
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
|
||||
OPERATION_CHOICES = [
|
||||
('create', _('Entity Created')),
|
||||
('update', _("Entity Updated")),
|
||||
('delete', _("Entity Deleted")),
|
||||
('associate', _("Entity Associated with another Entity")),
|
||||
('disassociate', _("Entity was Disassociated with another Entity"))
|
||||
]
|
||||
|
||||
user = models.ForeignKey('auth.User', null=True, on_delete=models.SET_NULL, related_name='activity_stream')
|
||||
operation = models.CharField(max_length=13, choices=OPERATION_CHOICES)
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
changes = models.TextField(blank=True)
|
||||
|
||||
object1_id = models.PositiveIntegerField(db_index=True)
|
||||
object1 = models.TextField()
|
||||
object1_type = models.TextField()
|
||||
|
||||
object2_id = models.PositiveIntegerField(db_index=True, null=True)
|
||||
object2 = models.TextField(null=True, blank=True)
|
||||
object2_type = models.TextField(null=True, blank=True)
|
||||
|
||||
object_relationship_type = models.TextField(blank=True)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:activity_stream_detail', args=(self.pk,))
|
||||
@ -370,3 +370,28 @@ class CommonTask(PrimordialModel):
|
||||
self.cancel_flag = True
|
||||
self.save(update_fields=['cancel_flag'])
|
||||
return self.cancel_flag
|
||||
|
||||
class ActivityStream(models.Model):
|
||||
'''
|
||||
Model used to describe activity stream (audit) events
|
||||
'''
|
||||
OPERATION_CHOICES = [
|
||||
('create', _('Entity Created')),
|
||||
('update', _("Entity Updated")),
|
||||
('delete', _("Entity Deleted")),
|
||||
('associate', _("Entity Associated with another Entity")),
|
||||
('disaassociate', _("Entity was Disassociated with another Entity"))
|
||||
]
|
||||
|
||||
user = models.ForeignKey('auth.User', null=True, on_delete=models.SET_NULL)
|
||||
operation = models.CharField(max_length=9, choices=OPERATION_CHOICES)
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
changes = models.TextField(blank=True)
|
||||
|
||||
object1_id = models.PositiveIntegerField(db_index=True)
|
||||
object1_type = models.TextField()
|
||||
|
||||
object2_id = models.PositiveIntegerField(db_index=True)
|
||||
object2_type = models.TextField()
|
||||
|
||||
object_relationship_type = models.TextField()
|
||||
|
||||
42
awx/main/registrar.py
Normal file
42
awx/main/registrar.py
Normal file
@ -0,0 +1,42 @@
|
||||
import logging
|
||||
|
||||
from django.db.models.signals import pre_save, post_save, post_delete, m2m_changed
|
||||
from signals import activity_stream_create, activity_stream_update, activity_stream_delete, activity_stream_associate
|
||||
|
||||
logger = logging.getLogger('awx.main.registrar')
|
||||
|
||||
class ActivityStreamRegistrar(object):
|
||||
|
||||
def __init__(self):
|
||||
self.models = []
|
||||
|
||||
def connect(self, model):
|
||||
#(receiver, sender=model, dispatch_uid=self._dispatch_uid(signal, model))
|
||||
if model not in self.models:
|
||||
self.models.append(model)
|
||||
post_save.connect(activity_stream_create, sender=model, dispatch_uid=str(self.__class__) + str(model) + "_create")
|
||||
pre_save.connect(activity_stream_update, sender=model, dispatch_uid=str(self.__class__) + str(model) + "_update")
|
||||
post_delete.connect(activity_stream_delete, sender=model, dispatch_uid=str(self.__class__) + str(model) + "_delete")
|
||||
|
||||
for m2mfield in model._meta.many_to_many:
|
||||
try:
|
||||
m2m_attr = getattr(model, m2mfield.name)
|
||||
m2m_changed.connect(activity_stream_associate, sender=m2m_attr.through,
|
||||
dispatch_uid=str(self.__class__) + str(m2m_attr.through) + "_associate")
|
||||
except AttributeError:
|
||||
pass
|
||||
#logger.warning("Failed to attach m2m activity stream tracker on class %s attribute %s" % (model, m2mfield.name))
|
||||
|
||||
def disconnect(self, model):
|
||||
if model in self.models:
|
||||
post_save.disconnect(dispatch_uid=str(self.__class__) + str(model) + "_create")
|
||||
pre_save.disconnect(dispatch_uid=str(self.__class__) + str(model) + "_update")
|
||||
post_delete.disconnect(dispatch_uid=str(self.__class__) + str(model) + "_delete")
|
||||
self.models.pop(model)
|
||||
|
||||
|
||||
for m2mfield in model._meta.many_to_many:
|
||||
m2m_attr = getattr(model, m2mfield.name)
|
||||
m2m_changed.disconnect(dispatch_uid=str(self.__class__) + str(m2m_attr.through) + "_associate")
|
||||
|
||||
activity_stream_registrar = ActivityStreamRegistrar()
|
||||
@ -4,6 +4,7 @@
|
||||
# Python
|
||||
import logging
|
||||
import threading
|
||||
import json
|
||||
|
||||
# Django
|
||||
from django.db.models.signals import pre_save, post_save, pre_delete, post_delete, m2m_changed
|
||||
@ -11,6 +12,7 @@ from django.dispatch import receiver
|
||||
|
||||
# AWX
|
||||
from awx.main.models import *
|
||||
from awx.main.utils import model_instance_diff, model_to_dict, camelcase_to_underscore
|
||||
|
||||
__all__ = []
|
||||
|
||||
@ -168,3 +170,65 @@ def update_host_last_job_after_job_deleted(sender, **kwargs):
|
||||
hosts_pks = getattr(instance, '_saved_hosts_pks', [])
|
||||
for host in Host.objects.filter(pk__in=hosts_pks):
|
||||
_update_host_last_jhs(host)
|
||||
|
||||
# Set via ActivityStreamRegistrar to record activity stream events
|
||||
|
||||
def activity_stream_create(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
activity_entry = ActivityStream(
|
||||
operation='create',
|
||||
object1_id=instance.id,
|
||||
object1=camelcase_to_underscore(instance.__class__.__name__),
|
||||
object1_type=instance.__class__.__module__ + "." + instance.__class__.__name__,
|
||||
changes=json.dumps(model_to_dict(instance)))
|
||||
activity_entry.save()
|
||||
|
||||
def activity_stream_update(sender, instance, **kwargs):
|
||||
try:
|
||||
old = sender.objects.get(id=instance.id)
|
||||
except sender.DoesNotExist:
|
||||
return
|
||||
|
||||
new = instance
|
||||
changes = model_instance_diff(old, new)
|
||||
activity_entry = ActivityStream(
|
||||
operation='update',
|
||||
object1_id=instance.id,
|
||||
object1=camelcase_to_underscore(instance.__class__.__name__),
|
||||
object1_type=instance.__class__.__module__ + "." + instance.__class__.__name__,
|
||||
changes=json.dumps(changes))
|
||||
activity_entry.save()
|
||||
|
||||
|
||||
def activity_stream_delete(sender, instance, **kwargs):
|
||||
activity_entry = ActivityStream(
|
||||
operation='delete',
|
||||
object1_id=instance.id,
|
||||
object1=camelcase_to_underscore(instance.__class__.__name__),
|
||||
object1_type=instance.__class__.__module__ + "." + instance.__class__.__name__)
|
||||
activity_entry.save()
|
||||
|
||||
def activity_stream_associate(sender, instance, **kwargs):
|
||||
if 'pre_add' in kwargs['action'] or 'pre_remove' in kwargs['action']:
|
||||
if kwargs['action'] == 'pre_add':
|
||||
action = 'associate'
|
||||
elif kwargs['action'] == 'pre_remove':
|
||||
action = 'disassociate'
|
||||
else:
|
||||
return
|
||||
obj1 = instance
|
||||
obj1_id = obj1.id
|
||||
obj_rel = sender.__module__ + "." + sender.__name__
|
||||
for entity_acted in kwargs['pk_set']:
|
||||
obj2 = kwargs['model']
|
||||
obj2_id = entity_acted
|
||||
activity_entry = ActivityStream(
|
||||
operation=action,
|
||||
object1_id=obj1_id,
|
||||
object1=camelcase_to_underscore(obj1.__class__.__name__),
|
||||
object1_type=obj1.__class__.__module__ + "." + obj1.__class__.__name__,
|
||||
object2_id=obj2_id,
|
||||
object2=camelcase_to_underscore(obj2.__name__),
|
||||
object2_type=obj2.__module__ + "." + obj2.__name__,
|
||||
object_relationship_type=obj_rel)
|
||||
activity_entry.save()
|
||||
|
||||
@ -10,4 +10,4 @@ from awx.main.tests.scripts import *
|
||||
from awx.main.tests.tasks import RunJobTest
|
||||
from awx.main.tests.licenses import LicenseTests
|
||||
from awx.main.tests.jobs import *
|
||||
|
||||
from awx.main.tests.activity_stream import *
|
||||
|
||||
61
awx/main/tests/activity_stream.py
Normal file
61
awx/main/tests/activity_stream.py
Normal file
@ -0,0 +1,61 @@
|
||||
# Copyright (c) 2013 AnsibleWorks, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
# Python
|
||||
import contextlib
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
import django.test
|
||||
from django.test.client import Client
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
# AWX
|
||||
from awx.main.models import *
|
||||
from awx.main.tests.base import BaseTest
|
||||
|
||||
class ActivityStreamTest(BaseTest):
|
||||
|
||||
def collection(self):
|
||||
return reverse('api:activity_stream_list')
|
||||
|
||||
def item(self, item_id):
|
||||
return reverse('api:activity_stream_detail', args=(item_id,))
|
||||
|
||||
def setUp(self):
|
||||
super(ActivityStreamTest, self).setUp()
|
||||
self.setup_users()
|
||||
self.organization = self.make_organizations(self.normal_django_user, 1)[0]
|
||||
self.project = self.make_projects(self.normal_django_user, 1)[0]
|
||||
self.organization.projects.add(self.project)
|
||||
self.organization.users.add(self.normal_django_user)
|
||||
|
||||
def test_get_activity_stream_list(self):
|
||||
url = self.collection()
|
||||
|
||||
with self.current_user(self.normal_django_user):
|
||||
self.options(url, expect=200)
|
||||
self.head(url, expect=200)
|
||||
response = self.get(url, expect=200)
|
||||
self.check_pagination_and_size(response, 4, previous=None, next=None)
|
||||
|
||||
def test_basic_fields(self):
|
||||
org_item = self.item(self.organization.id)
|
||||
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.get(org_item, expect=200)
|
||||
self.assertEqual(response['object1_id'], self.organization.id)
|
||||
self.assertEqual(response['object1_type'], "awx.main.models.organization.Organization")
|
||||
self.assertEqual(response['object2_id'], None)
|
||||
self.assertEqual(response['object2_type'], None)
|
||||
|
||||
self.assertTrue("related" in response)
|
||||
self.assertTrue("object1" in response['related'])
|
||||
self.assertTrue("summary_fields" in response)
|
||||
self.assertTrue("object1" in response['summary_fields'])
|
||||
self.assertEquals(response['summary_fields']['object1']['base'], "organization")
|
||||
@ -10,6 +10,9 @@ import subprocess
|
||||
import sys
|
||||
import urlparse
|
||||
|
||||
# Django
|
||||
from django.db.models import Model
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework.exceptions import ParseError, PermissionDenied
|
||||
|
||||
@ -219,3 +222,45 @@ def update_scm_url(scm_type, url, username=True, password=True):
|
||||
new_url = urlparse.urlunsplit([parts.scheme, netloc, parts.path,
|
||||
parts.query, parts.fragment])
|
||||
return new_url
|
||||
|
||||
def model_instance_diff(old, new):
|
||||
"""
|
||||
Calculate the differences between two model instances. One of the instances may be None (i.e., a newly
|
||||
created model or deleted model). This will cause all fields with a value to have changed (from None).
|
||||
"""
|
||||
if not(old is None or isinstance(old, Model)):
|
||||
raise TypeError('The supplied old instance is not a valid model instance.')
|
||||
if not(new is None or isinstance(new, Model)):
|
||||
raise TypeError('The supplied new instance is not a valid model instance.')
|
||||
|
||||
diff = {}
|
||||
|
||||
if old is not None and new is not None:
|
||||
fields = set(old._meta.fields + new._meta.fields)
|
||||
elif old is not None:
|
||||
fields = set(old._meta.fields)
|
||||
elif new is not None:
|
||||
fields = set(new._meta.fields)
|
||||
else:
|
||||
fields = set()
|
||||
|
||||
for field in fields:
|
||||
old_value = str(getattr(old, field.name, None))
|
||||
new_value = str(getattr(new, field.name, None))
|
||||
|
||||
if old_value != new_value:
|
||||
diff[field.name] = (old_value, new_value)
|
||||
|
||||
if len(diff) == 0:
|
||||
diff = None
|
||||
|
||||
return diff
|
||||
|
||||
def model_to_dict(obj):
|
||||
"""
|
||||
Serialize a model instance to a dictionary as best as possible
|
||||
"""
|
||||
attr_d = {}
|
||||
for field in obj._meta.fields:
|
||||
attr_d[field.name] = str(getattr(obj, field.name, None))
|
||||
return attr_d
|
||||
|
||||
@ -105,6 +105,7 @@ TEMPLATE_CONTEXT_PROCESSORS += (
|
||||
MIDDLEWARE_CLASSES += (
|
||||
'django.middleware.transaction.TransactionMiddleware',
|
||||
# Middleware loaded after this point will be subject to transactions.
|
||||
'awx.main.middleware.ActivityStreamMiddleware'
|
||||
)
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
|
||||
@ -846,7 +846,7 @@ body .ui-tooltip {
|
||||
.ui-widget-content .ui-state-focus,
|
||||
.ui-widget-header .ui-state-focus {
|
||||
border: 1px solid #e3e3e3;
|
||||
background: #e5e3e3 url(/static/css/images/ui-bg_flat_75_e5e3e3_40x100.png) 50% 50% repeat-x;
|
||||
background: #e5e3e3 url(/static/css/custom-theme/images/ui-bg_flat_75_e5e3e3_40x100.png) 50% 50% repeat-x;
|
||||
font-weight: bold;
|
||||
color: #005580;
|
||||
}
|
||||
|
||||
@ -84,7 +84,8 @@ angular.module('ansible', [
|
||||
'TimerService',
|
||||
'StreamListDefinition',
|
||||
'HomeGroupListDefinition',
|
||||
'HomeHostListDefinition'
|
||||
'HomeHostListDefinition',
|
||||
'ActivityDetailDefinition'
|
||||
])
|
||||
.config(['$routeProvider', function($routeProvider) {
|
||||
$routeProvider.
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, CredentialList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, GetBasePath, SelectionInit, GetChoices)
|
||||
ClearScope, ProcessErrors, GetBasePath, SelectionInit, GetChoices, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -86,14 +86,17 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res
|
||||
scope.deleteCredential = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
@ -109,13 +112,13 @@ function CredentialsList ($scope, $rootScope, $location, $log, $routeParams, Res
|
||||
|
||||
CredentialsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'CredentialList', 'GenerateList',
|
||||
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'SelectionInit', 'GetChoices'];
|
||||
'GetBasePath', 'SelectionInit', 'GetChoices', 'Wait' ];
|
||||
|
||||
|
||||
function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
||||
GenerateList, SearchInit, PaginateInit, LookUpInit, UserList, TeamList, GetBasePath,
|
||||
GetChoices, Empty, KindChange, OwnerChange, FormSave)
|
||||
GetChoices, Empty, KindChange, OwnerChange, FormSave, DebugForm)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -158,6 +161,7 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
// Get the username based on incoming route
|
||||
scope['owner'] = 'user';
|
||||
scope['user'] = $routeParams.user_id;
|
||||
OwnerChange({ scope: scope });
|
||||
var url = GetBasePath('users') + $routeParams.user_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
@ -173,6 +177,7 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
// Get the username based on incoming route
|
||||
scope['owner'] = 'team';
|
||||
scope['team'] = $routeParams.team_id;
|
||||
OwnerChange({ scope: scope });
|
||||
var url = GetBasePath('teams') + $routeParams.team_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
@ -238,7 +243,7 @@ function CredentialsAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
CredentialsAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'CredentialForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList',
|
||||
'SearchInit', 'PaginateInit', 'LookUpInit', 'UserList', 'TeamList', 'GetBasePath', 'GetChoices', 'Empty',
|
||||
'KindChange', 'OwnerChange', 'FormSave'];
|
||||
'KindChange', 'OwnerChange', 'FormSave', 'DebugForm'];
|
||||
|
||||
|
||||
function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm,
|
||||
@ -358,14 +363,16 @@ function CredentialsEdit ($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
master['secret_key'] = scope['secret_key'];
|
||||
break;
|
||||
case 'ssh':
|
||||
scope['ssh_username'] = data.username;
|
||||
scope['ssh_password'] = data.password;
|
||||
master['ssh_username'] = scope['ssh_username'];
|
||||
master['ssh_password'] = scope['ssh_password'];
|
||||
break;
|
||||
case 'scm':
|
||||
scope['scm_key_unlock'] = data['ssh_key_unlock'];
|
||||
break;
|
||||
case 'rax':
|
||||
scope['api_key'] = data['password'];
|
||||
master['api_key'] = scope['api_key'];
|
||||
break;
|
||||
}
|
||||
|
||||
scope.$emit('credentialLoaded');
|
||||
|
||||
@ -16,28 +16,33 @@ function Home ($routeParams, $scope, $rootScope, $location, Wait, ObjectCount, J
|
||||
ClearScope('home'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
|
||||
var waitCount = 4;
|
||||
var loadedCount = 0;
|
||||
|
||||
if (!$routeParams['login']) {
|
||||
// If we're not logging in, start the Wait widget. Otherwise, it's already running.
|
||||
Wait('start');
|
||||
}
|
||||
|
||||
JobStatus({ target: 'container1' });
|
||||
InventorySyncStatus({ target: 'container2' });
|
||||
SCMSyncStatus({ target: 'container4' });
|
||||
ObjectCount({ target: 'container3' });
|
||||
|
||||
$rootScope.showActivity = function() { Stream(); }
|
||||
|
||||
$rootScope.$on('WidgetLoaded', function() {
|
||||
// Once all the widgets report back 'loaded', turn off Wait widget
|
||||
loadedCount++;
|
||||
if ( loadedCount == waitCount ) {
|
||||
Wait('stop');
|
||||
var load = function() {
|
||||
var waitCount = 4;
|
||||
var loadedCount = 0;
|
||||
|
||||
if (!$routeParams['login']) {
|
||||
// If we're not logging in, start the Wait widget. Otherwise, it's already running.
|
||||
Wait('start');
|
||||
}
|
||||
});
|
||||
|
||||
JobStatus({ target: 'container1' });
|
||||
InventorySyncStatus({ target: 'container2' });
|
||||
SCMSyncStatus({ target: 'container4' });
|
||||
ObjectCount({ target: 'container3' });
|
||||
|
||||
$rootScope.$on('WidgetLoaded', function() {
|
||||
// Once all the widgets report back 'loaded', turn off Wait widget
|
||||
loadedCount++;
|
||||
if ( loadedCount == waitCount ) {
|
||||
Wait('stop');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$rootScope.showActivity = function() { Stream(); }
|
||||
$rootScope.refresh = function() { load(); }
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
Home.$inject=[ '$routeParams', '$scope', '$rootScope', '$location', 'Wait', 'ObjectCount', 'JobStatus', 'InventorySyncStatus',
|
||||
@ -96,6 +101,14 @@ function HomeGroups ($location, $routeParams, HomeGroupList, GenerateList, Proce
|
||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||
|
||||
// Process search params
|
||||
if ($routeParams['name']) {
|
||||
scope[list.iterator + 'InputDisable'] = false;
|
||||
scope[list.iterator + 'SearchValue'] = $routeParams['name'];
|
||||
scope[list.iterator + 'SearchField'] = 'name';
|
||||
scope[list.iterator + 'SearchFieldLabel'] = list.fields['name'].label;
|
||||
scope[list.iterator + 'SearchSelectValue'] = null;
|
||||
}
|
||||
|
||||
if ($routeParams['has_active_failures']) {
|
||||
scope[list.iterator + 'InputDisable'] = true;
|
||||
scope[list.iterator + 'SearchValue'] = $routeParams['has_active_failures'];
|
||||
@ -180,7 +193,15 @@ function HomeHosts ($location, $routeParams, HomeHostList, GenerateList, Process
|
||||
|
||||
SearchInit({ scope: scope, set: 'hosts', list: list, url: defaultUrl });
|
||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||
|
||||
|
||||
// Process search params
|
||||
if ($routeParams['name']) {
|
||||
scope[HomeHostList.iterator + 'InputDisable'] = false;
|
||||
scope[HomeHostListiterator + 'SearchValue'] = $routeParams['name'];
|
||||
scope[HomeHostList.iterator + 'SearchField'] = 'name';
|
||||
scope[lHomeHostList.iterator + 'SearchFieldLabel'] = list.fields['name'].label;
|
||||
}
|
||||
|
||||
if ($routeParams['has_active_failures']) {
|
||||
scope[HomeHostList.iterator + 'InputDisable'] = true;
|
||||
scope[HomeHostList.iterator + 'SearchValue'] = $routeParams['has_active_failures'];
|
||||
|
||||
@ -150,6 +150,7 @@ function InventoriesList ($scope, $rootScope, $location, $log, $routeParams, Res
|
||||
scope.deleteInventory = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
$('#prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
@ -207,7 +208,7 @@ InventoriesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$route
|
||||
function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, InventoryForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
||||
GenerateList, OrganizationList, SearchInit, PaginateInit, LookUpInit, GetBasePath,
|
||||
ParseTypeChange)
|
||||
ParseTypeChange, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -239,6 +240,7 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
// Save
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
try {
|
||||
// Make sure we have valid variable data
|
||||
if (scope.inventoryParseType == 'json') {
|
||||
@ -273,23 +275,28 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
Rest.setUrl(data.related.variable_data);
|
||||
Rest.put(json_data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$location.path('/inventories/' + inventory_id + '/groups');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to add inventory varaibles. PUT returned status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
Wait('stop');
|
||||
$location.path('/inventories/' + inventory_id + '/groups');
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to add new inventory. Post returned status: ' + status });
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing inventory variables. Parser returned: " + err);
|
||||
}
|
||||
|
||||
@ -304,13 +311,14 @@ function InventoriesAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
|
||||
InventoriesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'InventoryForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList',
|
||||
'OrganizationList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'GetBasePath', 'ParseTypeChange'];
|
||||
'OrganizationList', 'SearchInit', 'PaginateInit', 'LookUpInit', 'GetBasePath', 'ParseTypeChange', 'Wait'];
|
||||
|
||||
|
||||
function InventoriesEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, InventoryForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
||||
RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt, OrganizationList,
|
||||
GetBasePath, LoadInventory, ParseTypeChange, EditInventory, SaveInventory, PostLoadInventory)
|
||||
GetBasePath, LoadInventory, ParseTypeChange, EditInventory, SaveInventory, PostLoadInventory
|
||||
)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobTemplateList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, GetBasePath, PromptPasswords, JobTemplateForm, CredentialList,
|
||||
LookUpInit, SubmitJob)
|
||||
LookUpInit, SubmitJob, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -49,14 +49,17 @@ function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Re
|
||||
|
||||
scope.deleteJobTemplate = function(id, name) {
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
@ -77,13 +80,13 @@ function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Re
|
||||
JobTemplatesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobTemplateList',
|
||||
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||
'ProcessErrors','GetBasePath', 'PromptPasswords', 'JobTemplateForm', 'CredentialList', 'LookUpInit',
|
||||
'SubmitJob'
|
||||
'SubmitJob', 'Wait'
|
||||
];
|
||||
|
||||
function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
||||
GetBasePath, InventoryList, CredentialList, ProjectList, LookUpInit,
|
||||
md5Setup, ParseTypeChange)
|
||||
md5Setup, ParseTypeChange, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -224,6 +227,7 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
// Save
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
var data = {}
|
||||
try {
|
||||
// Make sure we have valid variable data
|
||||
@ -258,16 +262,19 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'job_templates') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to add new job template. POST returned status: ' + status });
|
||||
});
|
||||
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing extra variables. Parser returned: " + err);
|
||||
}
|
||||
};
|
||||
@ -286,14 +293,14 @@ function JobTemplatesAdd ($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
JobTemplatesAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope',
|
||||
'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit',
|
||||
'md5Setup', 'ParseTypeChange' ];
|
||||
'md5Setup', 'ParseTypeChange', 'Wait'];
|
||||
|
||||
|
||||
function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
||||
RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList,
|
||||
ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, ParseTypeChange,
|
||||
JobStatusToolTip, FormatDate)
|
||||
JobStatusToolTip, FormatDate, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -539,6 +546,7 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route
|
||||
// Save changes to the parent
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
var data = {}
|
||||
try {
|
||||
// Make sure we have valid variable data
|
||||
@ -573,16 +581,19 @@ function JobTemplatesEdit ($scope, $rootScope, $compile, $location, $log, $route
|
||||
Rest.setUrl(defaultUrl + id + '/');
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'job_templates') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update job template. PUT returned status: ' + status });
|
||||
});
|
||||
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing extra variables. Parser returned: " + err);
|
||||
}
|
||||
};
|
||||
@ -640,5 +651,5 @@ JobTemplatesEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
|
||||
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList',
|
||||
'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup', 'ParseTypeChange',
|
||||
'JobStatusToolTip', 'FormatDate'
|
||||
'JobStatusToolTip', 'FormatDate', 'Wait'
|
||||
];
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, Rest, Alert, LoadBreadCrumbs, Prompt,
|
||||
GenerateList, OrganizationList, SearchInit, PaginateInit, ClearScope, ProcessErrors,
|
||||
GetBasePath, SelectionInit, Wait)
|
||||
GetBasePath, SelectionInit, Wait, Stream)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -36,6 +36,8 @@ function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, R
|
||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||
scope.search(list.iterator);
|
||||
|
||||
scope.showActivity = function() { Stream(); }
|
||||
|
||||
scope.addOrganization = function() {
|
||||
$location.path($location.path() + '/add');
|
||||
}
|
||||
@ -47,14 +49,17 @@ function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, R
|
||||
scope.deleteOrganization = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
@ -70,12 +75,12 @@ function OrganizationsList ($routeParams, $scope, $rootScope, $location, $log, R
|
||||
|
||||
OrganizationsList.$inject=[ '$routeParams', '$scope', '$rootScope', '$location', '$log', 'Rest', 'Alert', 'LoadBreadCrumbs', 'Prompt',
|
||||
'GenerateList', 'OrganizationList', 'SearchInit', 'PaginateInit', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'SelectionInit', 'Wait' ];
|
||||
'GetBasePath', 'SelectionInit', 'Wait', 'Stream'];
|
||||
|
||||
|
||||
function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, OrganizationForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath,
|
||||
ReturnToCaller)
|
||||
ReturnToCaller, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -92,12 +97,14 @@ function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $route
|
||||
// Save
|
||||
scope.formSave = function() {
|
||||
form.clearApiErrors();
|
||||
Wait('start');
|
||||
var url = GetBasePath(base);
|
||||
url += (base != 'organizations') ? $routeParams['project_id'] + '/organizations/' : '';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ name: $scope.name,
|
||||
description: $scope.description })
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
if (base == 'organizations') {
|
||||
$rootScope.flashMessage = "New organization successfully created!";
|
||||
$location.path('/organizations/' + data.id);
|
||||
@ -107,6 +114,7 @@ function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $route
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, OrganizationForm,
|
||||
{ hdr: 'Error!', msg: 'Failed to add new organization. Post returned status: ' + status });
|
||||
});
|
||||
@ -121,12 +129,12 @@ function OrganizationsAdd ($scope, $rootScope, $compile, $location, $log, $route
|
||||
|
||||
OrganizationsAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'OrganizationForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath',
|
||||
'ReturnToCaller' ];
|
||||
'ReturnToCaller', 'Wait'];
|
||||
|
||||
|
||||
function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, OrganizationForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
||||
RelatedPaginateInit, Prompt, ClearScope, GetBasePath)
|
||||
RelatedPaginateInit, Prompt, ClearScope, GetBasePath, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -184,6 +192,7 @@ function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $rout
|
||||
// Save changes to the parent
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
var params = {};
|
||||
for (var fld in form.fields) {
|
||||
params[fld] = scope[fld];
|
||||
@ -191,10 +200,12 @@ function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $rout
|
||||
Rest.setUrl(defaultUrl + id + '/');
|
||||
Rest.put(params)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
master = params;
|
||||
$rootScope.flashMessage = "Your changes were successfully saved!";
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, OrganizationForm,
|
||||
{ hdr: 'Error!', msg: 'Failed to update organization: ' + id + '. PUT status: ' + status });
|
||||
});
|
||||
@ -226,14 +237,17 @@ function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $rout
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + $routeParams.organization_id + '/' + set + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ id: itm_id, disassociate: 1 })
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(form.related[set].iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. POST returned status: ' + status });
|
||||
@ -250,4 +264,4 @@ function OrganizationsEdit ($scope, $rootScope, $compile, $location, $log, $rout
|
||||
|
||||
OrganizationsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'OrganizationForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
|
||||
'RelatedPaginateInit', 'Prompt', 'ClearScope', 'GetBasePath'];
|
||||
'RelatedPaginateInit', 'Prompt', 'ClearScope', 'GetBasePath', 'Wait'];
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
function PermissionsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, PermissionList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, GetBasePath, CheckAccess)
|
||||
ClearScope, ProcessErrors, GetBasePath, CheckAccess, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -35,14 +35,17 @@ function PermissionsList ($scope, $rootScope, $location, $log, $routeParams, Res
|
||||
|
||||
scope.deletePermission = function(id, name) {
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = GetBasePath('base') + 'permissions/' + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
@ -60,13 +63,14 @@ function PermissionsList ($scope, $rootScope, $location, $log, $routeParams, Res
|
||||
|
||||
PermissionsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'PermissionList',
|
||||
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller',
|
||||
'ClearScope', 'ProcessErrors', 'GetBasePath', 'CheckAccess'
|
||||
'ClearScope', 'ProcessErrors', 'GetBasePath', 'CheckAccess', 'Wait'
|
||||
];
|
||||
|
||||
|
||||
function PermissionsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, PermissionsForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope,
|
||||
GetBasePath, ReturnToCaller, InventoryList, ProjectList, LookUpInit, CheckAccess)
|
||||
GetBasePath, ReturnToCaller, InventoryList, ProjectList, LookUpInit, CheckAccess,
|
||||
Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -110,6 +114,7 @@ function PermissionsAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
// Save
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
if (scope.PermissionAddAllowed) {
|
||||
var data = {};
|
||||
for (var fld in form.fields) {
|
||||
@ -119,9 +124,11 @@ function PermissionsAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
Rest.setUrl(url);
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, PermissionsForm,
|
||||
{ hdr: 'Error!', msg: 'Failed to create new permission. Post returned status: ' + status });
|
||||
});
|
||||
@ -153,13 +160,14 @@ function PermissionsAdd ($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
|
||||
PermissionsAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'PermissionsForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath',
|
||||
'ReturnToCaller', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess'
|
||||
'ReturnToCaller', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess', 'Wait'
|
||||
];
|
||||
|
||||
|
||||
function PermissionsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, PermissionsForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller,
|
||||
ClearScope, Prompt, GetBasePath, InventoryList, ProjectList, LookUpInit, CheckAccess)
|
||||
ClearScope, Prompt, GetBasePath, InventoryList, ProjectList, LookUpInit, CheckAccess,
|
||||
Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -247,6 +255,7 @@ function PermissionsEdit ($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
// Save changes to the parent
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
var data = {}
|
||||
for (var fld in form.fields) {
|
||||
data[fld] = scope[fld];
|
||||
@ -254,9 +263,11 @@ function PermissionsEdit ($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update Permission: ' + $routeParams.id + '. PUT status: ' + status });
|
||||
});
|
||||
@ -286,6 +297,7 @@ function PermissionsEdit ($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
|
||||
PermissionsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'PermissionsForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller',
|
||||
'ClearScope', 'Prompt', 'GetBasePath', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess'
|
||||
'ClearScope', 'Prompt', 'GetBasePath', 'InventoryList', 'ProjectList', 'LookUpInit', 'CheckAccess',
|
||||
'Wait'
|
||||
];
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, ProjectList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, GetBasePath, SelectionInit, ProjectUpdate, ProjectStatus,
|
||||
FormatDate, Refresh)
|
||||
FormatDate, Refresh, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -112,14 +112,17 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
||||
|
||||
scope.deleteProject = function(id, name) {
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
@ -225,13 +228,13 @@ function ProjectsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
||||
|
||||
ProjectsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'ProjectList', 'GenerateList',
|
||||
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'SelectionInit', 'ProjectUpdate', 'ProjectStatus', 'FormatDate', 'Refresh' ];
|
||||
'GetBasePath', 'SelectionInit', 'ProjectUpdate', 'ProjectStatus', 'FormatDate', 'Refresh', 'Wait' ];
|
||||
|
||||
|
||||
function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, ProjectsForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope,
|
||||
GetBasePath, ReturnToCaller, GetProjectPath, LookUpInit, OrganizationList,
|
||||
CredentialList, GetChoices, DebugForm)
|
||||
CredentialList, GetChoices, DebugForm, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -291,6 +294,7 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
|
||||
// Save
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
var data = {};
|
||||
for (var fld in form.fields) {
|
||||
if (form.fields[fld].type == 'checkbox_group') {
|
||||
@ -322,6 +326,7 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
|
||||
Rest.setUrl(url);
|
||||
Rest.post(org)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$rootScope.flashMessage = "New project successfully created!";
|
||||
(base == 'projects') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
@ -331,6 +336,7 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
|
||||
});
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, ProjectsForm,
|
||||
{ hdr: 'Error!', msg: 'Failed to create new project. POST returned status: ' + status });
|
||||
});
|
||||
@ -357,14 +363,14 @@ function ProjectsAdd ($scope, $rootScope, $compile, $location, $log, $routeParam
|
||||
ProjectsAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'ProjectsForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath',
|
||||
'ReturnToCaller', 'GetProjectPath', 'LookUpInit', 'OrganizationList', 'CredentialList', 'GetChoices',
|
||||
'DebugForm'
|
||||
'DebugForm', 'Wait'
|
||||
];
|
||||
|
||||
|
||||
function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, ProjectsForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
||||
RelatedPaginateInit, Prompt, ClearScope, GetBasePath, ReturnToCaller, GetProjectPath,
|
||||
Authorization, CredentialList, LookUpInit, GetChoices, Empty, DebugForm)
|
||||
Authorization, CredentialList, LookUpInit, GetChoices, Empty, DebugForm, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -499,6 +505,7 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
|
||||
// Save changes to the parent
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
$rootScope.flashMessage = null;
|
||||
var params = {};
|
||||
for (var fld in form.fields) {
|
||||
@ -525,9 +532,11 @@ function ProjectsEdit ($scope, $rootScope, $compile, $location, $log, $routePara
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(params)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ReturnToCaller();
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update project: ' + id + '. PUT status: ' + status });
|
||||
});
|
||||
@ -591,5 +600,5 @@ ProjectsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log'
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
|
||||
'RelatedPaginateInit', 'Prompt', 'ClearScope', 'GetBasePath', 'ReturnToCaller',
|
||||
'GetProjectPath', 'Authorization', 'CredentialList', 'LookUpInit', 'GetChoices', 'Empty',
|
||||
'DebugForm'
|
||||
'DebugForm', 'Wait'
|
||||
];
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
function TeamsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, TeamList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, SetTeamListeners, GetBasePath, SelectionInit)
|
||||
ClearScope, ProcessErrors, SetTeamListeners, GetBasePath, SelectionInit, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -56,14 +56,17 @@ function TeamsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Ale
|
||||
scope.deleteTeam = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
@ -90,12 +93,12 @@ function TeamsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Ale
|
||||
|
||||
TeamsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'TeamList', 'GenerateList',
|
||||
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'SetTeamListeners', 'GetBasePath', 'SelectionInit'];
|
||||
'SetTeamListeners', 'GetBasePath', 'SelectionInit', 'Wait'];
|
||||
|
||||
|
||||
function TeamsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
||||
GenerateList, OrganizationList, SearchInit, PaginateInit, GetBasePath, LookUpInit)
|
||||
function TeamsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm, GenerateForm,
|
||||
Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GenerateList,
|
||||
OrganizationList, SearchInit, PaginateInit, GetBasePath, LookUpInit, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -120,6 +123,7 @@ function TeamsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
// Save
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
Rest.setUrl(defaultUrl);
|
||||
var data = {}
|
||||
for (var fld in form.fields) {
|
||||
@ -127,10 +131,12 @@ function TeamsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
}
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$rootScope.flashMessage = "New team successfully created!";
|
||||
$location.path('/teams/' + data.id);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to add new team. Post returned status: ' + status });
|
||||
});
|
||||
@ -145,13 +151,13 @@ function TeamsAdd ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
|
||||
TeamsAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList',
|
||||
'OrganizationList', 'SearchInit', 'PaginateInit', 'GetBasePath', 'LookUpInit' ];
|
||||
'OrganizationList', 'SearchInit', 'PaginateInit', 'GetBasePath', 'LookUpInit', 'Wait'];
|
||||
|
||||
|
||||
function TeamsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, TeamForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
||||
RelatedPaginateInit, ReturnToCaller, ClearScope, LookUpInit, Prompt,
|
||||
GetBasePath, CheckAccess, OrganizationList)
|
||||
GetBasePath, CheckAccess, OrganizationList, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -230,6 +236,7 @@ function TeamsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
// Save changes to the parent
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
$rootScope.flashMessage = null;
|
||||
Rest.setUrl(defaultUrl + $routeParams.team_id +'/');
|
||||
var data = {}
|
||||
@ -238,10 +245,12 @@ function TeamsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
}
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'teams') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update team: ' + $routeParams.team_id + '. PUT status: ' + status });
|
||||
});
|
||||
@ -335,6 +344,6 @@ function TeamsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
TeamsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
|
||||
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt',
|
||||
'GetBasePath', 'CheckAccess', 'OrganizationList'
|
||||
'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait'
|
||||
];
|
||||
|
||||
|
||||
@ -10,9 +10,9 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
||||
Alert, UserList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit,
|
||||
ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, SelectionInit)
|
||||
function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, UserList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
|
||||
ClearScope, ProcessErrors, GetBasePath, SelectionInit, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -47,14 +47,17 @@ function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
||||
scope.deleteUser = function(id, name) {
|
||||
|
||||
var action = function() {
|
||||
Wait('start')
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
$('#prompt-modal').modal('hide');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
@ -70,12 +73,12 @@ function UsersList ($scope, $rootScope, $location, $log, $routeParams, Rest,
|
||||
|
||||
UsersList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'UserList', 'GenerateList',
|
||||
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
|
||||
'GetBasePath', 'SelectionInit'];
|
||||
'GetBasePath', 'SelectionInit', 'Wait' ];
|
||||
|
||||
|
||||
function UsersAdd ($scope, $rootScope, $compile, $location, $log, $routeParams, UserForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
||||
GetBasePath, LookUpInit, OrganizationList, ResetForm)
|
||||
GetBasePath, LookUpInit, OrganizationList, ResetForm, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -121,6 +124,7 @@ function UsersAdd ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
// Save
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
if (scope.organization !== undefined && scope.organization !== null && scope.organization !== '') {
|
||||
Rest.setUrl(defaultUrl + scope.organization + '/users/');
|
||||
var data = {}
|
||||
@ -138,6 +142,7 @@ function UsersAdd ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
if (base == 'users') {
|
||||
$rootScope.flashMessage = 'New user successfully created!';
|
||||
@ -148,6 +153,7 @@ function UsersAdd ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to add new user. POST returned status: ' + status });
|
||||
});
|
||||
@ -174,12 +180,13 @@ function UsersAdd ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
|
||||
UsersAdd.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'UserForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GetBasePath',
|
||||
'LookUpInit', 'OrganizationList', 'ResetForm' ];
|
||||
'LookUpInit', 'OrganizationList', 'ResetForm', 'Wait' ];
|
||||
|
||||
|
||||
function UsersEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, UserForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
|
||||
RelatedPaginateInit, ReturnToCaller, ClearScope, GetBasePath, Prompt, CheckAccess, ResetForm)
|
||||
RelatedPaginateInit, ReturnToCaller, ClearScope, GetBasePath, Prompt, CheckAccess,
|
||||
ResetForm, Wait)
|
||||
{
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -252,6 +259,7 @@ function UsersEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
// Save changes to the parent
|
||||
scope.formSave = function() {
|
||||
generator.clearApiErrors();
|
||||
Wait('start');
|
||||
$rootScope.flashMessage = null;
|
||||
Rest.setUrl(defaultUrl + id + '/');
|
||||
var data = {}
|
||||
@ -269,10 +277,12 @@ function UsersEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'users') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update users: ' + $routeParams.id + '. PUT status: ' + status });
|
||||
});
|
||||
@ -425,5 +435,5 @@ function UsersEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
|
||||
UsersEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'UserForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
|
||||
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'Prompt', 'CheckAccess',
|
||||
'ResetForm' ];
|
||||
'ResetForm', 'Wait' ];
|
||||
|
||||
|
||||
64
awx/ui/static/js/forms/ActivityDetail.js
Normal file
64
awx/ui/static/js/forms/ActivityDetail.js
Normal file
@ -0,0 +1,64 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2013 AnsibleWorks, Inc.
|
||||
*
|
||||
* ActivityDetail.js
|
||||
* Form definition for Activity Stream detail
|
||||
*
|
||||
*/
|
||||
angular.module('ActivityDetailDefinition', [])
|
||||
.value(
|
||||
'ActivityDetailForm', {
|
||||
|
||||
name: 'activity',
|
||||
editTitle: 'Activity Detail',
|
||||
well: false,
|
||||
'class': 'horizontal-narrow',
|
||||
|
||||
fields: {
|
||||
timestamp: {
|
||||
label: 'Time',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
id: {
|
||||
label: 'Event ID',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
operation: {
|
||||
label: 'Operation',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
object1: {
|
||||
label: 'Object 1',
|
||||
type: 'text',
|
||||
ngHide: '!object1',
|
||||
readonly: true
|
||||
},
|
||||
object1_name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
ngHide: '!object1',
|
||||
readonly: true
|
||||
},
|
||||
object2: {
|
||||
label: 'Object 2',
|
||||
type: 'text',
|
||||
ngHide: '!object2',
|
||||
readonly: true
|
||||
},
|
||||
object2_name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
ngHide: '!object2',
|
||||
readonly: true
|
||||
},
|
||||
changes: {
|
||||
label: 'Changes',
|
||||
type: 'textarea',
|
||||
readonly: true
|
||||
}
|
||||
}
|
||||
|
||||
}); //Form
|
||||
@ -114,11 +114,22 @@ angular.module('CredentialFormDefinition', [])
|
||||
awRequiredWhen: {variable: 'rackspace_required', init: false },
|
||||
autocomplete: false
|
||||
},
|
||||
"api_key": {
|
||||
label: 'API Key',
|
||||
type: 'password',
|
||||
ngShow: "kind.value == 'rax'",
|
||||
awRequiredWhen: { variable: "rackspace_required", init: false },
|
||||
autocomplete: false,
|
||||
ask: false,
|
||||
clear: false,
|
||||
apiField: 'passwowrd'
|
||||
},
|
||||
"password": {
|
||||
label: 'Password',
|
||||
type: 'password',
|
||||
ngShow: "kind.value == 'rax' || kind.value == 'scm'",
|
||||
awRequiredWhen: {variable: 'rackspace_required', init: false },
|
||||
ngShow: "kind.value == 'scm'",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
ngChange: "clearPWConfirm('password_confirm')",
|
||||
ask: false,
|
||||
clear: false,
|
||||
@ -128,7 +139,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
"password_confirm": {
|
||||
label: 'Confirm Password',
|
||||
type: 'password',
|
||||
ngShow: "kind.value == 'rax' || kind.value == 'scm'",
|
||||
ngShow: "kind.value == 'scm'",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPassMatch: true,
|
||||
|
||||
@ -42,7 +42,9 @@ angular.module('ProjectFormDefinition', [])
|
||||
ngClick: 'lookUpOrganization()',
|
||||
awRequiredWhen: {variable: "organizationrequired", init: "true" },
|
||||
awPopOver: '<p>A project must have at least one organization. Pick one organization now to create the project, and then after ' +
|
||||
'the project is created you can add additional organizations.' ,
|
||||
'the project is created you can add additional organizations.</p><p>Only super users and organization administrators are allowed ' +
|
||||
'to make changes to projects. Associating one or more organizations to a project determins which organizations admins have ' +
|
||||
'access to modify the project.',
|
||||
dataTitle: 'Organization',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right'
|
||||
|
||||
@ -44,6 +44,7 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
if (reset) {
|
||||
scope['access_key'] = null;
|
||||
scope['secret_key'] = null;
|
||||
scope['api_key'] = null;
|
||||
scope['username'] = null;
|
||||
scope['password'] = null;
|
||||
scope['password_confirm'] = null;
|
||||
@ -94,14 +95,16 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
}])
|
||||
|
||||
|
||||
.factory('FormSave', ['$location', 'Rest', 'ProcessErrors', 'Empty', 'GetBasePath', 'CredentialForm', 'ReturnToCaller',
|
||||
function($location, Rest, ProcessErrors, Empty, GetBasePath, CredentialForm, ReturnToCaller) {
|
||||
.factory('FormSave', ['$location', 'Rest', 'ProcessErrors', 'Empty', 'GetBasePath', 'CredentialForm', 'ReturnToCaller', 'Wait',
|
||||
function($location, Rest, ProcessErrors, Empty, GetBasePath, CredentialForm, ReturnToCaller, Wait) {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var mode = params.mode; // add or edit
|
||||
var form = CredentialForm;
|
||||
var data = {}
|
||||
|
||||
Wait('start');
|
||||
|
||||
for (var fld in form.fields) {
|
||||
if (fld !== 'access_key' && fld !== 'secret_key' && fld !== 'ssh_username' &&
|
||||
fld !== 'ssh_password') {
|
||||
@ -127,7 +130,6 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
|
||||
switch (data['kind']) {
|
||||
case 'ssh':
|
||||
data['username'] = scope['ssh_username'];
|
||||
data['password'] = scope['ssh_password'];
|
||||
break;
|
||||
case 'aws':
|
||||
@ -137,6 +139,9 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
case 'scm':
|
||||
data['ssh_key_unlock'] = scope['scm_key_unlock'];
|
||||
break;
|
||||
case 'rax':
|
||||
data['password'] = scope['api_key'];
|
||||
break;
|
||||
}
|
||||
|
||||
if (Empty(data.team) && Empty(data.user)) {
|
||||
@ -150,10 +155,12 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
Rest.setUrl(url);
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'credentials') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to create new Credential. POST status: ' + status });
|
||||
});
|
||||
@ -163,10 +170,12 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
Rest.setUrl(url);
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'credentials') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update Credential. PUT status: ' + status });
|
||||
});
|
||||
|
||||
@ -564,9 +564,9 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
}])
|
||||
|
||||
.factory('GroupsAdd', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'GroupsEdit', 'BuildTree', 'ClickNode',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'GroupsEdit', 'BuildTree', 'ClickNode', 'Wait',
|
||||
function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors,
|
||||
GetBasePath, ParseTypeChange, GroupsEdit, BuildTree, ClickNode) {
|
||||
GetBasePath, ParseTypeChange, GroupsEdit, BuildTree, ClickNode, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var inventory_id = params.inventory_id;
|
||||
@ -603,6 +603,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
|
||||
// Save
|
||||
scope.formModalAction = function() {
|
||||
Wait('start');
|
||||
try {
|
||||
scope.formModalActionDisabled = true;
|
||||
|
||||
@ -638,6 +639,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
groupCreated = true;
|
||||
scope.formModalActionDisabled = false;
|
||||
scope.showGroupHelp = false; //get rid of the Hint
|
||||
@ -653,12 +655,14 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
});
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
scope.formModalActionDisabled = false;
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to add new group. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
scope.formModalActionDisabled = false;
|
||||
Alert("Error", "Error parsing group variables. Parser returned: " + err);
|
||||
}
|
||||
@ -675,10 +679,10 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
|
||||
.factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate',
|
||||
'GetUpdateIntervalOptions', 'ClickNode', 'LookUpInit', 'CredentialList', 'Empty',
|
||||
'GetUpdateIntervalOptions', 'ClickNode', 'LookUpInit', 'CredentialList', 'Empty', 'Wait',
|
||||
function($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors,
|
||||
GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, GetUpdateIntervalOptions, ClickNode,
|
||||
LookUpInit, CredentialList, Empty) {
|
||||
LookUpInit, CredentialList, Empty, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var group_id = params.group_id;
|
||||
@ -942,6 +946,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
|
||||
// Save changes to the parent
|
||||
scope.formSave = function() {
|
||||
Wait('start');
|
||||
try {
|
||||
var refreshHosts = false;
|
||||
|
||||
@ -967,6 +972,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
if (scope.variables) {
|
||||
//update group variables
|
||||
Rest.setUrl(scope.variable_url);
|
||||
@ -979,11 +985,13 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
scope.$emit('formSaveSuccess', data.id);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update group: ' + group_id + '. PUT status: ' + status });
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing group variables. Parser returned: " + err);
|
||||
}
|
||||
};
|
||||
|
||||
@ -161,9 +161,9 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
||||
|
||||
|
||||
.factory('HostsAdd', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait',
|
||||
function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors,
|
||||
GetBasePath, HostsReload, ParseTypeChange) {
|
||||
GetBasePath, HostsReload, ParseTypeChange, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var inventory_id = params.inventory_id;
|
||||
@ -202,6 +202,8 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
||||
// Save
|
||||
scope.formModalAction = function() {
|
||||
|
||||
Wait('start');
|
||||
|
||||
function finished() {
|
||||
$('#form-modal').modal('hide');
|
||||
scope.$emit('hostsReload');
|
||||
@ -245,15 +247,18 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
finished();
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
scope.formModalActionDisabled = false;
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to add new host. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
scope.formModalActionDisabled = false;
|
||||
Alert("Error", "Error parsing host variables. Parser returned: " + err);
|
||||
}
|
||||
@ -270,9 +275,9 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
||||
|
||||
|
||||
.factory('HostsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait',
|
||||
function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors,
|
||||
GetBasePath, HostsReload, ParseTypeChange) {
|
||||
GetBasePath, HostsReload, ParseTypeChange, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var host_id = params.host_id;
|
||||
@ -366,6 +371,8 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
||||
// Save changes to the parent
|
||||
scope.formModalAction = function() {
|
||||
|
||||
Wait('start');
|
||||
|
||||
function finished() {
|
||||
$('#form-modal').modal('hide');
|
||||
if (hostsReload) {
|
||||
@ -406,14 +413,17 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
finished();
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update host: ' + host_id + '. PUT returned status: ' + status });
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing host variables. Parser returned: " + err);
|
||||
}
|
||||
};
|
||||
|
||||
@ -8,8 +8,9 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
|
||||
'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper', 'GroupFormDefinition', 'GroupsHelper' ])
|
||||
|
||||
.factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', 'GroupForm', 'ProjectsForm', '$compile', 'Rest', '$location', 'ProcessErrors',
|
||||
'GetBasePath', 'Alert', 'Empty',
|
||||
function(CredentialForm, JobTemplateForm, ProjectsForm, GroupForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty) {
|
||||
'GetBasePath', 'Alert', 'Empty', 'Wait',
|
||||
function(CredentialForm, JobTemplateForm, ProjectsForm, GroupForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty,
|
||||
Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
@ -65,6 +66,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
|
||||
|
||||
scope.startJob = function() {
|
||||
$('#password-modal').modal('hide');
|
||||
Wait('start');
|
||||
var pswd = {};
|
||||
var value_supplied = false;
|
||||
$('.password-field').each(function(index) {
|
||||
@ -77,17 +79,20 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
|
||||
Rest.setUrl(start_url);
|
||||
Rest.post(pswd)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
scope.$emit('UpdateSubmitted','started');
|
||||
if (form.name == 'credential') {
|
||||
navigate(false);
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'POST to ' + start_url + ' failed with status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
Wait('stop');
|
||||
Alert('No Passwords', 'Required password(s) not provided. The request was not submitted.', 'alert-info');
|
||||
if (form.name == 'credential') {
|
||||
// No passwords provided, so we can't start the job. Rather than leave the job in a 'new'
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
|
||||
angular.module('SelectionHelper', ['Utilities', 'RestServices'])
|
||||
|
||||
.factory('SelectionInit', [ 'Rest', 'Alert', 'ProcessErrors', 'ReturnToCaller',
|
||||
function(Rest, Alert, ProcessErrors, ReturnToCaller) {
|
||||
.factory('SelectionInit', [ 'Rest', 'Alert', 'ProcessErrors', 'ReturnToCaller', 'Wait',
|
||||
function(Rest, Alert, ProcessErrors, ReturnToCaller, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope; // current scope
|
||||
@ -74,6 +74,8 @@ angular.module('SelectionHelper', ['Utilities', 'RestServices'])
|
||||
scope.queue = [];
|
||||
scope.formModalActionDisabled = true;
|
||||
|
||||
Wait('start');
|
||||
|
||||
function finished() {
|
||||
scope.selected = [];
|
||||
if (returnToCaller !== undefined) {
|
||||
@ -92,6 +94,7 @@ angular.module('SelectionHelper', ['Utilities', 'RestServices'])
|
||||
// We call the API for each selected item. We need to hang out until all the api
|
||||
// calls are finished.
|
||||
if (scope.queue.length == scope.selected.length) {
|
||||
Wait('stop');
|
||||
var errors = 0;
|
||||
for (var i=0; i < scope.queue.length; i++) {
|
||||
if (scope.queue[i].result == 'error') {
|
||||
|
||||
@ -106,9 +106,9 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
|
||||
}])
|
||||
|
||||
.factory('SaveInventory', ['InventoryForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList',
|
||||
'GetBasePath', 'ParseTypeChange', 'LoadInventory',
|
||||
'GetBasePath', 'ParseTypeChange', 'LoadInventory', 'Wait',
|
||||
function(InventoryForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange,
|
||||
LoadInventory) {
|
||||
LoadInventory, Wait) {
|
||||
return function(params) {
|
||||
|
||||
// Save inventory property modifications
|
||||
@ -116,6 +116,8 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
|
||||
var scope = params.scope;
|
||||
var form = InventoryForm;
|
||||
var defaultUrl=GetBasePath('inventory');
|
||||
|
||||
Wait('start');
|
||||
|
||||
try {
|
||||
// Make sure we have valid variable data
|
||||
@ -150,6 +152,7 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
|
||||
Rest.setUrl(data.related.variable_data);
|
||||
Rest.put(json_data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
scope.$emit('inventorySaved');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
@ -162,11 +165,13 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update inventory. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing inventory variables. Parser returned: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,9 +70,11 @@ angular.module('PaginateHelper', ['RefreshHelper', 'ngCookies'])
|
||||
|
||||
scope[iterator + 'Page'] = 0;
|
||||
var new_url = url.replace(/\?page_size\=\d+/,'');
|
||||
var connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
console.log('new_url: ' + new_url);
|
||||
var connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += (scope[iterator + 'SearchParams']) ? connect + scope[iterator + 'SearchParams'] + '&page_size=' + scope[iterator + 'PageSize' ] :
|
||||
+ connect + 'page_size=' + scope[iterator + 'PageSize' ];
|
||||
connect + 'page_size=' + scope[iterator + 'PageSize' ];
|
||||
console.log('new_url: ' + new_url);
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,11 +33,16 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities'])
|
||||
scope[iterator + 'PageCount'] = Math.ceil((data.count / scope[iterator + 'PageSize']));
|
||||
scope[iterator + 'SearchSpin'] = false;
|
||||
scope[iterator + 'Loading'] = false;
|
||||
for (var i=1; i <= 3; i++) {
|
||||
var modifier = (i == 1) ? '' : i;
|
||||
scope[iterator + 'HoldInput' + modifier] = false;
|
||||
}
|
||||
scope[set] = data['results'];
|
||||
scope.$emit('PostRefresh');
|
||||
})
|
||||
.error ( function(data, status, headers, config) {
|
||||
scope[iterator + 'SearchSpin'] = false;
|
||||
scope[iterator + 'HoldInput'] = false;
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status });
|
||||
});
|
||||
|
||||
@ -16,7 +16,8 @@
|
||||
*/
|
||||
|
||||
angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
.factory('SearchInit', ['Alert', 'Rest', 'Refresh', '$location', function(Alert, Rest, Refresh, $location) {
|
||||
.factory('SearchInit', ['Alert', 'Rest', 'Refresh', '$location', 'GetBasePath', 'Empty', '$timeout',
|
||||
function(Alert, Rest, Refresh, $location, GetBasePath, Empty, $timeout) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
@ -25,211 +26,355 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
var list = params.list;
|
||||
var iterator = (params.iterator) ? params.iterator : list.iterator;
|
||||
var sort_order;
|
||||
|
||||
if (scope.searchTimer) {
|
||||
$timeout.cancel(scope.searchTimer);
|
||||
}
|
||||
|
||||
function setDefaults() {
|
||||
function setDefaults(widget) {
|
||||
// Set default values
|
||||
var modifier = (widget == undefined || widget == 1) ? '' : widget;
|
||||
scope[iterator + 'SearchField' + modifier] = '';
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = '';
|
||||
for (fld in list.fields) {
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].sourceModel) {
|
||||
var fka = list.fields[fld].sourceModel + '__' + list.fields[fld].sourceField;
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fka : fka;
|
||||
}
|
||||
else {
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fld : fld;
|
||||
}
|
||||
if (list.fields[fld].searchable == undefined || list.fields[fld].searchable == true) {
|
||||
scope[iterator + 'SearchField'] = fld;
|
||||
scope[iterator + 'SearchFieldLabel'] = list.fields[fld].label;
|
||||
}
|
||||
break;
|
||||
if (list.fields[fld].searchWidget == undefined && widget == 1 ||
|
||||
list.fields[fld].searchWidget == widget) {
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].sourceModel) {
|
||||
var fka = list.fields[fld].sourceModel + '__' + list.fields[fld].sourceField;
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fka : fka;
|
||||
}
|
||||
else {
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fld : fld;
|
||||
}
|
||||
if (list.fields[fld].searchable == undefined || list.fields[fld].searchable == true) {
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = list.fields[fld].label;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!scope[iterator + 'SearchField']) {
|
||||
// A field marked as key may not be 'searchable'
|
||||
if (Empty(scope[iterator + 'SearchField' + modifier])) {
|
||||
// A field marked as key may not be 'searchable'. Find the first searchable field.
|
||||
for (fld in list.fields) {
|
||||
if (list.fields[fld].searchable == undefined || list.fields[fld].searchable == true) {
|
||||
scope[iterator + 'SearchField'] = fld;
|
||||
scope[iterator + 'SearchFieldLabel'] = list.fields[fld].label;
|
||||
break;
|
||||
if (list.fields[fld].searchWidget == undefined && widget == 1 ||
|
||||
list.fields[fld].searchWidget == widget) {
|
||||
if (list.fields[fld].searchable == undefined || list.fields[fld].searchable == true) {
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = list.fields[fld].label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope[iterator + 'SearchType'] = 'icontains';
|
||||
scope[iterator + 'SearchTypeLabel'] = 'Contains';
|
||||
scope[iterator + 'SearchParams'] = '';
|
||||
scope[iterator + 'SearchValue'] = '';
|
||||
scope[iterator + 'SelectShow'] = false; // show/hide the Select
|
||||
scope[iterator + 'HideSearchType'] = false;
|
||||
scope[iterator + 'InputDisable'] = false;
|
||||
scope[iterator + 'ExtraParms'] = '';
|
||||
scope[iterator + 'SearchType' + modifier] = 'icontains';
|
||||
scope[iterator + 'SearchTypeLabel' + modifier] = 'Contains';
|
||||
scope[iterator + 'SearchParams' + modifier] = '';
|
||||
scope[iterator + 'SearchValue' + modifier] = '';
|
||||
scope[iterator + 'SelectShow' + modifier] = false; // show/hide the Select
|
||||
scope[iterator + 'HideSearchType' + modifier] = false;
|
||||
scope[iterator + 'InputDisable' + modifier] = false;
|
||||
scope[iterator + 'ExtraParms' + modifier] = '';
|
||||
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] =
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) ?
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder : 'Search';
|
||||
|
||||
scope[iterator + 'InputDisable' + modifier] =
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject == 'all') ? true : false;
|
||||
|
||||
var f = scope[iterator + 'SearchField']
|
||||
if (list.fields[f].searchType && ( list.fields[f].searchType == 'boolean'
|
||||
|| list.fields[f].searchType == 'select')) {
|
||||
scope[iterator + 'SelectShow'] = true;
|
||||
scope[iterator + 'SearchSelectOpts'] = list.fields[f].searchOptions;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType == 'int') {
|
||||
scope[iterator + 'HideSearchType'] = true;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType == 'gtzero') {
|
||||
scope[iterator + "InputHide"] = true;
|
||||
var f = scope[iterator + 'SearchField' + modifier];
|
||||
if (list.fields[f]) {
|
||||
if ( list.fields[f].searchType && (list.fields[f].searchType == 'boolean'
|
||||
|| list.fields[f].searchType == 'select') ) {
|
||||
scope[iterator + 'SelectShow' + modifier] = true;
|
||||
scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[f].searchOptions;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType == 'int') {
|
||||
scope[iterator + 'HideSearchType' + modifier] = true;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType == 'gtzero') {
|
||||
scope[iterator + 'InputHide' + modifier] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setDefaults();
|
||||
for (var i=1; i <= 3; i++) {
|
||||
var modifier = (i == 1) ? '' : i;
|
||||
if ( $('#search-widget-container' + modifier) ) {
|
||||
setDefaults(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions to handle search widget changes
|
||||
scope.setSearchField = function(iterator, fld, label) {
|
||||
scope[iterator + 'SearchFieldLabel'] = label;
|
||||
scope[iterator + 'SearchField'] = fld;
|
||||
scope[iterator + 'SearchValue'] = '';
|
||||
scope[iterator + 'SelectShow'] = false;
|
||||
scope[iterator + 'HideSearchType'] = false;
|
||||
scope[iterator + 'InputHide'] = false;
|
||||
scope[iterator + 'InputDisable'] = false;
|
||||
scope[iterator + 'SearchType'] = 'icontains';
|
||||
scope.setSearchField = function(iterator, fld, label, widget) {
|
||||
|
||||
var modifier = (widget == undefined || widget == 1) ? '' : widget;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = label;
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchValue' + modifier] = '';
|
||||
scope[iterator + 'SelectShow' + modifier] = false;
|
||||
scope[iterator + 'HideSearchType' + modifier] = false;
|
||||
scope[iterator + 'InputHide' + modifier] = false;
|
||||
scope[iterator + 'SearchType' + modifier] = 'icontains';
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = (list.fields[fld].searchPlaceholder) ? list.fields[fld].searchPlaceholder : 'Search';
|
||||
scope[iterator + 'InputDisable' + modifier] = (list.fields[fld].searchObject == 'all') ? true : false;
|
||||
|
||||
if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') {
|
||||
scope[iterator + "InputDisable"] = true;
|
||||
scope[iterator + "InputDisable" + modifier] = true;
|
||||
}
|
||||
else if (list.fields[fld].searchSingleValue){
|
||||
// Query a specific attribute for one specific value
|
||||
// searchSingleValue: true
|
||||
// searchType: 'boolean|int|etc.'
|
||||
// searchValue: < value to match for boolean use 'true'|'false' >
|
||||
scope[iterator + 'InputDisable'] = true;
|
||||
scope[iterator + "SearchValue"] = list.fields[fld].searchValue;
|
||||
scope[iterator + 'InputDisable' + modifier] = true;
|
||||
scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue;
|
||||
// For boolean type, SearchValue must be an object
|
||||
if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'true') {
|
||||
scope[iterator + "SearchSelectValue"] = { value: 1 };
|
||||
scope[iterator + "SearchSelectValue" + modifier] = { value: 1 };
|
||||
}
|
||||
else if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'false') {
|
||||
scope[iterator + "SearchSelectValue"] = { value: 0 };
|
||||
scope[iterator + "SearchSelectValue" + modifier] = { value: 0 };
|
||||
}
|
||||
else {
|
||||
scope[iterator + "SearchSelectValue"] = { value: list.fields[fld].searchValue };
|
||||
scope[iterator + "SearchSelectValue" + modifier] = { value: list.fields[fld].searchValue };
|
||||
}
|
||||
}
|
||||
else if (list.fields[fld].searchType == 'in') {
|
||||
scope[iterator + "SearchType"] = 'in';
|
||||
scope[iterator + "SearchValue"] = list.fields[fld].searchValue;
|
||||
scope[iterator + "InputDisable"] = true;
|
||||
scope[iterator + "SearchType" + modifier] = 'in';
|
||||
scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue;
|
||||
scope[iterator + "InputDisable" + modifier] = true;
|
||||
}
|
||||
else if (list.fields[fld].searchType && (list.fields[fld].searchType == 'boolean'
|
||||
|| list.fields[fld].searchType == 'select')) {
|
||||
scope[iterator + 'SelectShow'] = true;
|
||||
scope[iterator + 'SearchSelectOpts'] = list.fields[fld].searchOptions;
|
||||
|| list.fields[fld].searchType == 'select' || list.fields[fld].searchType == 'select_or')) {
|
||||
scope[iterator + 'SelectShow' + modifier] = true;
|
||||
scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[fld].searchOptions;
|
||||
}
|
||||
else if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') {
|
||||
scope[iterator + 'HideSearchType'] = true;
|
||||
}
|
||||
scope[iterator + 'HideSearchType' + modifier] = true;
|
||||
}
|
||||
else if (list.fields[fld].searchType && list.fields[fld].searchType == 'isnull') {
|
||||
scope[iterator + 'SearchType' + modifier] = 'isnull';
|
||||
scope[iterator + 'InputDisable' + modifier] = true;
|
||||
scope[iterator + 'SearchValue' + modifier] = 'true';
|
||||
}
|
||||
scope.search(iterator);
|
||||
}
|
||||
|
||||
scope.resetSearch = function(iterator) {
|
||||
scope.resetSearch = function(iterator, widget) {
|
||||
// Respdond to click of reset button
|
||||
setDefaults();
|
||||
setDefaults(widget);
|
||||
// Force removal of search keys from the URL
|
||||
window.location = '/#' + $location.path();
|
||||
scope.search(iterator);
|
||||
}
|
||||
|
||||
scope.setSearchType = function(iterator, type, label) {
|
||||
scope[iterator + 'SearchTypeLabel'] = label;
|
||||
scope[iterator + 'SearchType'] = type;
|
||||
scope.search(iterator);
|
||||
//scope.setSearchType = function(iterator, type, label) {
|
||||
// scope[iterator + 'SearchTypeLabel'] = label;
|
||||
// scope[iterator + 'SearchType'] = type;
|
||||
// scope.search(iterator);
|
||||
// }
|
||||
|
||||
|
||||
if (scope.removeDoSearch) {
|
||||
scope.removeDoSearch();
|
||||
}
|
||||
scope.removeDoSearch = scope.$on('doSearch', function(e, iterator, page, load, spin) {
|
||||
//
|
||||
// Execute the search
|
||||
//
|
||||
scope[iterator + 'SearchSpin'] = (spin == undefined || spin == true) ? true : false;
|
||||
scope[iterator + 'Loading'] = (load == undefined || load == true) ? true : false;
|
||||
var url = defaultUrl;
|
||||
|
||||
//finalize and execute the query
|
||||
scope[iterator + 'Page'] = (page) ? parseInt(page) - 1 : 0;
|
||||
if (/\/$/.test(url)) {
|
||||
url += '?' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
else {
|
||||
url += '&' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
url = url.replace(/\&\&/,'&');
|
||||
url += (scope[iterator + 'PageSize']) ? '&page_size=' + scope[iterator + 'PageSize'] : "";
|
||||
if (page) {
|
||||
url += '&page=' + page;
|
||||
}
|
||||
if (scope[iterator + 'ExtraParms']) {
|
||||
url += scope[iterator + 'ExtraParms'];
|
||||
}
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: url });
|
||||
});
|
||||
|
||||
|
||||
if (scope.removePrepareSearch) {
|
||||
scope.removePrepareSearch();
|
||||
}
|
||||
scope.removePrepareSearch = scope.$on('prepareSearch', function(e, iterator, page, load, spin) {
|
||||
//
|
||||
// Start build the search key/value pairs. This will process the first search widget, if the
|
||||
// selected field is an object type (used on activity stream).
|
||||
//
|
||||
scope[iterator + 'HoldInput'] = true;
|
||||
scope[iterator + 'SearchParams'] = '';
|
||||
if (list.fields[scope[iterator + 'SearchField']].searchObject &&
|
||||
list.fields[scope[iterator + 'SearchField']].searchObject !== 'all') {
|
||||
//This is specifically for activity stream. We need to identify which type of object is being searched
|
||||
//and then provide a list of PK values corresponding to the list of objects the user is interested in.
|
||||
var objs = list.fields[scope[iterator + 'SearchField']].searchObject;
|
||||
var o = (objs == 'inventories') ? 'inventory' : objs.replace(/s$/,'');
|
||||
scope[iterator + 'SearchParams'] = 'or__object1=' + o + '&or__object2=' + o;
|
||||
if (scope[iterator + 'SearchValue']) {
|
||||
var objUrl = GetBasePath('base') + objs + '/?name__icontains=' + scope[iterator + 'SearchValue'];
|
||||
Rest.setUrl(objUrl);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
var list='';
|
||||
for (var i=0; i < data.results.length; i++) {
|
||||
list += "," + data.results[i].id;
|
||||
}
|
||||
list = list.replace(/^\,/,'');
|
||||
if (!Empty(list)) {
|
||||
scope[iterator + 'SearchParams'] += '&or__object1_id__in=' + list + '&or__object2_id__in=' + list;
|
||||
}
|
||||
//scope[iterator + 'SearchParams'] += (sort_order) ? '&order_by=' + escape(sort_order) : "";
|
||||
scope.$emit('prepareSearch2', iterator, page, load, spin, 2);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Retrieving list of ' + obj + ' where name contains: ' + scope[iterator + 'SearchValue'] +
|
||||
' GET returned status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
scope.$emit('prepareSearch2', iterator, page, load, spin, 2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope.$emit('prepareSearch2', iterator, page, load, spin, 1);
|
||||
}
|
||||
});
|
||||
|
||||
if (scope.removePrepareSearch2) {
|
||||
scope.removePrepareSearch2();
|
||||
}
|
||||
scope.removePrepareSearch2 = scope.$on('prepareSearch2', function(e, iterator, page, load, spin, startingWidget) {
|
||||
// Continue building the search by examining the remaining search widgets. If we're looking at activity_stream,
|
||||
// there's more than one.
|
||||
for (var i=startingWidget; i <= 3; i++) {
|
||||
var modifier = (i == 1) ? '' : i;
|
||||
scope[iterator + 'HoldInput' + modifier] = true;
|
||||
if ( $('#search-widget-container' + modifier) ) {
|
||||
// if the search widget exists, add its parameters to the query
|
||||
if ( (!scope[iterator + 'SelectShow' + modifier] && !Empty(scope[iterator + 'SearchValue' + modifier])) ||
|
||||
(scope[iterator + 'SelectShow' + modifier] && scope[iterator + 'SearchSelectValue' + modifier]) ||
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'gtzero') ) {
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchField) {
|
||||
scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField' + modifier]].searchField + '__';
|
||||
}
|
||||
else if (list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel) {
|
||||
// handle fields whose source is a related model e.g. inventories.organization
|
||||
scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel + '__' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].sourceField + '__';
|
||||
}
|
||||
else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue' + modifier].value == '' ||
|
||||
scope[iterator + 'SearchSelectValue' + modifier].value == null) ) {
|
||||
scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField' + modifier];
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField' + modifier] + '__';
|
||||
}
|
||||
|
||||
if ( list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'int' ||
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'boolean' ) ) {
|
||||
scope[iterator + 'SearchParams'] += 'int=';
|
||||
}
|
||||
else if ( list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'gtzero' ) {
|
||||
scope[iterator + 'SearchParams'] += 'gt=0';
|
||||
}
|
||||
else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue' + modifier].value == '' ||
|
||||
scope[iterator + 'SearchSelectValue' + modifier].value == null) ) {
|
||||
scope[iterator + 'SearchParams'] += 'iexact=';
|
||||
}
|
||||
else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'or')) ) {
|
||||
scope[iterator + 'SearchParams'] = ''; //start over
|
||||
var val = scope[iterator + 'SearchValue' + modifier];
|
||||
for (var k=0; k < list.fields[scope[iterator + 'SearchField' + modifier]].searchFields.length; k++) {
|
||||
scope[iterator + 'SearchParams'] += '&or__' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchFields[k] +
|
||||
'__icontains=' + escape(val);
|
||||
}
|
||||
scope[iterator + 'SearchParams'].replace(/^\&/,'');
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType' + modifier] + '=';
|
||||
}
|
||||
|
||||
if ( list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'boolean'
|
||||
|| list.fields[scope[iterator + 'SearchField' + modifier]].searchType == 'select') ) {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchSelectValue' + modifier].value;
|
||||
}
|
||||
else {
|
||||
if ( (!list.fields[scope[iterator + 'SearchField' + modifier]].searchType) ||
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType !== 'or') ) {
|
||||
scope[iterator + 'SearchParams'] += escape(scope[iterator + 'SearchValue' + modifier]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (iterator == 'inventory' && scope.inventoryFailureFilter) ||
|
||||
(iterator == 'host' && scope.hostFailureFilter) ) {
|
||||
//Things that bypass the search widget. Should go back and add a second widget possibly on
|
||||
//inventory pages and eliminate this
|
||||
scope[iterator + 'SearchParams'] += '&has_active_failures=true';
|
||||
}
|
||||
|
||||
if (sort_order) {
|
||||
scope[iterator + 'SearchParams'] += (scope[iterator + 'SearchParams']) ? '&' : '';
|
||||
scope[iterator + 'SearchParams'] += 'order_by=' + escape(sort_order);
|
||||
}
|
||||
|
||||
scope.$emit('doSearch', iterator, page, load, spin);
|
||||
});
|
||||
|
||||
scope.startSearch = function(iterator) {
|
||||
//Called on each keydown event for seachValue field. Using a timer
|
||||
//to prevent executing a search until user is finished typing.
|
||||
if (scope.searchTimer) {
|
||||
$timeout.cancel(scope.searchTimer);
|
||||
}
|
||||
scope.searchTimer = $timeout(
|
||||
function() {
|
||||
scope.$emit('prepareSearch', iterator);
|
||||
}
|
||||
, 1000);
|
||||
}
|
||||
|
||||
scope.search = function(iterator, page, load, spin) {
|
||||
// Called to initiate a searh.
|
||||
// Page is optional. Added to accomodate back function on Job Events detail.
|
||||
// Spin optional -set to false if spin not desired.
|
||||
// Load optional -set to false if loading message not desired
|
||||
|
||||
scope[iterator + 'SearchSpin'] = (spin == undefined || spin == true) ? true : false;
|
||||
scope[iterator + 'Loading'] = (load == undefined || load == true) ? true : false;
|
||||
scope[iterator + 'SearchParms'] = '';
|
||||
var url = defaultUrl;
|
||||
|
||||
if ( (scope[iterator + 'SelectShow'] == false && scope[iterator + 'SearchValue'] != '' && scope[iterator + 'SearchValue'] != undefined) ||
|
||||
(scope[iterator + 'SelectShow'] && scope[iterator + 'SearchSelectValue']) ||
|
||||
(list.fields[scope[iterator + 'SearchField']].searchType && list.fields[scope[iterator + 'SearchField']].searchType == 'gtzero') ) {
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField']].searchField) {
|
||||
scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField']].searchField + '__';
|
||||
}
|
||||
else if (list.fields[scope[iterator + 'SearchField']].sourceModel) {
|
||||
// handle fields whose source is a related model e.g. inventories.organization
|
||||
scope[iterator + 'SearchParams'] = list.fields[scope[iterator + 'SearchField']].sourceModel + '__' +
|
||||
list.fields[scope[iterator + 'SearchField']].sourceField + '__';
|
||||
}
|
||||
else if ( (list.fields[scope[iterator + 'SearchField']].searchType == 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue'].value == '' ||
|
||||
scope[iterator + 'SearchSelectValue'].value == null) ) {
|
||||
scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField'];
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField'] + '__';
|
||||
}
|
||||
|
||||
if ( list.fields[scope[iterator + 'SearchField']].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField']].searchType == 'int' ||
|
||||
list.fields[scope[iterator + 'SearchField']].searchType == 'boolean' ) ) {
|
||||
scope[iterator + 'SearchParams'] += 'int=';
|
||||
}
|
||||
else if ( list.fields[scope[iterator + 'SearchField']].searchType &&
|
||||
list.fields[scope[iterator + 'SearchField']].searchType == 'gtzero' ) {
|
||||
scope[iterator + 'SearchParams'] += 'gt=0';
|
||||
}
|
||||
else if ( (list.fields[scope[iterator + 'SearchField']].searchType == 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue'].value == '' ||
|
||||
scope[iterator + 'SearchSelectValue'].value == null) ) {
|
||||
scope[iterator + 'SearchParams'] += 'iexact=';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType'] + '=';
|
||||
}
|
||||
|
||||
if ( list.fields[scope[iterator + 'SearchField']].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField']].searchType == 'boolean'
|
||||
|| list.fields[scope[iterator + 'SearchField']].searchType == 'select') ) {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchSelectValue'].value;
|
||||
}
|
||||
else {
|
||||
//if ( list.fields[scope[iterator + 'SearchField']].searchType == undefined ||
|
||||
// list.fields[scope[iterator + 'SearchField']].searchType == 'gtzero' ) {
|
||||
scope[iterator + 'SearchParams'] += escape(scope[iterator + 'SearchValue']);
|
||||
}
|
||||
scope[iterator + 'SearchParams'] += (sort_order) ? '&order_by=' + escape(sort_order) : '';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] = (sort_order) ? 'order_by=' + escape(sort_order) : "";
|
||||
}
|
||||
|
||||
if ( (iterator == 'inventory' && scope.inventoryFailureFilter) ||
|
||||
(iterator == 'host' && scope.hostFailureFilter) ) {
|
||||
scope[iterator + 'SearchParams'] += '&has_active_failures=true';
|
||||
}
|
||||
|
||||
scope[iterator + 'Page'] = (page) ? parseInt(page) - 1 : 0;
|
||||
if (/\/$/.test(url)) {
|
||||
url += '?' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
else {
|
||||
url += '&' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
url = url.replace(/\&\&/,'&');
|
||||
url += (scope[iterator + 'PageSize']) ? '&page_size=' + scope[iterator + 'PageSize'] : "";
|
||||
if (page) {
|
||||
url += '&page=' + page;
|
||||
}
|
||||
if (scope[iterator + 'ExtraParms']) {
|
||||
url += scope[iterator + 'ExtraParms'];
|
||||
}
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: url });
|
||||
scope.$emit('prepareSearch', iterator, page, load, spin);
|
||||
}
|
||||
|
||||
|
||||
scope.sort = function(fld) {
|
||||
// reset sort icons back to 'icon-sort' on all columns
|
||||
// except the one clicked
|
||||
|
||||
@ -35,6 +35,15 @@ angular.module('OrganizationListDefinition', [])
|
||||
ngClick: 'addOrganization()',
|
||||
"class": 'btn-success btn-xs',
|
||||
awToolTip: 'Create a new organization'
|
||||
},
|
||||
stream: {
|
||||
'class': "btn-primary btn-xs activity-btn",
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
dataPlacement: "top",
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'all',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -17,22 +17,102 @@ angular.module('StreamListDefinition', [])
|
||||
index: false,
|
||||
hover: true,
|
||||
"class": "table-condensed",
|
||||
searchWidgetLabel: 'Object',
|
||||
searchWidgetLabel2: 'Modified by',
|
||||
|
||||
fields: {
|
||||
event_time: {
|
||||
timestamp: {
|
||||
label: 'Event Time',
|
||||
key: true,
|
||||
label: 'When'
|
||||
desc: true,
|
||||
noLink: true,
|
||||
searchable: false
|
||||
},
|
||||
user: {
|
||||
label: 'Who',
|
||||
label: 'User',
|
||||
ngBindHtml: 'activity.user',
|
||||
sourceModel: 'user',
|
||||
sourceField: 'username'
|
||||
sourceField: 'username',
|
||||
awToolTip: "\{\{ userToolTip \}\}",
|
||||
dataPlacement: 'top',
|
||||
searchPlaceholder: 'Username',
|
||||
searchWidget: 2
|
||||
},
|
||||
operation: {
|
||||
label: 'Operation'
|
||||
objects: {
|
||||
label: 'Objects',
|
||||
ngBindHtml: 'activity.objects',
|
||||
nosort: true,
|
||||
searchable: false
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
label: 'Description',
|
||||
ngBindHtml: 'activity.description',
|
||||
nosort: true,
|
||||
searchable: false
|
||||
},
|
||||
system_event: {
|
||||
label: 'System',
|
||||
searchOnly: true,
|
||||
searchType: 'isnull',
|
||||
sourceModel: 'user',
|
||||
sourceField: 'username',
|
||||
searchWidget: 2
|
||||
},
|
||||
// The following fields exist to forces loading each type of object into the search
|
||||
// dropdown
|
||||
all_objects: {
|
||||
label: 'All',
|
||||
searchOnly: true,
|
||||
searchObject: 'all',
|
||||
searchPlaceholder: ' '
|
||||
},
|
||||
credential_search: {
|
||||
label: 'Credential',
|
||||
searchOnly: true,
|
||||
searchObject: 'credentials',
|
||||
searchPlaceholder: 'Credential name'
|
||||
},
|
||||
group_search: {
|
||||
label: 'Group',
|
||||
searchOnly: true,
|
||||
searchObject: 'groups',
|
||||
searchPlaceholder: 'Group name'
|
||||
},
|
||||
host_search: {
|
||||
label: 'Host',
|
||||
searchOnly: true,
|
||||
searchObject: 'hosts',
|
||||
searchPlaceholder: 'Host name'
|
||||
},
|
||||
inventory_search: {
|
||||
label: 'Inventory',
|
||||
searchOnly: true,
|
||||
searchObject: 'inventories',
|
||||
searchPlaceholder: 'Inventory name'
|
||||
},
|
||||
job_template_search: {
|
||||
label: 'Job Template',
|
||||
searchOnly: true,
|
||||
searchObject: 'job_templates',
|
||||
searchPlaceholder: 'Job template name'
|
||||
},
|
||||
organization_search: {
|
||||
label: 'Organization',
|
||||
searchOnly: true,
|
||||
searchObject: 'organizations',
|
||||
searchPlaceholder: 'Organization name'
|
||||
},
|
||||
project_search: {
|
||||
label: 'Project',
|
||||
searchOnly: true,
|
||||
searchObject: 'projects',
|
||||
searchPlaceholder: 'Project name'
|
||||
},
|
||||
user_search: {
|
||||
label: 'User',
|
||||
searchOnly: true,
|
||||
searchObject: 'users',
|
||||
searchPlaceholder: 'Username'
|
||||
}
|
||||
},
|
||||
|
||||
@ -58,5 +138,14 @@ angular.module('StreamListDefinition', [])
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'View',
|
||||
ngClick: "showDetail(\{\{ activity.id \}\})",
|
||||
icon: 'icon-zoom-in',
|
||||
"class": 'btn-default btn-xs',
|
||||
awToolTip: 'View event details',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -27,7 +27,7 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
|
||||
|
||||
// Try not to overlap footer. Because stream is positioned absolute, the parent
|
||||
// doesn't resize correctly when stream is loaded.
|
||||
$('#tab-content-container').css({ 'min-height': stream.height() });
|
||||
$('#tab-content-container').css({ 'min-height': stream.height() + 50 });
|
||||
|
||||
// Slide in stream
|
||||
stream.show('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });
|
||||
@ -35,9 +35,10 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('HideStream', [ 'ClearScope', function(ClearScope) {
|
||||
.factory('HideStream', [ function() {
|
||||
return function() {
|
||||
// Remove the stream widget
|
||||
|
||||
var stream = $('#stream-container');
|
||||
stream.hide('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });
|
||||
|
||||
@ -54,15 +55,140 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('FixUrl', [ function() {
|
||||
return function(u) {
|
||||
return u.replace(/\/api\/v1\//,'/#/');
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('BuildUrl', [ function() {
|
||||
return function(obj) {
|
||||
var url = '/#/';
|
||||
switch(obj.base) {
|
||||
case 'group':
|
||||
case 'host':
|
||||
url += 'home/' + obj.base + 's/?name=' + obj.name;
|
||||
break;
|
||||
case 'inventory':
|
||||
url += 'inventories/' + obj.id;
|
||||
break;
|
||||
default:
|
||||
url += obj.base + 's/' + obj.id;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('BuildDescription', ['FixUrl', 'BuildUrl', function(FixUrl, BuildUrl) {
|
||||
return function(activity) {
|
||||
var descr = '';
|
||||
if (activity.summary_fields.user) {
|
||||
// this is a user transaction
|
||||
var usr = FixUrl(activity.related.user);
|
||||
descr += 'User <a href=\"' + usr + '\">' + activity.summary_fields.user.username + '</a> ';
|
||||
}
|
||||
else {
|
||||
descr += 'System ';
|
||||
}
|
||||
descr += activity.operation;
|
||||
descr += (/e$/.test(activity.operation)) ? 'd ' : 'ed ';
|
||||
if (activity.summary_fields.object2) {
|
||||
descr += activity.summary_fields.object2.base + ' <a href=\"' + BuildUrl(activity.summary_fields.object2) + '\">'
|
||||
+ activity.summary_fields.object2.name + '</a>' + [ (activity.operation == 'disassociate') ? ' from ' : ' to '];
|
||||
}
|
||||
if (activity.summary_fields.object1) {
|
||||
descr += activity.summary_fields.object1.base + ' <a href=\"' + BuildUrl(activity.summary_fields.object1) + '\">'
|
||||
+ activity.summary_fields.object1.name + '</a>';
|
||||
}
|
||||
return descr;
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('ShowDetail', ['Rest', 'Alert', 'GenerateForm', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'ActivityDetailForm',
|
||||
function(Rest, Alert, GenerateForm, ProcessErrors, GetBasePath, FormatDate, ActivityDetailForm) {
|
||||
return function(activity_id) {
|
||||
|
||||
var generator = GenerateForm;
|
||||
var form = ActivityDetailForm;
|
||||
var scope;
|
||||
|
||||
var url = GetBasePath('activity_stream') + activity_id + '/';
|
||||
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
// load up the form
|
||||
var results = data;
|
||||
|
||||
$('#form-modal').on('show.bs.modal', function (e) {
|
||||
$('#form-modal-body').css({
|
||||
width:'auto', //probably not needed
|
||||
height:'auto', //probably not needed
|
||||
'max-height':'100%'
|
||||
});
|
||||
});
|
||||
|
||||
//var n = results['changes'].match(/\n/g);
|
||||
//var rows = (n) ? n.length : 1;
|
||||
//rows = (rows < 1) ? 3 : 10;
|
||||
form.fields['changes'].rows = 10;
|
||||
scope = generator.inject(form, { mode: 'edit', modal: true, related: false});
|
||||
generator.reset();
|
||||
for (var fld in form.fields) {
|
||||
if (results[fld]) {
|
||||
if (fld == 'timestamp') {
|
||||
scope[fld] = FormatDate(new Date(results[fld]));
|
||||
}
|
||||
else {
|
||||
scope[fld] = results[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (results.summary_fields.object1) {
|
||||
scope['object1_name'] = results.summary_fields.object1.name;
|
||||
}
|
||||
if (results.summary_fields.object2) {
|
||||
scope['object2_name'] = results.summary_fields.object2.name;
|
||||
}
|
||||
scope['changes'] = JSON.stringify(results['changes'], null, '\t');
|
||||
scope.formModalAction = function() {
|
||||
$('#form-modal').modal("hide");
|
||||
}
|
||||
scope.formModalActionLabel = 'OK';
|
||||
scope.formModalCancelShow = false;
|
||||
scope.formModalInfo = false;
|
||||
//scope.formModalHeader = results.summary_fields.project.name + '<span class="subtitle"> - SCM Status</span>';
|
||||
$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
|
||||
$('#form-modal').addClass('skinny-modal');
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
$('#form-modal').modal("hide");
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to retrieve activity: ' + activity_id + '. GET status: ' + status });
|
||||
});
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('Stream', ['$rootScope', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit',
|
||||
'PaginateInit', 'GenerateList', 'FormatDate', 'ShowStream', 'HideStream',
|
||||
'PaginateInit', 'GenerateList', 'FormatDate', 'ShowStream', 'HideStream', 'BuildDescription', 'FixUrl', 'BuildUrl',
|
||||
'ShowDetail',
|
||||
function($rootScope, $location, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList,
|
||||
FormatDate, ShowStream, HideStream) {
|
||||
FormatDate, ShowStream, HideStream, BuildDescription, FixUrl, BuildUrl, ShowDetail) {
|
||||
return function(params) {
|
||||
|
||||
var list = StreamList;
|
||||
var defaultUrl = $basePath + 'html/event_log.html/';
|
||||
var defaultUrl = GetBasePath('activity_stream');
|
||||
var view = GenerateList;
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
|
||||
if (base !== 'home') {
|
||||
var type = (base == 'inventories') ? 'inventory' : base.replace(/s$/,'');
|
||||
defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
|
||||
}
|
||||
|
||||
// Push the current page onto browser histor. If user clicks back button, restore current page without
|
||||
// stream widget
|
||||
@ -70,23 +196,29 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
|
||||
|
||||
// Add a container for the stream widget
|
||||
$('#tab-content-container').append('<div id="stream-container"><div id=\"stream-content\"></div></div><!-- Stream widget -->');
|
||||
|
||||
ShowStream();
|
||||
|
||||
// Generate the list
|
||||
var scope = view.inject(list, {
|
||||
mode: 'edit',
|
||||
id: 'stream-content',
|
||||
breadCrumbs: true,
|
||||
searchSize: 'col-lg-4'
|
||||
searchSize: 'col-lg-3',
|
||||
secondWidget: true
|
||||
});
|
||||
|
||||
scope.closeStream = function() {
|
||||
HideStream();
|
||||
}
|
||||
HideStream();
|
||||
}
|
||||
|
||||
scope.refreshStream = function() {
|
||||
scope['activities'].splice(10,10);
|
||||
//scope.search(list.iterator);
|
||||
}
|
||||
scope.search(list.iterator);
|
||||
}
|
||||
|
||||
scope.showDetail = function(id) {
|
||||
ShowDetail(id);
|
||||
}
|
||||
|
||||
if (scope.removePostRefresh) {
|
||||
scope.removePostRefresh();
|
||||
@ -94,12 +226,41 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
|
||||
scope.removePostRefresh = scope.$on('PostRefresh', function() {
|
||||
for (var i=0; i < scope['activities'].length; i++) {
|
||||
// Convert event_time date to local time zone
|
||||
cDate = new Date(scope['activities'][i].event_time);
|
||||
scope['activities'][i].event_time = FormatDate(cDate);
|
||||
cDate = new Date(scope['activities'][i].timestamp);
|
||||
scope['activities'][i].timestamp = FormatDate(cDate);
|
||||
|
||||
// Display username
|
||||
scope['activities'][i].user = scope.activities[i].summary_fields.user.username;
|
||||
scope['activities'][i].user = (scope['activities'][i].summary_fields.user) ? scope['activities'][i].summary_fields.user.username :
|
||||
'system';
|
||||
if (scope['activities'][i].user !== 'system') {
|
||||
// turn user into a link when not 'system'
|
||||
scope['activities'][i].user = "<a href=\"" + FixUrl(scope['activities'][i].related.user) + "\">" +
|
||||
scope['activities'][i].user + "</a>";
|
||||
}
|
||||
|
||||
// Objects
|
||||
var href;
|
||||
var deleted = /^\_delete/;
|
||||
if (scope['activities'][i].summary_fields.object1) {
|
||||
if ( !deleted.test(scope['activities'][i].summary_fields.object1.name) ) {
|
||||
href = BuildUrl(scope['activities'][i].summary_fields.object1);
|
||||
scope['activities'][i].objects = "<a href=\"" + href + "\">" + scope['activities'][i].summary_fields.object1.name + "</a>";
|
||||
}
|
||||
else {
|
||||
scope['activities'][i].objects = scope['activities'][i].summary_fields.object1.name;
|
||||
}
|
||||
}
|
||||
if (scope['activities'][i].summary_fields.object2) {
|
||||
if ( !deleted.test(scope['activities'][i].summary_fields.object2.name) ) {
|
||||
href = BuildUrl(scope['activities'][i].summary_fields.object2);
|
||||
scope['activities'][i].objects += ", <a href=\"" + href + "\">" + scope['activities'][i].summary_fields.object2.name + "</a>";
|
||||
}
|
||||
else {
|
||||
scope['activities'][i].objects += scope['activities'][i].summary_fields.object2.name;
|
||||
}
|
||||
}
|
||||
scope['activities'][i].description = BuildDescription(scope['activities'][i]);
|
||||
}
|
||||
ShowStream();
|
||||
});
|
||||
|
||||
// Initialize search and paginate pieces and load data
|
||||
@ -107,6 +268,15 @@ angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefiniti
|
||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||
scope.search(list.iterator);
|
||||
|
||||
/*
|
||||
scope.$watch(list.iterator + 'SearchField', function(newVal, oldVal) {
|
||||
console.log('newVal: ' + newVal);
|
||||
html += ""
|
||||
html += "<input id=\"search_attribute_input\" type=\"text\" ng-show=\"" + iterator + "ShowAttribute\" class=\"form-control ";
|
||||
html += "\" ng-model=\"" + iterator + "AttributeValue\" ng-change=\"search('" + iterator +
|
||||
"')\" aw-placeholder=\"" + iterator + "AttributePlaceholder\" type=\"text\">\n";
|
||||
});*/
|
||||
|
||||
}
|
||||
}]);
|
||||
|
||||
@ -151,6 +151,20 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Hos
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// awPlaceholder: Dynamic placeholder set to a scope variable you want watched.
|
||||
// Value will be place in field placeholder attribute.
|
||||
.directive('awPlaceholder', [ function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
$(elm).attr('placeholder', scope[attrs.awPlaceholder]);
|
||||
scope.$watch(attrs.awPlaceholder, function(newVal, oldVal) {
|
||||
$(elm).attr('placeholder',newVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
}])
|
||||
|
||||
// lookup Validate lookup value against API
|
||||
//
|
||||
|
||||
@ -340,6 +340,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
html += (field.ngClass) ? Attr(field, 'ngClass') : "";
|
||||
html += (options.mode == 'lookup' || options.mode == 'select') ? " ng-click=\"toggle_" + list.iterator +"({{ " + list.iterator + ".id }})\"" : "";
|
||||
html += (field.columnShow) ? Attr(field, 'columnShow') : "";
|
||||
html += (field.ngBindHtml) ? "ng-bind-html-unsafe=\"" + field.ngBindHtml + "\" " : "";
|
||||
html += ">\n";
|
||||
|
||||
// Add ngShow
|
||||
@ -359,7 +360,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
|
||||
// Start the Link
|
||||
if ( (field.key || field.link || field.linkTo || field.ngClick || field.ngHref) &&
|
||||
options['mode'] != 'lookup' && options['mode'] != 'select' && !field.noLink ) {
|
||||
options['mode'] != 'lookup' && options['mode'] != 'select' && !field.noLink && !field.ngBindHtml) {
|
||||
var cap=false;
|
||||
if (field.linkTo) {
|
||||
html += "<a href=\"" + field.linkTo + "\" ";
|
||||
@ -397,7 +398,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
}
|
||||
|
||||
// Add data binds
|
||||
if (field.showValue == undefined || field.showValue == true) {
|
||||
if (!field.ngBindHtml && (field.showValue == undefined || field.showValue == true)) {
|
||||
if (field.ngBind) {
|
||||
html += "{{ " + field.ngBind + " }}";
|
||||
}
|
||||
@ -417,7 +418,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
|
||||
// close the link
|
||||
if ( (field.key || field.link || field.linkTo || field.ngClick || field.ngHref )
|
||||
&& options.mode != 'lookup' && options.mode != 'select' && !field.noLink ) {
|
||||
&& options.mode != 'lookup' && options.mode != 'select' && !field.noLink && !field.ngBindHtml ) {
|
||||
html += "</a>";
|
||||
}
|
||||
// close ngShow
|
||||
@ -476,20 +477,20 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
var iterator = params.iterator;
|
||||
var form = params.template;
|
||||
var useMini = params.mini;
|
||||
var label = (params.label) ? params.label : null;
|
||||
//var label = (params.label) ? params.label : null;
|
||||
var html= '';
|
||||
var secondWidget = params.secondWidget;
|
||||
|
||||
html += "<div class=\"row search-widget\">\n";
|
||||
html += "<div class=\"";
|
||||
html += (params.size) ? params.size : "col-lg-4 col-md-6 col-sm-11 col-xs-11";
|
||||
html += "\">\n";
|
||||
html += (label) ? "<label>" + label +"</label>" : "";
|
||||
html += "\" id=\"search-widget-container\">\n";
|
||||
html += (form.searchWidgetLabel) ? "<label style=\"display:block\">" + form.searchWidgetLabel +"</label>" : "";
|
||||
html += "<div class=\"input-group";
|
||||
html += (useMini) ? " input-group-sm" : " input-group-sm";
|
||||
html += "\">\n";
|
||||
html += "<div class=\"input-group-btn dropdown\">\n";
|
||||
|
||||
// Use standard button on mobile
|
||||
html += "<button type=\"button\" ";
|
||||
html += "id=\"search_field_ddown\" ";
|
||||
html += "class=\"btn ";
|
||||
@ -498,27 +499,22 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
html += "<span ng-bind=\"" + iterator + "SearchFieldLabel\"></span>\n";
|
||||
html += "<span class=\"caret\"></span>\n";
|
||||
html += "</button>\n";
|
||||
|
||||
// Use link and hover activation on desktop
|
||||
//html += "<a href=\"\" id=\"search_field_ddown\" class=\"btn btn-default visible-lg\">";
|
||||
//html += "<span ng-bind=\"" + iterator + "SearchFieldLabel\"></span>\n";
|
||||
//html += "<span class=\"caret\"></span>\n";
|
||||
//html += "</a>\n";
|
||||
|
||||
|
||||
html += "<ul class=\"dropdown-menu\" id=\"" + iterator + "SearchDropdown\">\n";
|
||||
for ( var fld in form.fields) {
|
||||
if (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true) {
|
||||
html += "<li><a href=\"\" ng-click=\"setSearchField('" + iterator + "','";
|
||||
html += fld + "','";
|
||||
if (form.fields[fld].searchLabel) {
|
||||
html += form.fields[fld].searchLabel + "')\">" +
|
||||
form.fields[fld].searchLabel + "</a></li>\n";
|
||||
}
|
||||
else {
|
||||
html += form.fields[fld].label.replace(/\<br\>/g,' ') + "')\">" +
|
||||
form.fields[fld].label.replace(/\<br\>/g,' ') + "</a></li>\n";
|
||||
}
|
||||
}
|
||||
if ( (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true)
|
||||
&& (form.fields[fld].searchWidget == undefined || form.fields[fld].searchWidget == 1) ) {
|
||||
html += "<li><a href=\"\" ng-click=\"setSearchField('" + iterator + "','";
|
||||
html += fld + "','";
|
||||
if (form.fields[fld].searchLabel) {
|
||||
html += form.fields[fld].searchLabel + "', 1)\">" +
|
||||
form.fields[fld].searchLabel + "</a></li>\n";
|
||||
}
|
||||
else {
|
||||
html += form.fields[fld].label.replace(/\<br\>/g,' ') + "')\">" +
|
||||
form.fields[fld].label.replace(/\<br\>/g,' ') + "</a></li>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
html += "</ul>\n";
|
||||
html += "</div><!-- input-group-btn -->\n";
|
||||
@ -528,37 +524,71 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
|
||||
html += "\"></select>\n";
|
||||
|
||||
html += "<input id=\"search_value_input\" type=\"text\" ng-hide=\"" + iterator + "SelectShow || " + iterator + "InputHide\" class=\"form-control ";
|
||||
html += "\" ng-model=\"" + iterator + "SearchValue\" ng-change=\"search('" + iterator +
|
||||
"')\" placeholder=\"Search\" type=\"text\" ng-disabled=\"" + iterator + "InputDisable\">\n";
|
||||
|
||||
/*
|
||||
html += "<div class=\"input-group-btn dropdown\">\n";
|
||||
html += "<button type=\"button\" ";
|
||||
html += "id=\"search_option_ddown\" ";
|
||||
html += "ng-hide=\"" + iterator + "SelectShow || " + iterator + "HideSearchType || " + iterator + "InputHide\" class=\"btn ";
|
||||
html += "dropdown-toggle\" data-toggle=\"dropdown\">\n";
|
||||
html += "<span ng-bind=\"" + iterator + "SearchTypeLabel\"></span>\n";
|
||||
html += "<span class=\"caret\"></span>\n";
|
||||
html += "</button>\n";
|
||||
html += "<ul class=\"dropdown-menu pull-right\">\n";
|
||||
html += "<li><a href=\"\" ng-click=\"setSearchType('" + iterator + "','iexact','Exact Match')\">Exact Match</a></li>\n";
|
||||
html += "<li><a href=\"\" ng-click=\"setSearchType('" + iterator + "','icontains','Contains')\">Contains</a></li>\n";
|
||||
html += "</ul>\n";
|
||||
html += "</div><!-- input-group-btn -->\n";
|
||||
*/
|
||||
|
||||
html += "\" ng-model=\"" + iterator + "SearchValue\" ng-keydown=\"startSearch('" + iterator + "')\" " +
|
||||
"aw-placeholder=\"" + iterator + "SearchPlaceholder\" type=\"text\" ng-disabled=\"" + iterator + "InputDisable || " + iterator +
|
||||
"HoldInput\">\n";
|
||||
|
||||
// Reset button
|
||||
html += "<div class=\"input-group-btn\">\n";
|
||||
html += "<button type=\"button\" class=\"btn btn-default btn-small\" ng-click=\"resetSearch('" + iterator + "')\" " +
|
||||
html += "<button type=\"button\" class=\"btn btn-default btn-small\" ng-click=\"resetSearch('" + iterator + "', 1)\" " +
|
||||
"aw-tool-tip=\"Reset filter\" data-placement=\"top\" " +
|
||||
"><i class=\"icon-undo\"></i></button>\n";
|
||||
html += "</div><!-- input-group-btn -->\n";
|
||||
html += "</div><!-- input-group -->\n";
|
||||
|
||||
html += "</div><!-- col-lg-x -->\n";
|
||||
|
||||
// Search Widget 2
|
||||
// Used on activity stream. Set 'searchWidget2: true' on fields to be included.
|
||||
if (secondWidget) {
|
||||
html += "<div class=\"col-lg-3\" id=\"search-widget-container2\">\n";
|
||||
html += (form.searchWidgetLabel2) ? "<label style=\"display:block\">" + form.searchWidgetLabel2 +"</label>" : "";
|
||||
html += "<div class=\"input-group input-group-sm\">\n";
|
||||
html += "<div class=\"input-group-btn dropdown2\">\n";
|
||||
html += "<button type=\"button\" ";
|
||||
html += "id=\"search_field_ddown2\" ";
|
||||
html += "class=\"btn dropdown-toggle\" data-toggle=\"dropdown\">\n";
|
||||
html += "<span ng-bind=\"" + iterator + "SearchFieldLabel2\"></span>\n";
|
||||
html += "<span class=\"caret\"></span>\n";
|
||||
html += "</button>\n";
|
||||
|
||||
html += "<ul class=\"dropdown-menu\" id=\"" + iterator + "SearchDropdown2\">\n";
|
||||
for ( var fld in form.fields) {
|
||||
if ( (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true)
|
||||
&& form.fields[fld].searchWidget == 2 ) {
|
||||
html += "<li><a href=\"\" ng-click=\"setSearchField('" + iterator + "','";
|
||||
html += fld + "','";
|
||||
if (form.fields[fld].searchLabel) {
|
||||
html += form.fields[fld].searchLabel + "', 2)\">" +
|
||||
form.fields[fld].searchLabel + "</a></li>\n";
|
||||
}
|
||||
else {
|
||||
html += form.fields[fld].label.replace(/\<br\>/g,' ') + "', 2)\">" +
|
||||
form.fields[fld].label.replace(/\<br\>/g,' ') + "</a></li>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
html += "</ul>\n";
|
||||
html += "</div><!-- input-group-btn -->\n";
|
||||
|
||||
html += "<input id=\"search_value_input\" type=\"text\" ng-hide=\"" + iterator + "SelectShow2 || " + iterator + "InputHide2\" class=\"form-control ";
|
||||
html += "\" ng-model=\"" + iterator + "SearchValue2\" ng-keydown=\"startSearch('" + iterator + "')\" " +
|
||||
"aw-placeholder=\"" + iterator + "SearchPlaceholder2\" type=\"text\" ng-disabled=\"" + iterator + "InputDisable2 || " + iterator +
|
||||
"HoldInput2\">\n";
|
||||
|
||||
// Reset button
|
||||
html += "<div class=\"input-group-btn\">\n";
|
||||
html += "<button type=\"button\" class=\"btn btn-default btn-small\" ng-click=\"resetSearch('" + iterator + "', 2)\" " +
|
||||
"aw-tool-tip=\"Reset filter\" data-placement=\"top\" " +
|
||||
"><i class=\"icon-undo\"></i></button>\n";
|
||||
html += "</div><!-- input-group-btn -->\n";
|
||||
html += "</div><!-- input-group -->\n";
|
||||
html += "</div><!-- col-lg-x -->\n";
|
||||
}
|
||||
|
||||
// Spinner
|
||||
html += "<div class=\"col-lg-1 col-md-1 col-sm-1 col-xs-1\"><i class=\"icon-spinner icon-spin icon-large\" ng-show=\"" + iterator +
|
||||
"SearchSpin == true\"></i></div>\n";
|
||||
|
||||
return html;
|
||||
|
||||
}
|
||||
|
||||
@ -194,7 +194,8 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
*/
|
||||
|
||||
if (options.searchSize) {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize });
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize,
|
||||
secondWidget: options.secondWidget });
|
||||
}
|
||||
else if (options.mode == 'summary') {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-6' });
|
||||
@ -214,6 +215,7 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
if (options.searchSize) {
|
||||
// User supplied searchSize, calc the remaining
|
||||
var size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g,''));
|
||||
size += (options.secondWidget) ? 3 : 0;
|
||||
html += 'col-lg-' + (11 - size);
|
||||
}
|
||||
else if (options.mode == 'summary') {
|
||||
|
||||
@ -75,6 +75,7 @@
|
||||
<script src="{{ STATIC_URL }}js/forms/License.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/HostGroups.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/InventoryStatus.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/ActivityDetail.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/lists/Users.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/lists/Organizations.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/lists/Admins.js"></script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user