├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── app ├── index.js └── templates │ ├── Gruntfile.js │ ├── _README.md │ ├── _bower.json │ ├── _package.json │ ├── assets │ ├── javascripts │ │ ├── application.coffee │ │ └── dashing.coffee │ └── stylesheets │ │ └── application.scss │ ├── bowerrc │ ├── dashboards │ ├── layout.gerb │ └── sample.gerb │ ├── gitattributes │ ├── gitignore │ ├── jobs │ ├── buzzwords.go │ ├── convergence.go │ └── sample.go │ ├── public │ ├── 404.html │ ├── favicon.ico │ └── images │ │ └── logo.png │ ├── server.go │ └── widgets │ ├── clock │ ├── clock.coffee │ ├── clock.html │ └── clock.scss │ ├── comments │ ├── comments.coffee │ ├── comments.html │ └── comments.scss │ ├── graph │ ├── graph.coffee │ ├── graph.html │ └── graph.scss │ ├── iframe │ ├── iframe.coffee │ ├── iframe.html │ └── iframe.scss │ ├── image │ ├── image.coffee │ ├── image.html │ └── image.scss │ ├── list │ ├── list.coffee │ ├── list.html │ └── list.scss │ ├── meter │ ├── meter.coffee │ ├── meter.html │ └── meter.scss │ ├── number │ ├── number.coffee │ ├── number.html │ └── number.scss │ └── text │ ├── text.coffee │ ├── text.html │ └── text.scss ├── dashboard ├── index.js └── templates │ └── dashboard.gerb ├── job ├── index.js └── templates │ └── _job.go ├── package.json ├── screenshot.png ├── test ├── test-creation.js └── test-load.js └── widget ├── index.js └── templates ├── _widget.coffee ├── _widget.scss └── widget.html /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*.js] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | temp/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Chris Heng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | generator-dashing-go 2 | ==================== 3 | 4 | This is a [Yeoman][1] generator for creating dashboards with the [dashing-go][2] library, a Go port of [Shopify/dashing][3]. 5 | 6 | The dashboard runs on the [Martini][4] microframework, while the frontend dependencies are managed by [Grunt][5] and [Bower][6]. 7 | 8 | ![screenshot](https://raw.githubusercontent.com/gigablah/generator-dashing-go/master/screenshot.png) 9 | 10 | For a live demo, check out the [sample dashboard][7]. 11 | 12 | ## Requirements 13 | 14 | * [Git][8] 15 | * [Node.js ~0.10][9] 16 | * [Go ~1.2][10] 17 | 18 | ## Installation 19 | 20 | Install Yeoman, and dependencies: 21 | 22 | npm install -g yo grunt grunt-cli bower 23 | 24 | Install the dashing-go generator: 25 | 26 | npm install -g generator-dashing-go 27 | 28 | ## Creating a project 29 | 30 | Create a new directory: 31 | 32 | mkdir my-dashboard && cd $_ 33 | 34 | Generate the project (this will also run the initial Bower and Grunt tasks): 35 | 36 | yo dashing-go 37 | 38 | Grab the Go dependencies: 39 | 40 | go get 41 | 42 | Start the server: 43 | 44 | go run server.go 45 | 46 | The sample dashboard is now available at [http://localhost:3000](http://localhost:3000). 47 | 48 | ## Asset pipeline 49 | 50 | The `init` task copies third party assets (installed by Bower) into position and compiles BatmanJS. This should have been run automatically as a post-install script, but if you've added new dependencies or need to do it manually: 51 | 52 | bower install 53 | grunt init 54 | 55 | ## Hot reloading 56 | 57 | You may also start a livereload server that watches the `assets` directory for changes and runs the build pipeline automatically. When you access it (port 9000 by default), it injects a script into the page that initiates a reload whenever the compiled assets are updated. 58 | 59 | grunt serve 60 | 61 | ## Building Stuff 62 | 63 | grunt build 64 | 65 | If you need to build just `application.js` or `application.css`, you may run each task individually: 66 | 67 | grunt js 68 | grunt css 69 | 70 | ## Minifying Stuff 71 | 72 | grunt minify 73 | 74 | `application.js` and `application.css` are minified in-place. 75 | 76 | ## Generating Stuff 77 | 78 | Create new dashboards, jobs and widgets: 79 | 80 | yo dashing-go:dashboard foo 81 | yo dashing-go:job foo 82 | yo dashing-go:widget foo 83 | 84 | Note the following naming conventions (the generator automatically enforces them): 85 | 86 | * dashed-slug for widget and dashboard names 87 | * under_score for Go job filenames 88 | * camelCase for Go job structs 89 | 90 | Existing third party Dashing widgets should be compatible with dashing-go. 91 | 92 | ## License 93 | 94 | Released under the MIT license. 95 | 96 | [1]: http://yeoman.io 97 | [2]: https://github.com/gigablah/dashing-go 98 | [3]: http://shopify.github.io/dashing 99 | [4]: http://martini.codegangsta.io 100 | [5]: http://gruntjs.com 101 | [6]: http://bower.io 102 | [7]: http://dashing.kuanyen.net 103 | [8]: http://git-scm.com 104 | [9]: http://nodejs.org 105 | [10]: http://golang.org 106 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var yeoman = require('yeoman-generator'); 5 | 6 | var DashingGoGenerator = yeoman.generators.Base.extend({ 7 | init: function () { 8 | this.pkg = require('../package.json'); 9 | 10 | this.on('end', function () { 11 | if (!this.options['skip-install']) { 12 | this.installDependencies(); 13 | } 14 | }); 15 | }, 16 | 17 | askFor: function () { 18 | var done = this.async(); 19 | 20 | // have Yeoman greet the user 21 | this.log(this.yeoman); 22 | 23 | this.log('\n' + 24 | " _ _ _ \n" + 25 | " __| | __ _ ___| |__ (_)_ __ __ _ __ _ ___ \n" + 26 | " / _` |/ _` / __| '_ \\| | '_ \\ / _` |___/ _` |/ _ \\ \n" + 27 | "| (_| | (_| \\__ \\ | | | | | | | (_| /__| (_| | (_) |\n" + 28 | " \\__,_|\\__,_|___/_| |_|_|_| |_|\\__, | \\__, |\\___/ \n" + 29 | " |___/ |___/ \n" + 30 | '\n'); 31 | 32 | var prompts = [{ 33 | name: 'appName', 34 | message: 'What would you like to call your project?', 35 | default: 'dashboard' 36 | }]; 37 | 38 | this.prompt(prompts, function (props) { 39 | this.appName = props.appName; 40 | 41 | done(); 42 | }.bind(this)); 43 | }, 44 | 45 | app: function () { 46 | this.directory('assets', 'assets'); 47 | this.directory('dashboards', 'dashboards'); 48 | this.directory('jobs', 'jobs'); 49 | this.directory('public', 'public'); 50 | this.directory('widgets', 'widgets'); 51 | 52 | this.copy('server.go', 'server.go'); 53 | 54 | this.mkdir('build'); 55 | this.mkdir('public/javascripts'); 56 | this.mkdir('public/stylesheets'); 57 | }, 58 | 59 | git: function () { 60 | this.copy('gitignore', '.gitignore'); 61 | this.copy('gitattributes', '.gitattributes'); 62 | }, 63 | 64 | bower: function () { 65 | this.copy('bowerrc', '.bowerrc'); 66 | this.template('_bower.json', 'bower.json'); 67 | }, 68 | 69 | package: function () { 70 | this.template('_package.json', 'package.json'); 71 | }, 72 | 73 | grunt: function () { 74 | this.copy('Gruntfile.js', 'Gruntfile.js'); 75 | } 76 | }); 77 | 78 | module.exports = DashingGoGenerator; 79 | -------------------------------------------------------------------------------- /app/templates/Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var LIVERELOAD_PORT = 35729; 4 | 5 | module.exports = function (grunt) { 6 | // Load all grunt tasks 7 | require('load-grunt-tasks')(grunt); 8 | // Show elapsed time at the end 9 | require('time-grunt')(grunt); 10 | 11 | // Project configuration. 12 | grunt.initConfig({ 13 | // Metadata. 14 | pkg: grunt.file.readJSON('package.json'), 15 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> */\n', 16 | dir: { 17 | asset: 'assets/', 18 | build: 'build/', 19 | bower: 'bower_components/' 20 | }, 21 | // Task configuration. 22 | clean: { 23 | build: [ 24 | '<%= dir.build %>*' 25 | ] 26 | }, 27 | copy: { 28 | static: { 29 | files: [ 30 | { cwd: '<%= dir.bower %>font-awesome/fonts/', src: ['**'], dest: 'public/fonts/', expand: true } 31 | ] 32 | }, 33 | js: { 34 | files: [ 35 | { cwd: '<%= dir.bower %>es5-shim/', src: ['es5-shim.js'], dest: '<%= dir.build %>dashing/', expand: true }, 36 | { cwd: '<%= dir.bower %>jquery/dist/', src: ['jquery.js'], dest: '<%= dir.build %>dashing/', expand: true }, 37 | { cwd: '<%= dir.bower %>gridster/dist/', src: ['jquery.gridster.js'], dest: '<%= dir.build %>application/', expand: true }, 38 | { cwd: '<%= dir.bower %>jquery-knob/js/', src: ['jquery.knob.js'], dest: '<%= dir.build %>application/', expand: true }, 39 | { cwd: '<%= dir.bower %>jquery-leanmodal/', src: ['jquery.leanModal.js'], dest: '<%= dir.build %>application/', expand: true }, 40 | { cwd: '<%= dir.bower %>rickshaw/', src: ['rickshaw.js'], dest: '<%= dir.build %>application/', expand: true }, 41 | { cwd: '<%= dir.bower %>d3/', src: ['d3.js'], dest: '<%= dir.build %>application/', expand: true } 42 | ] 43 | }, 44 | css: { 45 | files: [ 46 | { cwd: '<%= dir.bower %>font-awesome/css/', src: ['font-awesome.css'], dest: '<%= dir.build %>css/lib/', expand: true }, 47 | { cwd: '<%= dir.bower %>gridster/dist/', src: ['jquery.gridster.css'], dest: '<%= dir.build %>css/lib/', expand: true } 48 | ] 49 | }, 50 | coffee: { 51 | files: [ 52 | { cwd: '<%= dir.asset %>javascripts/', src: ['dashing.coffee'], dest: '<%= dir.build %>dashing/', expand: true }, 53 | { cwd: '<%= dir.asset %>javascripts/', src: ['application.coffee'], dest: '<%= dir.build %>application/', expand: true } 54 | ] 55 | } 56 | }, 57 | 'string-replace': { 58 | fix_abstract_binding: { 59 | options: { 60 | replacements: [ 61 | { pattern: /(@accessor 'filteredValue')$/m, replacement: "$1," }, 62 | { pattern: /(@accessor 'unfilteredValue')$/m, replacement: "$1," } 63 | ] 64 | }, 65 | src: '<%= dir.bower %>batman/src/view/bindings/abstract_binding.coffee', 66 | dest: '<%= dir.bower %>batman/src/view/bindings/abstract_binding.coffee' 67 | }, 68 | fix_view: { 69 | options: { 70 | replacements: [ 71 | { pattern: /(@accessor 'node')$/m, replacement: "$1," } 72 | ] 73 | }, 74 | src: '<%= dir.bower %>batman/src/view/view.coffee', 75 | dest: '<%= dir.bower %>batman/src/view/view.coffee' 76 | } 77 | }, 78 | snockets: { 79 | batman: { 80 | src: '<%= dir.bower %>batman/src/batman.coffee', 81 | dest: '<%= dir.build %>dashing/batman.js' 82 | }, 83 | batman_jquery: { 84 | src: '<%= dir.bower %>batman/src/platform/jquery.coffee', 85 | dest: '<%= dir.build %>dashing/batman.jquery.js' 86 | }, 87 | dashing: { 88 | src: '<%= dir.build %>dashing/dashing.coffee', 89 | dest: '<%= dir.build %>application/dashing.js' 90 | }, 91 | application: { 92 | src: '<%= dir.build %>application/application.coffee', 93 | dest: 'public/javascripts/application.js' 94 | } 95 | }, 96 | sass: { 97 | widgets: { 98 | cwd: 'widgets/', 99 | src: '**/*.scss', 100 | dest: '<%= dir.build %>css/widgets/', 101 | expand: true, 102 | flatten: true, 103 | ext: '.css' 104 | }, 105 | application: { 106 | src: '<%= dir.asset %>stylesheets/application.scss', 107 | dest: '<%= dir.build %>css/application.css' 108 | } 109 | }, 110 | concat: { 111 | css: { 112 | src: [ 113 | '<%= dir.build %>css/lib/*.css', 114 | '<%= dir.build %>css/widgets/*.css', 115 | '<%= dir.build %>css/application.css' 116 | ], 117 | dest: 'public/stylesheets/application.css', 118 | } 119 | }, 120 | uglify: { 121 | options: { 122 | banner: '<%= banner %>' 123 | }, 124 | application: { 125 | src: '<%= snockets.application.dest %>', 126 | dest: '<%= snockets.application.dest %>' 127 | } 128 | }, 129 | cssmin: { 130 | application: { 131 | src: '<%= concat.css.dest %>', 132 | dest: '<%= concat.css.dest %>' 133 | } 134 | }, 135 | watch: { 136 | options: { 137 | livereload: LIVERELOAD_PORT 138 | }, 139 | src: { 140 | files: [ 141 | '<%= dir.asset %>javascripts/**/*', 142 | '<%= dir.asset %>stylesheets/**/*', 143 | 'widgets/**/*' 144 | ], 145 | tasks: ['build'] 146 | }, 147 | livereload: { 148 | options: { 149 | livereload: true 150 | }, 151 | files: [ 152 | 'public/**/*' 153 | ] 154 | } 155 | }, 156 | connect: { 157 | options: { 158 | hostname: '0.0.0.0', 159 | port: 9000, 160 | livereload: LIVERELOAD_PORT 161 | }, 162 | server: { 163 | proxies: [ 164 | { 165 | context: [''], 166 | host: '0.0.0.0', 167 | port: 3000, 168 | https: false, 169 | changeOrigin: false 170 | } 171 | ], 172 | }, 173 | livereload: { 174 | options: { 175 | open: true, 176 | base: ['public'], 177 | middleware: function () { 178 | return [require('grunt-connect-proxy/lib/utils').proxyRequest]; 179 | } 180 | } 181 | } 182 | } 183 | }); 184 | 185 | grunt.registerTask('init', ['clean', 'copy:static', 'copy:js', 'copy:css', 'string-replace', 'snockets:batman', 'snockets:batman_jquery']); 186 | 187 | grunt.registerTask('js', ['copy:coffee', 'snockets:dashing', 'snockets:application']); 188 | grunt.registerTask('css', ['sass', 'concat:css']); 189 | grunt.registerTask('build', ['js', 'css']); 190 | grunt.registerTask('minify', ['uglify', 'cssmin']); 191 | 192 | grunt.registerTask('serve', ['build', 'configureProxies:server', 'connect:livereload', 'watch']); 193 | }; 194 | -------------------------------------------------------------------------------- /app/templates/_README.md: -------------------------------------------------------------------------------- 1 | # <%= _.slugify(appName) %> 2 | 3 | A dashboard to do the thing with the stuff. 4 | 5 | ## Getting Started 6 | 7 | The `init` task copies third party assets (installed by Bower) into position and compiles BatmanJS. This should have been run automatically as a post-install script, but if you've added new dependencies or need to do it manually: 8 | 9 | bower install 10 | grunt init 11 | 12 | ## Running Stuff 13 | 14 | This starts the backend (port 3000 by default). 15 | 16 | go run server.go 17 | 18 | You may also start a livereload server that watches the `assets` directory for changes and runs the build pipeline automatically. When you access it (port 9000 by default), it injects a script into the page that initiates a reload whenever the compiled assets are updated. 19 | 20 | grunt serve 21 | 22 | ## Building Stuff 23 | 24 | grunt build 25 | 26 | If you need to build just `application.js` or `application.css`, you may run each task individually: 27 | 28 | grunt js 29 | grunt css 30 | 31 | ## Minifying Stuff 32 | 33 | grunt minify 34 | 35 | `application.js` and `application.css` are minified in-place. 36 | 37 | ## Generating Stuff 38 | 39 | Create new dashboards, jobs and widgets: 40 | 41 | yo dashing-go:dashboard foo 42 | yo dashing-go:job foo 43 | yo dashing-go:widget foo 44 | 45 | Note the following naming conventions (the generator automatically enforces them): 46 | 47 | * dashed-slug for widget and dashboard names 48 | * under_score for Go job filenames 49 | * camelCase for Go job structs 50 | 51 | Existing third party Dashing widgets should be compatible with dashing-go. 52 | 53 | ## License 54 | 55 | Released under the MIT license. 56 | -------------------------------------------------------------------------------- /app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appName) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "jquery": "~2.1.0", 6 | "es5-shim": "~2.3.0", 7 | "font-awesome": "~4.0.3", 8 | "batman": "~0.14.1", 9 | "d3": "~3.4.3", 10 | "rickshaw": "~1.4.6", 11 | "gridster": "~0.5.1", 12 | "jquery-knob": "~1.2.3", 13 | "jquery-leanmodal": "FinelySliced/leanModal.js" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appName) %>", 3 | "version": "0.0.0", 4 | "description": "A dashing-go dashboard", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/gigablah/generator-dashing-go.git" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "grunt": "~0.4.1", 12 | "load-grunt-tasks": "~0.3.0", 13 | "time-grunt": "~0.2.0", 14 | "grunt-contrib-clean": "~0.5.0", 15 | "grunt-contrib-copy": "~0.5.0", 16 | "grunt-contrib-concat": "~0.3.0", 17 | "grunt-contrib-uglify": "~0.4.0", 18 | "grunt-contrib-cssmin": "~0.9.0", 19 | "grunt-contrib-watch": "~0.6.0", 20 | "grunt-contrib-connect": "~0.7.0", 21 | "grunt-connect-proxy": "~0.1.10", 22 | "grunt-sass": "~0.7.0", 23 | "grunt-string-replace": "~0.2.7", 24 | "grunt-snockets": "umurgdk/grunt-snockets" 25 | }, 26 | "engines": { 27 | "node": ">=0.10.0" 28 | }, 29 | "scripts": { 30 | "postinstall" : "grunt init build" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/templates/assets/javascripts/application.coffee: -------------------------------------------------------------------------------- 1 | # dashing.js is located in the dashing framework 2 | # It includes jquery & batman for you. 3 | #= require dashing.js 4 | 5 | #= require_tree ./ 6 | #= require_tree ../../widgets 7 | 8 | console.log("Yeah! The dashboard has started!") 9 | 10 | Dashing.on 'ready', -> 11 | Dashing.widget_margins ||= [5, 5] 12 | Dashing.widget_base_dimensions ||= [300, 360] 13 | Dashing.numColumns ||= 4 14 | 15 | contentWidth = (Dashing.widget_base_dimensions[0] + Dashing.widget_margins[0] * 2) * Dashing.numColumns 16 | 17 | Batman.setImmediate -> 18 | $('.gridster').width(contentWidth) 19 | $('.gridster ul:first').gridster 20 | widget_margins: Dashing.widget_margins 21 | widget_base_dimensions: Dashing.widget_base_dimensions 22 | avoid_overlapped_widgets: !Dashing.customGridsterLayout 23 | draggable: 24 | stop: Dashing.showGridsterInstructions 25 | start: -> Dashing.currentWidgetPositions = Dashing.getWidgetPositions() 26 | -------------------------------------------------------------------------------- /app/templates/assets/javascripts/dashing.coffee: -------------------------------------------------------------------------------- 1 | #= require jquery 2 | #= require es5-shim 3 | #= require batman 4 | #= require batman.jquery 5 | 6 | 7 | Batman.Filters.prettyNumber = (num) -> 8 | num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") unless isNaN(num) 9 | 10 | Batman.Filters.dashize = (str) -> 11 | dashes_rx1 = /([A-Z]+)([A-Z][a-z])/g; 12 | dashes_rx2 = /([a-z\d])([A-Z])/g; 13 | 14 | return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace(/_/g, '-').toLowerCase() 15 | 16 | Batman.Filters.shortenedNumber = (num) -> 17 | return num if isNaN(num) 18 | if num >= 1000000000 19 | (num / 1000000000).toFixed(1) + 'B' 20 | else if num >= 1000000 21 | (num / 1000000).toFixed(1) + 'M' 22 | else if num >= 1000 23 | (num / 1000).toFixed(1) + 'K' 24 | else 25 | num 26 | 27 | class window.Dashing extends Batman.App 28 | @on 'reload', (data) -> 29 | window.location.reload(true) 30 | 31 | @root -> 32 | Dashing.params = Batman.URI.paramsFromQuery(window.location.search.slice(1)); 33 | 34 | class Dashing.Widget extends Batman.View 35 | constructor: -> 36 | # Set the view path 37 | @constructor::source = Batman.Filters.underscore(@constructor.name) 38 | super 39 | 40 | @mixin($(@node).data()) 41 | Dashing.widgets[@id] ||= [] 42 | Dashing.widgets[@id].push(@) 43 | @mixin(Dashing.lastEvents[@id]) # in case the events from the server came before the widget was rendered 44 | 45 | type = Batman.Filters.dashize(@view) 46 | $(@node).addClass("widget widget-#{type} #{@id}") 47 | 48 | @accessor 'updatedAtMessage', -> 49 | if updatedAt = @get('updatedAt') 50 | timestamp = new Date(updatedAt * 1000) 51 | hours = timestamp.getHours() 52 | minutes = ("0" + timestamp.getMinutes()).slice(-2) 53 | "Last updated at #{hours}:#{minutes}" 54 | 55 | @::on 'ready', -> 56 | Dashing.Widget.fire 'ready' 57 | 58 | receiveData: (data) => 59 | @mixin(data) 60 | @onData(data) 61 | 62 | onData: (data) => 63 | # Widgets override this to handle incoming data 64 | 65 | Dashing.AnimatedValue = 66 | get: Batman.Property.defaultAccessor.get 67 | set: (k, to) -> 68 | if !to? || isNaN(to) 69 | @[k] = to 70 | else 71 | timer = "interval_#{k}" 72 | num = if (!isNaN(@[k]) && @[k]?) then @[k] else 0 73 | unless @[timer] || num == to 74 | to = parseFloat(to) 75 | num = parseFloat(num) 76 | up = to > num 77 | num_interval = Math.abs(num - to) / 90 78 | @[timer] = 79 | setInterval => 80 | num = if up then Math.ceil(num+num_interval) else Math.floor(num-num_interval) 81 | if (up && num > to) || (!up && num < to) 82 | num = to 83 | clearInterval(@[timer]) 84 | @[timer] = null 85 | delete @[timer] 86 | @[k] = num 87 | @set k, to 88 | , 10 89 | @[k] = num 90 | 91 | Dashing.widgets = widgets = {} 92 | Dashing.lastEvents = lastEvents = {} 93 | Dashing.debugMode = false 94 | 95 | source = new EventSource('events') 96 | source.addEventListener 'open', (e) -> 97 | console.log("Connection opened", e) 98 | 99 | source.addEventListener 'error', (e)-> 100 | console.log("Connection error", e) 101 | if (e.currentTarget.readyState == EventSource.CLOSED) 102 | console.log("Connection closed") 103 | setTimeout (-> 104 | window.location.reload() 105 | ), 5*60*1000 106 | 107 | source.addEventListener 'message', (e) -> 108 | data = JSON.parse(e.data) 109 | if lastEvents[data.id]?.updatedAt != data.updatedAt 110 | if Dashing.debugMode 111 | console.log("Received data for #{data.id}", data) 112 | lastEvents[data.id] = data 113 | if widgets[data.id]?.length > 0 114 | for widget in widgets[data.id] 115 | widget.receiveData(data) 116 | 117 | source.addEventListener 'dashboards', (e) -> 118 | data = JSON.parse(e.data) 119 | if Dashing.debugMode 120 | console.log("Received data for dashboards", data) 121 | if data.dashboard is '*' or window.location.pathname is "/#{data.dashboard}" 122 | Dashing.fire data.event, data 123 | 124 | $(document).ready -> 125 | Dashing.run() 126 | -------------------------------------------------------------------------------- /app/templates/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | /* 2 | //=require_directory . 3 | //=require_tree ../../widgets 4 | */ 5 | // ---------------------------------------------------------------------------- 6 | // Sass declarations 7 | // ---------------------------------------------------------------------------- 8 | $background-color: #222; 9 | $text-color: #fff; 10 | 11 | $background-warning-color-1: #e82711; 12 | $background-warning-color-2: #9b2d23; 13 | $text-warning-color: #fff; 14 | 15 | $background-danger-color-1: #eeae32; 16 | $background-danger-color-2: #ff9618; 17 | $text-danger-color: #fff; 18 | 19 | @-webkit-keyframes status-warning-background { 20 | 0% { background-color: $background-warning-color-1; } 21 | 50% { background-color: $background-warning-color-2; } 22 | 100% { background-color: $background-warning-color-1; } 23 | } 24 | @-webkit-keyframes status-danger-background { 25 | 0% { background-color: $background-danger-color-1; } 26 | 50% { background-color: $background-danger-color-2; } 27 | 100% { background-color: $background-danger-color-1; } 28 | } 29 | @mixin animation($animation-name, $duration, $function, $animation-iteration-count:""){ 30 | -webkit-animation: $animation-name $duration $function #{$animation-iteration-count}; 31 | -moz-animation: $animation-name $duration $function #{$animation-iteration-count}; 32 | -ms-animation: $animation-name $duration $function #{$animation-iteration-count}; 33 | } 34 | 35 | // ---------------------------------------------------------------------------- 36 | // Base styles 37 | // ---------------------------------------------------------------------------- 38 | html { 39 | font-size: 100%; 40 | -webkit-text-size-adjust: 100%; 41 | -ms-text-size-adjust: 100%; 42 | } 43 | 44 | body { 45 | margin: 0; 46 | background-color: $background-color; 47 | font-size: 20px; 48 | color: $text-color; 49 | font-family: 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; 50 | } 51 | 52 | b, strong { 53 | font-weight: bold; 54 | } 55 | 56 | a { 57 | text-decoration: none; 58 | color: inherit; 59 | } 60 | 61 | img { 62 | border: 0; 63 | -ms-interpolation-mode: bicubic; 64 | vertical-align: middle; 65 | } 66 | 67 | img, object { 68 | max-width: 100%; 69 | } 70 | 71 | iframe { 72 | max-width: 100%; 73 | } 74 | 75 | table { 76 | border-collapse: collapse; 77 | border-spacing: 0; 78 | width: 100%; 79 | } 80 | 81 | td { 82 | vertical-align: middle; 83 | } 84 | 85 | ul, ol { 86 | padding: 0; 87 | margin: 0; 88 | } 89 | 90 | h1, h2, h3, h4, h5, p { 91 | padding: 0; 92 | margin: 0; 93 | } 94 | h1 { 95 | margin-bottom: 12px; 96 | text-align: center; 97 | font-size: 30px; 98 | font-weight: 400; 99 | } 100 | h2 { 101 | text-transform: uppercase; 102 | font-size: 76px; 103 | font-weight: 700; 104 | color: $text-color; 105 | } 106 | h3 { 107 | font-size: 25px; 108 | font-weight: 600; 109 | color: $text-color; 110 | } 111 | 112 | // ---------------------------------------------------------------------------- 113 | // Base widget styles 114 | // ---------------------------------------------------------------------------- 115 | .gridster { 116 | margin: 0px auto; 117 | } 118 | 119 | .icon-background { 120 | width: 100%!important; 121 | height: 100%; 122 | position: absolute; 123 | left: 0; 124 | top: 0; 125 | opacity: 0.1; 126 | font-size: 275px; 127 | text-align: center; 128 | margin-top: 82px; 129 | } 130 | 131 | .list-nostyle { 132 | list-style: none; 133 | } 134 | 135 | .gridster ul { 136 | list-style: none; 137 | } 138 | 139 | .gs-w { 140 | width: 100%; 141 | display: table; 142 | cursor: pointer; 143 | } 144 | 145 | .widget { 146 | padding: 25px 12px; 147 | text-align: center; 148 | width: 100%; 149 | display: table-cell; 150 | vertical-align: middle; 151 | } 152 | 153 | .widget.status-warning { 154 | background-color: $background-warning-color-1; 155 | @include animation(status-warning-background, 2s, ease, infinite); 156 | 157 | .icon-warning-sign { 158 | display: inline-block; 159 | } 160 | 161 | .title, .more-info { 162 | color: $text-warning-color; 163 | } 164 | } 165 | 166 | .widget.status-danger { 167 | color: $text-danger-color; 168 | background-color: $background-danger-color-1; 169 | @include animation(status-danger-background, 2s, ease, infinite); 170 | 171 | .icon-warning-sign { 172 | display: inline-block; 173 | } 174 | 175 | .title, .more-info { 176 | color: $text-danger-color; 177 | } 178 | } 179 | 180 | .more-info { 181 | font-size: 15px; 182 | position: absolute; 183 | bottom: 32px; 184 | left: 0; 185 | right: 0; 186 | } 187 | 188 | .updated-at { 189 | font-size: 15px; 190 | position: absolute; 191 | bottom: 12px; 192 | left: 0; 193 | right: 0; 194 | } 195 | 196 | #save-gridster { 197 | display: none; 198 | position: fixed; 199 | top: 0; 200 | margin: 0px auto; 201 | left: 50%; 202 | z-index: 1000; 203 | background: black; 204 | width: 190px; 205 | text-align: center; 206 | border: 1px solid white; 207 | border-top: 0px; 208 | margin-left: -95px; 209 | padding: 15px; 210 | } 211 | 212 | #save-gridster:hover { 213 | padding-top: 25px; 214 | } 215 | 216 | #saving-instructions { 217 | display: none; 218 | padding: 10px; 219 | width: 500px; 220 | height: 122px; 221 | z-index: 1000; 222 | background: white; 223 | top: 100px; 224 | color: black; 225 | font-size: 15px; 226 | padding-bottom: 4px; 227 | 228 | textarea { 229 | white-space: nowrap; 230 | width: 494px; 231 | height: 80px; 232 | } 233 | } 234 | 235 | #lean_overlay { 236 | position: fixed; 237 | z-index:100; 238 | top: 0px; 239 | left: 0px; 240 | height:100%; 241 | width:100%; 242 | background: #000; 243 | display: none; 244 | } 245 | 246 | #container { 247 | padding-top: 5px; 248 | } 249 | 250 | 251 | // ---------------------------------------------------------------------------- 252 | // Clearfix 253 | // ---------------------------------------------------------------------------- 254 | .clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; } 255 | .clearfix:after { clear: both; } 256 | .clearfix { zoom: 1; } 257 | -------------------------------------------------------------------------------- /app/templates/bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/dashboards/layout.gerb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= yield("title") %> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | <%! yield %> 22 |
23 | 24 | <% if development { %> 25 |
26 |

Paste the following at the top of <%= dashboard %>.gerb

27 | 28 |
29 | Save this layout 30 | <% } %> 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/templates/dashboards/sample.gerb: -------------------------------------------------------------------------------- 1 | <% content "title" { %>My super sweet dashboard<% } %> 2 |
3 | 24 |
Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' http://<%= request.host %>/widgets/welcome
25 |
26 | -------------------------------------------------------------------------------- /app/templates/gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /app/templates/gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components 3 | /build 4 | -------------------------------------------------------------------------------- /app/templates/jobs/buzzwords.go: -------------------------------------------------------------------------------- 1 | package jobs 2 | 3 | import ( 4 | "time" 5 | "math/rand" 6 | 7 | "github.com/gigablah/dashing-go" 8 | ) 9 | 10 | type buzzwords struct{ 11 | words []map[string]interface{} 12 | } 13 | 14 | func (j *buzzwords) Work(send chan *dashing.Event) { 15 | ticker := time.NewTicker(1 * time.Second) 16 | for { 17 | select { 18 | case <- ticker.C: 19 | for i := 0; i < len(j.words); i++ { 20 | if 1 < rand.Intn(3) { 21 | value := j.words[i]["value"].(int) 22 | j.words[i]["value"] = (value + 1) % 30 23 | } 24 | } 25 | send <- &dashing.Event{"buzzwords", map[string]interface{}{ 26 | "items": j.words, 27 | }, ""} 28 | } 29 | } 30 | } 31 | 32 | func init() { 33 | dashing.Register(&buzzwords{[]map[string]interface{} { 34 | {"label": "Paradigm shift", "value": 0}, 35 | {"label": "Leverage", "value": 0}, 36 | {"label": "Pivoting", "value": 0}, 37 | {"label": "Turn-key", "value": 0}, 38 | {"label": "Streamlininess", "value": 0}, 39 | {"label": "Exit strategy", "value": 0}, 40 | {"label": "Synergy", "value": 0}, 41 | {"label": "Enterprise", "value": 0}, 42 | {"label": "Web 2.0", "value": 0}, 43 | }}) 44 | } 45 | -------------------------------------------------------------------------------- /app/templates/jobs/convergence.go: -------------------------------------------------------------------------------- 1 | package jobs 2 | 3 | import ( 4 | "time" 5 | "math/rand" 6 | 7 | "github.com/gigablah/dashing-go" 8 | ) 9 | 10 | type convergence struct{ 11 | points []map[string]int 12 | } 13 | 14 | func (j *convergence) Work(send chan *dashing.Event) { 15 | ticker := time.NewTicker(1 * time.Second) 16 | for { 17 | select { 18 | case <- ticker.C: 19 | j.points = j.points[1:] 20 | j.points = append(j.points, map[string]int{ 21 | "x": j.points[len(j.points)-1]["x"] + 1, 22 | "y": rand.Intn(50), 23 | }) 24 | send <- &dashing.Event{"convergence", map[string]interface{}{ 25 | "points": j.points, 26 | }, ""} 27 | } 28 | } 29 | } 30 | 31 | func init() { 32 | c := &convergence{} 33 | for i := 0; i < 10; i++ { 34 | c.points = append(c.points, map[string]int{ 35 | "x": i, 36 | "y": rand.Intn(50), 37 | }) 38 | } 39 | dashing.Register(c) 40 | } 41 | -------------------------------------------------------------------------------- /app/templates/jobs/sample.go: -------------------------------------------------------------------------------- 1 | package jobs 2 | 3 | import ( 4 | "time" 5 | "math/rand" 6 | 7 | "github.com/gigablah/dashing-go" 8 | ) 9 | 10 | type sample struct{} 11 | 12 | func (j *sample) Work(send chan *dashing.Event) { 13 | ticker := time.NewTicker(1 * time.Second) 14 | var lastValuation, lastKarma, currentValuation, currentKarma int 15 | for { 16 | select { 17 | case <- ticker.C: 18 | lastValuation, currentValuation = currentValuation, rand.Intn(100) 19 | lastKarma, currentKarma = currentKarma, rand.Intn(200000) 20 | send <- &dashing.Event{"valuation", map[string]interface{}{ 21 | "current": currentValuation, 22 | "last": lastValuation, 23 | }, ""} 24 | send <- &dashing.Event{"karma", map[string]interface{}{ 25 | "current": currentKarma, 26 | "last": lastKarma, 27 | }, ""} 28 | send <- &dashing.Event{"synergy", map[string]interface{}{ 29 | "value": rand.Intn(100), 30 | }, ""} 31 | } 32 | } 33 | } 34 | 35 | func init() { 36 | dashing.Register(&sample{}) 37 | } 38 | -------------------------------------------------------------------------------- /app/templates/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This Dashboard doesn't exist. 5 | 17 | 18 | 19 | 20 | 21 |
22 |

Drats! That Dashboard doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /app/templates/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gigablah/generator-dashing-go/a49126abc869926f5b7b777f7a17fa1659033ed7/app/templates/public/favicon.ico -------------------------------------------------------------------------------- /app/templates/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gigablah/generator-dashing-go/a49126abc869926f5b7b777f7a17fa1659033ed7/app/templates/public/images/logo.png -------------------------------------------------------------------------------- /app/templates/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gigablah/dashing-go" 5 | _ "./jobs" 6 | ) 7 | 8 | func main() { 9 | dashing.Start() 10 | } 11 | -------------------------------------------------------------------------------- /app/templates/widgets/clock/clock.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Clock extends Dashing.Widget 2 | 3 | ready: -> 4 | setInterval(@startTime, 500) 5 | 6 | startTime: => 7 | today = new Date() 8 | 9 | h = today.getHours() 10 | m = today.getMinutes() 11 | s = today.getSeconds() 12 | m = @formatTime(m) 13 | s = @formatTime(s) 14 | @set('time', h + ":" + m + ":" + s) 15 | @set('date', today.toDateString()) 16 | 17 | formatTime: (i) -> 18 | if i < 10 then "0" + i else i -------------------------------------------------------------------------------- /app/templates/widgets/clock/clock.html: -------------------------------------------------------------------------------- 1 |

2 |

-------------------------------------------------------------------------------- /app/templates/widgets/clock/clock.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #dc5945; 5 | 6 | // ---------------------------------------------------------------------------- 7 | // Widget-clock styles 8 | // ---------------------------------------------------------------------------- 9 | .widget-clock { 10 | 11 | background-color: $background-color; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/templates/widgets/comments/comments.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Comments extends Dashing.Widget 2 | 3 | @accessor 'quote', -> 4 | "“#{@get('current_comment')?.body}”" 5 | 6 | ready: -> 7 | @currentIndex = 0 8 | @commentElem = $(@node).find('.comment-container') 9 | @nextComment() 10 | @startCarousel() 11 | 12 | onData: (data) -> 13 | @currentIndex = 0 14 | 15 | startCarousel: -> 16 | setInterval(@nextComment, 8000) 17 | 18 | nextComment: => 19 | comments = @get('comments') 20 | if comments 21 | @commentElem.fadeOut => 22 | @currentIndex = (@currentIndex + 1) % comments.length 23 | @set 'current_comment', comments[@currentIndex] 24 | @commentElem.fadeIn() 25 | -------------------------------------------------------------------------------- /app/templates/widgets/comments/comments.html: -------------------------------------------------------------------------------- 1 |

2 |
3 |

4 |

5 |
6 | 7 |

8 | -------------------------------------------------------------------------------- /app/templates/widgets/comments/comments.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #eb9c3c; 5 | 6 | $title-color: rgba(255, 255, 255, 0.7); 7 | $moreinfo-color: rgba(255, 255, 255, 0.7); 8 | 9 | // ---------------------------------------------------------------------------- 10 | // Widget-comment styles 11 | // ---------------------------------------------------------------------------- 12 | .widget-comments { 13 | 14 | background-color: $background-color; 15 | 16 | .title { 17 | color: $title-color; 18 | margin-bottom: 15px; 19 | } 20 | 21 | .name { 22 | padding-left: 5px; 23 | } 24 | 25 | .comment-container { 26 | display: none; 27 | } 28 | 29 | .more-info { 30 | color: $moreinfo-color; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/templates/widgets/graph/graph.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Graph extends Dashing.Widget 2 | 3 | @accessor 'current', -> 4 | return @get('displayedValue') if @get('displayedValue') 5 | points = @get('points') 6 | if points 7 | points[points.length - 1].y 8 | 9 | ready: -> 10 | container = $(@node).parent() 11 | # Gross hacks. Let's fix this. 12 | width = (Dashing.widget_base_dimensions[0] * container.data("sizex")) + Dashing.widget_margins[0] * 2 * (container.data("sizex") - 1) 13 | height = (Dashing.widget_base_dimensions[1] * container.data("sizey")) 14 | @graph = new Rickshaw.Graph( 15 | element: @node 16 | width: width 17 | height: height 18 | renderer: @get("graphtype") 19 | series: [ 20 | { 21 | color: "#fff", 22 | data: [{x:0, y:0}] 23 | } 24 | ] 25 | ) 26 | 27 | @graph.series[0].data = @get('points') if @get('points') 28 | 29 | x_axis = new Rickshaw.Graph.Axis.Time(graph: @graph) 30 | y_axis = new Rickshaw.Graph.Axis.Y(graph: @graph, tickFormat: Rickshaw.Fixtures.Number.formatKMBT) 31 | @graph.render() 32 | 33 | onData: (data) -> 34 | if @graph 35 | @graph.series[0].data = data.points 36 | @graph.render() 37 | -------------------------------------------------------------------------------- /app/templates/widgets/graph/graph.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | -------------------------------------------------------------------------------- /app/templates/widgets/graph/graph.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #dc5945; 5 | 6 | $title-color: rgba(255, 255, 255, 0.7); 7 | $moreinfo-color: rgba(255, 255, 255, 0.3); 8 | $tick-color: rgba(0, 0, 0, 0.4); 9 | 10 | 11 | // ---------------------------------------------------------------------------- 12 | // Widget-graph styles 13 | // ---------------------------------------------------------------------------- 14 | .widget-graph { 15 | 16 | background-color: $background-color; 17 | position: relative; 18 | 19 | 20 | svg { 21 | position: absolute; 22 | opacity: 0.4; 23 | fill-opacity: 0.4; 24 | left: 0px; 25 | top: 0px; 26 | } 27 | 28 | .title, .value { 29 | position: relative; 30 | z-index: 99; 31 | } 32 | 33 | .title { 34 | color: $title-color; 35 | } 36 | 37 | .more-info { 38 | color: $moreinfo-color; 39 | font-weight: 600; 40 | font-size: 20px; 41 | margin-top: 0; 42 | } 43 | 44 | .x_tick { 45 | position: absolute; 46 | bottom: 0; 47 | .title { 48 | font-size: 20px; 49 | color: $tick-color; 50 | opacity: 0.5; 51 | padding-bottom: 3px; 52 | } 53 | } 54 | 55 | .y_ticks { 56 | font-size: 20px; 57 | fill: $tick-color; 58 | fill-opacity: 1; 59 | } 60 | 61 | .domain { 62 | display: none; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /app/templates/widgets/iframe/iframe.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Iframe extends Dashing.Widget 2 | 3 | ready: -> 4 | # This is fired when the widget is done being rendered 5 | 6 | onData: (data) -> 7 | # Handle incoming data 8 | # You can access the html node of this widget with `@node` 9 | # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. 10 | -------------------------------------------------------------------------------- /app/templates/widgets/iframe/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/templates/widgets/iframe/iframe.scss: -------------------------------------------------------------------------------- 1 | .widget-iframe { 2 | padding: 3px 0px 0px 0px !important; 3 | 4 | iframe { 5 | width: 100%; 6 | height: 100%; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/templates/widgets/image/image.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Image extends Dashing.Widget 2 | 3 | ready: -> 4 | # This is fired when the widget is done being rendered 5 | 6 | onData: (data) -> 7 | # Handle incoming data 8 | # You can access the html node of this widget with `@node` 9 | # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. 10 | -------------------------------------------------------------------------------- /app/templates/widgets/image/image.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/templates/widgets/image/image.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #4b4b4b; 5 | 6 | // ---------------------------------------------------------------------------- 7 | // Widget-image styles 8 | // ---------------------------------------------------------------------------- 9 | .widget-image { 10 | 11 | background-color: $background-color; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/templates/widgets/list/list.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.List extends Dashing.Widget 2 | ready: -> 3 | if @get('unordered') 4 | $(@node).find('ol').remove() 5 | else 6 | $(@node).find('ul').remove() 7 | -------------------------------------------------------------------------------- /app/templates/widgets/list/list.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |
    4 |
  1. 5 | 6 | 7 |
  2. 8 |
9 | 10 | 16 | 17 |

18 |

19 | -------------------------------------------------------------------------------- /app/templates/widgets/list/list.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #12b0c5; 5 | $value-color: #fff; 6 | 7 | $title-color: rgba(255, 255, 255, 0.7); 8 | $label-color: rgba(255, 255, 255, 0.7); 9 | $moreinfo-color: rgba(255, 255, 255, 0.7); 10 | 11 | // ---------------------------------------------------------------------------- 12 | // Widget-list styles 13 | // ---------------------------------------------------------------------------- 14 | .widget-list { 15 | 16 | background-color: $background-color; 17 | vertical-align: top; 18 | 19 | .title { 20 | color: $title-color; 21 | } 22 | 23 | ol, ul { 24 | margin: 0 15px; 25 | text-align: left; 26 | color: $label-color; 27 | } 28 | 29 | ol { 30 | list-style-position: inside; 31 | } 32 | 33 | li { 34 | margin-bottom: 5px; 35 | } 36 | 37 | .list-nostyle { 38 | list-style: none; 39 | } 40 | 41 | .label { 42 | color: $label-color; 43 | } 44 | 45 | .value { 46 | float: right; 47 | margin-left: 12px; 48 | font-weight: 600; 49 | color: $value-color; 50 | } 51 | 52 | .updated-at { 53 | color: rgba(0, 0, 0, 0.3); 54 | } 55 | 56 | .more-info { 57 | color: $moreinfo-color; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/templates/widgets/meter/meter.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Meter extends Dashing.Widget 2 | 3 | @accessor 'value', Dashing.AnimatedValue 4 | 5 | constructor: -> 6 | super 7 | @observe 'value', (value) -> 8 | $(@node).find(".meter").val(value).trigger('change') 9 | 10 | ready: -> 11 | meter = $(@node).find(".meter") 12 | meter.attr("data-bgcolor", meter.css("background-color")) 13 | meter.attr("data-fgcolor", meter.css("color")) 14 | meter.knob() 15 | -------------------------------------------------------------------------------- /app/templates/widgets/meter/meter.html: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 |

8 | -------------------------------------------------------------------------------- /app/templates/widgets/meter/meter.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #9c4274; 5 | 6 | $title-color: rgba(255, 255, 255, 0.7); 7 | $moreinfo-color: rgba(255, 255, 255, 0.3); 8 | 9 | $meter-background: darken($background-color, 15%); 10 | 11 | // ---------------------------------------------------------------------------- 12 | // Widget-meter styles 13 | // ---------------------------------------------------------------------------- 14 | .widget-meter { 15 | 16 | background-color: $background-color; 17 | 18 | input.meter { 19 | background-color: $meter-background; 20 | color: #fff; 21 | } 22 | 23 | .title { 24 | color: $title-color; 25 | } 26 | 27 | .more-info { 28 | color: $moreinfo-color; 29 | } 30 | 31 | .updated-at { 32 | color: rgba(0, 0, 0, 0.3); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/templates/widgets/number/number.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Number extends Dashing.Widget 2 | @accessor 'current', Dashing.AnimatedValue 3 | 4 | @accessor 'difference', -> 5 | if @get('last') 6 | last = parseInt(@get('last')) 7 | current = parseInt(@get('current')) 8 | if last != 0 9 | diff = Math.abs(Math.round((current - last) / last * 100)) 10 | "#{diff}%" 11 | else 12 | "" 13 | 14 | @accessor 'arrow', -> 15 | if @get('last') 16 | if parseInt(@get('current')) > parseInt(@get('last')) then 'icon-arrow-up' else 'icon-arrow-down' 17 | 18 | onData: (data) -> 19 | if data.status 20 | # clear existing "status-*" classes 21 | $(@get('node')).attr 'class', (i,c) -> 22 | c.replace /\bstatus-\S+/g, '' 23 | # add new class 24 | $(@get('node')).addClass "status-#{data.status}" 25 | -------------------------------------------------------------------------------- /app/templates/widgets/number/number.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | 7 |

8 | 9 |

10 | 11 |

12 | -------------------------------------------------------------------------------- /app/templates/widgets/number/number.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #47bbb3; 5 | $value-color: #fff; 6 | 7 | $title-color: rgba(255, 255, 255, 0.7); 8 | $moreinfo-color: rgba(255, 255, 255, 0.7); 9 | 10 | // ---------------------------------------------------------------------------- 11 | // Widget-number styles 12 | // ---------------------------------------------------------------------------- 13 | .widget-number { 14 | 15 | background-color: $background-color; 16 | 17 | .title { 18 | color: $title-color; 19 | } 20 | 21 | .value { 22 | color: $value-color; 23 | } 24 | 25 | .change-rate { 26 | font-weight: 500; 27 | font-size: 30px; 28 | color: $value-color; 29 | } 30 | 31 | .more-info { 32 | color: $moreinfo-color; 33 | } 34 | 35 | .updated-at { 36 | color: rgba(0, 0, 0, 0.3); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/templates/widgets/text/text.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.Text extends Dashing.Widget 2 | -------------------------------------------------------------------------------- /app/templates/widgets/text/text.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | 7 |

8 | -------------------------------------------------------------------------------- /app/templates/widgets/text/text.scss: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Sass declarations 3 | // ---------------------------------------------------------------------------- 4 | $background-color: #ec663c; 5 | 6 | $title-color: rgba(255, 255, 255, 0.7); 7 | $moreinfo-color: rgba(255, 255, 255, 0.7); 8 | 9 | // ---------------------------------------------------------------------------- 10 | // Widget-text styles 11 | // ---------------------------------------------------------------------------- 12 | .widget-text { 13 | 14 | background-color: $background-color; 15 | 16 | .title { 17 | color: $title-color; 18 | } 19 | 20 | .more-info { 21 | color: $moreinfo-color; 22 | } 23 | 24 | .updated-at { 25 | color: rgba(255, 255, 255, 0.7); 26 | } 27 | 28 | 29 | &.large h3 { 30 | font-size: 65px; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dashboard/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var yeoman = require('yeoman-generator'); 5 | 6 | var DashboardGenerator = yeoman.generators.NamedBase.extend({ 7 | init: function () { 8 | this.name = this._.slugify(this._.humanize(this.name)); 9 | this.log('Generating the ' + this.name + ' dashboard...'); 10 | }, 11 | 12 | files: function () { 13 | this.mkdir('dashboards'); 14 | this.copy('dashboard.gerb', 'dashboards/' + this.name + '.gerb'); 15 | } 16 | }); 17 | 18 | module.exports = DashboardGenerator; 19 | -------------------------------------------------------------------------------- /dashboard/templates/dashboard.gerb: -------------------------------------------------------------------------------- 1 | <% content "title" { %>My super sweet dashboard<% } %> 2 |
3 | 8 |
9 | -------------------------------------------------------------------------------- /job/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var yeoman = require('yeoman-generator'); 5 | 6 | var JobGenerator = yeoman.generators.NamedBase.extend({ 7 | init: function () { 8 | this.name = this._.underscored(this._.humanize(this.name)); 9 | this.log('Generating the ' + this.name + ' job...'); 10 | }, 11 | 12 | files: function () { 13 | this.mkdir('jobs'); 14 | this.template('_job.go', 'jobs/' + this.name + '.go'); 15 | } 16 | }); 17 | 18 | module.exports = JobGenerator; 19 | -------------------------------------------------------------------------------- /job/templates/_job.go: -------------------------------------------------------------------------------- 1 | package jobs 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/gigablah/dashing-go" 7 | ) 8 | 9 | type <%= _.camelize(name) %> struct{} 10 | 11 | func (j *<%= _.camelize(name) %>) Work(send chan *dashing.Event) { 12 | ticker := time.NewTicker(1 * time.Second) 13 | for { 14 | select { 15 | case <- ticker.C: 16 | 17 | // do something 18 | 19 | send <- &dashing.Event{"<%= _.slugify(name) %>", map[string]interface{}{ 20 | "foo": "bar", 21 | }, ""} 22 | } 23 | } 24 | } 25 | 26 | func init() { 27 | dashing.Register(&<%= _.camelize(name) %>{}) 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-dashing-go", 3 | "version": "0.0.1", 4 | "description": "A Yeoman generator for dashing-go", 5 | "keywords": [ 6 | "yeoman-generator", 7 | "go", 8 | "golang", 9 | "Martini", 10 | "dashing", 11 | "dashboard" 12 | ], 13 | "homepage": "https://github.com/gigablah/generator-dashing-go", 14 | "bugs": "https://github.com/gigablah/generator-dashing-go/issues", 15 | "author": { 16 | "name": "Chris Heng", 17 | "email": "bigblah@gmail.com", 18 | "url": "https://github.com/gigablah" 19 | }, 20 | "main": "app/index.js", 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/gigablah/generator-dashing-go.git" 24 | }, 25 | "scripts": { 26 | "test": "mocha" 27 | }, 28 | "files": [ 29 | "app" 30 | ], 31 | "dependencies": { 32 | "yeoman-generator": "~0.16.0" 33 | }, 34 | "devDependencies": { 35 | "mocha": "*" 36 | }, 37 | "peerDependencies": { 38 | "yo": ">=1.0.0" 39 | }, 40 | "engines": { 41 | "node": ">=0.10.0", 42 | "npm": ">=1.2.10" 43 | }, 44 | "license": "MIT" 45 | } 46 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gigablah/generator-dashing-go/a49126abc869926f5b7b777f7a17fa1659033ed7/screenshot.png -------------------------------------------------------------------------------- /test/test-creation.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it */ 2 | 'use strict'; 3 | var path = require('path'); 4 | var helpers = require('yeoman-generator').test; 5 | 6 | describe('dashing-go generator', function () { 7 | beforeEach(function (done) { 8 | helpers.testDirectory(path.join(__dirname, 'temp'), function (err) { 9 | if (err) { 10 | return done(err); 11 | } 12 | 13 | this.app = helpers.createGenerator('dashing-go:app', [ 14 | '../../app' 15 | ]); 16 | done(); 17 | }.bind(this)); 18 | }); 19 | 20 | it('creates expected files', function (done) { 21 | var expected = [ 22 | // add files you expect to exist here. 23 | '.jshintrc', 24 | '.editorconfig' 25 | ]; 26 | 27 | helpers.mockPrompt(this.app, { 28 | 'someOption': true 29 | }); 30 | this.app.options['skip-install'] = true; 31 | this.app.run({}, function () { 32 | helpers.assertFile(expected); 33 | done(); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/test-load.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 'use strict'; 3 | var assert = require('assert'); 4 | 5 | describe('dashing-go generator', function () { 6 | it('can be imported without blowing up', function () { 7 | var app = require('../app'); 8 | assert(app !== undefined); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /widget/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var yeoman = require('yeoman-generator'); 5 | 6 | var WidgetGenerator = yeoman.generators.NamedBase.extend({ 7 | init: function () { 8 | this.name = this._.slugify(this._.humanize(this.name)); 9 | this.log('Generating the ' + this.name + ' widget...'); 10 | }, 11 | 12 | files: function () { 13 | var widgetDir = 'widgets/' + this.name; 14 | var widgetPath = widgetDir + '/' + this.name; 15 | 16 | this.mkdir(widgetDir); 17 | 18 | this.template('_widget.coffee', widgetPath + '.coffee'); 19 | this.template('_widget.scss', widgetPath + '.scss'); 20 | this.copy('widget.html', widgetPath + '.html'); 21 | } 22 | }); 23 | 24 | module.exports = WidgetGenerator; 25 | -------------------------------------------------------------------------------- /widget/templates/_widget.coffee: -------------------------------------------------------------------------------- 1 | class Dashing.<%= _.classify(name) %> extends Dashing.Widget 2 | 3 | ready: -> 4 | # This is fired when the widget is done being rendered 5 | 6 | onData: (data) -> 7 | # Handle incoming data 8 | # You can access the html node of this widget with `@node` 9 | # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. -------------------------------------------------------------------------------- /widget/templates/_widget.scss: -------------------------------------------------------------------------------- 1 | .widget-<%= _.slugify(name) %> { 2 | 3 | } -------------------------------------------------------------------------------- /widget/templates/widget.html: -------------------------------------------------------------------------------- 1 |
--------------------------------------------------------------------------------