Merge "add overriding state to navigation"
diff --git a/generator-xos-gui-extension/.gitignore b/generator-xos-gui-extension/.gitignore
new file mode 100644
index 0000000..9ba488b
--- /dev/null
+++ b/generator-xos-gui-extension/.gitignore
@@ -0,0 +1,2 @@
+*.DS_Store
+node_modules/
diff --git a/generator-xos-gui-extension/generators/README.md b/generator-xos-gui-extension/generators/README.md
new file mode 100644
index 0000000..c13ead2
--- /dev/null
+++ b/generator-xos-gui-extension/generators/README.md
@@ -0,0 +1,11 @@
+#generator-xos-gui-extension
+
+## About
+This is a Yeoman generator intended to aid with the development of new XOS GUI Extensions. It generates a new GUI extension
+with only one component.
+
+## Installation
+Run the following command in this directory and follow the prompts.
+```
+yo xos-gui-extension
+```
\ No newline at end of file
diff --git a/generator-xos-gui-extension/generators/index.js b/generator-xos-gui-extension/generators/index.js
new file mode 100644
index 0000000..aecfda2
--- /dev/null
+++ b/generator-xos-gui-extension/generators/index.js
@@ -0,0 +1,136 @@
+
+/*
+ * 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.
+ */
+
+'use strict';
+
+var Generator = require('yeoman-generator');
+var Path = require('path');
+
+var extensionName, extensionFolder;
+
+module.exports = Generator.extend({
+
+ prompting: {
+
+ init() {
+ this.log('---------------------------');
+ this.log('XOS GUI Extension Generator');
+ this.log('---------------------------');
+ },
+
+ name() {
+ var done = this.async();
+ this.log(`Your extension will be created in the current working directory, ${this.destinationRoot()}`);
+ this.prompt({
+ type: 'input',
+ name: 'name',
+ message: 'Enter the name of your XOS GUI Extension',
+ default: 'new-gui-extension',
+ filter: (str) => {
+ var newstr = str.replace(' ', '-');
+ return newstr;
+ }
+ }).then((answers) => {
+ extensionName = answers.name;
+ done();
+ });
+ },
+ },
+
+ writing: {
+
+ noTmplRoot() {
+ this.log('Creating non-templated files in the extension root...');
+ this.fs.copy(this.templatePath('.dockerignore'), this.destinationPath(`${extensionName}/.dockerignore`));
+ this.fs.copy(this.templatePath('.gitignore'), this.destinationPath(`${extensionName}/.gitignore`));
+ this.fs.copy(this.templatePath('Dockerfile'), this.destinationPath(`${extensionName}/Dockerfile`));
+ this.fs.copy(this.templatePath('gulpfile.js'), this.destinationPath(`${extensionName}/gulpfile.js`));
+ this.fs.copy(this.templatePath('package.json'), this.destinationPath(`${extensionName}/package.json`));
+ this.fs.copy(this.templatePath('tsconfig.json'), this.destinationPath(`${extensionName}/tsconfig.json`));
+ this.fs.copy(this.templatePath('tslint.json'), this.destinationPath(`${extensionName}/tslint.json`));
+ this.fs.copy(this.templatePath('typings.json'), this.destinationPath(`${extensionName}/typings.json`));
+ },
+
+ tmplRoot() {
+ this.log('Creating templated files in the extension root...');
+ this.fs.copyTpl(
+ this.templatePath('README.md'),
+ this.destinationPath(`${extensionName}/README.md`),
+ {
+ name: extensionName
+ });
+ this.fs.copyTpl(
+ this.templatePath('xos-sample-gui-extension.yaml'),
+ this.destinationPath(`${extensionName}/${extensionName}.yml`),
+ {
+ name: extensionName
+ });
+ this.fs.copyTpl(
+ this.templatePath('Dockerfile'),
+ this.destinationPath(`${extensionName}/Dockerfile`),
+ {
+ name: extensionName
+ });
+ },
+
+ conf() {
+ this.log('Creating conf...');
+ this.fs.copyTpl(
+ this.templatePath('conf'),
+ this.destinationPath(`${extensionName}/conf`),
+ {
+ name: extensionName
+ });
+ },
+
+ gulp() {
+ this.log('Creating gulp_tasks...');
+ this.fs.copy(this.templatePath('gulp_tasks'), this.destinationPath(`${extensionName}/gulp_tasks`));
+ },
+
+ src() {
+ this.log('Creating src...');
+ this.fs.copyTpl(
+ this.templatePath('src'),
+ this.destinationPath(`${extensionName}/src`),
+ {
+ name: extensionName
+ });
+ }
+ },
+
+ install (){
+ var done = this.async();
+ this.prompt({
+ type: 'confirm',
+ name: 'deps',
+ message: 'Install dependencies?',
+ default: false
+ }).then((answers) => {
+ if(answers.deps){
+ process.chdir(`${extensionName}/`);
+ this.installDependencies({
+ npm: true,
+ bower: false,
+ yarn: false
+ });
+ }
+ done();
+ });
+ }
+
+});
diff --git a/generator-xos-gui-extension/generators/templates/.dockerignore b/generator-xos-gui-extension/generators/templates/.dockerignore
new file mode 100644
index 0000000..de807ff
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/.dockerignore
@@ -0,0 +1,3 @@
+node_modules
+typings
+npm-debug.log
\ No newline at end of file
diff --git a/generator-xos-gui-extension/generators/templates/.gitignore b/generator-xos-gui-extension/generators/templates/.gitignore
new file mode 100644
index 0000000..217665e
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/.gitignore
@@ -0,0 +1,6 @@
+node_modules/
+dist/
+.tmp/
+.idea/
+*.DS_Store
+typings/
diff --git a/generator-xos-gui-extension/generators/templates/Dockerfile b/generator-xos-gui-extension/generators/templates/Dockerfile
new file mode 100644
index 0000000..9670776
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/Dockerfile
@@ -0,0 +1,49 @@
+# <%= name %>
+FROM xosproject/xos-gui-extension-builder:candidate
+
+# Set environment vars
+ENV CODE_SOURCE .
+ENV CODE_DEST /var/www
+ENV VHOST /var/www/dist
+
+# Add the app deps
+COPY ${CODE_SOURCE}/package.json ${CODE_DEST}/package.json
+COPY ${CODE_SOURCE}/typings.json ${CODE_DEST}/typings.json
+
+# Install Deps
+WORKDIR ${CODE_DEST}
+RUN npm install
+RUN npm run typings
+
+# Build the app
+COPY ${CODE_SOURCE}/conf ${CODE_DEST}/conf
+COPY ${CODE_SOURCE}/gulp_tasks ${CODE_DEST}/gulp_tasks
+COPY ${CODE_SOURCE}/src ${CODE_DEST}/src
+COPY ${CODE_SOURCE}/gulpfile.js ${CODE_DEST}/gulpfile.js
+COPY ${CODE_SOURCE}/tsconfig.json ${CODE_DEST}/tsconfig.json
+COPY ${CODE_SOURCE}/tslint.json ${CODE_DEST}/tslint.json
+
+# Label image
+ARG org_label_schema_schema_version=1.0
+ARG org_label_schema_name=xos-tosca
+ARG org_label_schema_version=unknown
+ARG org_label_schema_vcs_url=unknown
+ARG org_label_schema_vcs_ref=unknown
+ARG org_label_schema_build_date=unknown
+ARG org_opencord_vcs_commit_date=unknown
+ARG org_opencord_component_xos_gui_vcs_ref=unknown
+ARG org_opencord_component_xos_gui_vcs_url=unknown
+ARG org_opencord_component_xos_gui_version=unknown
+
+LABEL org.label-schema.schema-version=$org_label_schema_schema_version \
+ org.label-schema.name=$org_label_schema_name \
+ org.label-schema.version=$org_label_schema_version \
+ org.label-schema.vcs-url=$org_label_schema_vcs_url \
+ org.label-schema.vcs-ref=$org_label_schema_vcs_ref \
+ org.label-schema.build-date=$org_label_schema_build_date \
+ org.opencord.vcs-commit-date=$org_opencord_vcs_commit_date \
+ org.opencord.component.xos-gui.vcs-ref=$org_opencord_component_xos_gui_vcs_ref \
+ org.opencord.component.xos-gui.vcs-url=$org_opencord_component_xos_gui_vcs_url \
+ org.opencord.component.xos-gui.version=$org_opencord_component_xos_gui_version
+
+RUN npm run build
diff --git a/generator-xos-gui-extension/generators/templates/README.md b/generator-xos-gui-extension/generators/templates/README.md
new file mode 100644
index 0000000..a2263bb
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/README.md
@@ -0,0 +1,105 @@
+# <%= name %>
+
+This is a temporary README included with the creation of your extension intended to help guide development. Feel free to
+overrwite with your own changes.
+
+If you chose to install dependencies during setup, you can run `npm start` to view the extension in your web browser,
+other wise run `npm install` before `npm start`.
+
+## Installation with platform-install
+
+To install an extension, add the following to the profile manifest `.yml` file intended to be deployed in`build/platform-install/`
+, and deploy with `ansible-playbook -i inventory/{PROFILE_NAME} deploy-xos-playbook.yml`
+
+```
+enabled_gui_extensions:
+ - name: <%= name %>
+ path: orchestration/<%= name %>
+```
+
+_NOTE: the `name` field must match the subdirectory specified in `conf/app/gulp.conf.js` (eg: `dist/extensions/<%= name %>`)_
+
+## Development Tips
+
+### Including Extra Files
+
+Additional necessary files (such as stylesheets or config files) can be added to the profile manifest as follows, with `<%= name %>/src/` as the root.
+
+```yaml
+enabled_gui_extensions:
+ - name: <%= name %>
+ path: orchestration/<%= name %>
+ extra_files:
+ - app/style/style.css
+```
+
+### Generating config files
+
+During development, you may find it necessary to create separate config files in order to include other files used in
+your extension (such as images). The path to your extension may vary depending on whether you are running it locally
+(`./xos/extensions/extension-name`) vs. on a container in production (`./extensions/extension-name`).
+
+You can create separate `customconfig.local.js` and `customconfig.production.js` files in the `conf/` folder, and then edit the
+following portion of the appropriate `webpack.conf.js` file as follows:
+
+```js
+new CopyWebpackPlugin([
+ { from: `./conf/app/app.config.${env}.js`, to: `app.config.js` },
+ { from: `./conf/app/style.config.${brand}.js`, to: `style.config.js` },
+ // add your file here
+ { from: `./conf/app/customconfig.local.js`, to: `customconfig.js`}
+ ])
+```
+
+`webpack.conf.js` will be used in a local development environment, such as when running `npm start`
+
+`webpack-dist.conf.js` will be used in a production container after deploying a profile.
+
+### Handy XOS Components and Services
+
+#### XosNavigationService
+Used to create custom navigation links in the left navigation panel.
+
+#### XosModelStore
+Provides easy access to model ngResources provided by an XOS service. Can be used as follows:
+
+```typescript
+import {Subscription} from 'rxjs/Subscription';
+export class ExampleComponent {
+ static $inject = ['XosModelStore'];
+ public resource;
+ private modelSubscription : Subscription;
+ constructor(
+ private XosModelStore: any,
+ ){}
+
+ $onInit() {
+ this.modelSubscription = this.XosModelStore.query('SampleModel', '/sampleservice/SampleModels').subscribe(
+ res => {
+ this.resource = res;
+ }
+ );
+ }
+}
+export const exampleComponent : angular.IComponentOptions = {
+ template: require('./example.component.html'),
+ controllerAs: 'vm',
+ controller: ExampleComponent
+}
+```
+
+#### XosKeyboardShortcut
+Allows for the creation of custom user keyboard shortcuts. See the provided `components/demo.ts` as an example.
+
+#### XosComponentInjector
+Allows for the injection of components into the XOS GUI by specifying a target element ID. Useful IDs include:
+* `#dashboard-component-container`: the dashboard as seen on the XOS home
+* `#side-panel-container`: a side panel that can slide out from the right. However, there is also a `XosSidePanel`
+service that can make development easier.
+
+#### XosSidePanel
+Makes the injection of a custom side panel somewhat easier (no need to specify a target)
+
+#### XosConfirm
+Allows for the creation of confirmation modal dialogs to confirm whether or not to execute a selected action.
+
diff --git a/generator-xos-gui-extension/generators/templates/conf/app/README.md b/generator-xos-gui-extension/generators/templates/conf/app/README.md
new file mode 100755
index 0000000..6c45737
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/app/README.md
@@ -0,0 +1,45 @@
+# XOS-GUI Config
+
+### Note: The configurations defined in this folder are for development only, they are most likely to be overridden by a volume mount defined in `service-profile`
+
+## App Config
+
+This configuration will specify the REST API base URL and the WebSocket address.
+
+```
+angular.module('app')
+ .constant('AppConfig', {
+ apiEndpoint: '/xos/api',
+ websocketClient: '/'
+ });
+
+```
+
+## Style Config
+
+This configuration will contain branding information, such as title, logo and navigation items.
+
+```
+angular.module('app')
+ .constant('StyleConfig', {
+ projectName: 'CORD',
+ favicon: 'cord-favicon.png',
+ background: 'cord-bg.jpg',
+ payoff: 'Your VNF orchestrator',
+ logo: 'cord-logo.png',
+ routes: [
+ {
+ label: 'Slices',
+ state: 'xos.core.slices'
+ },
+ {
+ label: 'Instances',
+ state: 'xos.core.instances'
+ },
+ {
+ label: 'Nodes',
+ state: 'xos.core.nodes'
+ }
+ ]
+});
+```
\ No newline at end of file
diff --git a/generator-xos-gui-extension/generators/templates/conf/app/app.config.dev.js b/generator-xos-gui-extension/generators/templates/conf/app/app.config.dev.js
new file mode 100755
index 0000000..4872661
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/app/app.config.dev.js
@@ -0,0 +1,23 @@
+
+/*
+ * 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.
+ */
+
+
+angular.module('app')
+ .constant('AppConfig', {
+ apiEndpoint: 'http://xos.dev:3000/api',
+ websocketClient: 'http://xos.dev:3000'
+ });
diff --git a/generator-xos-gui-extension/generators/templates/conf/app/app.config.production.js b/generator-xos-gui-extension/generators/templates/conf/app/app.config.production.js
new file mode 100755
index 0000000..de6179f
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/app/app.config.production.js
@@ -0,0 +1,23 @@
+
+/*
+ * 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.
+ */
+
+
+angular.module('app')
+ .constant('AppConfig', {
+ apiEndpoint: '/xos/api',
+ websocketClient: '/'
+ });
diff --git a/generator-xos-gui-extension/generators/templates/conf/app/app.config.test.js b/generator-xos-gui-extension/generators/templates/conf/app/app.config.test.js
new file mode 100755
index 0000000..37034fb
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/app/app.config.test.js
@@ -0,0 +1,23 @@
+
+/*
+ * 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.
+ */
+
+
+angular.module('app')
+ .constant('AppConfig', {
+ apiEndpoint: 'http://xos-test:3000/api',
+ websocketClient: 'http://xos-test:3000'
+ });
diff --git a/generator-xos-gui-extension/generators/templates/conf/app/style.config.cord.js b/generator-xos-gui-extension/generators/templates/conf/app/style.config.cord.js
new file mode 100755
index 0000000..022938b
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/app/style.config.cord.js
@@ -0,0 +1,40 @@
+
+/*
+ * 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.
+ */
+
+
+angular.module('app')
+ .constant('StyleConfig', {
+ projectName: 'CORD',
+ favicon: 'cord-favicon.png',
+ background: 'cord-bg.jpg',
+ payoff: 'Your VNF orchestrator',
+ logo: 'cord-logo.png',
+ routes: [
+ {
+ label: 'Slices',
+ state: 'xos.core.slices'
+ },
+ {
+ label: 'Instances',
+ state: 'xos.core.instances'
+ },
+ {
+ label: 'Nodes',
+ state: 'xos.core.nodes'
+ }
+ ]
+});
diff --git a/generator-xos-gui-extension/generators/templates/conf/app/style.config.opencloud.js b/generator-xos-gui-extension/generators/templates/conf/app/style.config.opencloud.js
new file mode 100755
index 0000000..2c1776e
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/app/style.config.opencloud.js
@@ -0,0 +1,32 @@
+
+/*
+ * 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.
+ */
+
+
+angular.module('app')
+ .constant('StyleConfig', {
+ projectName: 'OpenCloud',
+ favicon: 'opencloud-favicon.png',
+ background: 'opencloud-bg.jpg',
+ payoff: 'Your OS resource manager',
+ logo: 'opencloud-logo.png',
+ routes: [
+ {
+ label: 'Slices',
+ state: 'xos.core.slices'
+ }
+ ]
+});
diff --git a/generator-xos-gui-extension/generators/templates/conf/browsersync-dist.conf.js b/generator-xos-gui-extension/generators/templates/conf/browsersync-dist.conf.js
new file mode 100755
index 0000000..704b46c
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/browsersync-dist.conf.js
@@ -0,0 +1,30 @@
+
+/*
+ * 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.
+ */
+
+
+const conf = require('./gulp.conf');
+
+module.exports = function () {
+ return {
+ server: {
+ baseDir: [
+ conf.paths.dist
+ ]
+ },
+ open: false
+ };
+};
diff --git a/generator-xos-gui-extension/generators/templates/conf/browsersync.conf.js b/generator-xos-gui-extension/generators/templates/conf/browsersync.conf.js
new file mode 100755
index 0000000..7e3fbc2
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/browsersync.conf.js
@@ -0,0 +1,40 @@
+
+/*
+ * 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.
+ */
+
+
+const conf = require('./gulp.conf');
+const proxy = require('./proxy');
+
+module.exports = function () {
+ return {
+ server: {
+ baseDir: [
+ conf.paths.tmp,
+ conf.paths.src
+ ],
+ middleware: function (req, res, next) {
+ if (req.url.indexOf('xosapi') !== -1 || req.url.indexOf('xos') !== -1 || req.url.indexOf('socket') !== -1) {
+ proxy.api.web(req, res);
+ }
+ else {
+ next();
+ }
+ }
+ },
+ open: false
+ };
+};
diff --git a/generator-xos-gui-extension/generators/templates/conf/gulp.conf.js b/generator-xos-gui-extension/generators/templates/conf/gulp.conf.js
new file mode 100755
index 0000000..87b6849
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/gulp.conf.js
@@ -0,0 +1,66 @@
+
+/*
+ * 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.
+ */
+
+
+'use strict';
+
+/**
+ * This file contains the variables used in other gulp files
+ * which defines tasks
+ * By design, we only put there very generic config values
+ * which are used in several places to keep good readability
+ * of the tasks
+ */
+
+const path = require('path');
+const gutil = require('gulp-util');
+
+exports.ngModule = 'app';
+
+/**
+ * The main paths of your project handle these with care
+ */
+exports.paths = {
+ src: 'src',
+ dist: 'dist/extensions/<%= name %>',
+ appConfig: 'conf/app',
+ tmp: '.tmp',
+ e2e: 'e2e',
+ tasks: 'gulp_tasks'
+};
+
+exports.path = {};
+for (const pathName in exports.paths) {
+ if (exports.paths.hasOwnProperty(pathName)) {
+ exports.path[pathName] = function pathJoin() {
+ const pathValue = exports.paths[pathName];
+ const funcArgs = Array.prototype.slice.call(arguments);
+ const joinArgs = [pathValue].concat(funcArgs);
+ return path.join.apply(this, joinArgs);
+ };
+ }
+}
+
+/**
+ * Common implementation for an error handler of a Gulp plugin
+ */
+exports.errorHandler = function (title) {
+ return function (err) {
+ gutil.log(gutil.colors.red(`[${title}]`), err.toString());
+ this.emit('end');
+ };
+};
diff --git a/generator-xos-gui-extension/generators/templates/conf/karma-auto.conf.js b/generator-xos-gui-extension/generators/templates/conf/karma-auto.conf.js
new file mode 100755
index 0000000..f4ce829
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/karma-auto.conf.js
@@ -0,0 +1,79 @@
+
+/*
+ * 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.
+ */
+
+
+const conf = require('./gulp.conf');
+const pkg = require('../package.json');
+
+module.exports = function (config) {
+ const configuration = {
+ basePath: '../',
+ singleRun: false,
+ autoWatch: true,
+ logLevel: 'INFO',
+ junitReporter: {
+ outputDir: 'test-reports'
+ },
+ browsers: [
+ 'PhantomJS',
+ // 'Chrome'
+ ],
+ frameworks: [
+ 'jasmine',
+ 'es6-shim'
+ ],
+ files: [
+ 'node_modules/es6-shim/es6-shim.js',
+ conf.path.src('index.spec.js'),
+ conf.path.src('**/*.html')
+ ],
+ preprocessors: {
+ [conf.path.src('index.spec.js')]: [
+ 'webpack'
+ ],
+ [conf.path.src('**/*.html')]: [
+ 'ng-html2js'
+ ]
+ },
+ ngHtml2JsPreprocessor: {
+ stripPrefix: `${conf.paths.src}/`
+ },
+ reporters: ['mocha', 'coverage'],
+ coverageReporter: {
+ type: 'html',
+ dir: 'coverage/'
+ },
+ webpack: require('./webpack-test.conf'),
+ webpackMiddleware: {
+ noInfo: true
+ },
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-junit-reporter'),
+ require('karma-coverage'),
+ require('karma-phantomjs-launcher'),
+ require('karma-chrome-launcher'),
+ require('karma-phantomjs-shim'),
+ require('karma-ng-html2js-preprocessor'),
+ require('karma-webpack'),
+ require('karma-es6-shim'),
+ require('karma-mocha-reporter')
+ ]
+ };
+
+ config.set(configuration);
+};
diff --git a/generator-xos-gui-extension/generators/templates/conf/karma.conf.js b/generator-xos-gui-extension/generators/templates/conf/karma.conf.js
new file mode 100755
index 0000000..c8bc5f5
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/karma.conf.js
@@ -0,0 +1,75 @@
+
+/*
+ * 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.
+ */
+
+
+const conf = require('./gulp.conf');
+
+module.exports = function (config) {
+ const configuration = {
+ basePath: '../',
+ singleRun: true,
+ autoWatch: false,
+ logLevel: 'INFO',
+ junitReporter: {
+ outputDir: 'test-reports'
+ },
+ browsers: [
+ 'PhantomJS'
+ ],
+ frameworks: [
+ 'jasmine',
+ 'es6-shim'
+ ],
+ files: [
+ 'node_modules/es6-shim/es6-shim.js',
+ conf.path.src('index.spec.js'),
+ conf.path.src('**/*.html')
+ ],
+ preprocessors: {
+ [conf.path.src('index.spec.js')]: [
+ 'webpack'
+ ],
+ [conf.path.src('**/*.html')]: [
+ 'ng-html2js'
+ ]
+ },
+ ngHtml2JsPreprocessor: {
+ stripPrefix: `${conf.paths.src}/`
+ },
+ reporters: ['progress', 'coverage'],
+ coverageReporter: {
+ type: 'html',
+ dir: 'coverage/'
+ },
+ webpack: require('./webpack-test.conf'),
+ webpackMiddleware: {
+ noInfo: true
+ },
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-junit-reporter'),
+ require('karma-coverage'),
+ require('karma-phantomjs-launcher'),
+ require('karma-phantomjs-shim'),
+ require('karma-ng-html2js-preprocessor'),
+ require('karma-webpack'),
+ require('karma-es6-shim')
+ ]
+ };
+
+ config.set(configuration);
+};
diff --git a/generator-xos-gui-extension/generators/templates/conf/proxy.js b/generator-xos-gui-extension/generators/templates/conf/proxy.js
new file mode 100644
index 0000000..ab11963
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/proxy.js
@@ -0,0 +1,36 @@
+
+/*
+ * 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.
+ */
+
+
+const httpProxy = require('http-proxy');
+
+const target = process.env.PROXY || '192.168.46.100';
+
+const apiProxy = httpProxy.createProxyServer({
+ target: `http://${target}`
+});
+
+apiProxy.on('error', (error, req, res) => {
+ res.writeHead(500, {
+ 'Content-Type': 'text/plain'
+ });
+ console.error('[Proxy]', error);
+});
+
+module.exports = {
+ api: apiProxy
+};
diff --git a/generator-xos-gui-extension/generators/templates/conf/webpack-dist.conf.js b/generator-xos-gui-extension/generators/templates/conf/webpack-dist.conf.js
new file mode 100755
index 0000000..c870043
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/webpack-dist.conf.js
@@ -0,0 +1,121 @@
+
+/*
+ * 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.
+ */
+
+
+const webpack = require('webpack');
+const conf = require('./gulp.conf');
+const path = require('path');
+
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const ExtractTextPlugin = require('extract-text-webpack-plugin');
+const pkg = require('../package.json');
+const autoprefixer = require('autoprefixer');
+const BaseHrefWebpackPlugin = require('base-href-webpack-plugin').BaseHrefWebpackPlugin;
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+const env = process.env.NODE_ENV || 'production';
+const brand = process.env.BRAND || 'cord';
+
+module.exports = {
+ module: {
+ loaders: [
+ {
+ test: /.json$/,
+ loaders: [
+ 'json'
+ ]
+ },
+ {
+ test: /\.(css|scss)$/,
+ loaders: ExtractTextPlugin.extract({
+ fallbackLoader: 'style',
+ loader: 'css?minimize!sass!postcss'
+ })
+ },
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ loaders: [
+ 'ng-annotate',
+ 'ts'
+ ]
+ },
+ {
+ test: /.html$/,
+ loaders: [
+ 'html?' + JSON.stringify({
+ attrs: ["img:src", "img:ng-src"]
+ })
+ ]
+ },
+ {
+ test: /\.(png|woff|woff2|eot|ttf|svg|jpg|gif|jpeg)$/,
+ loader: 'url-loader?limit=100000'
+ }
+ ]
+ },
+ plugins: [
+ new CopyWebpackPlugin([
+ { from: `./conf/app/app.config.${env}.js`, to: `app.config.js` },
+ { from: `./conf/app/style.config.${brand}.js`, to: `style.config.js` },
+ ]),
+ new webpack.optimize.OccurrenceOrderPlugin(),
+ new webpack.NoErrorsPlugin(),
+ new HtmlWebpackPlugin({
+ inject: true,
+ template: conf.path.src('index.html')
+ }),
+ new webpack.optimize.UglifyJsPlugin({
+ compress: {unused: true, dead_code: true, warnings: false}, // eslint-disable-line camelcase
+ mangle: false // NOTE mangling was breaking the build
+ }),
+ new ExtractTextPlugin('index-[contenthash].css'),
+ new webpack.optimize.CommonsChunkPlugin({name: 'vendor'}),
+ new webpack.ProvidePlugin({
+ $: "jquery",
+ jQuery: "jquery"
+ }),
+ new BaseHrefWebpackPlugin({
+ baseHref: '/spa/'
+ }),
+ ],
+ postcss: () => [autoprefixer],
+ output: {
+ path: path.join(process.cwd(), conf.paths.dist),
+ publicPath: "/xos/", // enable apache proxying on the head node
+ filename: '[name].js'
+ },
+ resolve: {
+ extensions: [
+ '',
+ '.webpack.js',
+ '.web.js',
+ '.js',
+ '.ts'
+ ]
+ },
+ entry: {
+ app: `./${conf.path.src('index')}`,
+ vendor: Object.keys(pkg.dependencies)
+ },
+ ts: {
+ configFileName: 'tsconfig.json'
+ },
+ tslint: {
+ configuration: require('../tslint.json')
+ }
+};
+
diff --git a/generator-xos-gui-extension/generators/templates/conf/webpack-test.conf.js b/generator-xos-gui-extension/generators/templates/conf/webpack-test.conf.js
new file mode 100755
index 0000000..c0115ab
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/webpack-test.conf.js
@@ -0,0 +1,84 @@
+
+/*
+ * 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.
+ */
+
+
+module.exports = {
+ module: {
+ preLoaders: [
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ loader: 'tslint'
+ }
+ ],
+ loaders: [
+ {
+ test: /.json$/,
+ loaders: [
+ 'json'
+ ]
+ },
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ loaders: [
+ 'ng-annotate',
+ 'ts'
+ ]
+ },
+ {
+ test: /.html$/,
+ loaders: [
+ 'html?' + JSON.stringify({
+ attrs: ["img:src", "img:ng-src"]
+ })
+ ]
+ },
+ {
+ test: /\.(css|scss)$/,
+ loaders: [
+ 'style',
+ 'css',
+ 'sass',
+ 'postcss'
+ ]
+ },
+ {
+ test: /\.(png|woff|woff2|eot|ttf|svg|jpg|gif|jpeg)$/,
+ loader: 'url-loader?limit=100000'
+ }
+ ]
+ },
+ plugins: [],
+ debug: true,
+ devtool: 'source-map',
+ resolve: {
+ extensions: [
+ '',
+ '.webpack.js',
+ '.web.js',
+ '.js',
+ '.ts'
+ ]
+ },
+ ts: {
+ configFileName: 'tsconfig.json'
+ },
+ tslint: {
+ configuration: require('../tslint.json')
+ }
+};
diff --git a/generator-xos-gui-extension/generators/templates/conf/webpack.conf.js b/generator-xos-gui-extension/generators/templates/conf/webpack.conf.js
new file mode 100755
index 0000000..d70e771
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/conf/webpack.conf.js
@@ -0,0 +1,117 @@
+
+/*
+ * 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.
+ */
+
+
+const webpack = require('webpack');
+const conf = require('./gulp.conf');
+const path = require('path');
+
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const autoprefixer = require('autoprefixer');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+const env = process.env.NODE_ENV || 'production';
+const brand = process.env.BRAND || 'cord';
+
+module.exports = {
+ module: {
+ preLoaders: [
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ loader: 'tslint'
+ }
+ ],
+
+ loaders: [
+ {
+ test: /.json$/,
+ loaders: [
+ 'json'
+ ]
+ },
+ {
+ test: /\.(css|scss)$/,
+ loaders: [
+ 'style',
+ 'css',
+ 'sass',
+ 'postcss'
+ ]
+ },
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ loaders: [
+ 'ng-annotate',
+ 'ts'
+ ]
+ },
+ {
+ test: /.html$/,
+ loaders: [
+ 'html?' + JSON.stringify({
+ attrs: ["img:src", "img:ng-src"]
+ })
+ ]
+ },
+ {
+ test: /\.(png|woff|woff2|eot|ttf|svg|jpg|gif|jpeg)$/,
+ loader: 'url-loader?limit=100000'
+ }
+ ]
+ },
+ plugins: [
+ new CopyWebpackPlugin([
+ { from: `./conf/app/app.config.${env}.js`, to: `app.config.js` },
+ { from: `./conf/app/style.config.${brand}.js`, to: `style.config.js` },
+ ]),
+ new webpack.optimize.OccurrenceOrderPlugin(),
+ new webpack.NoErrorsPlugin(),
+ new HtmlWebpackPlugin({
+ template: conf.path.src('index.html')
+ })
+ ],
+ postcss: () => [autoprefixer],
+ debug: true,
+ devtool: 'source-map',
+ output: {
+ path: path.join(process.cwd(), conf.paths.tmp),
+ filename: 'index.js'
+ },
+ resolve: {
+ extensions: [
+ '',
+ '.webpack.js',
+ '.web.js',
+ '.js',
+ '.ts'
+ ]
+ },
+ entry: `./${conf.path.src('index')}`,
+ ts: {
+ configFileName: 'tsconfig.json'
+ },
+ tslint: {
+ configuration: require('../tslint.json')
+ },
+ stats: {
+ colors: true,
+ modules: true,
+ reasons: true,
+ errorDetails: true
+ }
+};
diff --git a/generator-xos-gui-extension/generators/templates/gulp_tasks/browsersync.js b/generator-xos-gui-extension/generators/templates/gulp_tasks/browsersync.js
new file mode 100755
index 0000000..0e4ada2
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/gulp_tasks/browsersync.js
@@ -0,0 +1,39 @@
+
+/*
+ * 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.
+ */
+
+
+const gulp = require('gulp');
+const browserSync = require('browser-sync');
+const spa = require('browser-sync-spa');
+
+const browserSyncConf = require('../conf/browsersync.conf');
+const browserSyncDistConf = require('../conf/browsersync-dist.conf');
+
+browserSync.use(spa());
+
+gulp.task('browsersync', browserSyncServe);
+gulp.task('browsersync:dist', browserSyncDist);
+
+function browserSyncServe(done) {
+ browserSync.init(browserSyncConf());
+ done();
+}
+
+function browserSyncDist(done) {
+ browserSync.init(browserSyncDistConf());
+ done();
+}
diff --git a/generator-xos-gui-extension/generators/templates/gulp_tasks/karma.js b/generator-xos-gui-extension/generators/templates/gulp_tasks/karma.js
new file mode 100755
index 0000000..9955d1a
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/gulp_tasks/karma.js
@@ -0,0 +1,45 @@
+
+/*
+ * 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.
+ */
+
+
+const path = require('path');
+
+const gulp = require('gulp');
+const karma = require('karma');
+
+gulp.task('karma:single-run', karmaSingleRun);
+gulp.task('karma:auto-run', karmaAutoRun);
+
+function karmaFinishHandler(done) {
+ return failCount => {
+ done(failCount ? new Error(`Failed ${failCount} tests.`) : null);
+ };
+}
+
+function karmaSingleRun(done) {
+ process.env.NODE_ENV = 'test';
+ const configFile = path.join(process.cwd(), 'conf', 'karma.conf.js');
+ const karmaServer = new karma.Server({configFile}, karmaFinishHandler(done));
+ karmaServer.start();
+}
+
+function karmaAutoRun(done) {
+ process.env.NODE_ENV = 'test';
+ const configFile = path.join(process.cwd(), 'conf', 'karma-auto.conf.js');
+ const karmaServer = new karma.Server({configFile}, karmaFinishHandler(done));
+ karmaServer.start();
+}
diff --git a/generator-xos-gui-extension/generators/templates/gulp_tasks/misc.js b/generator-xos-gui-extension/generators/templates/gulp_tasks/misc.js
new file mode 100755
index 0000000..2c9fbb0
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/gulp_tasks/misc.js
@@ -0,0 +1,56 @@
+
+/*
+ * 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.
+ */
+
+
+const path = require('path');
+
+const gulp = require('gulp');
+const del = require('del');
+const filter = require('gulp-filter');
+const rename = require('gulp-rename');
+const replace = require('gulp-replace');
+
+const conf = require('../conf/gulp.conf');
+
+gulp.task('clean', clean);
+gulp.task('other', other);
+
+function clean() {
+ return del([`${conf.paths.dist}/*`, conf.paths.tmp]);
+}
+
+function other() {
+ const fileFilter = filter(file => file.stat.isFile());
+
+ return gulp.src([
+ path.join(conf.paths.src, '/**/*'),
+ path.join(`!${conf.paths.src}`, '/**/*.{scss,ts,html}')
+ ])
+ .pipe(fileFilter)
+ .pipe(gulp.dest(conf.paths.dist));
+}
+
+function other() {
+ const fileFilter = filter(file => file.stat.isFile());
+
+ return gulp.src([
+ path.join(conf.paths.src, '/**/*'),
+ path.join(`!${conf.paths.src}`, '/**/*.{scss,ts,html}')
+ ])
+ .pipe(fileFilter)
+ .pipe(gulp.dest(conf.paths.dist));
+}
diff --git a/generator-xos-gui-extension/generators/templates/gulp_tasks/webpack.js b/generator-xos-gui-extension/generators/templates/gulp_tasks/webpack.js
new file mode 100755
index 0000000..ccb64c0
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/gulp_tasks/webpack.js
@@ -0,0 +1,67 @@
+
+/*
+ * 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.
+ */
+
+
+const gulp = require('gulp');
+const gutil = require('gulp-util');
+
+const webpack = require('webpack');
+const webpackConf = require('../conf/webpack.conf');
+const webpackDistConf = require('../conf/webpack-dist.conf');
+const gulpConf = require('../conf/gulp.conf');
+const browsersync = require('browser-sync');
+
+gulp.task('webpack:dev', done => {
+ webpackWrapper(false, webpackConf, done);
+});
+
+gulp.task('webpack:watch', done => {
+ webpackWrapper(true, webpackConf, done);
+});
+
+gulp.task('webpack:dist', done => {
+ process.env.NODE_ENV = 'production';
+ webpackWrapper(false, webpackDistConf, done);
+});
+
+function webpackWrapper(watch, conf, done) {
+ const webpackBundler = webpack(conf);
+
+ const webpackChangeHandler = (err, stats) => {
+ if (err) {
+ gulpConf.errorHandler('Webpack')(err);
+ }
+ gutil.log(stats.toString({
+ colors: true,
+ chunks: false,
+ hash: false,
+ version: false
+ }));
+ if (done) {
+ done();
+ done = null;
+ } else {
+ browsersync.reload();
+ }
+ };
+
+ if (watch) {
+ webpackBundler.watch(200, webpackChangeHandler);
+ } else {
+ webpackBundler.run(webpackChangeHandler);
+ }
+}
diff --git a/generator-xos-gui-extension/generators/templates/gulpfile.js b/generator-xos-gui-extension/generators/templates/gulpfile.js
new file mode 100755
index 0000000..a15e854
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/gulpfile.js
@@ -0,0 +1,47 @@
+
+/*
+ * 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.
+ */
+
+
+const gulp = require('gulp');
+const HubRegistry = require('gulp-hub');
+const browserSync = require('browser-sync');
+
+const conf = require('./conf/gulp.conf');
+
+// Load some files into the registry
+const hub = new HubRegistry([conf.path.tasks('*.js')]);
+
+// Tell gulp to use the tasks just loaded
+gulp.registry(hub);
+
+gulp.task('build', gulp.series(gulp.parallel('other', 'webpack:dist')));
+gulp.task('test', gulp.series('karma:single-run'));
+gulp.task('test:auto', gulp.series('karma:auto-run'));
+gulp.task('serve', gulp.series('webpack:watch', 'watch', 'browsersync'));
+gulp.task('serve:dist', gulp.series('default', 'browsersync:dist'));
+gulp.task('default', gulp.series('clean', 'build'));
+gulp.task('watch', watch);
+
+function reloadBrowserSync(cb) {
+ browserSync.reload();
+ cb();
+}
+
+function watch(done) {
+ gulp.watch(conf.path.tmp('index.html'), reloadBrowserSync);
+ done();
+}
diff --git a/generator-xos-gui-extension/generators/templates/package.json b/generator-xos-gui-extension/generators/templates/package.json
new file mode 100644
index 0000000..32a0676
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/package.json
@@ -0,0 +1,119 @@
+{
+ "version": "3.0.0",
+ "dependencies": {
+ "angular": "1.6.3",
+ "angular-animate": "1.6.3",
+ "angular-cookies": "1.6.3",
+ "angular-resource": "1.6.3",
+ "angular-toastr": "2.1.1",
+ "angular-ui-bootstrap": "2.5.0",
+ "angular-ui-router": "1.0.0-beta.1",
+ "bootstrap": "3.3.7",
+ "bootstrap-sass": "3.3.7",
+ "d3": "3.5.17",
+ "jquery": "3.1.1",
+ "lodash": "4.17.4",
+ "ngprogress": "1.1.1",
+ "oclazyload": "1.1.0",
+ "pluralize": "3.1.0",
+ "rxjs": "5.2.0",
+ "socket.io-client": "1.7.3"
+ },
+ "devDependencies": {
+ "angular-mocks": "1.6.4",
+ "autoprefixer": "6.7.7",
+ "babel-eslint": "6.1.2",
+ "babel-loader": "6.4.1",
+ "babel-plugin-istanbul": "2.0.3",
+ "base-href-webpack-plugin": "1.0.0",
+ "bluebird": "^3.5.0",
+ "browser-sync": "2.18.8",
+ "browser-sync-spa": "1.0.3",
+ "copy-webpack-plugin": "4.0.1",
+ "css-loader": "0.23.1",
+ "del": "2.2.2",
+ "es6-shim": "0.35.3",
+ "eslint": "3.19.0",
+ "eslint-config-angular": "0.5.0",
+ "eslint-config-xo-space": "0.12.0",
+ "eslint-loader": "1.7.1",
+ "eslint-plugin-angular": "1.6.4",
+ "eslint-plugin-babel": "3.3.0",
+ "extract-text-webpack-plugin": "2.0.0-beta.3",
+ "file-loader": "0.9.0",
+ "gitbook-cli": "^2.3.0",
+ "gulp": "gulpjs/gulp#4ed9a4a3275559c73a396eff7e1fde3824951ebb",
+ "gulp-angular-filesort": "1.1.1",
+ "gulp-angular-templatecache": "1.9.1",
+ "gulp-filter": "4.0.0",
+ "gulp-htmlmin": "1.3.0",
+ "gulp-hub": "frankwallis/gulp-hub#d461b9c700df9010d0a8694e4af1fb96d9f38bf4",
+ "gulp-insert": "0.5.0",
+ "gulp-ng-annotate": "1.1.0",
+ "gulp-rename": "1.2.2",
+ "gulp-replace": "0.5.4",
+ "gulp-sass": "2.3.2",
+ "gulp-util": "3.0.8",
+ "html-loader": "0.4.5",
+ "html-webpack-plugin": "2.28.0",
+ "http-proxy": "1.16.2",
+ "istanbul-instrumenter-loader": "2.0.0",
+ "jasmine": "2.5.3",
+ "jasmine-jquery": "2.1.1",
+ "jasmine-spec-reporter": "^4.0.0",
+ "json-loader": "0.5.4",
+ "karma": "1.6.0",
+ "karma-angular-filesort": "1.0.2",
+ "karma-chrome-launcher": "2.0.0",
+ "karma-coverage": "1.1.1",
+ "karma-es6-shim": "1.0.0",
+ "karma-jasmine": "1.1.0",
+ "karma-junit-reporter": "1.2.0",
+ "karma-mocha-reporter": "2.2.3",
+ "karma-ng-html2js-preprocessor": "0.2.2",
+ "karma-phantomjs-launcher": "1.0.4",
+ "karma-phantomjs-shim": "1.4.0",
+ "karma-webpack": "1.8.1",
+ "ng-annotate-loader": "0.0.10",
+ "node-sass": "3.13.1",
+ "phantomjs-prebuilt": "2.1.14",
+ "postcss-loader": "0.8.2",
+ "remap-istanbul": "0.9.5",
+ "resolve-url-loader": "1.6.1",
+ "sass-loader": "3.2.3",
+ "style-loader": "0.13.2",
+ "ts-loader": "0.8.2",
+ "tslint": "3.15.1",
+ "tslint-loader": "2.1.5",
+ "typescript": "2.2.2",
+ "typings": "1.5.0",
+ "url-loader": "0.5.8",
+ "webpack": "2.1.0-beta.20"
+ },
+ "scripts": {
+ "postinstall": "npm run typings",
+ "build": "gulp",
+ "start": "gulp serve",
+ "typings": "typings install",
+ "serve:dist": "gulp serve:dist",
+ "serve:dist:watch": "gulp serve:dist:watch",
+ "test": "gulp test",
+ "test:auto": "gulp test:auto",
+ "test:e2e": "protractor conf/protractor.conf.js",
+ "config": "gulp config",
+ "lint": "tslint -c ./tslint.json 'src/**/*.ts'"
+ },
+ "eslintConfig": {
+ "globals": {
+ "expect": true
+ },
+ "root": true,
+ "env": {
+ "browser": true,
+ "jasmine": true
+ },
+ "extends": [
+ "xo-space/esnext"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/generator-xos-gui-extension/generators/templates/src/app/components/demo.html b/generator-xos-gui-extension/generators/templates/src/app/components/demo.html
new file mode 100644
index 0000000..a9dcb86
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/src/app/components/demo.html
@@ -0,0 +1,26 @@
+
+<!--
+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">
+ <div class="col-xs-12">
+ <h1><%= name %></h1>
+ </div>
+ <div class="col-xs-12">
+ <p>This is a demo component generated with the creation of this GUI extension.</p>
+ </div>
+</div>
\ No newline at end of file
diff --git a/generator-xos-gui-extension/generators/templates/src/app/components/demo.ts b/generator-xos-gui-extension/generators/templates/src/app/components/demo.ts
new file mode 100644
index 0000000..c4230a4
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/src/app/components/demo.ts
@@ -0,0 +1,45 @@
+
+/*
+ * 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.
+ */
+
+
+class DemoComponent {
+ static $inject = ['XosSidePanel', 'XosKeyboardShortcut'];
+
+ constructor(
+ private XosSidePanel: any,
+ private XosKeyboardShortcut: any
+ ) {
+ this.XosKeyboardShortcut.registerKeyBinding({
+ key: 'v',
+ description: 'Alert popup',
+ cb: () => {
+ alert('This binding is provided by the extension <%= name %>');
+ },
+ }, 'view');
+ }
+
+ togglePanel() {
+ this.XosSidePanel.toggleComponent('xosAlert', {config: {type: 'info'}, show: true}, 'This content is being toggled by the extension <%= name %>');
+ }
+
+}
+
+export const xosDemoComponent: angular.IComponentOptions = {
+ template: require('./demo.html'),
+ controllerAs: 'vm',
+ controller: DemoComponent
+};
diff --git a/generator-xos-gui-extension/generators/templates/src/index.html b/generator-xos-gui-extension/generators/templates/src/index.html
new file mode 100644
index 0000000..619c817
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/src/index.html
@@ -0,0 +1,35 @@
+
+<!--
+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.
+-->
+
+
+<!DOCTYPE html>
+<html lang="en" ng-app="<%= name %>">
+<head>
+ <meta charset="UTF-8">
+ <title><%= name %></title>
+ <link href="/xos/loader.css" rel="stylesheet">
+ <link href="/xos/app.css" rel="stylesheet">
+</head>
+<body>
+ <div ui-view></div>
+ <script src="/xos/vendor.js"></script>
+ <script src="/xos/app.js"></script>
+ <script src="/xos/loader.js"></script>
+ <script src="/xos/app.config.js"></script>
+ <script src="/xos/style.config.js"></script>
+</body>
+</html>
diff --git a/generator-xos-gui-extension/generators/templates/src/index.ts b/generator-xos-gui-extension/generators/templates/src/index.ts
new file mode 100644
index 0000000..e33bae4
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/src/index.ts
@@ -0,0 +1,47 @@
+
+/*
+ * 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.
+ */
+
+
+/// <reference path="../typings/index.d.ts" />
+import * as angular from 'angular';
+
+import 'angular-ui-router';
+import 'angular-resource';
+import 'angular-cookies';
+import routesConfig from './routes';
+import {xosDemoComponent} from './app/components/demo';
+
+
+
+angular.module('<%= name %>', [
+ 'ui.router',
+ 'app'
+ ])
+ .config(routesConfig)
+ .component('demo', xosDemoComponent)
+ .run(function(
+ $log: ng.ILogService,
+ $state: ng.ui.IStateService,
+ XosNavigationService: any) {
+ $log.info('[<%= name %>] App is running');
+
+ XosNavigationService.add({
+ label: '<%= name %>',
+ state: 'xos.<%= name %>.demo',
+ });
+
+ });
diff --git a/generator-xos-gui-extension/generators/templates/src/routes.ts b/generator-xos-gui-extension/generators/templates/src/routes.ts
new file mode 100644
index 0000000..97f2925
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/src/routes.ts
@@ -0,0 +1,35 @@
+
+/*
+ * 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.
+ */
+
+
+export default routesConfig;
+
+function routesConfig($stateProvider: angular.ui.IStateProvider, $locationProvider: angular.ILocationProvider) {
+ $locationProvider.html5Mode(false).hashPrefix('');
+
+ $stateProvider
+ .state('xos.<%= name %>', {
+ url: '<%= name %>',
+ abstract: true,
+ template: '<div ui-view></div>'
+ })
+ .state('xos.<%= name %>.demo', {
+ url: '/demo',
+ parent: 'xos.<%= name %>',
+ component: 'demo'
+ });
+}
diff --git a/generator-xos-gui-extension/generators/templates/tsconfig.json b/generator-xos-gui-extension/generators/templates/tsconfig.json
new file mode 100644
index 0000000..c516fb7
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "sourceMap": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "removeComments": false,
+ "noImplicitAny": false
+ },
+ "compileOnSave": false,
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.tsx"
+ ],
+ "exclude": [
+ "typings/**",
+ "conf/app/**",
+ "node_modules"
+ ]
+}
diff --git a/generator-xos-gui-extension/generators/templates/tslint.json b/generator-xos-gui-extension/generators/templates/tslint.json
new file mode 100644
index 0000000..04d33e1
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/tslint.json
@@ -0,0 +1,84 @@
+{
+ "rules": {
+ "ban": [true,
+ ["_", "extend"],
+ ["_", "isNull"],
+ ["_", "isDefined"]
+ ],
+ "class-name": true,
+ "comment-format": [true,
+ "check-space"
+ ],
+ "curly": true,
+ "eofline": true,
+ "forin": true,
+ "indent": [true, "spaces"],
+ "interface-name": true,
+ "jsdoc-format": true,
+ "label-position": true,
+ "label-undefined": true,
+ "max-line-length": [false, 140],
+ "member-ordering": [true,
+ "public-before-private",
+ "static-before-instance",
+ "variables-before-functions"
+ ],
+ "no-arg": true,
+ "no-bitwise": true,
+ "no-console": [true,
+ "debug",
+ "info",
+ "time",
+ "timeEnd",
+ "trace",
+ "log",
+ "error"
+ ],
+ "no-construct": true,
+ "no-constructor-vars": false,
+ "no-debugger": true,
+ "no-duplicate-key": true,
+ "no-duplicate-variable": true,
+ "no-empty": true,
+ "no-eval": true,
+ "no-string-literal": false,
+ "no-switch-case-fall-through": true,
+ "trailing-comma": true,
+ "no-trailing-whitespace": true,
+ "no-unused-expression": true,
+ "no-unused-variable": true,
+ "no-unreachable": true,
+ "no-use-before-declare": true,
+ "no-var-requires": true,
+ "one-line": [true,
+ "check-open-brace",
+ "check-catch",
+ "check-whitespace"
+ ],
+ "quotemark": [true, "single"],
+ "radix": true,
+ "semicolon": true,
+ "triple-equals": [true, "allow-null-check"],
+ "typedef": [true,
+ "callSignature",
+ "indexSignature",
+ "parameter",
+ "propertySignature",
+ "variableDeclarator"
+ ],
+ "typedef-whitespace": [true,
+ ["callSignature", "noSpace"],
+ ["catchClause", "noSpace"],
+ ["indexSignature", "space"]
+ ],
+ "use-strict": false,
+ "variable-name": false,
+ "whitespace": [true,
+ "check-branch",
+ "check-decl",
+ "check-operator",
+ "check-separator",
+ "check-type"
+ ]
+ }
+}
diff --git a/generator-xos-gui-extension/generators/templates/typings.json b/generator-xos-gui-extension/generators/templates/typings.json
new file mode 100644
index 0000000..a830275
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/typings.json
@@ -0,0 +1,18 @@
+{
+ "globalDependencies": {
+ "angular": "registry:dt/angular#1.5.0+20161208205636",
+ "angular-cookies": "registry:dt/angular-cookies#1.4.0+20160317120654",
+ "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts#dc9dabe74a5be62613b17a3605309783a12ff28a",
+ "angular-resource": "registry:dt/angular-resource#1.5.0+20161114123626",
+ "angular-ui-router": "registry:dt/angular-ui-router#1.1.5+20160707113237",
+ "es6-shim": "registry:dt/es6-shim#0.31.2+20160602141504",
+ "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#dc9dabe74a5be62613b17a3605309783a12ff28a",
+ "jasmine-jquery": "registry:dt/jasmine-jquery#1.5.8+20161128184045",
+ "jquery": "registry:dt/jquery#1.10.0+20161119044246",
+ "require": "registry:dt/require#2.1.20+20160316155526",
+ "socket.io-client": "registry:dt/socket.io-client#1.4.4+20160317120654"
+ },
+ "dependencies": {
+ "angular-toastr": "registry:dt/angular-toastr#1.6.0+20160708003927"
+ }
+}
diff --git a/generator-xos-gui-extension/generators/templates/xos-sample-gui-extension.yaml b/generator-xos-gui-extension/generators/templates/xos-sample-gui-extension.yaml
new file mode 100644
index 0000000..576ea3f
--- /dev/null
+++ b/generator-xos-gui-extension/generators/templates/xos-sample-gui-extension.yaml
@@ -0,0 +1,31 @@
+
+# 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.
+
+
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: <%= name %>
+
+imports:
+ - custom_types/xos.yaml
+
+topology_template:
+ node_templates:
+
+ # UI Extension
+ <%= name %>:
+ type: tosca.nodes.XOSGuiExtension
+ properties:
+ files: /xos/extensions/<%= name %>/vendor.js, /xos/extensions/<%= name %>/app.js
diff --git a/generator-xos-gui-extension/package.json b/generator-xos-gui-extension/package.json
new file mode 100644
index 0000000..fa28798
--- /dev/null
+++ b/generator-xos-gui-extension/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "generator-xos-gui-extension",
+ "version": "1.0.0",
+ "description": "Yeoman generator for creating new XOS GUI Extensions",
+ "keywords": [
+ "yeoman-generator"
+ ],
+ "author": "Open Networking Foundation",
+ "license": "Apache-2.0",
+ "files": [
+ "generators"
+ ],
+ "dependencies": {
+ "yeoman-generator": "^1.1.1"
+ }
+}
diff --git a/src/app/core/debug/debug-model.spec.ts b/src/app/core/debug/debug-model.spec.ts
index 46b6344..b081de0 100644
--- a/src/app/core/debug/debug-model.spec.ts
+++ b/src/app/core/debug/debug-model.spec.ts
@@ -91,7 +91,7 @@
dateFields.forEach(f => {
const date = isolatedScope.parseField(f, model[f]);
- expect(date).toEqual('Thu Aug 17 2017 15:45:20 GMT-0700 (PDT)');
+ expect(date).toEqual(new Date(model[f] * 1000).toString());
});
});
diff --git a/src/app/core/debug/debug-summary.html b/src/app/core/debug/debug-summary.html
index 9807ac9..7e185da 100644
--- a/src/app/core/debug/debug-summary.html
+++ b/src/app/core/debug/debug-summary.html
@@ -41,5 +41,12 @@
<i class="fa fa-remove text-danger" ng-hide="vm.debugStatus.modelsTab"></i>
</td>
</tr>
+ <tr>
+ <td>Notifications</td>
+ <td class="text-right">
+ <i class="fa fa-check text-success" ng-show="vm.debugStatus.notifications"></i>
+ <i class="fa fa-remove text-danger" ng-hide="vm.debugStatus.notifications"></i>
+ </td>
+ </tr>
</tbody>
</table>
\ No newline at end of file
diff --git a/src/app/core/debug/debug.service.spec.ts b/src/app/core/debug/debug.service.spec.ts
index a26d8cc..99f9484 100644
--- a/src/app/core/debug/debug.service.spec.ts
+++ b/src/app/core/debug/debug.service.spec.ts
@@ -53,6 +53,13 @@
expect(service.status.events).toBeTruthy();
});
+ it('should read the notification status from localStorage', () => {
+ spyOn(window.localStorage, 'getItem')
+ .and.returnValue(null);
+ service = new XosDebugService($log, $scope, XosKeyboardShortcut);
+ expect(service.status.notifications).toBeTruthy();
+ });
+
it('should disable the global debug status', () => {
spyOn(window.localStorage, 'getItem')
.and.returnValue('true');
diff --git a/src/app/core/debug/debug.service.ts b/src/app/core/debug/debug.service.ts
index f23fa06..aee1064 100644
--- a/src/app/core/debug/debug.service.ts
+++ b/src/app/core/debug/debug.service.ts
@@ -20,12 +20,13 @@
global: boolean;
events: boolean;
modelsTab: boolean;
+ notifications: boolean;
}
export interface IXosDebugService {
status: IXosDebugStatus;
setupShortcuts(): void;
- toggleDebug(type: 'global' | 'events' | 'modelsTab'): void;
+ toggleDebug(type: 'global' | 'events' | 'modelsTab' | 'notifications'): void;
}
export class XosDebugService implements IXosDebugService {
@@ -35,7 +36,8 @@
public status: IXosDebugStatus = {
global: false,
events: false,
- modelsTab: false
+ modelsTab: false,
+ notifications: true
};
constructor (
@@ -51,6 +53,9 @@
const debugModelsTab = window.localStorage.getItem('debug-modelsTab');
this.status.modelsTab = (debugModelsTab === 'true');
+
+ const notifications = window.localStorage.getItem('debug-notifications');
+ this.status.notifications = (notifications !== null ? notifications === 'true' : true);
}
public setupShortcuts(): void {
@@ -65,9 +70,15 @@
cb: () => this.toggleDebug('events'),
description: 'Toggle debug messages for WS events in browser console'
}, 'global');
+
+ this.XosKeyboardShortcut.registerKeyBinding({
+ key: 'S',
+ cb: () => this.toggleDebug('notifications'),
+ description: 'Toggle notifications'
+ }, 'global');
}
- public toggleDebug(type: 'global' | 'events' | 'modelsTab'): void {
+ public toggleDebug(type: 'global' | 'events' | 'modelsTab' | 'notifications'): void {
if (window.localStorage.getItem(`debug-${type}`) === 'true') {
this.$log.info(`[XosDebug] Disabling ${type} debug`);
window.localStorage.setItem(`debug-${type}`, 'false');
diff --git a/src/app/core/header/header.spec.ts b/src/app/core/header/header.spec.ts
index eb236b1..a4a7d90 100644
--- a/src/app/core/header/header.spec.ts
+++ b/src/app/core/header/header.spec.ts
@@ -24,6 +24,7 @@
import 'angular-mocks';
import {xosHeader, INotification} from './header';
import {Subject} from 'rxjs';
+import {IXosDebugService} from '../debug/debug.service';
let element, scope: angular.IRootScopeService, compile: ng.ICompileService, isolatedScope;
const events = new Subject();
@@ -79,6 +80,17 @@
registerKeyBinding: jasmine.createSpy('registerKeyBinding')
};
+const MockXosDebug: IXosDebugService = {
+ status: {
+ global: false,
+ events: false,
+ modelsTab: false,
+ notifications: true
+ },
+ setupShortcuts: jasmine.createSpy('debug.createShortcuts'),
+ toggleDebug: jasmine.createSpy('debug.toggleDebug')
+};
+
describe('header component', () => {
beforeEach(() => {
angular
@@ -96,7 +108,8 @@
.value('StyleConfig', {
logo: 'cord-logo.png',
})
- .value('SearchService', {});
+ .value('SearchService', {})
+ .value('XosDebug', MockXosDebug);
angular.mock.module('xosHeader');
});
@@ -146,7 +159,16 @@
});
});
- it('should display a toastr for a new notification', () => {
+ it('should not display a toastr for a new notification (if notifications are disabled)', () => {
+ MockXosDebug.status.notifications = false;
+ sendEvent(infoNotification);
+ scope.$digest();
+
+ expect(MockToastr.info).not.toHaveBeenCalled();
+ });
+
+ it('should display a toastr for a new notification (if notifications are enabled)', () => {
+ MockXosDebug.status.notifications = true;
sendEvent(infoNotification);
scope.$digest();
diff --git a/src/app/core/header/header.ts b/src/app/core/header/header.ts
index a465f8f..26f6fd0 100644
--- a/src/app/core/header/header.ts
+++ b/src/app/core/header/header.ts
@@ -28,6 +28,7 @@
import {IXosKeyboardShortcutService} from '../services/keyboard-shortcut';
import {Subscription} from 'rxjs';
import {IXosConfigHelpersService} from '../services/helpers/config.helpers';
+import {IXosDebugService} from '../debug/debug.service';
export interface INotification extends IWSEvent {
viewed?: boolean;
@@ -47,7 +48,8 @@
'StyleConfig',
'SearchService',
'XosKeyboardShortcut',
- 'ConfigHelpers'
+ 'ConfigHelpers',
+ 'XosDebug'
];
public notifications: INotification[] = [];
public newNotifications: INotification[] = [];
@@ -73,7 +75,8 @@
private StyleConfig: IXosStyleConfig,
private SearchService: IXosSearchService,
private XosKeyboardShortcut: IXosKeyboardShortcutService,
- private ConfigHelpers: IXosConfigHelpersService
+ private ConfigHelpers: IXosConfigHelpersService,
+ private XosDebugService: IXosDebugService
) {
}
@@ -123,6 +126,12 @@
(event: IWSEvent) => {
this.$scope.$evalAsync(() => {
+ if (!this.XosDebugService.status.notifications) {
+ // NOTE: notifications can be disabled
+ return;
+ }
+
+
if (event.model === 'Diag') {
// NOTE skip notifications for Diag model
return;
diff --git a/src/app/datasources/helpers/store.helpers.spec.ts b/src/app/datasources/helpers/store.helpers.spec.ts
index f3b2321..2f617bc 100644
--- a/src/app/datasources/helpers/store.helpers.spec.ts
+++ b/src/app/datasources/helpers/store.helpers.spec.ts
@@ -26,6 +26,7 @@
import {ConfigHelpers} from '../../core/services/helpers/config.helpers';
import {AuthService} from '../rest/auth.rest';
import {IXosModeldefsCache} from './modeldefs.service';
+import {XosFormHelpers} from '../../core/form/form-helpers';
let service: IStoreHelpersService;
let subject: BehaviorSubject<any>;
@@ -42,6 +43,7 @@
.service('ModelRest', ModelRest) // NOTE evaluate mock
.service('StoreHelpers', StoreHelpers)
.service('AuthService', AuthService)
+ .service('XosFormHelpers', XosFormHelpers)
.value('XosModeldefsCache', {
get: jasmine.createSpy('XosModeldefsCache.get'),
getApiUrlFromModel: jasmine.createSpy('XosModeldefsCache.getApiUrlFromModel')
diff --git a/src/app/datasources/rest/model.rest.spec.ts b/src/app/datasources/rest/model.rest.spec.ts
index d545ac2..da4f2f4 100644
--- a/src/app/datasources/rest/model.rest.spec.ts
+++ b/src/app/datasources/rest/model.rest.spec.ts
@@ -22,6 +22,7 @@
import 'angular-cookies';
import {IXosResourceService} from './model.rest';
import {xosDataSources} from '../index';
+import {IXosFormHelpersService} from '../../core/form/form-helpers';
let service: IXosResourceService;
let resource: ng.resource.IResourceClass<any>;
@@ -34,6 +35,10 @@
websocketClient: 'http://xos-test:3000'
};
+const MockFormHelpers: IXosFormHelpersService = {
+ _getFieldFormat: () => 'date'
+};
+
describe('The ModelRest service', () => {
beforeEach(angular.mock.module(xosDataSources));
@@ -41,7 +46,8 @@
beforeEach(() => {
angular.module(xosDataSources)
- .constant('AppConfig', MockAppCfg);
+ .constant('AppConfig', MockAppCfg)
+ .value('XosFormHelpers', MockFormHelpers);
angular.mock.module(xosDataSources);
});
@@ -99,4 +105,31 @@
$scope.$apply();
httpBackend.flush();
});
+
+ describe('when saving a model', () => {
+
+ let item, date;
+ const timestamp = 1509552402000;
+
+ beforeEach(() => {
+ httpBackend.expectPOST(`${MockAppCfg.apiEndpoint}/core/test`)
+ .respond((method, url, req) => {
+ return [200, req];
+ });
+ resource = service.getResource('/core/test');
+ date = new Date(timestamp);
+ item = new resource({date: date.toString()});
+ });
+
+ xit('should convert dates to timestamps', (done) => {
+ item.$save()
+ .then(res => {
+ expect(res.date).toEqual(timestamp);
+ done();
+ });
+ $scope.$apply();
+ httpBackend.flush();
+ done();
+ });
+ });
});
diff --git a/src/app/datasources/rest/model.rest.ts b/src/app/datasources/rest/model.rest.ts
index 6c72d99..f390616 100644
--- a/src/app/datasources/rest/model.rest.ts
+++ b/src/app/datasources/rest/model.rest.ts
@@ -15,37 +15,48 @@
* limitations under the License.
*/
-
+import * as _ from 'lodash';
import {IXosAppConfig} from '../../../index';
+import {IXosFormHelpersService} from '../../core/form/form-helpers';
+
export interface IXosResourceService {
getResource(url: string): ng.resource.IResourceClass<any>;
}
export class ModelRest implements IXosResourceService {
- static $inject = ['$resource', 'AppConfig'];
+ static $inject = ['$resource', 'AppConfig', 'XosFormHelpers'];
/** @ngInject */
constructor(
private $resource: ng.resource.IResourceService,
- private AppConfig: IXosAppConfig
+ private AppConfig: IXosAppConfig,
+ private XosFormHelpers: IXosFormHelpersService
) {
}
public getResource(url: string): ng.resource.IResourceClass<ng.resource.IResource<any>> {
+ const self = this;
const resource: angular.resource.IResourceClass<any> = this.$resource(`${this.AppConfig.apiEndpoint}${url}/:id/`, {id: '@id'}, {
update: { method: 'PUT' },
query: {
method: 'GET',
isArray: true,
transformResponse: (res) => {
- // FIXME chameleon return everything inside "items"
return res.items ? res.items : res;
}
}
});
resource.prototype.$save = function() {
+
+ // NOTE converting dates back to timestamp
+ _.forEach(Object.keys(this), (k: string) => {
+ if (self.XosFormHelpers._getFieldFormat(this[k]) === 'date') {
+ this[k] = new Date(this[k]).getTime();
+ }
+ });
+
if (this.id) {
return this.$update();
} else {
diff --git a/src/app/datasources/stores/model.store.spec.ts b/src/app/datasources/stores/model.store.spec.ts
index 09dc3f9..ce3e2cd 100644
--- a/src/app/datasources/stores/model.store.spec.ts
+++ b/src/app/datasources/stores/model.store.spec.ts
@@ -28,6 +28,7 @@
import {AuthService} from '../rest/auth.rest';
import {XosDebouncer} from '../../core/services/helpers/debounce.helper';
import {IXosModeldefsCache} from '../helpers/modeldefs.service';
+import {XosFormHelpers} from '../../core/form/form-helpers';
let service: IXosModelStoreService;
let httpBackend: ng.IHttpBackendService;
@@ -70,6 +71,7 @@
.service('XosModelStore', XosModelStore)
.service('ConfigHelpers', ConfigHelpers) // TODO mock
.service('AuthService', AuthService)
+ .service('XosFormHelpers', XosFormHelpers)
.constant('AppConfig', MockAppCfg)
.value('XosModeldefsCache', {
get: jasmine.createSpy('XosModeldefsCache.get').and.returnValue({}),
diff --git a/src/app/views/dashboard/dashboard.ts b/src/app/views/dashboard/dashboard.ts
index 45bd138..285c2df 100644
--- a/src/app/views/dashboard/dashboard.ts
+++ b/src/app/views/dashboard/dashboard.ts
@@ -18,37 +18,53 @@
import {IXosModelStoreService} from '../../datasources/stores/model.store';
import {IXosAuthService} from '../../datasources/rest/auth.rest';
+import {Subscription} from 'rxjs/Subscription';
+
+
class DashboardController {
- static $inject = ['$scope', '$state', 'XosModelStore', 'AuthService'];
+ static $inject = [
+ '$log',
+ '$scope',
+ '$state',
+ 'XosModelStore',
+ 'AuthService'
+ ];
public nodes: number;
public slices: number;
public instances: number;
+ private nodeSubscription: Subscription;
+ private sliceSubscription: Subscription;
+ private instanceSubscription: Subscription;
+
constructor(
+ private $log: ng.ILogService,
private $scope: ng.IScope,
private $state: ng.ui.IStateService,
private store: IXosModelStoreService,
private auth: IXosAuthService
) {
+ this.$log.info(`[XosDashboardView] Setup`);
+
if (!this.auth.isAuthenticated()) {
this.$state.go('login');
}
else {
- this.store.query('Node')
+ this.nodeSubscription = this.store.query('Node')
.subscribe((event) => {
this.$scope.$evalAsync(() => {
this.nodes = event.length;
});
});
- this.store.query('Instance')
+ this.instanceSubscription = this.store.query('Instance')
.subscribe((event) => {
this.$scope.$evalAsync(() => {
this.instances = event.length;
});
});
- this.store.query('Slice')
+ this.sliceSubscription = this.store.query('Slice')
.subscribe((event) => {
this.$scope.$evalAsync(() => {
this.slices = event.length;
@@ -59,6 +75,12 @@
this.slices = 0;
}
}
+
+ $onDestroy () {
+ this.nodeSubscription.unsubscribe();
+ this.instanceSubscription.unsubscribe();
+ this.sliceSubscription.unsubscribe();
+ }
}
export const xosDashboard: angular.IComponentOptions = {
diff --git a/src/index.ts b/src/index.ts
index 2a287d5..68920b0 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -83,11 +83,12 @@
.component('xos', main)
.provider('XosConfig', function(){
// save the last visited state before reload
- const lastVisitedUrl = window.location.hash.replace('#', '');
+ let lastVisitedUrl = window.location.hash.replace('#', '');
this.$get = [() => {
- return {
- lastVisitedUrl
- };
+ if (lastVisitedUrl === '/login' || lastVisitedUrl === '/loader') {
+ lastVisitedUrl = '/dashboard';
+ }
+ return {lastVisitedUrl};
}] ;
return this;
})
@@ -129,11 +130,15 @@
// if the user is authenticated
$log.info(`[XOS] Is user authenticated? ${AuthService.isAuthenticated()}`);
if (AuthService.isAuthenticated()) {
+ $log.info(`[XOS] Redirect to "loader"`);
$state.go('loader');
+ $rootScope.$apply();
}
else {
AuthService.clearUser();
+ $log.info(`[XOS] Redirect to "login"`);
$state.go('login');
+ $rootScope.$apply();
}
// register keyboard shortcut