[CORD-1653] Adding a debug tab in model details
Change-Id: I6c3be4227309cbeb2dd7ab6252c1312dfd00fb18
diff --git a/src/app/core/debug/debug-model.html b/src/app/core/debug/debug-model.html
new file mode 100644
index 0000000..cf74189
--- /dev/null
+++ b/src/app/core/debug/debug-model.html
@@ -0,0 +1,22 @@
+<!--
+Copyright 2017-present Open Networking Foundation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<div class="row" ng-if="vm.ngModel[field]" ng-repeat="field in vm.debugFields">
+ <div class="col-xs-12">
+ <label>{{vm.toLabel(field)}}</label>
+ <pre>{{vm.parseField(field, vm.ngModel[field])}}</pre>
+ </div>
+</div>
\ No newline at end of file
diff --git a/src/app/core/debug/debug-model.spec.ts b/src/app/core/debug/debug-model.spec.ts
new file mode 100644
index 0000000..46b6344
--- /dev/null
+++ b/src/app/core/debug/debug-model.spec.ts
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as angular from 'angular';
+import 'angular-mocks';
+import 'angular-ui-router';
+import {xosDebugModel} from './debug-model';
+
+const MockConfigHelpers = {
+ toLabel: jasmine.createSpy('toLabel')
+};
+
+const model = {
+ policed: 1503009920,
+ backend_register: '{\"next_run\": 0, \"last_success\": 1502860176.52445, \"exponent\": 0}',
+ backend_status: '1 - OK',
+ id: 1,
+ backend_need_delete: true,
+ self_content_type_id: 'core.instance',
+ backend_need_reap: false,
+ no_sync: false,
+ updated: 1503009920,
+ deleted: false,
+ policy_status: '2 - AuthorizationFailure(Authorization Failed: SSL exception connecting to https://192.168.108.119:5000/v2.0/tokens,) // Exception(Ansible playbook failed. // Error in creating the server, please check logs,) // The VM is available but not Active. state:ERROR,)',
+ lazy_blocked: false,
+ enacted: 1503009920,
+ enabled: 1503009920,
+ leaf_model_name: 'Instance',
+ created: 1503009920,
+ write_protect: false,
+ no_policy: false,
+ class_names: 'Instance,XOSBase'
+};
+
+describe('The xosDebugModel component', () => {
+ let scope, rootScope, element, compile , isolatedScope;
+
+ const compileElement = () => {
+
+ if (!scope) {
+ scope = rootScope.$new();
+ }
+
+ element = angular.element(`<xos-debug-model ng-model="model"></xos-debug-model>`);
+ compile(element)(scope);
+ scope.$digest();
+ isolatedScope = element.isolateScope().vm;
+ };
+
+ beforeEach(() => {
+ angular.module('xosDebugModel', [])
+ .component('xosDebugModel', xosDebugModel)
+ .value('ConfigHelpers', MockConfigHelpers);
+ angular.mock.module('xosDebugModel');
+
+ inject(($compile: ng.ICompileService, $rootScope: ng.IScope) => {
+ rootScope = $rootScope;
+ compile = $compile;
+ });
+ });
+
+ it('should have a toLabel method', () => {
+ compileElement();
+ expect(isolatedScope.toLabel).toBeDefined();
+ isolatedScope.toLabel('a');
+ expect(MockConfigHelpers.toLabel).toHaveBeenCalledWith('a');
+ });
+
+ describe('the parseField method', () => {
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.model = model;
+ compileElement();
+ });
+
+ it('should convert dates', () => {
+ const dateFields = ['created', 'updated', 'enacted', 'policed'];
+
+ dateFields.forEach(f => {
+ const date = isolatedScope.parseField(f, model[f]);
+ expect(date).toEqual('Thu Aug 17 2017 15:45:20 GMT-0700 (PDT)');
+ });
+ });
+
+ it('should convert strings to JSON', () => {
+ const res = isolatedScope.parseField('backend_register', model['backend_register']);
+ expect(res.next_run).toBe(0);
+ expect(res.exponent).toBe(0);
+ });
+
+ it('should parse backend_status and policy_status', () => {
+ const policy = isolatedScope.parseField('policy_status', model['policy_status']);
+ expect(policy.match(/\n/g).length).toBe(3);
+ });
+ });
+});
diff --git a/src/app/core/debug/debug-model.ts b/src/app/core/debug/debug-model.ts
new file mode 100644
index 0000000..9760520
--- /dev/null
+++ b/src/app/core/debug/debug-model.ts
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// NOTE this component will render the hidden model fields for debug purposes
+
+import {IXosConfigHelpersService} from '../services/helpers/config.helpers';
+export class XosDebugModelController {
+ static $inject = [
+ 'ConfigHelpers'
+ ];
+
+ public debugFields: string[];
+
+ constructor(
+ private ConfigHelpers: IXosConfigHelpersService
+ ) {
+
+ }
+
+ $onInit() {
+ this.debugFields = this.ConfigHelpers.form_excluded_fields;
+ }
+
+ public toLabel(string: string): string {
+ return this.ConfigHelpers.toLabel(string);
+ }
+
+ // NOTE each field has his own format, so make it human readable
+ public parseField(fieldName: string, value: any): any {
+ switch (fieldName) {
+ case 'created':
+ case 'updated':
+ case 'enacted':
+ case 'policed':
+ return new Date(parseInt(value, 10) * 1000).toString();
+ case 'backend_register':
+ return JSON.parse(value);
+ case 'policy_status':
+ case 'backend_status':
+ return value
+ .split(' // ')
+ .join('\n');
+ default:
+ return value;
+ }
+ }
+}
+
+export const xosDebugModel: angular.IComponentOptions = {
+ template: require('./debug-model.html'),
+ controllerAs: 'vm',
+ controller: XosDebugModelController,
+ bindings: {
+ ngModel: '=',
+ }
+};
diff --git a/src/app/core/debug/debug.html b/src/app/core/debug/debug-summary.html
similarity index 81%
rename from src/app/core/debug/debug.html
rename to src/app/core/debug/debug-summary.html
index 2590708..9807ac9 100644
--- a/src/app/core/debug/debug.html
+++ b/src/app/core/debug/debug-summary.html
@@ -34,5 +34,12 @@
<i class="fa fa-remove text-danger" ng-hide="vm.debugStatus.events"></i>
</td>
</tr>
+ <tr>
+ <td>Models</td>
+ <td class="text-right">
+ <i class="fa fa-check text-success" ng-show="vm.debugStatus.modelsTab"></i>
+ <i class="fa fa-remove text-danger" ng-hide="vm.debugStatus.modelsTab"></i>
+ </td>
+ </tr>
</tbody>
</table>
\ No newline at end of file
diff --git a/src/app/core/debug/debug.ts b/src/app/core/debug/debug-summary.ts
similarity index 85%
rename from src/app/core/debug/debug.ts
rename to src/app/core/debug/debug-summary.ts
index fe5d178..f037080 100644
--- a/src/app/core/debug/debug.ts
+++ b/src/app/core/debug/debug-summary.ts
@@ -16,7 +16,7 @@
import {IXosDebugStatus, IXosDebugService} from './debug.service';
-class XosDebugComponentController {
+class XosDebugSummaryController {
static $inject = ['$scope', 'XosDebug'];
public debugStatus: IXosDebugStatus;
@@ -33,8 +33,8 @@
}
}
-export const xosDebugComponent: angular.IComponentOptions = {
- template: require('./debug.html'),
+export const xosDebugSummary: angular.IComponentOptions = {
+ template: require('./debug-summary.html'),
controllerAs: 'vm',
- controller: XosDebugComponentController
+ controller: XosDebugSummaryController
};
diff --git a/src/app/core/debug/debug.service.spec.ts b/src/app/core/debug/debug.service.spec.ts
index 0d27fa6..a26d8cc 100644
--- a/src/app/core/debug/debug.service.spec.ts
+++ b/src/app/core/debug/debug.service.spec.ts
@@ -56,16 +56,16 @@
it('should disable the global debug status', () => {
spyOn(window.localStorage, 'getItem')
.and.returnValue('true');
- service.toggleGlobalDebug();
- expect(window.localStorage.setItem).toHaveBeenCalledWith('debug', 'false');
+ service.toggleDebug('global');
+ expect(window.localStorage.setItem).toHaveBeenCalledWith('debug-global', 'false');
expect(service.status.global).toBeFalsy();
expect($scope.$broadcast).toHaveBeenCalledWith('xos.debug.status', service.status);
});
it('should enable the global debug status', () => {
spyOn(window.localStorage, 'getItem')
.and.returnValue('false');
- service.toggleGlobalDebug();
- expect(window.localStorage.setItem).toHaveBeenCalledWith('debug', 'true');
+ service.toggleDebug('global');
+ expect(window.localStorage.setItem).toHaveBeenCalledWith('debug-global', 'true');
expect(service.status.global).toBeTruthy();
expect($scope.$broadcast).toHaveBeenCalledWith('xos.debug.status', service.status);
});
diff --git a/src/app/core/debug/debug.service.ts b/src/app/core/debug/debug.service.ts
index 3c6c2c8..f23fa06 100644
--- a/src/app/core/debug/debug.service.ts
+++ b/src/app/core/debug/debug.service.ts
@@ -19,13 +19,13 @@
export interface IXosDebugStatus {
global: boolean;
events: boolean;
+ modelsTab: boolean;
}
export interface IXosDebugService {
status: IXosDebugStatus;
setupShortcuts(): void;
- toggleGlobalDebug(): void;
- toggleEventDebug(): void;
+ toggleDebug(type: 'global' | 'events' | 'modelsTab'): void;
}
export class XosDebugService implements IXosDebugService {
@@ -34,7 +34,8 @@
public status: IXosDebugStatus = {
global: false,
- events: false
+ events: false,
+ modelsTab: false
};
constructor (
@@ -42,51 +43,40 @@
private $scope: ng.IScope,
private XosKeyboardShortcut: IXosKeyboardShortcutService
) {
- const debug = window.localStorage.getItem('debug');
+ const debug = window.localStorage.getItem('debug-global');
this.status.global = (debug === 'true');
- const debugEvent = window.localStorage.getItem('debug-event');
+ const debugEvent = window.localStorage.getItem('debug-events');
this.status.events = (debugEvent === 'true');
+
+ const debugModelsTab = window.localStorage.getItem('debug-modelsTab');
+ this.status.modelsTab = (debugModelsTab === 'true');
}
public setupShortcuts(): void {
this.XosKeyboardShortcut.registerKeyBinding({
key: 'D',
- cb: () => this.toggleGlobalDebug(),
+ cb: () => this.toggleDebug('global'),
description: 'Toggle debug messages in browser console'
}, 'global');
this.XosKeyboardShortcut.registerKeyBinding({
key: 'E',
- cb: () => this.toggleEventDebug(),
+ cb: () => this.toggleDebug('events'),
description: 'Toggle debug messages for WS events in browser console'
}, 'global');
}
- public toggleGlobalDebug(): void {
- if (window.localStorage.getItem('debug') === 'true') {
- this.$log.info(`[XosDebug] Disabling debug`);
- window.localStorage.setItem('debug', 'false');
- this.status.global = false;
+ public toggleDebug(type: 'global' | 'events' | 'modelsTab'): void {
+ if (window.localStorage.getItem(`debug-${type}`) === 'true') {
+ this.$log.info(`[XosDebug] Disabling ${type} debug`);
+ window.localStorage.setItem(`debug-${type}`, 'false');
+ this.status[type] = false;
}
else {
- window.localStorage.setItem('debug', 'true');
- this.$log.info(`[XosDebug] Enabling debug`);
- this.status.global = true;
- }
- this.$scope.$broadcast('xos.debug.status', this.status);
- }
-
- public toggleEventDebug(): void {
- if (window.localStorage.getItem('debug-event') === 'true') {
- this.$log.info(`[XosDebug] Disabling debug for WS events`);
- window.localStorage.setItem('debug-event', 'false');
- this.status.events = false;
- }
- else {
- window.localStorage.setItem('debug-event', 'true');
- this.$log.info(`[XosDebug] Enabling debug for WS events`);
- this.status.events = true;
+ this.$log.info(`[XosDebug] Enabling ${type} debug`);
+ window.localStorage.setItem(`debug-${type}`, 'true');
+ this.status[type] = true;
}
this.$scope.$broadcast('xos.debug.status', this.status);
}
diff --git a/src/app/core/index.ts b/src/app/core/index.ts
index 0172223..523bae6 100644
--- a/src/app/core/index.ts
+++ b/src/app/core/index.ts
@@ -43,8 +43,9 @@
import {XosDebouncer} from './services/helpers/debounce.helper';
import {ArrayToListFilter} from './table/array-to-list.filter';
import {xosLoader} from './loader/loader';
-import {xosDebugComponent} from './debug/debug';
+import {xosDebugSummary} from './debug/debug-summary';
import {XosDebugService} from './debug/debug.service';
+import {xosDebugModel} from './debug/debug-model';
export const xosCore = 'xosCore';
@@ -80,6 +81,7 @@
.component('xosValidation', xosValidation)
.component('xosSidePanel', xosSidePanel)
.component('xosKeyBindingPanel', xosKeyBindingPanel)
- .component('xosDebug', xosDebugComponent)
+ .component('xosDebugSummary', xosDebugSummary)
+ .component('xosDebugModel', xosDebugModel)
.filter('pagination', PaginationFilter)
.filter('arrayToList', ArrayToListFilter);
diff --git a/src/app/core/key-binding/key-binding-panel.html b/src/app/core/key-binding/key-binding-panel.html
index df26318..ed198fd 100644
--- a/src/app/core/key-binding/key-binding-panel.html
+++ b/src/app/core/key-binding/key-binding-panel.html
@@ -49,6 +49,6 @@
</div>
<div class="row">
<div class="col-xs-12">
- <xos-debug></xos-debug>
+ <xos-debug-summary></xos-debug-summary>
</div>
</div>
\ No newline at end of file
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index 81901e3..c177568 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -45,6 +45,7 @@
export interface IXosConfigHelpersService {
excluded_fields: string[];
+ form_excluded_fields: string[];
modelFieldsToColumnsCfg(model: IXosModeldef): IXosTableColumn[];
modelToTableCfg(model: IXosModeldef, modelName: string): IXosTableCfg;
modelFieldToInputCfg(fields: IXosModelDefsField[]): IXosFormInput[];
diff --git a/src/app/core/services/keyboard-shortcut.spec.ts b/src/app/core/services/keyboard-shortcut.spec.ts
index a4a15dd..fa9bf41 100644
--- a/src/app/core/services/keyboard-shortcut.spec.ts
+++ b/src/app/core/services/keyboard-shortcut.spec.ts
@@ -157,7 +157,8 @@
global: [
{
key: 'a',
- cb: 'cb'
+ cb: 'cb',
+ modifiers: undefined
}
],
view: []
diff --git a/src/app/core/services/keyboard-shortcut.ts b/src/app/core/services/keyboard-shortcut.ts
index 72a59a5..b8678f7 100644
--- a/src/app/core/services/keyboard-shortcut.ts
+++ b/src/app/core/services/keyboard-shortcut.ts
@@ -102,7 +102,6 @@
$('body').on('keydown', (e) => {
const pressedKey = this.whatKey(e.which);
-
if (!pressedKey) {
return;
}
@@ -141,7 +140,7 @@
}
binding.key = binding.key.toLowerCase();
- if (_.find(this.keyMapping.global, {key: binding.key}) || _.find(this.keyMapping.view, {key: binding.key})) {
+ if (_.find(this.keyMapping.global, {key: binding.key, modifiers: binding.modifiers}) || _.find(this.keyMapping.view, {key: binding.key, modifiers: binding.modifiers})) {
this.$log.warn(`[XosKeyboardShortcut] A shortcut for key "${binding.key}" has already been registered`);
return;
}
diff --git a/src/app/core/table/table.html b/src/app/core/table/table.html
index b8fe9f4..b7aaa96 100644
--- a/src/app/core/table/table.html
+++ b/src/app/core/table/table.html
@@ -14,8 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
<div ng-show="vm.data.length > 0 && vm.loader == false">
<div class="row" ng-if="vm.config.filter == 'fulltext'">
<div class="col-xs-12">
@@ -66,7 +64,7 @@
</tr>
</tbody>
<tbody>
- <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">
+ <tr ng-class="{active: vm.config.selectedRow == $index}" ng-repeat="item in (vm.config.filteredData = (vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length))) track by $index">
<td ng-repeat="col in vm.config.columns" xos-link-wrapper>
<span ng-if="!col.type || col.type === 'text'">{{item[col.prop]}}</span>
<span ng-if="col.type === 'boolean'">
diff --git a/src/app/core/table/table.scss b/src/app/core/table/table.scss
index 1189a9f..b20895b 100644
--- a/src/app/core/table/table.scss
+++ b/src/app/core/table/table.scss
@@ -56,5 +56,4 @@
margin-left: $padding-base-horizontal;
}
}
-
}
\ No newline at end of file
diff --git a/src/app/core/table/table.ts b/src/app/core/table/table.ts
index 46a5ca5..6c8d95c 100644
--- a/src/app/core/table/table.ts
+++ b/src/app/core/table/table.ts
@@ -52,6 +52,8 @@
};
order?: IXosTableCgfOrder;
filter?: string;
+ selectedRow?: number;
+ filteredData?: any[];
actions?: any[]; // TODO create interface
}
@@ -145,8 +147,6 @@
this.currentPage = 0;
}
- // this.columns = this.config.columns;
-
}
public goToPage = (n) => {