commit 197d5dd2bd9e7141e68fcdf6a43d7d262ea011e1 Author: Michael Krotscheck Date: Thu Dec 19 07:27:10 2013 -0800 Initial commit This contains the initial commit for the storyboard web client project, consisting of the basic build & testing harnesses, simple set of routes, and a list of basic dependencies necessary to run an application. It's purpose is to be reference Javascript/Angular project to test out the build images. diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..564b6438 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.build +.local +node_modules +bower_components +dist +npm-debug.log +*.iml +.idea +reports +cover \ No newline at end of file diff --git a/.gitreview b/.gitreview new file mode 100644 index 00000000..5fa3236e --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=review.openstack.org +port=29418 +project=openstack-infra/storyboard-webclient.git diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..a751de03 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,65 @@ +// Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +// +// 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. + +/** + * This file contains JSHint configuration settings, which allow us to enforce a + * coding standard programatically using jshint. It's as close to PEP-8 as we + * can get it. + * + * @see http://www.jshint.com/ + */ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 4, + "maxlen": 80, + "latedef": true, + "newcap": true, + "noarg": true, + "quotmark": "single", + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + + // Inform JSHint that the following globals are expected. + "globals": { + // Library constants + "$": false, // JQuery + "angular": false, // AngularJS + + // Unit test constants + "after": false, + "afterEach": false, + "before": false, + "beforeEach": false, + "describe": false, + "expect": false, + "inject": false, + "it": false, + "spyOn": false, + + // functional test constants + "browser": false, + "by": false, + "element": false + } +} \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 00000000..1c40555b --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This file serves as task declaration/configuration for steps executed + * during the grunt build. It loads grunt modules declared in package.json, + * configures them, and makes them available via 'grunt PLUGIN' on the + * commandline. It also groups these tasks into individual steps helpful during + * development, such as build, package, test, and release. + * + * @author Michael Krotscheck + */ +var config = { + livereload: { + port: 35729 + } +}; + +var lrSnippet = require('connect-livereload')(config.livereload); +var mountFolder = function (connect, dir) { + 'use strict'; + return connect.static(require('path').resolve(dir)); +}; + + +module.exports = function (grunt) { + 'use strict'; + + var dir = { + source : './src', + test : './test', + output : './dist', + report : './reports', + bower: './bower_components' + }; + + // load all grunt tasks + require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); + + grunt.initConfig({ + + /** + * grunt clean + * + * Cleans our output directories. + */ + clean: { + dist: { + files: [ + { + dot: true, + src: [ + dir.report, + './cover', + dir.output + ] + } + ] + } + }, + + /** + * grunt jshint + * + * Runs the JSHint linter against all the javascript files in our + * project, using the .jshintrc file shared with our IDE (sublime, + * eclipse, intellij, etc) + */ + jshint: { + options: { + jshintrc: '.jshintrc' + }, + all: [ + dir.source + '/**/*.js', + dir.test + '/**/*.js', + './*.js' + ] + }, + + /** + * grunt concat + * + * Creates a single file out of our javascript source in accordance + * with the concatenation priority. First the application module, then + * any dependent module declarations, and finally everything else. + */ + concat: { + dist: { + src: [ + dir.source + '/app/storyboard.js', + dir.source + '/app/**/module.js', + dir.source + '/app/**/*.js' + ], + dest: dir.output + '/js/storyboard.js' + } + }, + + /** + * grunt recess + * + * Compiles our .less CSS files into real CSS, linting as it goes. We + * do this manually during our build process so that we can inject + * our own variables into bootstrap and/or other CSS frameworks. + * + * Note: We're using LessCSS here because SASS requires ruby-compass, + * and cannot be easily installed with npm. + */ + recess: { + options: { + compile: true + }, + bootstrap: { + src: [ + dir.bower + '/bootstrap/less/bootstrap.less' + ], + dest: dir.output + '/styles/bootstrap.css' + }, + theme: { + src: [ + dir.source + '/styles/**/*.less' + ], + dest: dir.output + '/styles/theme.css' + } + }, + + /** + * grunt imagemin + * + * Runs optimizations on our images and copies them to the dist + * directory. + */ + imagemin: { + dist: { + files: [ + { + expand: true, + cwd: dir.source + '/images', + src: '**/*.{png,jpg,jpeg}', + dest: dir.output + '/images' + } + ] + } + }, + + /** + * grunt html2js + * + * A convenience method that converts all of the templates found in our + * project into a single javascript file (mostly by converting them + * into strings). This presents a tradeoff: All of the HTML layout + * is loaded up front, which could take a while, but it prevents load + * lag during application runtime. + */ + html2js: { + options: { + module: 'sb.templates', + base: dir.source + }, + main: { + src: [dir.source + '/app/templates/**/*.html'], + dest: dir.output + '/js/templates.js' + } + }, + + /** + * grunt copy + * + * Copies any as-yet-unprocessed files into the dist directory, as well + * as pulling any assets from imported libraries to their appropriate + * locations. + */ + copy: { + dist: { + files: [ + { + expand: true, + dot: true, + cwd: dir.source, + dest: dir.output, + src: [ + '**/*.{ico,txt,eot,ttf,woff}', + '*.html', + 'robots.txt' + ] + }, + { + expand: true, + dot: true, + cwd: dir.bower + '/font-awesome', + dest: dir.output, + src: [ + 'fonts/*.*' + ] + } + ] + } + }, + + /** + * @private + * + * grunt useminPrepare + * + * This task is a configuration builder, used to parse minification + * annotations in index.html. It's used in our compile step as an + * dependency concatenator, so that we can easily declare what we + * need in the index.html file and get all the pieces wrapped up + * nice and pretty by the script. + * + * It will generate configurations for the concat task (the others + * are explicitly disabled). + */ + useminPrepare: { + html: [dir.source + '/index.html'], + options: { + flow: { + steps: { + 'js': ['concat'], + 'css': ['concat'] + }, + post: [] + }, + dest: dir.output + } + }, + + /** + * grunt useminPrepare cssmin + * + * Parses all of the css references in our index.html and minifies them. + * The configuration for this task is generated by useminPrepare. + */ + cssmin: { + minify: { + expand: true, + cwd: dir.output + '/styles/', + src: ['*.css'], + dest: dir.output + '/styles/' + } + + }, + + /** + * grunt useminPrepare uglify + * + * Performs a minifcation on our concatenated javascript, making sure + * not to mangle angularjs' injector pattern. + */ + uglify: { + options: { + mangle: false + }, + dist: { + files: [ + { + expand: true, + cwd: dir.output + '/js', + src: '**/*.js', + dest: dir.output + '/js' + } + ] + } + }, + + /** + * grunt useminPrepare usemin + * + * Completes the packaging task by renaming all modified asset + * references from the previous steps in referencing documents. + */ + usemin: { + html: [ + dir.output + '/index.html' + ], + css: [ + dir.output + '/styles/**/*.css' + ], + options: { + dirs: [dir.output] + } + }, + + /** + * grunt htmlmin + * + * The final optimization step, which cleans up our html file and + * removes extraneous comments, tags, and more. + */ + htmlmin: { + dist: { + options: { + removeComments: true, + removeCommentsFromCDATA: true, + collapseWhitespace: false, + collapseBooleanAttributes: false, + removeAttributeQuotes: false, + removeRedundantAttributes: false, + useShortDoctype: false, + removeEmptyAttributes: true, + removeOptionalTags: true + }, + files: [ + { + expand: true, + cwd: dir.output, + src: ['index.html'], + dest: dir.output + } + ] + } + }, + + /** + * grunt open + * + * Opens your default web browser to the specified URL. This is mostly + * used when running server, so that the developer doesn't have to know + * what URL/port the dev box is running on. + */ + open: { + server: { + url: 'http://localhost:<%= connect.options.port %>' + } + }, + + /** + * grunt watch + * + * This task is run with grunt server, in order to automatically update + * the hosted files that are served via the devserver. The livereload + * directive will then communicate with the browser and refresh the page + * when necessary. + */ + watch: { + concat: { + files: [ + dir.source + '/app/storyboard.js', + dir.source + '/app/**/module.js', + dir.source + '/app/**/*.js' + ], + tasks: ['concat'] + }, + recess: { + files: [ + dir.source + '/styles/**/*.less' + ], + tasks: ['recess:bootstrap', 'recess:theme'] + }, + copy: { + files: [ + dir.source + '/**/*.{ico,txt,eot,ttf,woff}' + ], + tasks: ['copy'] + }, + index: { + files: [ + dir.source + '/index.html' + ], + tasks: ['compile'] + + }, + templates: { + files: [ + dir.source + '/app/templates/**/*.html' + ], + tasks: ['html2js'] + }, + jshint: { + files: [ + 'Gruntfile.js', + dir.source + '/**/*.js', + dir.test + '/**/*.js' + ], + tasks: ['jshint'] + }, + livereload: { + options: { + livereload: config.livereload.port + }, + files: [ + dir.output + '/**/*.*' + ] + } + }, + + /** + * grunt connect + * + * The connect plugin hosts a simple web server with our application, + * either under development or under test. + */ + connect: { + options: { + port: 9000, + hostname: 'localhost' + }, + livereload: { + options: { + middleware: function (connect) { + return [ + lrSnippet, + mountFolder(connect, dir.output) + ]; + } + } + }, + dist: { + options: { + keepalive: true, + middleware: function (connect) { + return [ + mountFolder(connect, dir.output) + ]; + } + } + }, + test: { + options: { + middleware: function (connect) { + return [ + mountFolder(connect, dir.output) + ]; + } + } + } + }, + + /** + * grunt karma:unit / grunt karma:integration + * + * This task runs the unit or integration suite on the compiled code. + */ + karma: { + unit: { + configFile: './karma-unit.conf.js' + }, + integration: { + configFile: './karma-integration.conf.js' + } + }, + + /** + * grunt shell:xvfbStart / grunt shell:xvfbStop + * + * Starts and stops a virtual frame buffer. + */ + shell: { + xvfbStart: { + command: 'source ./bin/xvfb.sh start' + }, + xvfbStop: { + command: 'source ./bin/xvfb.sh stop' + } + }, + + /** + * grunt protractor + * + * Protractor is an angular-provided method by which jasmine tests are + * executed via the selenium web driver. Its goal is to handle browser + * drive testing, rather than unit or integration testing. + */ + protractor: { + options: { + configFile: './protractor.conf.js', + keepAlive: true, + noColor: false, + args: { + } + }, + dist: {} + } + }); + + /** + * Compiles all of our sources. + */ + grunt.registerTask('compile', [ + 'jshint', + 'useminPrepare', + 'concat', + 'recess', + 'imagemin', + 'html2js', + 'copy', + 'usemin' + ]); + + /** + * Package built code into a release package. + */ + grunt.registerTask('package', [ + 'uglify', + 'cssmin', + 'htmlmin' + ]); + + /** + * Compile and packages our code. + */ + grunt.registerTask('build', [ + 'compile', + 'package' + ]); + + /** + * This task performs a full build of our application, and then runs that + * source in a local web server. It does no watching, it simply hosts the + * files. + */ + grunt.registerTask('server:dist', [ + 'clean', + 'compile', + 'package', + 'open', + 'connect:dist' + ]); + + /** + * Development server - runs a build and sets up concurrent watchers that + * will automatically lint, test, and refresh + * the code when a change is detected. + */ + grunt.registerTask('server', [ + 'clean', + 'compile', + 'connect:livereload', + 'open', + 'watch' + ]); + + /** + * grunt test:integration + * + * This command will create a clean build against which our unit + * tests will be run. For more information, please see + * karma-unit.conf.js + */ + grunt.registerTask('test:unit', [ + 'clean', + 'compile', + 'useminPrepare', + 'concat', + 'karma:unit' + ]); + + /** + * grunt test:integration + * + * This command will create a clean build against which our integration + * tests will be run. For more information, please see + * karma-integration.conf.js + */ + grunt.registerTask('test:integration', [ + 'clean', + 'compile', + 'useminPrepare', + 'concat', + 'karma:integration' + ]); + + /** + * grunt test:functional + * + * This command will create a clean build against which our functional + * tests will be run. For more information, please see + * karma-functional.conf.js + */ + grunt.registerTask('test:functional', [ + 'clean', + 'compile', + 'connect:test', + 'protractor' + ]); + + /** + * grunt test + * + * Run all the tests. + */ + grunt.registerTask('test', [ + 'clean', + 'compile', + 'useminPrepare', + 'concat', + 'karma:unit', + 'karma:integration', + 'package', + 'connect:test', + 'protractor' + ]); +}; diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e06d2081 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/README.md b/README.md new file mode 100644 index 00000000..6821dddd --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +storyboard-webclient +==================== + +A PoC WebClient for the OpenStack Storyboard project. + +### Prerequisites: Quick build/CI + +* Xvfb +* GCC 4.2 or newer +* Python 2.6 or 2.7 +* GNU Make 3.81 or newer +* libexecinfo (FreeBSD and OpenBSD only) + +### Prerequisites: Dev + +* NodeJS 0.10.24 or newer +* Grunt 0.4.2 +* bower 1.2.8 + +### Command reference: + +**Bootstrap & build the CI environment** + +* `./bin/bootstrap.sh` +* `./bin/build.sh` + +**Run a local development server** + +`grunt server` + +**Run the test suite** + +`grunt test` + +**Package the distro** + +`grunt build` \ No newline at end of file diff --git a/bin/bootstrap.sh b/bin/bootstrap.sh new file mode 100755 index 00000000..517c6bfd --- /dev/null +++ b/bin/bootstrap.sh @@ -0,0 +1,71 @@ +#!/bin/bash -xe + +# This script bootstraps the current workspace with a locally compiled +# node/grunt/bower javascript toolchain. This is done because recent NodeJS +# releases (v0.10+) are not available for the images we use for builds +# (CentOS, Ubuntu 12.04 precise), and because we only need node to generate our +# static assets. +# + +node_version=0.10.24 +script_dir="$( cd "$( dirname "$0" )" && pwd )" +workspace_path="$(dirname "$script_dir")" + +node_archive_path=~/.cache/storyboard/node-v$node_version.tar.gz +node_remote_path=http://nodejs.org/dist/v$node_version/node-v$node_version.tar.gz + +# Sanity check cleanup. +rm -fr $workspace_path/.local/ +rm -fr $workspace_path/.build/ + +# Create our working directories +mkdir -p $workspace_path/.local/ +mkdir -p $workspace_path/.build/ +mkdir -p ~/.cache/storyboard + +# Download the source if we don't have it already. +if [ ! -f $node_archive_path ]; then + echo "Downloading Node v$node_version..." + cd ~/.cache/storyboard + wget $node_remote_path -O $node_archive_path + cd $workspace_path +fi + +# Compile into the workspace, so we keep things isolated. +# Note that on build nodes without ccache this will take a while. + +cd $workspace_path/.build/ +tar -xf $node_archive_path +cd $workspace_path/.build/node-v$node_version + +# Run config, exit & dump if it fails. +echo 'Configuring...' +CONFIG_OUTPUT=$(./configure --prefix=$workspace_path/.local/ 2>&1) +if [ $? != 0 ]; then + echo $CONFIG_OUTPUT + cd $workspace_path + exit 1 +fi + +# Run make +echo 'Make...' +MAKE_OUTPUT=$(make 2>&1) +if [ $? != 0 ]; then + echo $MAKE_OUTPUT + cd $workspace_path + exit 1 +fi + +# Run make install +echo 'Make Install...' +MAKE_INSTALL_OUTPUT=$(make install 2>&1) +if [ $? != 0 ]; then + echo $MAKE_INSTALL_OUTPUT + cd $workspace_path + exit 1 +fi + +# Go back home... +cd $workspace_path + +exit 0 diff --git a/bin/build.sh b/bin/build.sh new file mode 100755 index 00000000..1968f05e --- /dev/null +++ b/bin/build.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# This script executes the build. + +VDISPLAY=99 +DIMENSIONS='1280x1024x24' +XVFB=/usr/bin/Xvfb +BIN_DIR="$( cd "$( dirname "$0" )" && pwd )" +WORKSPACE="$(dirname "$BIN_DIR")" + +# Add our new bin directory to the PATH +echo "Adding $WORKSPACE/.local/bin to PATH" +export PATH=$WORKSPACE/.local/bin:$PATH +echo "Adding $WORKSPACE/node_modules/.bin to PATH" +export PATH=$WORKSPACE/node_modules/.bin:$PATH + +cd $WORKSPACE; + +echo "Installing build dependencies" +npm prune +npm install + +echo "Installing compile dependencies" +bower prune +bower install + +echo "Launching Virtual Frame Buffer" +$XVFB :${VDISPLAY} -screen 0 ${DIMENSIONS} -ac +extension GLX +render -noreset 2>&1 > /dev/null & + +echo "Building" +set +e +DISPLAY=:${VDISPLAY} grunt clean test +result=$? + +pkill Xvfb 2>&1 > /dev/null +set -e + +exit $result \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..efdb42a3 --- /dev/null +++ b/bower.json @@ -0,0 +1,22 @@ +{ + "name": "storyboard-webclient", + "version": "0.0.1", + "dependencies": { + "jquery": "2.0.3", + "font-awesome": "4.0", + "angular": "1.2.5", + "angular-resource": "1.2.5", + "angular-cookies": "1.2.5", + "angular-sanitize": "1.2.5", + "bootstrap": "3.0.0", + "angular-ui-router": "0.2.0", + "angular-translate": "1.1.1" + }, + "devDependencies": { + "angular-mocks": "1.2.5", + "angular-scenario": "1.2.5" + }, + "resolutions": { + "angular": "1.2.5" + } +} diff --git a/karma-integration.conf.js b/karma-integration.conf.js new file mode 100644 index 00000000..4fe066f1 --- /dev/null +++ b/karma-integration.conf.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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 = function (config) { + 'use strict'; + + config.set({ + + basePath: '', + + frameworks: ['jasmine'], + + plugins: [ + 'karma-coverage', + 'karma-jasmine', + 'karma-html-reporter', + 'karma-phantomjs-launcher', + 'karma-chrome-launcher', + 'karma-firefox-launcher' + ], + + files: [ + './dist/js/*.js', + './test/unit/**/*.js' + ], + + exclude: [ + ], + + singleRun: true, + + reporters: ['dots', 'progress', 'coverage', 'html'], + + colors: false, + + browsers: [ 'PhantomJS', 'Firefox' ], + + preprocessors: { + './dist/js/storyboard.js': ['coverage'] + }, + + coverageReporter: { + type: 'html', + dir: './cover/integration/' + }, + + htmlReporter: { + outputDir: './reports/integration', + templatePath: './node_modules' + + '/karma-html-reporter/jasmine_template.html' + } + }); +}; \ No newline at end of file diff --git a/karma-unit.conf.js b/karma-unit.conf.js new file mode 100644 index 00000000..164d0c82 --- /dev/null +++ b/karma-unit.conf.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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 = function (config) { + 'use strict'; + + config.set({ + + basePath: '', + + frameworks: ['jasmine'], + + plugins: [ + 'karma-coverage', + 'karma-jasmine', + 'karma-html-reporter', + 'karma-phantomjs-launcher', + 'karma-chrome-launcher', + 'karma-firefox-launcher' + ], + + files: [ + './dist/js/*.js', + './test/unit/**/*.js' + ], + + exclude: [ + ], + + singleRun: true, + + reporters: ['dots', 'progress', 'coverage', 'html'], + + colors: false, + + browsers: [ 'PhantomJS', 'Firefox' ], + + preprocessors: { + './dist/js/storyboard.js': ['coverage'] + }, + + coverageReporter: { + type: 'html', + dir: './cover/unit/' + }, + + htmlReporter: { + outputDir: './reports/unit', + templatePath: './node_modules' + + '/karma-html-reporter/jasmine_template.html' + } + }); +}; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..bf87bfda --- /dev/null +++ b/package.json @@ -0,0 +1,57 @@ +{ + "name": "storyboard-webclient", + "version": "0.0.1", + "description": "An all-javascript webclient for the Storyboard API", + "main": "index.html", + "scripts": { + "test": "grunt test" + }, + "repository": "", + "keywords": [ + "openstack", + "storyboard", + "task", + "project management" + ], + "author": "Michael Krotscheck", + "license": "Apache2", + "devDependencies": { + "connect-livereload": "0.3.1", + "karma-jasmine": "0.1.4", + "grunt-contrib-concat": "0.3.0", + "grunt-contrib-copy": "0.4.1", + "grunt-contrib-clean": "0.5.0", + "grunt-html2js": "0.2.3", + "grunt-open": "0.2.2", + "grunt-usemin": "2.0.2", + "grunt-contrib-htmlmin": "0.1.3", + "grunt-contrib-cssmin": "0.7.0", + "grunt-karma": "0.6.2", + "grunt-contrib-connect": "0.5.0", + "grunt-contrib-watch": "0.5.3", + "grunt-contrib-jshint": "0.7.2", + "grunt-contrib-uglify": "0.2.7", + "grunt-contrib-imagemin": "0.4.0", + "grunt-recess": "0.5.0", + "grunt": "0.4.2", + "grunt-cli": "0.1.11", + "matchdep": "0.1.2", + "karma-script-launcher": "0.1.0", + "karma-chrome-launcher": "0.1.1", + "karma-html2js-preprocessor": "0.1.0", + "karma-firefox-launcher": "0.1.2", + "karma-coffee-preprocessor": "0.1.1", + "requirejs": "2.1.9", + "karma-requirejs": "0.2.0", + "karma-phantomjs-launcher": "0.1.1", + "karma": "0.10.8", + "bower": "1.2.8", + "grunt-shell": "0.6.1", + "karma-coverage": "0.1.4", + "grunt-env": "0.4.1", + "protractor": "0.15.0", + "grunt-protractor-runner": "0.2.0", + "selenium-standalone": "2.39.0-2.7.0", + "karma-html-reporter": "~0.1.1" + } +} diff --git a/protractor.conf.js b/protractor.conf.js new file mode 100644 index 00000000..44e0b623 --- /dev/null +++ b/protractor.conf.js @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +// A reference configuration file. +exports.config = { + seleniumServerJar: './node_modules/selenium-standalone/' + + '.selenium/2.39.0/server.jar', + chromeDriver: './node_modules/selenium-standalone/' + + '.selenium/2.39.0/chromedriver', + + chromeOnly: false, + // Additional command line options to pass to selenium. For example, + // if you need to change the browser timeout, use + // seleniumArgs: ['-browserTimeout=60'], + seleniumArgs: [], + + // The timeout for each script run on the browser. This should be longer + // than the maximum time your application needs to stabilize between tasks. + allScriptsTimeout: 11000, + + // ----- What tests to run ----- + // + // Spec patterns are relative to the location of this config. + specs: [ + './test/functional/**/*.js' + ], + + // ----- Capabilities to be passed to the webdriver instance ---- + // + // For a full list of available capabilities, see + // https://code.google.com/p/selenium/wiki/DesiredCapabilities + capabilities: { + 'browserName': 'firefox' + }, + + // ----- More information for your tests ---- + // + // A base URL for your application under test. Calls to protractor.get() + // with relative paths will be prepended with this. + baseUrl: 'http://localhost:9000', + + // Selector for the element housing the angular app - this defaults to + // body, but is necessary if ng-app is on a descendant of + rootElement: 'html', + + // A callback function called once protractor is ready and available, and + // before the specs are executed + // You can specify a file containing code to run by setting onPrepare to + // the filename string. + onPrepare: function () { + // At this point, global 'protractor' object will be set up, and jasmine + // will be available. For example, you can add a Jasmine reporter with: + // jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter( + // 'outputdir/', true, true)); + }, + + // The params object will be passed directly to the protractor instance, + // and can be accessed from your test. It is an arbitrary object and can + // contain anything you may need in your test. + // This can be changed via the command line as: + // --params.login.user 'Joe' + params: { + login: { + user: 'Jane', + password: '1234' + } + }, + + // ----- Options to be passed to minijasminenode ----- + // + // See the full list at https://github.com/juliemr/minijasminenode + jasmineNodeOpts: { + // onComplete will be called just before the driver quits. + onComplete: null, + // If true, display spec names. + isVerbose: false, + // If true, print colors to the terminal. + showColors: true, + // If true, include stack traces in failures. + includeStackTrace: true, + // Default time to wait in ms before a test fails. + defaultTimeoutInterval: 30000 + } +}; diff --git a/src/app/auth/controller/auth_list_controller.js b/src/app/auth/controller/auth_list_controller.js new file mode 100644 index 00000000..a2518661 --- /dev/null +++ b/src/app/auth/controller/auth_list_controller.js @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This controller handles the logic for the authorization provider list page. + * + * @author Michael Krotscheck + */ +angular.module('sb.auth').controller('AuthListController', + function ($scope, authProviders, $state) { + 'use strict'; + + // If there's only one auth provider, just use that. + if (!!authProviders && authProviders.length === 1) { + $state.go('auth.provider.id', {id: authProviders[0].id}); + } + + $scope.authProviders = authProviders; + + }); diff --git a/src/app/auth/controller/auth_login_controller.js b/src/app/auth/controller/auth_login_controller.js new file mode 100644 index 00000000..4051c63f --- /dev/null +++ b/src/app/auth/controller/auth_login_controller.js @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This controller handles the logic for the authorization provider list page. + * + * @author Michael Krotscheck + */ +angular.module('sb.auth').controller('AuthLoginController', + function ($scope, authProvider) { + 'use strict'; + + $scope.authProvider = authProvider; + + }); diff --git a/src/app/auth/module.js b/src/app/auth/module.js new file mode 100644 index 00000000..e6df7717 --- /dev/null +++ b/src/app/auth/module.js @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This Storyboard module contains our adaptive authentication and authorization + * logic. + * + * @author Michael Krotscheck + */ +angular.module('sb.auth', + [ 'sb.services', 'sb.templates', 'ui.router'] + ) + .config(function ($stateProvider, $urlRouterProvider, + AuthProviderResolver) { + 'use strict'; + + // Default rerouting. + $urlRouterProvider.when('/auth', '/auth/provider/list'); + $urlRouterProvider.when('/auth/provider', '/auth/provider/list'); + + // Declare the states for this module. + $stateProvider + .state('auth', { + abstract: true, + url: '/auth', + template: '
' + }) + .state('auth.provider', { + abstract: true, + url: '/provider', + template: '
' + }) + .state('auth.provider.list', { + url: '/list', + templateUrl: 'app/templates/auth/provider/list.html', + controller: 'AuthListController', + resolve: { + authProviders: AuthProviderResolver.resolveAuthProviders + } + }) + .state('auth.provider.id', { + url: '/:id', + templateUrl: 'app/templates/auth/provider/login.html', + controller: 'AuthLoginController', + resolve: { + authProvider: AuthProviderResolver.resolveAuthProvider('id') + } + }); + }); \ No newline at end of file diff --git a/src/app/pages/module.js b/src/app/pages/module.js new file mode 100644 index 00000000..5ffda99a --- /dev/null +++ b/src/app/pages/module.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * The Storyboard pages submodule contains mostly static content pages that + * require little functionality themselves. + * + * @author Michael Krotscheck + */ +angular.module('sb.pages', + [ 'sb.services', 'sb.templates', 'sb.pages', 'ui.router'] + ) + .config(function ($stateProvider) { + 'use strict'; + + // Set our page routes. + $stateProvider + .state('page', { + abstract: true, + url: '/page', + template: '
' + }) + .state('page.about', { + url: '/about', + templateUrl: 'app/templates/page/about.html' + }); + }); \ No newline at end of file diff --git a/src/app/projects/controllers/project_list_controller.js b/src/app/projects/controllers/project_list_controller.js new file mode 100644 index 00000000..1ce591ed --- /dev/null +++ b/src/app/projects/controllers/project_list_controller.js @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * The Storyboard project submodule handles most activity surrounding the + * creation and management of projects. + */ +angular.module('sb.projects').controller('ProjectListController', + function ($scope) { + 'use strict'; + + $scope.search = function () { + + }; + }); diff --git a/src/app/projects/module.js b/src/app/projects/module.js new file mode 100644 index 00000000..ebd4f681 --- /dev/null +++ b/src/app/projects/module.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * The Storyboard project submodule handles most activity surrounding the + * creation and management of projects. + * + * @author Michael Krotscheck + */ +angular.module('sb.projects', ['ui.router', 'sb.services']) + .config(function ($stateProvider, $urlRouterProvider) { + 'use strict'; + + // URL Defaults. + $urlRouterProvider.when('/project', '/project/list'); + + // Set our page routes. + $stateProvider + .state('project', { + abstract: true, + url: '/project', + template: '
' + }) + .state('project.list', { + url: '/list', + templateUrl: 'app/templates/project/provider.html' + }); + }); diff --git a/src/app/services/http/http_error_broadcaster.js b/src/app/services/http/http_error_broadcaster.js new file mode 100644 index 00000000..eb48628b --- /dev/null +++ b/src/app/services/http/http_error_broadcaster.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * An HTTP request interceptor that broadcasts response status codes to the + * rest of the application as events. These events are broadcast before the + * error response itself is passed back to the receiving closure, so please + * keep that in mind as you base your application logic on it. + * + * @author Michael Krotscheck + */ +angular.module('sb.services') + // Create an HTTP Error Broadcaster that intercepts requests and lets the + // rest of the application know about what happened. + .factory('httpErrorBroadcaster', function ($q, $rootScope) { + 'use strict'; + + function sendEvent(status, body) { + // Only send an event if a status is passed. + if (!!status) { + $rootScope.$broadcast('http_' + status, body || {}); + } + } + + + return { + /** + * Handle a success response. + */ + response: function (response) { + if (!!response) { + sendEvent(response.status); + } + return response; + }, + + /** + * Handle a fail response. + */ + responseError: function (response) { + if (!!response) { + sendEvent(response.status, response.body); + } + + return $q.reject(response); + } + }; + }) + // Attach the HTTP interceptor. + .config(function ($httpProvider) { + 'use strict'; + $httpProvider.interceptors.unshift('httpErrorBroadcaster'); + }); \ No newline at end of file diff --git a/src/app/services/module.js b/src/app/services/module.js new file mode 100644 index 00000000..12ca5cda --- /dev/null +++ b/src/app/services/module.js @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * The Storyboard Services module contains all of the necessary API resources + * used by the storyboard client. Its resources are available via injection to + * any module that declares it as a dependency. + * + * @author Michael Krotscheck + */ +angular.module('sb.services', ['ngResource', 'ngCookies', 'ngMockE2E']); \ No newline at end of file diff --git a/src/app/services/provider/storyboard_api_base.js b/src/app/services/provider/storyboard_api_base.js new file mode 100644 index 00000000..ef0d1f31 --- /dev/null +++ b/src/app/services/provider/storyboard_api_base.js @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This provider attempts to discover the API URI base for storyboard, by + * checking various expected configuration parameters. + * + * @author Michael Krotscheck + */ +angular.module('sb.services') + .config(function ($provide, $injector) { + 'use strict'; + + var propertyName = 'storyboardApiBase'; + + // First to see whether something's already been injected. + if ($injector.has(propertyName)) { + // We've already got one, exit. + return; + } + + // Do we have a global ENV property with something we can use? + if (window.hasOwnProperty('ENV')) { + var ENV = window.ENV; + if (ENV !== null && ENV.hasOwnProperty(propertyName)) { + $provide.constant(propertyName, ENV[propertyName]); + return; + } + } + + // If there is a tag, then we can use that. + if ($('base').length > 0) { + $provide.constant(propertyName, ''); + return; + } + + // Neither of those work, so default to something sane on the current + // domain + $provide.constant(propertyName, '/api/v1'); + }); diff --git a/src/app/services/resolver/auth_provider_resolver.js b/src/app/services/resolver/auth_provider_resolver.js new file mode 100644 index 00000000..03f4e616 --- /dev/null +++ b/src/app/services/resolver/auth_provider_resolver.js @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This collection of utility methods allow us to pre-resolve AuthProvider + * resources before a UI route switch is completed. + * + * @author Michael Krotscheck + */ +angular.module('sb.services').constant('AuthProviderResolver', { + + /** + * Resolves all available authorization providers. + */ + resolveAuthProviders: function ($q, AuthProvider, $log) { + 'use strict'; + + $log.debug('Resolving AuthProviders'); + + var deferred = $q.defer(); + + AuthProvider.query( + function (result) { + deferred.resolve(result); + }, + function (error) { + $log.warn('Route resolution rejected for AuthProviders'); + deferred.reject(error); + }); + + return deferred.promise; + }, + + /** + * Resolves an AuthProvider based on the unique ID passed via the + * stateParams. + */ + resolveAuthProvider: function (stateParamName) { + 'use strict'; + + return function ($q, AuthProvider, $stateParams, $log) { + + var deferred = $q.defer(); + + if (!$stateParams.hasOwnProperty(stateParamName)) { + $log.warn('State did not contain property of name ' + + stateParamName); + + deferred.reject({ + 'error': true + }); + } else { + var id = $stateParams[stateParamName]; + + $log.debug('Resolving AuthProvider: ' + id); + + AuthProvider.get({'id': id}, + function (result) { + deferred.resolve(result); + }, + function (error) { + $log.warn('Route resolution rejected for ' + + 'AuthProvider ' + id); + deferred.reject(error); + }); + + return deferred.promise; + } + }; + } +}); diff --git a/src/app/services/resource/auth_provider.js b/src/app/services/resource/auth_provider.js new file mode 100644 index 00000000..b6d9a29a --- /dev/null +++ b/src/app/services/resource/auth_provider.js @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This resource exposes authorization providers to our angularjs environment, + * allowing us to manage & control them. It's also used during the + * authorization/login process to determine how we're going to allow users to + * log in to storyboard. + * + * @author Michael Krotscheck + */ + +angular.module('sb.services').factory('AuthProvider', + function ($resource, storyboardApiBase) { + 'use strict'; + + return $resource(storyboardApiBase + '/auth/provider/:id', + {id: '@id'}, + { + 'create': { + method: 'POST' + }, + 'get': { + method: 'GET', + cache: true + }, + 'save': { + method: 'PUT' + }, + 'delete': { + method: 'DELETE' + }, + 'query': { + method: 'GET', + isArray: true, + transformResponse: function (data) { + if (data.error) { + return data; + } else { + return data.results; + } + } + } + }); + }); \ No newline at end of file diff --git a/src/app/services/resource/auth_provider_mock.js b/src/app/services/resource/auth_provider_mock.js new file mode 100644 index 00000000..82683ca7 --- /dev/null +++ b/src/app/services/resource/auth_provider_mock.js @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * Mock resource responses for the AuthProvider resource. + * + * @author Michael Krotscheck + */ + +angular.module('sb.services') + .run(function ($httpBackend, $injector) { + 'use strict'; + $httpBackend = $injector.get('$httpBackend'); + + var authProviders = [ + { + 'id': 1, + 'type': 'openid', + 'title': 'OpenID', + 'url': 'https://www.google.com/prediscovered' + + '/redirection/url', + 'params': { + 'list': 'of', + 'additional': 'parameters', + 'required': 'for.this.provider' + } + }, + { + 'id': 2, + 'type': 'openid_connect', + 'title': 'OpenID Connect', + 'url': 'https://www.google.com/prediscovered' + + '/redirection/url', + 'params': { + 'list': 'of', + 'additional': 'parameters', + 'required': 'for.this.provider' + } + }, + { + 'id': 3, + 'type': 'ldap', + 'title': 'LDAP', + 'url': 'https://www.google.com/prediscovered' + + '/redirection/url', + 'params': { + 'list': 'of', + 'additional': 'parameters', + 'required': 'for.this.provider' + } + } + ]; + + $httpBackend.when('GET', '/api/v1/auth/provider') + .respond( + { + total: 1, + offset: 0, + limit: 10, + results: authProviders + } + ); + + $httpBackend.when('GET', '/api/v1/auth/provider/1') + .respond(authProviders[0]); + $httpBackend.when('GET', '/api/v1/auth/provider/2') + .respond(authProviders[1]); + $httpBackend.when('GET', '/api/v1/auth/provider/3') + .respond(authProviders[2]); + }); \ No newline at end of file diff --git a/src/app/storyboard.js b/src/app/storyboard.js new file mode 100644 index 00000000..fd58d12c --- /dev/null +++ b/src/app/storyboard.js @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * The Storyboard root application module. + * + * This module contains the entire, standalone application for the Storyboard + * ticket tracking web client. + * + * @author Michael Krotscheck + */ +angular.module('storyboard', + [ 'sb.services', 'sb.templates', 'sb.pages', 'sb.projects', 'sb.auth', + 'ui.router'] + ) + .config(function ($provide, $stateProvider, $urlRouterProvider, + $locationProvider, $httpProvider) { + 'use strict'; + + // Default URL hashbang route + $urlRouterProvider.otherwise('/'); + + // Override the hash prefix for Google's AJAX crawling. + $locationProvider.hashPrefix('!'); + + // Set an intial home page. + $stateProvider + .state('index', { + url: '/', + templateUrl: 'app/templates/index.html' + }); + + // Attach common request headers out of courtesy to the API + $httpProvider.defaults.headers.common['X-Client'] = 'Storyboard'; + + }) + .run(function ($log, $rootScope, $location) { + 'use strict'; + + // Listen to changes on the root scope. If it's an error in the state + // changes (i.e. a 404) take the user back to the index. + $rootScope.$on('$stateChangeError', + function () { + $location.path('/'); + }); + }); \ No newline at end of file diff --git a/src/app/templates/auth/provider/list.html b/src/app/templates/auth/provider/list.html new file mode 100644 index 00000000..198ae419 --- /dev/null +++ b/src/app/templates/auth/provider/list.html @@ -0,0 +1,33 @@ + + +
+
+
+

How would you like to log in?

+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/templates/auth/provider/login.html b/src/app/templates/auth/provider/login.html new file mode 100644 index 00000000..f5967fe1 --- /dev/null +++ b/src/app/templates/auth/provider/login.html @@ -0,0 +1,23 @@ + + +
+
+
+

Login with {{authProvider.title}}

+
+
+
\ No newline at end of file diff --git a/src/app/templates/footer.html b/src/app/templates/footer.html new file mode 100644 index 00000000..06e352a4 --- /dev/null +++ b/src/app/templates/footer.html @@ -0,0 +1,23 @@ + +
+
+ + Powered by Storyboard | + About + + +
\ No newline at end of file diff --git a/src/app/templates/header.html b/src/app/templates/header.html new file mode 100644 index 00000000..4d8d535e --- /dev/null +++ b/src/app/templates/header.html @@ -0,0 +1,55 @@ + + +
+ + +
diff --git a/src/app/templates/index.html b/src/app/templates/index.html new file mode 100644 index 00000000..3fd9cbac --- /dev/null +++ b/src/app/templates/index.html @@ -0,0 +1,67 @@ + + +
+
+
+

Storyboard

+ +

A task tracking system for inter-related + projects.

+ +

StoryBoard lets you track what needs to be done across projects + and branches. + It is a proof-of-concept demo of what the ideal OpenStack task + tracker would + look like. It may or may not end up replacing Launchpad + Bugs/Blueprints for OpenStack task tracking and release + management.

+
+
+
+
+

Stories

+ +

It all begins with a story. A story is a bug + report or proposed feature. Stories are then further split into + tasks, which affect a given project and branch. + You can easily track backports of bugs to a specific branch, or + plan cross-project features.

+ Access Stories +
+
+

Projects

+ +

StoryBoard lets you efficiently track your work across a large + number of interrelated projects. Flexible project + groups lets you get the views that makes the most + sense to you.

+ Access Projects + +
+
+

But why?

+ +

The OpenStack project is now running into a number of limitations + and annoying differences in workflow with Launchpad. At the same + time, Launchpad development stalled, leaving us with little + chances to improve the tool to suit our needs. This POC reuses + key Launchpad concepts (like bug tasks) and goes beyond.

+ See project README +
+
+
\ No newline at end of file diff --git a/src/app/templates/page/about.html b/src/app/templates/page/about.html new file mode 100644 index 00000000..d58616d8 --- /dev/null +++ b/src/app/templates/page/about.html @@ -0,0 +1,95 @@ + + +
+
+
+

About Storyboard

+
+
+
+
+ +

Waxy gurn trimmed Leonine, waxy gurn 118 118 trimmed john cleese + theodore roosevelt charity donate socially mobile cigars Leonine + lando calrissian, john cleese testosterone trophy waxy gurn + musketeer lando calrissian helllloooo charming villain cigars + socially mobile 118 118 charity donate theodore roosevelt comb + Leonine trimmed. +

+ + + +

+ Old west sheriff comb soup strainer don’t panic en time-warped + cabbie, rugged et tudor philosopher comb don’t panic en + time-warped cabbie old west sheriff admiral soup strainer, + rugged et bruce forsyth clone zone shopper super mario comb old + west sheriff don’t panic en time-warped cabbie groomed country + baron admiral tudor philosopher soup strainer. +

+ +

+ Wario et sodales cum mustachioed wario hairy lipsum, holiday + waiter bruce forsyth hairy lipsum dick van dyke wario theodore + roosevelt wario leader of men horseshoe brandy sportacus + mustachioed et sodales cum, sportacus albert einstein leader of + men dick van dyke et sodales cum brandy wario theodore roosevelt + furry facial friend jolly good show bruce forsyth horseshoe + hairy lipsum holiday waiter wario mustachioed? Rock n roll star + groucho-a-like borat beefeater fox hunting, borat beefeater + groucho-a-like ian rush fox hunting toothbrush robot moustache + rock n roll star yeoman farmer groomed, robot moustache tudor + philosopher wario yeoman farmer groomed groucho-a-like borat ian + rush toothbrush beefeater rock n roll star hungarian fox + hunting? + +

+ +

Groucho marx mr frothy-top glorious facial hair mr + frothy-top albert einstein furry facial friend stiff upper lip. + Robert winston um yesbaby middle eastern despot brigadier + godlike sweat irrigator,, brigadier middle eastern despot sweat + irrigator, zap rowsdower jolly good show iron tache godlike + robert winston um yesbaby.

+ +
+ +

+
+
\ No newline at end of file diff --git a/src/app/templates/project/list.html b/src/app/templates/project/list.html new file mode 100644 index 00000000..d91f54d3 --- /dev/null +++ b/src/app/templates/project/list.html @@ -0,0 +1,48 @@ + + +
+
+
+ + + + +
+
+

Projects

+ + + + + + + + + + +
NameTitle
+ +
+ +
+
diff --git a/src/app/util/directive/active_path.js b/src/app/util/directive/active_path.js new file mode 100644 index 00000000..a5b2ab44 --- /dev/null +++ b/src/app/util/directive/active_path.js @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This directive requires ui-router, as it listens for events dispatched as + * a user navigates through the application, and adds the 'active' class to + * the bound element if the user's selected path matches the one configured. + * + * @author Michael Krotscheck + */ +angular.module('sb.util').directive('activePath', + function ($location, $rootScope) { + 'use strict'; + + return { + link: function ($scope, element, attrs) { + var activePath = attrs.activePath; + + function setActivePath() { + var isActive = activePath === $location.path(); + element.toggleClass('active', isActive); + } + + $scope.$on('$destroy', + $rootScope.$on('$stateChangeSuccess', setActivePath) + ); + + // INIT + setActivePath(); + } + }; + }); \ No newline at end of file diff --git a/src/app/util/directive/enter.js b/src/app/util/directive/enter.js new file mode 100644 index 00000000..e49aa49e --- /dev/null +++ b/src/app/util/directive/enter.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * This directive adds the often sought, but never found, ng-enter directive. + * It intercepts keystrokes and will execute the bound method if that keystroke + * is the enter key. + * + * @author Michael Krotscheck + */ +angular.module('sb.util').directive('ngEnter', function () { + 'use strict'; + + return function (scope, element, attrs) { + + element.bind('keydown keypress', function (event) { + if (event.which === 13) { + scope.$apply(function () { + scope.$eval(attrs.ngEnter); + }); + + event.preventDefault(); + } + }); + }; +}); diff --git a/src/app/util/filter/debug_filter.js b/src/app/util/filter/debug_filter.js new file mode 100644 index 00000000..090ddf87 --- /dev/null +++ b/src/app/util/filter/debug_filter.js @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * A helpful development filter that will console.log out any value you bind + * to it in the DOM. You should probably only use this while debugging. + * + * @author Michael Krotscheck + */ +angular.module('sb.util').filter('debug', + function () { + 'use strict'; + + return function (value) { + console.warn('DEBUG', value); + return value; + }; + }); \ No newline at end of file diff --git a/src/app/util/module.js b/src/app/util/module.js new file mode 100644 index 00000000..a4b691bf --- /dev/null +++ b/src/app/util/module.js @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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('sb.util', ['ui.router']); \ No newline at end of file diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 00000000..40b3ac5d Binary files /dev/null and b/src/favicon.ico differ diff --git a/src/fonts/custom_font_icons.eot b/src/fonts/custom_font_icons.eot new file mode 100644 index 00000000..a2c2073a Binary files /dev/null and b/src/fonts/custom_font_icons.eot differ diff --git a/src/fonts/custom_font_icons.ttf b/src/fonts/custom_font_icons.ttf new file mode 100644 index 00000000..7df7ca39 Binary files /dev/null and b/src/fonts/custom_font_icons.ttf differ diff --git a/src/fonts/custom_font_icons.woff b/src/fonts/custom_font_icons.woff new file mode 100644 index 00000000..18df7d64 Binary files /dev/null and b/src/fonts/custom_font_icons.woff differ diff --git a/src/images/logo/logo_128.png b/src/images/logo/logo_128.png new file mode 100644 index 00000000..b52a9a13 Binary files /dev/null and b/src/images/logo/logo_128.png differ diff --git a/src/images/logo/logo_16.png b/src/images/logo/logo_16.png new file mode 100644 index 00000000..2bfe2a84 Binary files /dev/null and b/src/images/logo/logo_16.png differ diff --git a/src/images/logo/logo_256.png b/src/images/logo/logo_256.png new file mode 100644 index 00000000..2c5031fa Binary files /dev/null and b/src/images/logo/logo_256.png differ diff --git a/src/images/logo/logo_32.png b/src/images/logo/logo_32.png new file mode 100644 index 00000000..a9006d28 Binary files /dev/null and b/src/images/logo/logo_32.png differ diff --git a/src/images/logo/logo_48.png b/src/images/logo/logo_48.png new file mode 100644 index 00000000..ecc06156 Binary files /dev/null and b/src/images/logo/logo_48.png differ diff --git a/src/images/logo/logo_512.png b/src/images/logo/logo_512.png new file mode 100644 index 00000000..146bcd47 Binary files /dev/null and b/src/images/logo/logo_512.png differ diff --git a/src/images/logo/logo_64.png b/src/images/logo/logo_64.png new file mode 100644 index 00000000..ad528654 Binary files /dev/null and b/src/images/logo/logo_64.png differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 00000000..b6dc20f5 --- /dev/null +++ b/src/index.html @@ -0,0 +1,61 @@ + + + + + + + + Storyboard + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/src/robots.txt b/src/robots.txt new file mode 100644 index 00000000..94174950 --- /dev/null +++ b/src/robots.txt @@ -0,0 +1,3 @@ +# robotstxt.org + +User-agent: * diff --git a/src/styles/auth.less b/src/styles/auth.less new file mode 100644 index 00000000..4fdc35e2 --- /dev/null +++ b/src/styles/auth.less @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * Styles specific to the auth pages. + */ +a.auth-provider.btn { + text-align: left; + padding-left: 10px; + padding-right: 10px; +} \ No newline at end of file diff --git a/src/styles/custom_font_icons.less b/src/styles/custom_font_icons.less new file mode 100644 index 00000000..bfd25292 --- /dev/null +++ b/src/styles/custom_font_icons.less @@ -0,0 +1,24 @@ +@font-face { + font-family: custom_font_icons; + src: url(../fonts/custom_font_icons.eot); + src: url(../fonts/custom_font_icons.eot?#iefix) format("embedded-opentype"), url(../fonts/custom_font_icons.woff) format("woff"), url(../fonts/custom_font_icons.ttf) format("truetype"); + font-weight: 400; + font-style: normal +} + +.icon { + font-family: custom_font_icons; + display: inline-block; + font-weight: 400; + font-style: normal; + speak: none; + text-decoration: inherit; + text-transform: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.icon_openstack:before { + content: "\f100" +} \ No newline at end of file diff --git a/src/styles/main.less b/src/styles/main.less new file mode 100644 index 00000000..fd0827bd --- /dev/null +++ b/src/styles/main.less @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +/** + * Our main SCSS layout. + */ +body { + margin-top: 70px; +} + +i.icon { + line-height: .5em; +} \ No newline at end of file diff --git a/test/functional/module.js b/test/functional/module.js new file mode 100644 index 00000000..7c9c338b --- /dev/null +++ b/test/functional/module.js @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +describe('Storyboard Homepage', function () { + 'use strict'; + + it('should have storyboard as the title', function () { + // Load the AngularJS homepage. + browser.get('http://localhost:9000'); + + var title = element(by.tagName('title')); + expect(title.getInnerHtml()).toEqual('Storyboard'); + }); +}); diff --git a/test/integration/services/module.js b/test/integration/services/module.js new file mode 100644 index 00000000..4fa4cdd2 --- /dev/null +++ b/test/integration/services/module.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +describe('sb.services', function () { + 'use strict'; + + var module; + var dependencies = []; + + var hasModule = function (module) { + return dependencies.indexOf(module) >= 0; + }; + + beforeEach(function () { + // Get module + module = angular.module('sb.services'); + dependencies = module.requires; + }); + + it('should exist', function () { + expect(module).toBeTruthy(); + }); + + it('should load cookies module', function () { + expect(hasModule('ngCookies')).toBeTruthy(); + }); +}); diff --git a/test/unit/services/module.js b/test/unit/services/module.js new file mode 100644 index 00000000..4fa4cdd2 --- /dev/null +++ b/test/unit/services/module.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 Hewlett-Packard Development Company, L.P. + * + * 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. + */ + +describe('sb.services', function () { + 'use strict'; + + var module; + var dependencies = []; + + var hasModule = function (module) { + return dependencies.indexOf(module) >= 0; + }; + + beforeEach(function () { + // Get module + module = angular.module('sb.services'); + dependencies = module.requires; + }); + + it('should exist', function () { + expect(module).toBeTruthy(); + }); + + it('should load cookies module', function () { + expect(hasModule('ngCookies')).toBeTruthy(); + }); +});