diff --git a/backend/src/appenlight/static/js/appenlight.js b/backend/src/appenlight/static/js/appenlight.js index 3b02f52..a67aaf1 100644 --- a/backend/src/appenlight/static/js/appenlight.js +++ b/backend/src/appenlight/static/js/appenlight.js @@ -2547,7 +2547,7 @@ function decodeEncodedJSON (input){ delete doc; return val; }catch(exc){ - + console.error('decodeEncodedJSON:' + exc + ' input:' + input); delete doc; } } @@ -2600,16 +2600,16 @@ function timeSpanToStartDate(timeSpan){ /* Sets server validation messages on form using angular machinery + * custom key holding actual error messages */ function setServerValidation(form, errors){ - + console.log('form', form); if (typeof form.ae_validation === 'undefined'){ form.ae_validation = {}; - + console.log('create ae_validation key'); } for (var key in form.ae_validation){ form.ae_validation[key] = []; - + console.log('clear key:', key); } - + console.log('errors:',errors); for (var key in form){ if (key[0] !== '$' && key !== 'ae_validation'){ @@ -2684,6 +2684,10 @@ angular.module('appenlight.components', [ 'appenlight.components.eventBrowserView', 'appenlight.components.userProfileView', 'appenlight.components.userIdentitiesView', + 'appenlight.components.userPasswordView', + 'appenlight.components.userAuthTokensView', + 'appenlight.components.userAlertChannelsListView', + 'appenlight.components.userAlertChannelsEmailNewView', 'appenlight.components.settingsView' ]); angular.module('appenlight.directives', [ @@ -2716,7 +2720,7 @@ var pluginsToLoad = _.map(decodeEncodedJSON(window.AE.plugins), function(item){ return item.config.angular_module }); - +console.log(pluginsToLoad); angular.module('appenlight.plugins', pluginsToLoad); var app = angular.module('appenlight', [ @@ -2812,7 +2816,7 @@ function kickstartAE(initialUserData) { AeConfig.urls.otherRoutes.lostPassword, AeConfig.urls.otherRoutes.lostPasswordGenerate ]; - + console.log('$transitions.onBefore', path, $transition$.to().name, $state); _.each(openViews, function (url) { var url = '/' + url.split('/').slice(3).join('/'); if (url === path) { @@ -2821,7 +2825,7 @@ function kickstartAE(initialUserData) { }); if (stateHolder.AeUser.id === null && !isGuestState && !isOpenView) { if (window.location.toString().indexOf(AeConfig.urls.otherRoutes.register) === -1) { - + console.log('redirect to register'); var newLocation = AeConfig.urls.otherRoutes.register + '?came_from=' + encodeURIComponent(window.location); // fix infinite digest here $rootScope.$on('$locationChangeStart', @@ -3503,6 +3507,194 @@ function kickstartAE(initialUserData) { ); + $templateCache.put('components/views/user-alert-channel-email-new-view/user-alert-channel-email-new-view.html', + "\n" + + "\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "

Adding email alert channel - after you authorize your email in the system we can send alerts directly to this mailbox.

\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + ); + + + $templateCache.put('components/views/user-alert-channels-list-view/user-alert-channels-list-view.html', + "\n" + + "\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "

Report alert rules

\n" + + "

\n" + + " Add top-level rule\n" + + "

\n" + + "\n" + + " \n" + + "\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "

Alert channels

\n" + + "\n" + + "

Here you can configure your alert channels.

\n" + + "\n" + + "

An alert channel serves as means of delivery of notifications about important events that happen in your applications.

\n" + + "\n" + + "
You can add more integrations that support different alert channels via application management panel.
\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
{{ channel.channel_visible_value }}\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Alerts\n" + + " \n" + + " \n" + + " Daily digests\n" + + " \n" + + "\n" + + " \n" + + " Remove\n" + + "
    \n" + + "
  • No
  • \n" + + "
  • Yes
  • \n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + ); + + + $templateCache.put('components/views/user-auth-tokens-view/user-auth-tokens-view.html', + "\n" + + "\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "\n" + + "
You can use those tokens to authenticate yourself when performing various API calls
\n" + + "\n" + + "
\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "\n" + + "\n" + + "
\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
Your current tokens
DescriptionCreatedExpires

{{token.description}}

\n" + + "
{{token.token| limitTo:token.limit}}...
\n" + + "
{{token.creation_date | isoToRelativeTime}}{{token.expires | isoToRelativeTime}}\n" + + " Never\n" + + " \n" + + " \n" + + "
    \n" + + "
  • No
  • \n" + + "
  • Yes
  • \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + ); + + $templateCache.put('components/views/user-identities-view/user-identities-view.html', "\n" + "\n" + @@ -3555,6 +3747,60 @@ function kickstartAE(initialUserData) { ); + $templateCache.put('components/views/user-password-view/user-password-view.html', + "\n" + + "\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + ); + + $templateCache.put('components/views/user-profile-view/user-profile-view.html', "\n" + "\n" + @@ -6854,274 +7100,22 @@ function kickstartAE(initialUserData) { ); - $templateCache.put('templates/user/alert_channels_email.html', - "\n" + - "\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - "
\n" + - "

Adding email alert channel - after you authorize your email in the system we can send alerts directly to this mailbox.

\n" + - "
\n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - " \n" + - "
\n" + - "
\n" + - "
\n" + - " \n" + - "
\n" + - " \n" + - "
\n" + - "
\n" + - "
\n" + - "
\n" + - "
\n" + - "
\n" + $templateCache.put('templates/user/breadcrumbs.html', + "
    \n" + + "
  1. Settings
  2. \n" + + "
  3. User Profile
  4. \n" + + "
  5. Password
  6. \n" + + "
  7. Identities
  8. \n" + + "
  9. Auth Tokens
  10. \n" + + "
\n" + + "
    \n" + + "
  1. Notifications
  2. \n" + + "
  3. Alert Channels
  4. \n" + + "
  5. Create email channel
  6. \n" + + "
\n" ); - - $templateCache.put('templates/user/alert_channels_list.html', - "\n" + - "\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - "
\n" + - "

Report alert rules

\n" + - "

\n" + - " Add top-level rule\n" + - "

\n" + - "\n" + - " \n" + - "\n" + - "
\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - "

Alert channels

\n" + - "\n" + - "

Here you can configure your alert channels.

\n" + - "\n" + - "

An alert channel serves as means of delivery of notifications about important events that happen in your applications.

\n" + - "\n" + - "
You can add more integrations that support different alert channels via application management panel.
\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "
{{ channel.channel_visible_value }}\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " Alerts\n" + - " \n" + - " \n" + - " Daily digests\n" + - " \n" + - "\n" + - " \n" + - " Remove\n" + - "
    \n" + - "
  • No
  • \n" + - "
  • Yes
  • \n" + - "
\n" + - "
\n" + - "\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - "\n" + - "
\n" - ); - - - $templateCache.put('templates/user/alert_channels.html', - "" - ); - - - $templateCache.put('templates/user/auth_tokens.html', - "\n" + - "\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - "\n" + - "
\n" + - "\n" + - "
You can use those tokens to authenticate yourself when performing various API calls
\n" + - "\n" + - "
\n" + - "\n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - "
\n" + - "\n" + - "
\n" + - "\n" + - "\n" + - "
\n" + - "\n" + - "
\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "
Your current tokens
DescriptionCreatedExpires

{{token.description}}

\n" + - "
{{token.token| limitTo:token.limit}}...
\n" + - "
{{token.creation_date | isoToRelativeTime}}{{token.expires | isoToRelativeTime}}\n" + - " Never\n" + - " \n" + - " \n" + - "
    \n" + - "
  • No
  • \n" + - "
  • Yes
  • \n" + - "
\n" + - "
\n" + - "
\n" + - "
\n" + - "\n" + - "
\n" - ); - - - $templateCache.put('templates/user/breadcrumbs.html', - "
    \n" + - "
  1. Settings
  2. \n" + - "
  3. User Profile
  4. \n" + - "
  5. Password
  6. \n" + - "
  7. Identities
  8. \n" + - "
\n" + - "\n" + - "
    \n" + - "
  1. Notifications
  2. \n" + - "
  3. Alert Channels
  4. \n" + - "
  5. Create email channel
  6. \n" + - "
\n" - ); - - - $templateCache.put('templates/user/index.html', - "" - ); - - - $templateCache.put('templates/user/profile_password.html', - "\n" + - "\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - " \n" + - "
\n" + - "
\n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - " \n" + - "
\n" + - "
\n" + - "
\n" + - " \n" + - " \n" + - "
\n" + - " \n" + - "
\n" + - "
\n" + - "
\n" + - " \n" + - "
\n" + - " \n" + - "
\n" + - "
\n" + - "
\n" + - "\n" + - "
\n" + - "
\n" + - "
\n" - ); - -}]); +}]); ;// # Copyright (C) 2010-2016 RhodeCode GmbH // # @@ -7151,7 +7145,7 @@ angular.module('appenlight.components.appenlightApp', []) AppEnlightAppController.$inject = ['$scope','$state', 'stateHolder', 'AeConfig']; function AppEnlightAppController($scope, $state, stateHolder, AeConfig){ - + console.log('app start'); // to keep bw compatibility $scope.$state = $state; $scope.stateHolder = stateHolder; @@ -7247,7 +7241,7 @@ function AppEnlightHeaderController($state, stateHolder, AeConfig){ $state.go('uptime', {resource:event.resource_id, start_date:event.start_date}); } else{ - + console.log('other'); } } } @@ -7288,13 +7282,13 @@ function ChannelstreamController($rootScope, stateHolder, userSelfPropertyResour userSelfPropertyResource.get({key: 'websocket'}, function (data) { stateHolder.websocket = new ReconnectingWebSocket(this.config.ws_url + '/ws?conn_id=' + data.conn_id); stateHolder.websocket.onopen = function (event) { - + console.log('open'); }; stateHolder.websocket.onmessage = function (event) { var data = JSON.parse(event.data); $rootScope.$apply(function (scope) { _.each(data, function (message) { - + console.log('channelstream-message', message); if(typeof message.message.topic !== 'undefined'){ $rootScope.$emit( 'channelstream-message.'+message.message.topic, message); @@ -7306,11 +7300,11 @@ function ChannelstreamController($rootScope, stateHolder, userSelfPropertyResour }); }; stateHolder.websocket.onclose = function (event) { - + console.log('closed'); }; stateHolder.websocket.onerror = function (event) { - + console.log('error'); }; }.bind(this)); } @@ -7356,7 +7350,7 @@ function EventBrowserController(eventsNoIdResource, eventsResource) { vm.closeEvent = function (event) { - + console.log('closeEvent'); eventsResource.update({eventId: event.id}, {status: 0}, function (data) { event.status = 0; }); @@ -7778,7 +7772,7 @@ function IndexDashboardController($rootScope, $scope, $location, $cookies, $inte if (!vm.resource){ var cookieResource = $cookies.getObject('resource'); - + console.log('cookieResource', cookieResource); if (cookieResource) { vm.resource = cookieResource; @@ -8028,7 +8022,6 @@ function IndexDashboardController($rootScope, $scope, $location, $cookies, $inte if (stateHolder.AeUser.applications.length){ vm.show_dashboard = true; vm.determineStartState(); - vm.refreshData(); } } @@ -8296,7 +8289,7 @@ function LogsBrowserController($location, stateHolder, typeAheadTagHelper, logsN searchParams['view'] = 'fetch_series'; vm.isLoading.series = true; sectionViewResource.query(searchParams, function (data) { - + console.log('show node here'); vm.logEventsChartData = { json: data, xFormat: '%Y-%m-%dT%H:%M:%S', @@ -8356,9 +8349,10 @@ angular.module('appenlight.components.settingsView', []) controller: SettingsViewController }); -SettingsViewController.$inject = []; +SettingsViewController.$inject = ['$state']; -function SettingsViewController() { +function SettingsViewController($state) { + this.$state = $state; console.info('SettingsViewController'); } @@ -8381,43 +8375,35 @@ function SettingsViewController() { // # services, and proprietary license terms, please see // # https://rhodecode.com/licenses/ -angular.module('appenlight.components.userIdentitiesView', []) - .component('userIdentitiesView', { - templateUrl: 'components/views/user-identities-view/user-identities-view.html', - controller: UserIdentitiesController +angular.module('appenlight.components.userAlertChannelsEmailNewView', []) + .component('userAlertChannelsEmailNewView', { + templateUrl: 'components/views/user-alert-channel-email-new-view/user-alert-channel-email-new-view.html', + controller: AlertChannelsEmailController }); -UserIdentitiesController.$inject = ['userSelfPropertyResource', 'AeConfig']; +AlertChannelsEmailController.$inject = ['$state','userSelfPropertyResource']; -function UserIdentitiesController(userSelfPropertyResource, AeConfig) { - +function AlertChannelsEmailController($state, userSelfPropertyResource) { + console.debug('AlertChannelsEmailController'); var vm = this; - vm.AeConfig = AeConfig; - vm.loading = {identities: true}; + vm.$state = $state; + vm.loading = {email: false}; + vm.form = {}; - vm.identities = userSelfPropertyResource.query( - {key: 'external_identities'}, - function (data) { - vm.loading.identities = false; - + vm.createChannel = function () { + vm.loading.email = true; + console.log('createChannel'); + userSelfPropertyResource.save({key: 'alert_channels'}, vm.form, function () { + //vm.loading.email = false; + //setServerValidation(vm.channelForm); + //vm.form = {}; + $state.go('user.alert_channels.list'); + }, function (response) { + if (response.status == 422) { + setServerValidation(vm.channelForm, response.data); + } + vm.loading.email = false; }); - - vm.removeProvider = function (provider) { - - userSelfPropertyResource.delete( - { - key: 'external_identities', - provider: provider.provider, - id: provider.id - }, - function (status) { - if (status){ - vm.identities = _.filter(vm.identities, function (item) { - return item != provider - }); - } - - }); } } @@ -8440,39 +8426,122 @@ function UserIdentitiesController(userSelfPropertyResource, AeConfig) { // # services, and proprietary license terms, please see // # https://rhodecode.com/licenses/ -angular.module('appenlight.components.userProfileView', []) - .component('userProfileView', { - templateUrl: 'components/views/user-profile-view/user-profile-view.html', - controller: UserProfileViewController +angular.module('appenlight.components.userAlertChannelsListView', []) + .component('userAlertChannelsListView', { + templateUrl: 'components/views/user-alert-channels-list-view/user-alert-channels-list-view.html', + controller: userAlertChannelsListViewController }); -UserProfileViewController.$inject = ['userSelfResource']; +userAlertChannelsListViewController.$inject = ['$state','userSelfPropertyResource', 'applicationsNoIdResource']; -function UserProfileViewController(userSelfResource) { - +function userAlertChannelsListViewController($state, userSelfPropertyResource, applicationsNoIdResource) { + console.debug('AlertChannelsController'); var vm = this; - vm.loading = {profile: true}; - - vm.user = userSelfResource.get(null, function (data) { - vm.loading.profile = false; - - }); - - vm.updateProfile = function () { - vm.loading.profile = true; + vm.$state = $state; + vm.loading = {channels: true, applications: true, actions:true}; - - vm.user.$update(null, function () { - vm.loading.profile = false; - setServerValidation(vm.profileForm); - }, function (response) { - if (response.status == 422) { - setServerValidation(vm.profileForm, response.data); - } - vm.loading.profile = false; + vm.alertChannels = userSelfPropertyResource.query({key: 'alert_channels'}, + function (data) { + vm.loading.channels = false; }); - } -} + + vm.alertActions = userSelfPropertyResource.query({key: 'alert_actions'}, + function (data) { + vm.loading.actions = false; + }); + + vm.applications = applicationsNoIdResource.query({permission: 'view'}, + function (data) { + vm.loading.applications = false; + }); + + var allOps = { + 'eq': 'Equal', + 'ne': 'Not equal', + 'ge': 'Greater or equal', + 'gt': 'Greater than', + 'le': 'Lesser or equal', + 'lt': 'Lesser than', + 'startswith': 'Starts with', + 'endswith': 'Ends with', + 'contains': 'Contains' + }; + + var fieldOps = {}; + fieldOps['http_status'] = ['eq', 'ne', 'ge', 'le']; + fieldOps['group:priority'] = ['eq', 'ne', 'ge', 'le']; + fieldOps['duration'] = ['ge', 'le']; + fieldOps['url_domain'] = ['eq', 'ne', 'startswith', 'endswith', + 'contains']; + fieldOps['url_path'] = ['eq', 'ne', 'startswith', 'endswith', + 'contains']; + fieldOps['error'] = ['eq', 'ne', 'startswith', 'endswith', + 'contains']; + fieldOps['tags:server_name'] = ['eq', 'ne', 'startswith', 'endswith', + 'contains']; + fieldOps['group:occurences'] = ['eq', 'ne', 'ge', 'le']; + + var possibleFields = { + '__AND__': 'All met (composite rule)', + '__OR__': 'One met (composite rule)', + '__NOT__': 'Not met (composite rule)', + 'http_status': 'HTTP Status', + 'duration': 'Request duration', + 'group:priority': 'Group -> Priority', + 'url_domain': 'Domain', + 'url_path': 'URL Path', + 'error': 'Error', + 'tags:server_name': 'Tag -> Server name', + 'group:occurences': 'Group -> Occurences' + }; + + vm.ruleDefinitions = { + fieldOps: fieldOps, + allOps: allOps, + possibleFields: possibleFields + }; + + vm.addAction = function (channel) { + console.log('test'); + userSelfPropertyResource.save({key: 'alert_channels_rules'}, {}, function (data) { + vm.alertActions.push(data); + }, function (response) { + if (response.status == 422) { + console.log('scope', response); + } + }); + }; + + vm.updateChannel = function (channel, subKey) { + var params = { + key: 'alert_channels', + channel_name: channel['channel_name'], + channel_value: channel['channel_value'] + }; + var toUpdate = {}; + if (['daily_digest', 'send_alerts'].indexOf(subKey) !== -1) { + toUpdate[subKey] = !channel[subKey]; + } + userSelfPropertyResource.update(params, toUpdate, function (data) { + _.extend(channel, data); + }); + }; + + vm.removeChannel = function (channel) { + console.log(channel); + userSelfPropertyResource.delete({ + key: 'alert_channels', + channel_name: channel.channel_name, + channel_value: channel.channel_value + }, function () { + vm.alertChannels = _.filter(vm.alertChannels, function(item){ + return item != channel; + }); + }); + + } + +} ;// # Copyright (C) 2010-2016 RhodeCode GmbH // # @@ -8493,22 +8562,57 @@ function UserProfileViewController(userSelfResource) { // # services, and proprietary license terms, please see // # https://rhodecode.com/licenses/ -var aeconfig = angular.module('appenlight.config', []); -aeconfig.factory('AeConfig', function () { - var obj = {}; - obj.flashMessages = decodeEncodedJSON(window.AE.flash_messages); - obj.timeOptions = decodeEncodedJSON(window.AE.timeOptions); - obj.plugins = decodeEncodedJSON(window.AE.plugins); - obj.topNav = decodeEncodedJSON(window.AE.topNav); - obj.ws_url = window.AE.ws_url; - obj.urls = window.AE.urls; - // set keys on values because we wont be able to retrieve them everywhere - for (var key in obj.timeOptions) { - obj.timeOptions[key]['key'] = key; +angular.module('appenlight.components.userAuthTokensView', []) + .component('userAuthTokensView', { + templateUrl: 'components/views/user-auth-tokens-view/user-auth-tokens-view.html', + controller: userAuthTokensViewController + }); + +userAuthTokensViewController.$inject = ['$state', 'userSelfPropertyResource', 'AeConfig']; + +function userAuthTokensViewController($state, userSelfPropertyResource, AeConfig) { + console.debug('userAuthTokensViewController'); + var vm = this; + vm.$state = $state; + vm.loading = {tokens: true}; + + vm.expireOptions = AeConfig.timeOptions; + + vm.tokens = userSelfPropertyResource.query({key: 'auth_tokens'}, + function (data) { + vm.loading.tokens = false; + }); + + vm.addToken = function () { + vm.loading.tokens = true; + userSelfPropertyResource.save({key: 'auth_tokens'}, + vm.form, + function (data) { + vm.loading.tokens = false; + setServerValidation(vm.TokenForm); + vm.form = {}; + vm.tokens.push(data); + }, function (response) { + vm.loading.tokens = false; + if (response.status == 422) { + setServerValidation(vm.TokenForm, response.data); + } + }) + }; + + vm.removeToken = function (token) { + userSelfPropertyResource.delete({ + key: 'auth_tokens', + token: token.token + }, + function () { + var index = vm.tokens.indexOf(token); + if (index !== -1) { + vm.tokens.splice(index, 1); + } + }) } - console.info('config', obj); - return obj; -}); +} ;// # Copyright (C) 2010-2016 RhodeCode GmbH // # @@ -8529,22 +8633,46 @@ aeconfig.factory('AeConfig', function () { // # services, and proprietary license terms, please see // # https://rhodecode.com/licenses/ -angular.module('appenlight.controllers').controller('AdminApplicationsListController', AdminApplicationsListController); +angular.module('appenlight.components.userIdentitiesView', []) + .component('userIdentitiesView', { + templateUrl: 'components/views/user-identities-view/user-identities-view.html', + controller: UserIdentitiesController + }); -AdminApplicationsListController.$inject = ['applicationsResource']; +UserIdentitiesController.$inject = ['$state', 'userSelfPropertyResource', 'AeConfig']; -function AdminApplicationsListController(applicationsResource) { - +function UserIdentitiesController($state, userSelfPropertyResource, AeConfig) { + console.debug('UserIdentitiesController'); var vm = this; - vm.loading = {applications: true}; + vm.$state = $state; + vm.AeConfig = AeConfig; + vm.loading = {identities: true}; - vm.applications = applicationsResource.query({ - root_list: true, - resource_type: 'application' - }, function (data) { - vm.loading = {applications: false}; - }); -}; + vm.identities = userSelfPropertyResource.query( + {key: 'external_identities'}, + function (data) { + vm.loading.identities = false; + console.log(vm.identities); + }); + + vm.removeProvider = function (provider) { + console.log('provider', provider); + userSelfPropertyResource.delete( + { + key: 'external_identities', + provider: provider.provider, + id: provider.id + }, + function (status) { + if (status){ + vm.identities = _.filter(vm.identities, function (item) { + return item != provider + }); + } + + }); + } +} ;// # Copyright (C) 2010-2016 RhodeCode GmbH // # @@ -8565,44 +8693,38 @@ function AdminApplicationsListController(applicationsResource) { // # services, and proprietary license terms, please see // # https://rhodecode.com/licenses/ -angular.module('appenlight.controllers').controller('ConfigsListController', ConfigsListController); +angular.module('appenlight.components.userPasswordView', []) + .component('userPasswordView', { + templateUrl: 'components/views/user-password-view/user-password-view.html', + controller: UserPasswordViewController + }); -ConfigsListController.$inject = ['configsResource', 'configsNoIdResource']; +UserPasswordViewController.$inject = ['$state', 'userSelfPropertyResource']; -function ConfigsListController(configsResource, configsNoIdResource) { +function UserPasswordViewController($state, userSelfPropertyResource) { + console.debug('UserPasswordViewController'); var vm = this; - vm.loading = {config: true}; - - var filters = [ - 'template_footer_html:global', - 'list_groups_to_non_admins:global', - 'per_application_reports_rate_limit:global', - 'per_application_logs_rate_limit:global', - 'per_application_metrics_rate_limit:global', - ]; - - vm.configs = {}; - - vm.configList = configsResource.query({filter: filters}, - function (data) { - vm.loading = {config: false}; - _.each(data, function (item) { - if (vm.configs[item.section] === undefined) { - vm.configs[item.section] = {}; - } - vm.configs[item.section][item.key] = item; - }); - }); + vm.$state = $state; + vm.loading = {password: false}; + vm.form = {}; - vm.save = function () { - vm.loading.config = true; - _.each(vm.configList, function (item) { - item.$save(); + vm.updatePassword = function () { + vm.loading.password = true; + console.log('updatePassword'); + userSelfPropertyResource.update({key: 'password'}, vm.form, function () { + vm.loading.password = false; + vm.form = {}; + setServerValidation(vm.passwordForm); + }, function (response) { + if (response.status == 422) { + console.log('vm', vm); + setServerValidation(vm.passwordForm, response.data); + console.log(response.data); + } + vm.loading.password = false; }); - vm.loading.config = false; - }; - -}; + } +} ;// # Copyright (C) 2010-2016 RhodeCode GmbH // # @@ -8623,16 +8745,200 @@ function ConfigsListController(configsResource, configsNoIdResource) { // # services, and proprietary license terms, please see // # https://rhodecode.com/licenses/ -angular.module('appenlight.controllers').controller('AdminGroupsCreateController', AdminGroupsCreateController); +angular.module('appenlight.components.userProfileView', []) + .component('userProfileView', { + templateUrl: 'components/views/user-profile-view/user-profile-view.html', + controller: UserProfileViewController + }); -AdminGroupsCreateController.$inject = ['$state', 'groupsResource', 'groupsPropertyResource', 'sectionViewResource', 'AeConfig']; +UserProfileViewController.$inject = ['$state', 'userSelfResource']; -function AdminGroupsCreateController($state, groupsResource, groupsPropertyResource, sectionViewResource, AeConfig) { - +function UserProfileViewController($state, userSelfResource) { + console.debug('UserProfileViewController'); var vm = this; - vm.loading = { - group: false, - resource_permissions: false, + vm.$state = $state; + vm.loading = {profile: true}; + + vm.user = userSelfResource.get(null, function (data) { + vm.loading.profile = false; + console.log('loaded profile'); + }); + + vm.updateProfile = function () { + vm.loading.profile = true; + + console.log('updateProfile'); + vm.user.$update(null, function () { + vm.loading.profile = false; + setServerValidation(vm.profileForm); + }, function (response) { + if (response.status == 422) { + setServerValidation(vm.profileForm, response.data); + } + vm.loading.profile = false; + }); + } +} + +;// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # This program is distributed in the hope that it will be useful, +// # but WITHOUT ANY WARRANTY; without even the implied warranty of +// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// # GNU General Public License for more details. +// # +// # You should have received a copy of the GNU Affero General Public License +// # along with this program. If not, see . +// # +// # This program is dual-licensed. If you wish to learn more about the +// # AppEnlight Enterprise Edition, including its added features, Support +// # services, and proprietary license terms, please see +// # https://rhodecode.com/licenses/ + +var aeconfig = angular.module('appenlight.config', []); +aeconfig.factory('AeConfig', function () { + var obj = {}; + obj.flashMessages = decodeEncodedJSON(window.AE.flash_messages); + obj.timeOptions = decodeEncodedJSON(window.AE.timeOptions); + obj.plugins = decodeEncodedJSON(window.AE.plugins); + obj.topNav = decodeEncodedJSON(window.AE.topNav); + obj.ws_url = window.AE.ws_url; + obj.urls = window.AE.urls; + // set keys on values because we wont be able to retrieve them everywhere + for (var key in obj.timeOptions) { + obj.timeOptions[key]['key'] = key; + } + console.info('config', obj); + return obj; +}); + +;// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # This program is distributed in the hope that it will be useful, +// # but WITHOUT ANY WARRANTY; without even the implied warranty of +// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// # GNU General Public License for more details. +// # +// # You should have received a copy of the GNU Affero General Public License +// # along with this program. If not, see . +// # +// # This program is dual-licensed. If you wish to learn more about the +// # AppEnlight Enterprise Edition, including its added features, Support +// # services, and proprietary license terms, please see +// # https://rhodecode.com/licenses/ + +angular.module('appenlight.controllers').controller('AdminApplicationsListController', AdminApplicationsListController); + +AdminApplicationsListController.$inject = ['applicationsResource']; + +function AdminApplicationsListController(applicationsResource) { + console.debug('AdminApplicationsListController'); + var vm = this; + vm.loading = {applications: true}; + + vm.applications = applicationsResource.query({ + root_list: true, + resource_type: 'application' + }, function (data) { + vm.loading = {applications: false}; + }); +}; + +;// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # This program is distributed in the hope that it will be useful, +// # but WITHOUT ANY WARRANTY; without even the implied warranty of +// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// # GNU General Public License for more details. +// # +// # You should have received a copy of the GNU Affero General Public License +// # along with this program. If not, see . +// # +// # This program is dual-licensed. If you wish to learn more about the +// # AppEnlight Enterprise Edition, including its added features, Support +// # services, and proprietary license terms, please see +// # https://rhodecode.com/licenses/ + +angular.module('appenlight.controllers').controller('ConfigsListController', ConfigsListController); + +ConfigsListController.$inject = ['configsResource', 'configsNoIdResource']; + +function ConfigsListController(configsResource, configsNoIdResource) { + var vm = this; + vm.loading = {config: true}; + + var filters = [ + 'template_footer_html:global', + 'list_groups_to_non_admins:global', + 'per_application_reports_rate_limit:global', + 'per_application_logs_rate_limit:global', + 'per_application_metrics_rate_limit:global', + ]; + + vm.configs = {}; + + vm.configList = configsResource.query({filter: filters}, + function (data) { + vm.loading = {config: false}; + _.each(data, function (item) { + if (vm.configs[item.section] === undefined) { + vm.configs[item.section] = {}; + } + vm.configs[item.section][item.key] = item; + }); + }); + + vm.save = function () { + vm.loading.config = true; + _.each(vm.configList, function (item) { + item.$save(); + }); + vm.loading.config = false; + }; + +}; + +;// # Copyright (C) 2010-2016 RhodeCode GmbH +// # +// # This program is free software: you can redistribute it and/or modify +// # it under the terms of the GNU Affero General Public License, version 3 +// # (only), as published by the Free Software Foundation. +// # +// # This program is distributed in the hope that it will be useful, +// # but WITHOUT ANY WARRANTY; without even the implied warranty of +// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// # GNU General Public License for more details. +// # +// # You should have received a copy of the GNU Affero General Public License +// # along with this program. If not, see . +// # +// # This program is dual-licensed. If you wish to learn more about the +// # AppEnlight Enterprise Edition, including its added features, Support +// # services, and proprietary license terms, please see +// # https://rhodecode.com/licenses/ + +angular.module('appenlight.controllers').controller('AdminGroupsCreateController', AdminGroupsCreateController); + +AdminGroupsCreateController.$inject = ['$state', 'groupsResource', 'groupsPropertyResource', 'sectionViewResource', 'AeConfig']; + +function AdminGroupsCreateController($state, groupsResource, groupsPropertyResource, sectionViewResource, AeConfig) { + console.debug('AdminGroupsCreateController'); + var vm = this; + vm.loading = { + group: false, + resource_permissions: false, users: false }; @@ -8658,7 +8964,7 @@ function AdminGroupsCreateController($state, groupsResource, groupsPropertyResou } }; _.each(data, function (item) { - + console.log(item); var section = tmpObj[item.type][item.resource_type]; if (typeof section[item.resource_id] == 'undefined') { section[item.resource_id] = { @@ -8669,6 +8975,7 @@ function AdminGroupsCreateController($state, groupsResource, groupsPropertyResou section[item.resource_id].permissions.push(item.perm_name); }); + console.log(tmpObj) vm.resourcePermissions = tmpObj; }); @@ -8733,7 +9040,7 @@ function AdminGroupsCreateController($state, groupsResource, groupsPropertyResou } vm.searchUsers = function (searchPhrase) { - + console.log(searchPhrase); return sectionViewResource.query({ section: 'users_section', view: 'search_users', @@ -8770,7 +9077,7 @@ angular.module('appenlight.controllers').controller('AdminGroupsController', Adm AdminGroupsController.$inject = ['groupsResource']; function AdminGroupsController(groupsResource) { - + console.debug('AdminGroupsController'); var vm = this; vm.loading = {groups: true}; @@ -8782,13 +9089,13 @@ function AdminGroupsController(groupsResource) { } return memo; }, 0); - + console.log(vm.groups); }); vm.removeGroup = function (group) { groupsResource.remove({groupId: group.id}, function (data, responseHeaders) { - + console.log('x',data, responseHeaders()); if (data) { var index = vm.groups.indexOf(group); if (index !== -1) { @@ -8859,7 +9166,7 @@ function AdminPartitionsController(sectionViewResource) { else { var val = false; } - + console.log('scope', scope); _.each(vm[scope], function (item) { _.each(item[1].pg, function (index) { index.checked = val; @@ -8911,7 +9218,7 @@ function AdminPartitionsController(sectionViewResource) { } }); }); - + console.log(es_indices, pg_indices); vm.loading = {partitions: true}; sectionViewResource.save({section:'admin_section', @@ -8994,7 +9301,7 @@ angular.module('appenlight.controllers').controller('AdminUsersCreateController' AdminUsersCreateController.$inject = ['$state', 'usersResource', 'usersPropertyResource', 'sectionViewResource', 'AeConfig']; function AdminUsersCreateController($state, usersResource, usersPropertyResource, sectionViewResource, AeConfig) { - + console.debug('AdminUsersCreateController'); var vm = this; vm.loading = {user: false}; @@ -9024,7 +9331,7 @@ function AdminUsersCreateController($state, usersResource, usersPropertyResource } }; _.each(data, function (item) { - + console.log(item); var section = tmpObj[item.type][item.resource_type]; if (typeof section[item.resource_id] == 'undefined'){ section[item.resource_id] = { @@ -9035,6 +9342,7 @@ function AdminUsersCreateController($state, usersResource, usersPropertyResource section[item.resource_id].permissions.push(item.perm_name); }); + console.log(tmpObj) vm.resourcePermissions = tmpObj; }); @@ -9055,7 +9363,7 @@ function AdminUsersCreateController($state, usersResource, usersPropertyResource vm.createUser = function () { vm.loading.user = true; - + console.log('updateProfile'); if (userId) { usersResource.update({userId: vm.user.id}, vm.user, function (data) { setServerValidation(vm.profileForm); @@ -9077,7 +9385,7 @@ function AdminUsersCreateController($state, usersResource, usersPropertyResource vm.gen_pass += charset.charAt(Math.floor(Math.random() * n)); } vm.user.user_password = '' + vm.gen_pass; - + console.log('x', vm.gen_pass); } vm.reloginUser = function () { @@ -9115,7 +9423,7 @@ angular.module('appenlight.controllers').controller('AdminUsersController', Admi AdminUsersController.$inject = ['usersResource']; function AdminUsersController(usersResource) { - + console.debug('AdminUsersController'); var vm = this; vm.loading = {users: true}; @@ -9127,13 +9435,13 @@ function AdminUsersController(usersResource) { } return memo; }, 0); - + console.log(vm.users); }); vm.removeUser = function (user) { usersResource.remove({userId: user.id}, function (data, responseHeaders) { - + console.log('x',data, responseHeaders()); if (data) { var index = vm.users.indexOf(user); if (index !== -1) { @@ -9171,7 +9479,7 @@ ApplicationsUpdateController.$inject = ['$state', 'applicationsNoIdResource', 'a function ApplicationsUpdateController($state, applicationsNoIdResource, applicationsResource, applicationsPropertyResource, stateHolder) { 'use strict'; - + console.debug('ApplicationsUpdateController'); var vm = this; vm.loading = {application: false}; @@ -9223,7 +9531,7 @@ function ApplicationsUpdateController($state, applicationsNoIdResource, applicat setServerValidation(vm.BasicForm, response.data); } vm.loading.application = false; - + console.log(vm.BasicForm); }); } else { @@ -9242,7 +9550,7 @@ function ApplicationsUpdateController($state, applicationsNoIdResource, applicat }; vm.addRule = function () { - + console.log('addrule'); applicationsPropertyResource.save({ resourceId: vm.resource.resource_id, key: 'postprocessing_rules' @@ -9268,7 +9576,7 @@ function ApplicationsUpdateController($state, applicationsNoIdResource, applicat function (response) { if (response.status == 422) { setServerValidation(vm.regenerateAPIKeysForm, response.data); - + console.log(response.data); } vm.loading.application = false; } @@ -9288,7 +9596,7 @@ function ApplicationsUpdateController($state, applicationsNoIdResource, applicat function (response) { if (response.status == 422) { setServerValidation(vm.formDelete, response.data); - + console.log(response.data); } vm.loading.application = false; } @@ -9307,7 +9615,7 @@ function ApplicationsUpdateController($state, applicationsNoIdResource, applicat function (response) { if (response.status == 422) { setServerValidation(vm.formTransfer, response.data); - + console.log(response.data); } vm.loading.application = false; } @@ -9341,7 +9649,7 @@ angular.module('appenlight.controllers') IntegrationController.$inject = ['$state', 'integrationResource']; function IntegrationController($state, integrationResource) { - + console.debug('IntegrationController'); var vm = this; vm.loading = {integration: true}; vm.config = integrationResource.get( @@ -9401,7 +9709,7 @@ function IntegrationController($state, integrationResource) { }); } - + console.log(vm); } ;// # Copyright (C) 2010-2016 RhodeCode GmbH @@ -9429,7 +9737,7 @@ angular.module('appenlight.controllers') IntegrationsListController.$inject = ['$state', 'applicationsResource']; function IntegrationsListController($state, applicationsResource) { - + console.debug('IntegrationsListController'); var vm = this; vm.loading = {application: true}; vm.resource = applicationsResource.get({resourceId: $state.params.resourceId}, function (data) { @@ -9463,7 +9771,7 @@ angular.module('appenlight.controllers') ApplicationsListController.$inject = ['applicationsResource']; function ApplicationsListController(applicationsResource) { - + console.debug('ApplicationsListController'); var vm = this; vm.loading = {applications: true}; vm.applications = applicationsResource.query(null, function(){ @@ -9496,7 +9804,7 @@ angular.module('appenlight.controllers') ApplicationsPurgeLogsController.$inject = ['applicationsResource', 'sectionViewResource', 'logsNoIdResource']; function ApplicationsPurgeLogsController(applicationsResource, sectionViewResource, logsNoIdResource) { - + console.debug('ApplicationsPurgeLogsController'); var vm = this; vm.loading = {applications: true}; @@ -9780,7 +10088,7 @@ function JiraIntegrationCtrl($uibModalInstance, $state, report, integrationName, vm.form.responsible = vm.assignees[0]; vm.form.priority = vm.priorities[0]; }, function (error_data) { - + console.log('ERROR'); if (error_data.data.error_messages) { vm.error_messages = error_data.data.error_messages; } @@ -10171,7 +10479,7 @@ function ReportsListSlowController($location, $cookies, stateHolder, typeAheadTa vm.is_loading = true; slowReportsResource.query(searchParams, function (data, getResponseHeaders) { var headers = getResponseHeaders(); - + console.log(headers); vm.is_loading = false; vm.reportsPage = _.map(data, function (item) { return reportPresentation(item); @@ -10488,7 +10796,7 @@ function ReportsListController($location, $cookies, stateHolder, vm.is_loading = true; reportsResource.query(searchParams, function (data, getResponseHeaders) { var headers = getResponseHeaders(); - + console.log(headers); vm.is_loading = false; vm.reportsPage = _.map(data, function (item) { return reportPresentation(item); @@ -10512,7 +10820,7 @@ function ReportsListController($location, $cookies, stateHolder, vm.searchParams = parseSearchToTags($location.search()); vm.page = Number(vm.searchParams.page) || 1; var params = parseTagsToSearch(vm.searchParams); - + console.log(params); vm.fetchReports(params); }; // initial load @@ -10642,7 +10950,7 @@ function ReportsViewController($window, $location, $state, $uibModal, $cookies, }; vm.searchTag = function (tag, value) { - + console.log(tag, value); if (vm.report.report_type === 3) { $location.url($state.href('report.list_slow')); } @@ -10720,448 +11028,158 @@ function ReportsViewController($window, $location, $state, $uibModal, $cookies, vm.traceback = data.traceback; _.each(vm.traceback, function (frame) { if (frame.line) { - vm.rawTraceback += 'File ' + frame.file + ' line ' + frame.line + ' in ' + frame.fn + ": \r\n"; - } - vm.rawTraceback += ' ' + frame.cline + "\r\n"; - }); - - if (stateHolder.AeUser.id){ - vm.fetchHistory(); - } - - vm.selectedTab($cookies.selectedReportTab); - - }, function (response) { - - if (response.status == 403) { - var uid = response.headers('x-appenlight-uid'); - if (!uid) { - window.location = '/register?came_from=' + encodeURIComponent(window.location); - } - } - vm.is_loading.report = false; - }); - }; - - vm.selectedTab = function(tab_name){ - $cookies.selectedReportTab = tab_name; - if (tab_name == 'logs' && vm.reportLogs === null) { - vm.fetchLogs(); - } - }; - - vm.markFixed = function () { - reportGroupResource.update({ - groupId: vm.report.group_id - }, {fixed: !vm.report.group.fixed}, - function (data) { - vm.report.group.fixed = data.fixed; - }); - }; - - vm.markPublic = function () { - reportGroupResource.update({ - groupId: vm.report.group_id - }, {public: !vm.report.group.public}, - function (data) { - vm.report.group.public = data.public; - }); - }; - - vm.delete = function () { - reportGroupResource.delete({'groupId': vm.report.group_id}, - function (data) { - $state.go('report.list'); - }) - }; - - vm.assignUsersModal = function (index) { - vm.opts = { - backdrop: 'static', - templateUrl: 'AssignReportCtrl.html', - controller: 'AssignReportCtrl as ctrl', - resolve: { - report: function () { - return vm.report; - } - } - }; - var modalInstance = $uibModal.open(vm.opts); - modalInstance.result.then(function (report) { - - }, function () { - console.info('Modal dismissed at: ' + new Date()); - }); - - }; - - vm.fetchHistory = function () { - reportGroupPropertyResource.query({ - groupId: vm.report.group_id, - key: 'history' - }, function (data) { - vm.reportHistoryData = { - json: data, - keys: { - x: 'x', - value: ["reports"] - }, - names: { - reports: 'Reports history' - }, - type: 'bar' - }; - vm.is_loading.history = false; - }); - }; - - vm.nextDetail = function () { - $state.go('report.view_detail', { - groupId: vm.report.group_id, - reportId: vm.report.group.next_report - }); - }; - vm.previousDetail = function () { - $state.go('report.view_detail', { - groupId: vm.report.group_id, - reportId: vm.report.group.previous_report - }); - }; - - vm.runIntegration = function (integration_name) { - - if (integration_name == 'bitbucket') { - var controller = 'BitbucketIntegrationCtrl as ctrl'; - var template_url = 'templates/integrations/bitbucket.html'; - } - else if (integration_name == 'github') { - var controller = 'GithubIntegrationCtrl as ctrl'; - var template_url = 'templates/integrations/github.html'; - } - else if (integration_name == 'jira') { - var controller = 'JiraIntegrationCtrl as ctrl'; - var template_url = 'templates/integrations/jira.html'; - } - else { - return false; - } - - vm.opts = { - backdrop: 'static', - templateUrl: template_url, - controller: controller, - resolve: { - integrationName: function () { - return integration_name - }, - report: function () { - return vm.report; - } - } - }; - var modalInstance = $uibModal.open(vm.opts); - modalInstance.result.then(function (report) { - - }, function () { - console.info('Modal dismissed at: ' + new Date()); - }); - - }; - - // load report - vm.fetchReport(); - - -} - -;// # Copyright (C) 2010-2016 RhodeCode GmbH -// # -// # This program is free software: you can redistribute it and/or modify -// # it under the terms of the GNU Affero General Public License, version 3 -// # (only), as published by the Free Software Foundation. -// # -// # This program is distributed in the hope that it will be useful, -// # but WITHOUT ANY WARRANTY; without even the implied warranty of -// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// # GNU General Public License for more details. -// # -// # You should have received a copy of the GNU Affero General Public License -// # along with this program. If not, see . -// # -// # This program is dual-licensed. If you wish to learn more about the -// # AppEnlight Enterprise Edition, including its added features, Support -// # services, and proprietary license terms, please see -// # https://rhodecode.com/licenses/ - -angular.module('appenlight.controllers') - .controller('AlertChannelsEmailController', AlertChannelsEmailController) - -AlertChannelsEmailController.$inject = ['$state','userSelfPropertyResource']; - -function AlertChannelsEmailController($state, userSelfPropertyResource) { - - var vm = this; - vm.loading = {email: false}; - vm.form = {}; - - vm.createChannel = function () { - vm.loading.email = true; - - userSelfPropertyResource.save({key: 'alert_channels'}, vm.form, function () { - //vm.loading.email = false; - //setServerValidation(vm.channelForm); - //vm.form = {}; - $state.go('user.alert_channels.list'); - }, function (response) { - if (response.status == 422) { - setServerValidation(vm.channelForm, response.data); - } - vm.loading.email = false; - }); - } -} - -;// # Copyright (C) 2010-2016 RhodeCode GmbH -// # -// # This program is free software: you can redistribute it and/or modify -// # it under the terms of the GNU Affero General Public License, version 3 -// # (only), as published by the Free Software Foundation. -// # -// # This program is distributed in the hope that it will be useful, -// # but WITHOUT ANY WARRANTY; without even the implied warranty of -// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// # GNU General Public License for more details. -// # -// # You should have received a copy of the GNU Affero General Public License -// # along with this program. If not, see . -// # -// # This program is dual-licensed. If you wish to learn more about the -// # AppEnlight Enterprise Edition, including its added features, Support -// # services, and proprietary license terms, please see -// # https://rhodecode.com/licenses/ - -angular.module('appenlight.controllers').controller('AlertChannelsController', AlertChannelsController); - -AlertChannelsController.$inject = ['userSelfPropertyResource', 'applicationsNoIdResource']; - -function AlertChannelsController(userSelfPropertyResource, applicationsNoIdResource) { - - var vm = this; - vm.loading = {channels: true, applications: true, actions:true}; - - vm.alertChannels = userSelfPropertyResource.query({key: 'alert_channels'}, - function (data) { - vm.loading.channels = false; - }); - - vm.alertActions = userSelfPropertyResource.query({key: 'alert_actions'}, - function (data) { - vm.loading.actions = false; - }); - - vm.applications = applicationsNoIdResource.query({permission: 'view'}, - function (data) { - vm.loading.applications = false; - }); - - var allOps = { - 'eq': 'Equal', - 'ne': 'Not equal', - 'ge': 'Greater or equal', - 'gt': 'Greater than', - 'le': 'Lesser or equal', - 'lt': 'Lesser than', - 'startswith': 'Starts with', - 'endswith': 'Ends with', - 'contains': 'Contains' - }; - - var fieldOps = {}; - fieldOps['http_status'] = ['eq', 'ne', 'ge', 'le']; - fieldOps['group:priority'] = ['eq', 'ne', 'ge', 'le']; - fieldOps['duration'] = ['ge', 'le']; - fieldOps['url_domain'] = ['eq', 'ne', 'startswith', 'endswith', - 'contains']; - fieldOps['url_path'] = ['eq', 'ne', 'startswith', 'endswith', - 'contains']; - fieldOps['error'] = ['eq', 'ne', 'startswith', 'endswith', - 'contains']; - fieldOps['tags:server_name'] = ['eq', 'ne', 'startswith', 'endswith', - 'contains']; - fieldOps['group:occurences'] = ['eq', 'ne', 'ge', 'le']; - - var possibleFields = { - '__AND__': 'All met (composite rule)', - '__OR__': 'One met (composite rule)', - '__NOT__': 'Not met (composite rule)', - 'http_status': 'HTTP Status', - 'duration': 'Request duration', - 'group:priority': 'Group -> Priority', - 'url_domain': 'Domain', - 'url_path': 'URL Path', - 'error': 'Error', - 'tags:server_name': 'Tag -> Server name', - 'group:occurences': 'Group -> Occurences' - }; + vm.rawTraceback += 'File ' + frame.file + ' line ' + frame.line + ' in ' + frame.fn + ": \r\n"; + } + vm.rawTraceback += ' ' + frame.cline + "\r\n"; + }); - vm.ruleDefinitions = { - fieldOps: fieldOps, - allOps: allOps, - possibleFields: possibleFields - }; + if (stateHolder.AeUser.id){ + vm.fetchHistory(); + } + + vm.selectedTab($cookies.selectedReportTab); - vm.addAction = function (channel) { - - userSelfPropertyResource.save({key: 'alert_channels_rules'}, {}, function (data) { - vm.alertActions.push(data); }, function (response) { - if (response.status == 422) { - + console.log(response); + if (response.status == 403) { + var uid = response.headers('x-appenlight-uid'); + if (!uid) { + window.location = '/register?came_from=' + encodeURIComponent(window.location); + } } + vm.is_loading.report = false; }); }; - vm.updateChannel = function (channel, subKey) { - var params = { - key: 'alert_channels', - channel_name: channel['channel_name'], - channel_value: channel['channel_value'] - }; - var toUpdate = {}; - if (['daily_digest', 'send_alerts'].indexOf(subKey) !== -1) { - toUpdate[subKey] = !channel[subKey]; + vm.selectedTab = function(tab_name){ + $cookies.selectedReportTab = tab_name; + if (tab_name == 'logs' && vm.reportLogs === null) { + vm.fetchLogs(); } - userSelfPropertyResource.update(params, toUpdate, function (data) { - _.extend(channel, data); - }); }; - vm.removeChannel = function (channel) { - - userSelfPropertyResource.delete({ - key: 'alert_channels', - channel_name: channel.channel_name, - channel_value: channel.channel_value - }, function () { - vm.alertChannels = _.filter(vm.alertChannels, function(item){ - return item != channel; + vm.markFixed = function () { + reportGroupResource.update({ + groupId: vm.report.group_id + }, {fixed: !vm.report.group.fixed}, + function (data) { + vm.report.group.fixed = data.fixed; }); - }); - - } + }; -} + vm.markPublic = function () { + reportGroupResource.update({ + groupId: vm.report.group_id + }, {public: !vm.report.group.public}, + function (data) { + vm.report.group.public = data.public; + }); + }; -;// # Copyright (C) 2010-2016 RhodeCode GmbH -// # -// # This program is free software: you can redistribute it and/or modify -// # it under the terms of the GNU Affero General Public License, version 3 -// # (only), as published by the Free Software Foundation. -// # -// # This program is distributed in the hope that it will be useful, -// # but WITHOUT ANY WARRANTY; without even the implied warranty of -// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// # GNU General Public License for more details. -// # -// # You should have received a copy of the GNU Affero General Public License -// # along with this program. If not, see . -// # -// # This program is dual-licensed. If you wish to learn more about the -// # AppEnlight Enterprise Edition, including its added features, Support -// # services, and proprietary license terms, please see -// # https://rhodecode.com/licenses/ + vm.delete = function () { + reportGroupResource.delete({'groupId': vm.report.group_id}, + function (data) { + $state.go('report.list'); + }) + }; -angular.module('appenlight.controllers').controller('UserAuthTokensController', UserAuthTokensController); + vm.assignUsersModal = function (index) { + vm.opts = { + backdrop: 'static', + templateUrl: 'AssignReportCtrl.html', + controller: 'AssignReportCtrl as ctrl', + resolve: { + report: function () { + return vm.report; + } + } + }; + var modalInstance = $uibModal.open(vm.opts); + modalInstance.result.then(function (report) { -UserAuthTokensController.$inject = ['$filter', 'userSelfPropertyResource', 'AeConfig']; + }, function () { + console.info('Modal dismissed at: ' + new Date()); + }); -function UserAuthTokensController($filter, userSelfPropertyResource, AeConfig) { - - var vm = this; - vm.loading = {tokens: true}; + }; - vm.expireOptions = AeConfig.timeOptions; + vm.fetchHistory = function () { + reportGroupPropertyResource.query({ + groupId: vm.report.group_id, + key: 'history' + }, function (data) { + vm.reportHistoryData = { + json: data, + keys: { + x: 'x', + value: ["reports"] + }, + names: { + reports: 'Reports history' + }, + type: 'bar' + }; + vm.is_loading.history = false; + }); + }; - vm.tokens = userSelfPropertyResource.query({key: 'auth_tokens'}, - function (data) { - vm.loading.tokens = false; + vm.nextDetail = function () { + $state.go('report.view_detail', { + groupId: vm.report.group_id, + reportId: vm.report.group.next_report + }); + }; + vm.previousDetail = function () { + $state.go('report.view_detail', { + groupId: vm.report.group_id, + reportId: vm.report.group.previous_report }); + }; - vm.addToken = function () { - vm.loading.tokens = true; - userSelfPropertyResource.save({key: 'auth_tokens'}, - vm.form, - function (data) { - vm.loading.tokens = false; - setServerValidation(vm.TokenForm); - vm.form = {}; - vm.tokens.push(data); - }, function (response) { - vm.loading.tokens = false; - if (response.status == 422) { - setServerValidation(vm.TokenForm, response.data); - } - }) - } + vm.runIntegration = function (integration_name) { + console.log(integration_name); + if (integration_name == 'bitbucket') { + var controller = 'BitbucketIntegrationCtrl as ctrl'; + var template_url = 'templates/integrations/bitbucket.html'; + } + else if (integration_name == 'github') { + var controller = 'GithubIntegrationCtrl as ctrl'; + var template_url = 'templates/integrations/github.html'; + } + else if (integration_name == 'jira') { + var controller = 'JiraIntegrationCtrl as ctrl'; + var template_url = 'templates/integrations/jira.html'; + } + else { + return false; + } - vm.removeToken = function (token) { - userSelfPropertyResource.delete({key: 'auth_tokens', - token:token.token}, - function () { - var index = vm.tokens.indexOf(token); - if (index !== -1) { - vm.tokens.splice(index, 1); + vm.opts = { + backdrop: 'static', + templateUrl: template_url, + controller: controller, + resolve: { + integrationName: function () { + return integration_name + }, + report: function () { + return vm.report; } - }) - } -} + } + }; + var modalInstance = $uibModal.open(vm.opts); + modalInstance.result.then(function (report) { -;// # Copyright (C) 2010-2016 RhodeCode GmbH -// # -// # This program is free software: you can redistribute it and/or modify -// # it under the terms of the GNU Affero General Public License, version 3 -// # (only), as published by the Free Software Foundation. -// # -// # This program is distributed in the hope that it will be useful, -// # but WITHOUT ANY WARRANTY; without even the implied warranty of -// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// # GNU General Public License for more details. -// # -// # You should have received a copy of the GNU Affero General Public License -// # along with this program. If not, see . -// # -// # This program is dual-licensed. If you wish to learn more about the -// # AppEnlight Enterprise Edition, including its added features, Support -// # services, and proprietary license terms, please see -// # https://rhodecode.com/licenses/ + }, function () { + console.info('Modal dismissed at: ' + new Date()); + }); -angular.module('appenlight.controllers') - .controller('UserPasswordController', UserPasswordController) + }; -UserPasswordController.$inject = ['userSelfPropertyResource']; + // load report + vm.fetchReport(); -function UserPasswordController(userSelfPropertyResource) { - - var vm = this; - vm.loading = {password: false}; - vm.form = {}; - vm.updatePassword = function () { - vm.loading.password = true; - - userSelfPropertyResource.update({key: 'password'}, vm.form, function () { - vm.loading.password = false; - vm.form = {}; - setServerValidation(vm.passwordForm); - }, function (response) { - if (response.status == 422) { - - setServerValidation(vm.passwordForm, response.data); - - } - vm.loading.password = false; - }); - } } ;// # Copyright (C) 2010-2016 RhodeCode GmbH @@ -11199,7 +11217,7 @@ angular.module('appenlight.directives.c3chart', []) if (!_.isEmpty($scope.data)) { _.extend(config.data, angular.copy($scope.data)); } - + console.log('ChartCtrl.showGraph', config); config.onresized = function () { if (this.currentWidth < 400){ $scope.chart.internal.config.axis_x_tick_culling_max = 3; @@ -11218,19 +11236,19 @@ angular.module('appenlight.directives.c3chart', []) originalXTickCount = $scope.chart.internal.config.axis_x_tick_culling_max; $scope.chart.internal.config.onresized.call($scope.chart.internal); } - + console.log('should update', $scope.update); if ($scope.update) { - + console.log('reload driven'); $scope.$watch('data', function () { if (!firstLoad) { - + console.log('data updated', $scope.data); $scope.chart.load(angular.copy($scope.data), {unload: true}); if (typeof $scope.data.groups != 'undefined') { - + console.log('add groups'); $scope.chart.groups($scope.data.groups); } if (typeof $scope.data.names != 'undefined') { - + console.log('add names'); $scope.chart.data.names($scope.data.names); } $scope.chart.flush(); @@ -11242,7 +11260,7 @@ angular.module('appenlight.directives.c3chart', []) return } if (typeof $scope.config.regions != 'undefined') { - + console.log('update regions', $scope.config.regions); $scope.chart.regions($scope.config.regions); } }); @@ -11318,7 +11336,7 @@ directive('confirmValidate', [function () { link: function ($scope, elem, attrs, ngModel) { ngModel.$validators.confirm = function (modelValue, viewValue) { var value = modelValue || viewValue; - + console.log('validate', value.toLowerCase() == 'confirm'); if (value.toLowerCase() == 'confirm') { return true; } @@ -11495,7 +11513,7 @@ function ApplicationPermissionsController(sectionViewResource, applicationsPrope vm.form.selectedGroup = vm.possibleGroups[0].id; } }); - + console.log('g', vm.possibleGroups); vm.possibleUsers = []; _.each(vm.resource.possible_permissions, function (perm) { vm.form.selectedUserPermissions[perm] = false; @@ -11511,7 +11529,7 @@ function ApplicationPermissionsController(sectionViewResource, applicationsPrope group: {} }; _.each(vm.currentPermissions, function (perm) { - + console.log(perm); if (perm.type == 'user') { if (typeof tmpObj[perm.type][perm.user_name] === 'undefined') { tmpObj[perm.type][perm.user_name] = { @@ -11541,10 +11559,10 @@ function ApplicationPermissionsController(sectionViewResource, applicationsPrope group: _.values(tmpObj.group), }; - + console.log('test', tmpObj, vm.currentPermissions); vm.searchUsers = function (searchPhrase) { - + console.log('SEARCHING'); vm.searchingUsers = true; return sectionViewResource.query({ section: 'users_section', @@ -11593,7 +11611,7 @@ function ApplicationPermissionsController(sectionViewResource, applicationsPrope vm.setUserPermission = function () { - + console.log('set permissions'); var POSTObj = { 'user_name': vm.form.autocompleteUser, 'permissions': [] @@ -11623,8 +11641,8 @@ function ApplicationPermissionsController(sectionViewResource, applicationsPrope } vm.removeUserPermission = function (perm_name, curr_perm) { - - + console.log(perm_name); + console.log(curr_perm); var POSTObj = { key: 'user_permissions', user_name: curr_perm.self.user_name, @@ -11641,7 +11659,7 @@ function ApplicationPermissionsController(sectionViewResource, applicationsPrope } vm.removeGroupPermission = function (perm_name, curr_perm) { - + console.log('g', curr_perm); var POSTObj = { key: 'group_permissions', group_id: curr_perm.self.group_id, @@ -11748,7 +11766,7 @@ angular.module('appenlight.directives.postProcessAction', []).directive('postPro }; function postProcessActionController(){ var vm = this; - + console.log(vm); var allOps = { 'eq': 'Equal', 'ne': 'Not equal', @@ -11832,7 +11850,7 @@ angular.module('appenlight.directives.postProcessAction', []).directive('postPro vm.setDirty = function() { vm.action.dirty = true; - + console.log('set dirty'); }; } @@ -11928,14 +11946,14 @@ angular.module('appenlight.directives.reportAlertAction', []).directive('reportA channel_pkey: vm.channelToBind.pkey, action_pkey: vm.action.pkey }; - + console.log(post); userSelfPropertyResource.save({key: 'alert_channels_actions_binds'}, post, function (data) { vm.action.channels = []; vm.action.channels = data.channels; }, function (response) { if (response.status == 422) { - + console.log('scope', response); } }); }; @@ -11951,7 +11969,7 @@ angular.module('appenlight.directives.reportAlertAction', []).directive('reportA vm.action.channels = data.channels; }, function (response) { if (response.status == 422) { - + console.log('scope', response); } }); }; @@ -11988,7 +12006,7 @@ angular.module('appenlight.directives.reportAlertAction', []).directive('reportA vm.setDirty = function() { vm.action.dirty = true; - + console.log('set dirty'); }; } @@ -12087,10 +12105,10 @@ angular.module('appenlight.directives.rule', []).directive('rule', function () { vm.setDirty = function() { vm.rule.dirty = true; - + console.log('set dirty'); if (vm.parentObj){ - - + console.log('p', vm.parentObj); + console.log('set parent dirty'); vm.parentObj.dirty = true; } }; @@ -12104,13 +12122,13 @@ angular.module('appenlight.directives.rule', []).directive('rule', function () { vm.rule.op = vm.ruleDefinitions.fieldOps[vm.rule.field][0]; } if ((new_is_compound && !old_was_compound)) { - + console.log('resetting config'); delete vm.rule.value; vm.rule.rules = []; vm.add(); } else if (!new_is_compound && old_was_compound) { - + console.log('resetting config'); delete vm.rule.rules; vm.rule.value = ''; } @@ -12460,8 +12478,7 @@ angular.module('appenlight').config(['$stateProvider', '$urlRouterProvider', fun $stateProvider.state('user.profile.password', { url: '/password', - templateUrl: 'templates/user/profile_password.html', - controller: 'UserPasswordController as password' + component: 'userPasswordView' }); $stateProvider.state('user.profile.identities', { @@ -12471,26 +12488,23 @@ angular.module('appenlight').config(['$stateProvider', '$urlRouterProvider', fun $stateProvider.state('user.profile.auth_tokens', { url: '/auth_tokens', - templateUrl: 'templates/user/auth_tokens.html', - controller: 'UserAuthTokensController as auth_tokens' + component: 'userAuthTokensView' }); $stateProvider.state('user.alert_channels', { abstract: true, url: '/alert_channels', - templateUrl: 'templates/user/alert_channels.html' + template: '' }); $stateProvider.state('user.alert_channels.list', { url: '/list', - templateUrl: 'templates/user/alert_channels_list.html', - controller: 'AlertChannelsController as channels' + component: 'userAlertChannelsListView' }); $stateProvider.state('user.alert_channels.email', { url: '/email', - templateUrl: 'templates/user/alert_channels_email.html', - controller: 'AlertChannelsEmailController as email' + component: 'userAlertChannelsEmailNewView' }); $stateProvider.state('applications', { @@ -12913,7 +12927,7 @@ angular.module('appenlight.services.stateHolder', []).factory('stateHolder', } } }.bind(this)); - + console.log('AeUser.hasContextPermission', permName, hasPerm); return hasPerm; }; @@ -12927,7 +12941,7 @@ angular.module('appenlight.services.stateHolder', []).factory('stateHolder', list: [], timeout: null, extend: function (values) { - + console.log('pushing flash', this); if (this.list.length > 2) { this.list.splice(0, this.list.length - 2); } @@ -12936,7 +12950,7 @@ angular.module('appenlight.services.stateHolder', []).factory('stateHolder', this.removeMessages(); }, pop: function () { - + console.log('popping flash'); this.list.pop(); }, cancelTimeout: function () { @@ -13031,7 +13045,7 @@ angular.module('appenlight.services.typeAheadTagHelper', []).factory('typeAheadT return true; }; typeAheadTagHelper.removeSearchTag = function (tag) { - + console.log(typeAheadTagHelper.tags); var indexValue = _.indexOf(typeAheadTagHelper.tags, tag); typeAheadTagHelper.tags.splice(indexValue, 1); diff --git a/frontend/src/components/views/user-alert-channel-email-new-view/user-alert-channel-email-new-view.js b/frontend/src/components/views/user-alert-channel-email-new-view/user-alert-channel-email-new-view.js index c104c9b..6049178 100644 --- a/frontend/src/components/views/user-alert-channel-email-new-view/user-alert-channel-email-new-view.js +++ b/frontend/src/components/views/user-alert-channel-email-new-view/user-alert-channel-email-new-view.js @@ -28,6 +28,7 @@ AlertChannelsEmailController.$inject = ['$state','userSelfPropertyResource']; function AlertChannelsEmailController($state, userSelfPropertyResource) { console.debug('AlertChannelsEmailController'); var vm = this; + vm.$state = $state; vm.loading = {email: false}; vm.form = {}; diff --git a/frontend/src/components/views/user-alert-channels-list-view/user-alert-channels-list-view.js b/frontend/src/components/views/user-alert-channels-list-view/user-alert-channels-list-view.js index 65b7fe6..0a6c3cd 100644 --- a/frontend/src/components/views/user-alert-channels-list-view/user-alert-channels-list-view.js +++ b/frontend/src/components/views/user-alert-channels-list-view/user-alert-channels-list-view.js @@ -23,11 +23,12 @@ angular.module('appenlight.components.userAlertChannelsListView', []) controller: userAlertChannelsListViewController }); -userAlertChannelsListViewController.$inject = ['userSelfPropertyResource', 'applicationsNoIdResource']; +userAlertChannelsListViewController.$inject = ['$state','userSelfPropertyResource', 'applicationsNoIdResource']; -function userAlertChannelsListViewController(userSelfPropertyResource, applicationsNoIdResource) { +function userAlertChannelsListViewController($state, userSelfPropertyResource, applicationsNoIdResource) { console.debug('AlertChannelsController'); var vm = this; + vm.$state = $state; vm.loading = {channels: true, applications: true, actions:true}; vm.alertChannels = userSelfPropertyResource.query({key: 'alert_channels'}, diff --git a/frontend/src/components/views/user-auth-tokens-view/user-auth-tokens-view.js b/frontend/src/components/views/user-auth-tokens-view/user-auth-tokens-view.js index 39085e6..1637431 100644 --- a/frontend/src/components/views/user-auth-tokens-view/user-auth-tokens-view.js +++ b/frontend/src/components/views/user-auth-tokens-view/user-auth-tokens-view.js @@ -23,11 +23,12 @@ angular.module('appenlight.components.userAuthTokensView', []) controller: userAuthTokensViewController }); -userAuthTokensViewController.$inject = ['userSelfPropertyResource', 'AeConfig']; +userAuthTokensViewController.$inject = ['$state', 'userSelfPropertyResource', 'AeConfig']; -function userAuthTokensViewController(userSelfPropertyResource, AeConfig) { +function userAuthTokensViewController($state, userSelfPropertyResource, AeConfig) { console.debug('userAuthTokensViewController'); var vm = this; + vm.$state = $state; vm.loading = {tokens: true}; vm.expireOptions = AeConfig.timeOptions; diff --git a/frontend/src/components/views/user-identities-view/user-identities-view.js b/frontend/src/components/views/user-identities-view/user-identities-view.js index e57abdd..57e8de3 100644 --- a/frontend/src/components/views/user-identities-view/user-identities-view.js +++ b/frontend/src/components/views/user-identities-view/user-identities-view.js @@ -23,11 +23,12 @@ angular.module('appenlight.components.userIdentitiesView', []) controller: UserIdentitiesController }); -UserIdentitiesController.$inject = ['userSelfPropertyResource', 'AeConfig']; +UserIdentitiesController.$inject = ['$state', 'userSelfPropertyResource', 'AeConfig']; -function UserIdentitiesController(userSelfPropertyResource, AeConfig) { +function UserIdentitiesController($state, userSelfPropertyResource, AeConfig) { console.debug('UserIdentitiesController'); var vm = this; + vm.$state = $state; vm.AeConfig = AeConfig; vm.loading = {identities: true}; diff --git a/frontend/src/components/views/user-password-view/user-password-view.js b/frontend/src/components/views/user-password-view/user-password-view.js index ed8f275..73b9754 100644 --- a/frontend/src/components/views/user-password-view/user-password-view.js +++ b/frontend/src/components/views/user-password-view/user-password-view.js @@ -23,11 +23,12 @@ angular.module('appenlight.components.userPasswordView', []) controller: UserPasswordViewController }); -UserPasswordViewController.$inject = ['userSelfPropertyResource']; +UserPasswordViewController.$inject = ['$state', 'userSelfPropertyResource']; -function UserPasswordViewController(userSelfPropertyResource) { +function UserPasswordViewController($state, userSelfPropertyResource) { console.debug('UserPasswordViewController'); var vm = this; + vm.$state = $state; vm.loading = {password: false}; vm.form = {}; diff --git a/frontend/src/components/views/user-profile-view/user-profile-view.js b/frontend/src/components/views/user-profile-view/user-profile-view.js index bcb26b2..da5c1cc 100644 --- a/frontend/src/components/views/user-profile-view/user-profile-view.js +++ b/frontend/src/components/views/user-profile-view/user-profile-view.js @@ -23,11 +23,12 @@ angular.module('appenlight.components.userProfileView', []) controller: UserProfileViewController }); -UserProfileViewController.$inject = ['userSelfResource']; +UserProfileViewController.$inject = ['$state', 'userSelfResource']; -function UserProfileViewController(userSelfResource) { +function UserProfileViewController($state, userSelfResource) { console.debug('UserProfileViewController'); var vm = this; + vm.$state = $state; vm.loading = {profile: true}; vm.user = userSelfResource.get(null, function (data) { diff --git a/frontend/src/templates/user/breadcrumbs.html b/frontend/src/templates/user/breadcrumbs.html index 7ffc112..bd1d353 100644 --- a/frontend/src/templates/user/breadcrumbs.html +++ b/frontend/src/templates/user/breadcrumbs.html @@ -1,11 +1,12 @@ -