diff --git a/.gitignore b/.gitignore index a6c563b..437cc6c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ spec/dummy/tmp/ spec/dummy/.sass-cache Gemfile.lock .byebug_history +.DS_Store diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..423f49f --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 10.15.0 diff --git a/admin/.bowerrc b/admin/.bowerrc deleted file mode 100644 index 959e169..0000000 --- a/admin/.bowerrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "directory": "bower_components", - "analytics": false -} diff --git a/admin/.editorconfig b/admin/.editorconfig index 2fe4874..219985c 100644 --- a/admin/.editorconfig +++ b/admin/.editorconfig @@ -13,21 +13,8 @@ insert_final_newline = true indent_style = space indent_size = 2 -[*.js] -indent_style = space -indent_size = 2 - [*.hbs] -indent_style = space -indent_size = 2 - -[*.css] -indent_style = space -indent_size = 2 - -[*.html] -indent_style = space -indent_size = 2 +insert_final_newline = false [*.{diff,md}] trim_trailing_whitespace = false diff --git a/admin/.ember-cli b/admin/.ember-cli index aeb9593..ee64cfe 100644 --- a/admin/.ember-cli +++ b/admin/.ember-cli @@ -1,4 +1,9 @@ { - "disableAnalytics": false, - "usePods": true + /** + Ember CLI sends analytics information by default. The data is completely + anonymous, but there are times when you might want to disable this behavior. + + Setting `disableAnalytics` to true will prevent any data from being sent. + */ + "disableAnalytics": false } diff --git a/admin/.eslintignore b/admin/.eslintignore new file mode 100644 index 0000000..72df373 --- /dev/null +++ b/admin/.eslintignore @@ -0,0 +1,20 @@ +# unconventional js +/blueprints/*/files/ +/vendor/ + +# compiled output +/dist/ +/tmp/ + +# dependencies +/bower_components/ +/node_modules/ + +# misc +/coverage/ +!.* + +# ember-try +/.node_modules.ember-try/ +/bower.json.ember-try +/package.json.ember-try diff --git a/admin/.eslintrc.js b/admin/.eslintrc.js new file mode 100644 index 0000000..78ab2f7 --- /dev/null +++ b/admin/.eslintrc.js @@ -0,0 +1,44 @@ +module.exports = { + globals: { + server: true, + }, + root: true, + parserOptions: { + ecmaVersion: 2017, + sourceType: 'module' + }, + plugins: [ + 'ember' + ], + extends: [ + 'eslint:recommended', + 'plugin:ember/recommended' + ], + env: { + browser: true + }, + rules: { + }, + overrides: [ + // node files + { + files: [ + '.eslintrc.js', + '.template-lintrc.js', + 'ember-cli-build.js', + 'testem.js', + 'blueprints/*/index.js', + 'config/**/*.js', + 'lib/*/index.js' + ], + parserOptions: { + sourceType: 'script', + ecmaVersion: 2015 + }, + env: { + browser: false, + node: true + } + } + ] +}; diff --git a/admin/.jshintrc b/admin/.jshintrc deleted file mode 100644 index 08096ef..0000000 --- a/admin/.jshintrc +++ /dev/null @@ -1,32 +0,0 @@ -{ - "predef": [ - "document", - "window", - "-Promise" - ], - "browser": true, - "boss": true, - "curly": true, - "debug": false, - "devel": true, - "eqeqeq": true, - "evil": true, - "forin": false, - "immed": false, - "laxbreak": false, - "newcap": true, - "noarg": true, - "noempty": false, - "nonew": false, - "nomen": false, - "onevar": false, - "plusplus": false, - "regexp": false, - "undef": true, - "sub": true, - "strict": false, - "white": false, - "eqnull": true, - "esnext": true, - "unused": true -} diff --git a/admin/.template-lintrc.js b/admin/.template-lintrc.js new file mode 100644 index 0000000..b45e96f --- /dev/null +++ b/admin/.template-lintrc.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + extends: 'recommended' +}; diff --git a/admin/.travis.yml b/admin/.travis.yml index cf23938..e63caa7 100644 --- a/admin/.travis.yml +++ b/admin/.travis.yml @@ -1,20 +1,27 @@ --- language: node_js +node_js: + - "6" sudo: false +dist: trusty + +addons: + chrome: stable cache: directories: - - node_modules + - $HOME/.npm -before_install: - - "npm config set spin false" - - "npm install -g npm@^2" +env: + global: + # See https://git.io/vdao3 for details. + - JOBS=1 -install: - - npm install -g bower - - npm install - - bower install +before_install: + - npm config set spin false script: + - npm run lint:hbs + - npm run lint:js - npm test diff --git a/admin/.watchmanconfig b/admin/.watchmanconfig new file mode 100644 index 0000000..e7834e3 --- /dev/null +++ b/admin/.watchmanconfig @@ -0,0 +1,3 @@ +{ + "ignore_dirs": ["tmp", "dist"] +} diff --git a/admin/Brocfile.js b/admin/Brocfile.js deleted file mode 100644 index b08d8fe..0000000 --- a/admin/Brocfile.js +++ /dev/null @@ -1,38 +0,0 @@ -/* global require, module */ - -var EmberApp = require('ember-cli/lib/broccoli/ember-app'); - -var app = new EmberApp({ - fingerprint: { - prepend: '/front_end_builds/' - }, - emberCliFontAwesome: { includeFontAwesomeAssets: false } -}); - -app.import("bower_components/arrive/src/arrive.js"); - -app.import("bower_components/bootstrap/dist/css/bootstrap.css"); -app.import("bower_components/bootstrap/dist/js/bootstrap.js"); - -app.import('bower_components/matchHeight/jquery.matchHeight.js'); - -app.import("bower_components/bootstrap-material-design/dist/css/material.css"); -app.import("bower_components/bootstrap-material-design/dist/css/ripples.css"); -app.import("bower_components/bootstrap-material-design/dist/js/material.js"); -app.import("bower_components/bootstrap-material-design/dist/js/ripples.js"); - -// Font Awesome -var fonts = [ - "fontawesome-webfont.eot", - "fontawesome-webfont.svg", - "fontawesome-webfont.ttf", - "fontawesome-webfont.woff", - "fontawesome-webfont.woff2", - "FontAwesome.otf" -]; -var fontDestDir = (app.env === 'production') ? '/assets' : '/front_end_builds/assets/'; -fonts.forEach(function(font) { - app.import('bower_components/font-awesome/fonts/' + font, { destDir: fontDestDir }); -}); - -module.exports = app.toTree(); diff --git a/admin/README.md b/admin/README.md index 48c1f51..27067d2 100644 --- a/admin/README.md +++ b/admin/README.md @@ -1,4 +1,4 @@ -# Admin +# admin This README outlines the details of collaborating on this Ember application. A short introduction of this app could easily go here. @@ -7,23 +7,22 @@ A short introduction of this app could easily go here. You will need the following things properly installed on your computer. -* [Git](http://git-scm.com/) -* [Node.js](http://nodejs.org/) (with NPM) -* [Bower](http://bower.io/) -* [Ember CLI](http://www.ember-cli.com/) -* [PhantomJS](http://phantomjs.org/) +* [Git](https://git-scm.com/) +* [Node.js](https://nodejs.org/) (with npm) +* [Ember CLI](https://ember-cli.com/) +* [Google Chrome](https://google.com/chrome/) ## Installation * `git clone ` this repository -* change into the new directory +* `cd admin` * `npm install` -* `bower install` ## Running / Development -* `ember server` +* `ember serve` * Visit your app at [http://localhost:4200](http://localhost:4200). +* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests). ### Code Generators @@ -34,6 +33,12 @@ Make use of the many generators for code, try `ember help generate` for more det * `ember test` * `ember test --server` +### Linting + +* `npm run lint:hbs` +* `npm run lint:js` +* `npm run lint:js -- --fix` + ### Building * `ember build` (development) @@ -45,9 +50,8 @@ Specify what it takes to deploy your app. ## Further Reading / Useful Links -* [ember.js](http://emberjs.com/) -* [ember-cli](http://www.ember-cli.com/) +* [ember.js](https://emberjs.com/) +* [ember-cli](https://ember-cli.com/) * Development Browser Extensions * [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi) * [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/) - diff --git a/admin/app/adapters/application.js b/admin/app/adapters/application.js index 62e9d14..dbe4b35 100644 --- a/admin/app/adapters/application.js +++ b/admin/app/adapters/application.js @@ -1,5 +1,5 @@ -import DS from 'ember-data'; +import ActiveModelAdapter from 'active-model-adapter'; -export default DS.ActiveModelAdapter.extend({ - namespace: window.RAILS_ENV.baseURL + (window.RAILS_ENV.baseURL ? '/' : '' ) + 'api' +export default ActiveModelAdapter.extend({ + namespace: (window.RAILS_ENV ? window.RAILS_ENV.baseURL + (window.RAILS_ENV.baseURL ? '/' : '' ) : '') + 'api' }); diff --git a/admin/app/app.js b/admin/app/app.js index 757df38..b3b2bd6 100644 --- a/admin/app/app.js +++ b/admin/app/app.js @@ -1,14 +1,12 @@ -import Ember from 'ember'; -import Resolver from 'ember/resolver'; -import loadInitializers from 'ember/load-initializers'; +import Application from '@ember/application'; +import Resolver from './resolver'; +import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; -Ember.MODEL_FACTORY_INJECTIONS = true; - -var App = Ember.Application.extend({ +const App = Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, - Resolver: Resolver + Resolver }); loadInitializers(App, config.modulePrefix); diff --git a/admin/app/index.html b/admin/app/index.html index 0331dea..5e723fd 100644 --- a/admin/app/index.html +++ b/admin/app/index.html @@ -7,24 +7,19 @@ - {{content-for 'head'}} + {{content-for "head"}} - - - + + - {{content-for 'head-footer'}} + {{content-for "head-footer"}} - {{content-for 'body'}} + {{content-for "body"}} - - + + - {{content-for 'body-footer'}} + {{content-for "body-footer"}} diff --git a/admin/public/.gitkeep b/admin/app/models/.gitkeep similarity index 100% rename from admin/public/.gitkeep rename to admin/app/models/.gitkeep diff --git a/admin/app/models/app.js b/admin/app/models/app.js index e4705a5..3dd6c53 100644 --- a/admin/app/models/app.js +++ b/admin/app/models/app.js @@ -1,16 +1,24 @@ import DS from 'ember-data'; -import Ember from 'ember'; +const { attr, belongsTo, hasMany } = DS; +import { computed } from '@ember/object'; -export default DS.Model.extend({ - builds: DS.hasMany('build'), - liveBuild: DS.belongsTo('build'), +import { validator, buildValidations } from 'ember-cp-validations'; - name: DS.attr('string', {defaultValue: ''}), - apiKey: DS.attr('string'), - location: DS.attr('string'), - requireManualActivation: DS.attr('boolean'), - activateNewDeploys: Ember.computed.not('requireManualActivation'), +const Validations = buildValidations({ + name: validator('presence', true), +}); + +export default DS.Model.extend(Validations, { + builds: hasMany('build'), + liveBuild: belongsTo('build'), + + name: attr('string', {defaultValue: ''}), + apiKey: attr('string'), + location: attr('string'), + + requireManualActivation: attr('boolean'), + activateNewDeploys: computed.not('requireManualActivation'), - buildsSorting: ['createdAt:desc'], - orderedBuilds: Ember.computed.sort('builds', 'buildsSorting'), + buildsSorting: Object.freeze(['createdAt:desc']), + orderedBuilds: computed.sort('builds', 'buildsSorting'), }); diff --git a/admin/app/models/build.js b/admin/app/models/build.js index c0a8070..be08fe5 100644 --- a/admin/app/models/build.js +++ b/admin/app/models/build.js @@ -1,30 +1,42 @@ import DS from 'ember-data'; +const { attr, belongsTo } = DS; +import { computed } from '@ember/object'; +import moment from 'moment'; export default DS.Model.extend({ - app: DS.belongsTo('app', {inverse: 'builds'}), + app: belongsTo('app', {inverse: 'builds'}), - sha: DS.attr('string'), - job: DS.attr('string'), - branch: DS.attr('string'), - createdAt: DS.attr('date'), + sha: attr('string'), + job: attr('string'), + branch: attr('string'), + createdAt: attr('date'), - isLive: function() { - return this === this.get('app.liveBuild'); - }.property('app.liveBuild'), + createdAtFormatted: computed('createdAt', function(){ + let createdAt = this.get('createdAt'); + return `${moment(createdAt).fromNow()} (${moment(createdAt).format('MMM D YYYY')})`; + }), - activate: function() { - return this.get('app').set('liveBuild', this).save(); - }, + isLive: computed('app.liveBuild', function() { + return this.get('id') === this.get('app.liveBuild.id'); + }), - shortSha: function() { - return this.get('sha').slice(0, 7); - }.property('sha'), + shortSha: computed('sha', function() { + return this.get('sha') ? this.get('sha').slice(0, 7) : ''; + }), - location: function() { + location: computed('app.location', 'isLive', 'id', function() { var base = this.get('app.location'); var isLive = this.get('isLive'); var id = this.get('id'); return isLive ? base : `${base}?id=${id}`; - }.property('app.location', 'isLive', 'id') + }), + + locationBranch: computed('app.location', 'isLive', 'branch', function() { + var base = this.get('app.location'); + var isLive = this.get('isLive'); + var branch = this.get('branch'); + + return isLive ? base : `${base}?branch=${branch}`; + }) }); diff --git a/admin/app/models/host-app.js b/admin/app/models/host-app.js index ceabbbf..2027c98 100644 --- a/admin/app/models/host-app.js +++ b/admin/app/models/host-app.js @@ -1,9 +1,11 @@ import DS from 'ember-data'; +const { attr } = DS; +import { computed } from '@ember/object'; export default DS.Model.extend({ - name: DS.attr('string'), + name: attr('string'), - friendlyName: function() { + friendlyName: computed('name', function() { return this.get('name').replace('_', ' ').capitalize(); - }.property('name') + }) }); diff --git a/admin/app/models/pubkey.js b/admin/app/models/pubkey.js index fe4d621..022b309 100644 --- a/admin/app/models/pubkey.js +++ b/admin/app/models/pubkey.js @@ -1,8 +1,22 @@ import DS from 'ember-data'; +const { attr } = DS; +import { computed } from '@ember/object'; +import moment from 'moment'; -export default DS.Model.extend({ - name: DS.attr('string'), - pubkey: DS.attr('string'), - fingerprint: DS.attr('string'), - lastUsedAt: DS.attr('date') +import { validator, buildValidations } from 'ember-cp-validations'; + +const Validations = buildValidations({ + name: validator('presence', true), + pubkey: validator('presence', true), +}); + +export default DS.Model.extend(Validations, { + name: attr('string'), + pubkey: attr('string'), + fingerprint: attr('string'), + lastUsedAt: attr('date'), + + lastUsedAtFormatted: computed('lastUsedAt', function(){ + return moment(this.get('lastUsedAt')).format('MMM D YYYY'); + }) }); diff --git a/admin/app/pods/app/controller.js b/admin/app/pods/app/controller.js index 6983302..1472bfe 100644 --- a/admin/app/pods/app/controller.js +++ b/admin/app/pods/app/controller.js @@ -1,17 +1,39 @@ -import Ember from 'ember'; +import Controller from '@ember/controller'; -export default Ember.Controller.extend({ +export default Controller.extend({ + + isRenameModalVisible: true, actions: { - willRenameApp: function() { - this.set('willRename', true); + startRenamingApp() { + this.set('isRenamingApp', true); }, - willDeleteApp: function() { - this.set('willDelete', true); - } + stopRenamingApp() { + this.set('isRenamingApp', false); + }, + + startDeletingApp() { + this.set('isDeletingApp', true); + }, + + stopDeletingApp() { + this.set('isDeletingApp', false); + }, + + toggleNewDeploys: function(value) { + var app = this.get('model'); + + app.set('requireManualActivation', !value); + app.save(); + }, + appDeleted: function() { + this.set('controller.willDelete', undefined); + // this.transitionTo('apps'); + } } + }); diff --git a/admin/app/pods/app/route.js b/admin/app/pods/app/route.js index 65305e3..cd86a5a 100644 --- a/admin/app/pods/app/route.js +++ b/admin/app/pods/app/route.js @@ -1,19 +1,7 @@ -import Ember from 'ember'; +import Route from '@ember/routing/route'; -export default Ember.Route.extend({ - - actions: { - activateNewDeploys: function(value) { - var app = this.controller.get('model'); - - app.set('requireManualActivation', !value); - app.save(); - }, - - appDeleted: function() { - this.set('controller.willDelete', undefined); - this.transitionTo('apps'); - } +export default Route.extend({ + model: function(params) { + return this.store.findRecord('app', params.app_id); } - }); diff --git a/admin/app/pods/app/template.hbs b/admin/app/pods/app/template.hbs index b2f5415..86e785a 100644 --- a/admin/app/pods/app/template.hbs +++ b/admin/app/pods/app/template.hbs @@ -1,115 +1,90 @@ {{#page-title name=model.name}} - - - {{/page-title}} -
-
-
-
-

- Active build - - {{#if app.liveBuild}} - - {{fa-icon 'external-link'}} - - {{/if}} -

+
+
+
+
+ Active build
-
+
{{build-info build=model.liveBuild}}
-
-
-
-

- Automatically activate new deploys -

+
+
+
+ Automatically activate new deploys
-
- +
{{toggle-switch label="Automatically activate" value=model.activateNewDeploys - action="activateNewDeploys"}} + action=(action "toggleNewDeploys")}} - +

When this option is on Front End Builds will automatically start serving new master branch deploys. If you want to smoke test your deploys before making them live then turn this option off. - +

-
-
-
- -
-

- Help & Guides -

+
+
+
+ Help & Guides
- -
- -
- Rails router setup - coming soon -
- -
- -
- Amazon S3 setup - coming soon -
- -
- -
- Ember-cli setup - coming soon -
- +
+
    +
  • + Rails router setup + coming soon-ish +
  • +
  • + Amazon S3 setup + coming soon-ish +
  • +
  • + Ember-cli setup + coming soon-ish +
  • +
-{{#if model.orderedBuilds}} -
-
-

- Builds -

-
- -
-

- A list of the most recent builds for - {{model.name}}. -

+
+
+ Builds +
- {{build-list builds=model.orderedBuilds}} -
+
+ {{build-table app=model}}
+
+ +{{#if isRenamingApp}} + {{rename-app-modal app=model dismiss=(action 'stopRenamingApp')}} +{{/if}} + +{{#if isDeletingApp}} + {{delete-app-modal app=model dismiss=(action 'stopDeletingApp')}} {{/if}} diff --git a/admin/app/pods/app/view.js b/admin/app/pods/app/view.js deleted file mode 100644 index 8c3dfe8..0000000 --- a/admin/app/pods/app/view.js +++ /dev/null @@ -1,11 +0,0 @@ -import Ember from 'ember'; - -export default Ember.View.extend({ - _startMatchHeight: function() { - this.$('.match-height').matchHeight(); - }.on('didInsertElement'), - - _removeMatchHeight: function() { - this.$('.match-height').matchHeight('remove'); - }.on('willRemoveElement') -}); diff --git a/admin/app/pods/application/route.js b/admin/app/pods/application/route.js index 2d48ec3..84290f1 100644 --- a/admin/app/pods/application/route.js +++ b/admin/app/pods/application/route.js @@ -1,8 +1,7 @@ -import Ember from 'ember'; +import Route from '@ember/routing/route'; -export default Ember.Route.extend({ +export default Route.extend({ model: function() { - return this.store.find('host-app', 'current'); + return this.store.findRecord('host-app', 'current'); } - }); diff --git a/admin/app/pods/application/template.hbs b/admin/app/pods/application/template.hbs index f2be473..375f830 100644 --- a/admin/app/pods/application/template.hbs +++ b/admin/app/pods/application/template.hbs @@ -1,32 +1,22 @@ -