Adds a Website Rebooter to reboot via AWS. (#9)

- Adds I18n to websites.
- Adds feather-icons JS in replace of images.
- Adds node-polyglot for client-side translations.
This commit is contained in:
Andrew Fomera 2017-09-17 16:50:30 -05:00 committed by Justin Licata
parent 1f5bef0df0
commit d9d9b466d5
36 changed files with 452 additions and 105 deletions

@ -5,6 +5,7 @@ git_source(:github) do |repo_name|
"https://github.com/#{repo_name}.git"
end
gem 'aws-sdk', '~> 2.10'
gem 'attr_encrypted', '~> 3.0', github: 'attr-encrypted/attr_encrypted'
gem 'bootstrap', '4.0.0.alpha6'
gem 'delayed_job_active_record', '~> 4.1.2'

@ -55,6 +55,14 @@ GEM
arel (8.0.0)
autoprefixer-rails (7.1.2.4)
execjs
aws-sdk (2.10.33)
aws-sdk-resources (= 2.10.33)
aws-sdk-core (2.10.33)
aws-sigv4 (~> 1.0)
jmespath (~> 1.0)
aws-sdk-resources (2.10.33)
aws-sdk-core (= 2.10.33)
aws-sigv4 (1.0.1)
bcrypt (3.1.11)
bindex (0.5.0)
bootstrap (4.0.0.alpha6)
@ -111,6 +119,7 @@ GEM
activesupport (>= 4.2.0)
hashdiff (0.3.5)
i18n (0.8.6)
jmespath (1.3.1)
kaminari (1.0.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.0.1)
@ -267,6 +276,7 @@ PLATFORMS
DEPENDENCIES
attr_encrypted (~> 3.0)!
aws-sdk (~> 2.10)
bootstrap (= 4.0.0.alpha6)
byebug
capybara (~> 2.13)

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#414345" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left"><path d="M20 12H4M10 18l-6-6 6-6"/></svg>

Before

Width:  |  Height:  |  Size: 252 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#1d3557" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart"><path d="M18 3h4v18h-4zM10 8h4v13h-4zM2 13h4v8H2z"/></svg>

Before

Width:  |  Height:  |  Size: 268 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit"><path d="M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34"/><path d="M18 2l4 4-10 10H8v-4L18 2z"/></svg>

Before

Width:  |  Height:  |  Size: 329 B

@ -1,4 +1,5 @@
//= require rails-ujs
//= require feather-icons/dist/feather
//= require clipboard/dist/clipboard
//= require local-time
//= require turbolinks

@ -12,35 +12,6 @@ a.card {
text-decoration: none;
}
@include media-breakpoint-up(lg) {
.card-deck .card-container:not(:last-child) {
margin-right: ($spacer * 2);
}
}
@include media-breakpoint-down(md) {
.card-deck {
display: block;
}
}
.card-container {
display: flex;
flex: 1 0 0;
flex-direction: column;
margin-bottom: ($spacer * 2);
.card {
margin-bottom: 0;
transition: all $base-duration $base-timing;
}
&:hover .card {
box-shadow: $box-shadow-hover;
transform: translateY(-2px);
}
}
.card-link {
transition: all $base-duration $base-timing;
@ -50,6 +21,23 @@ a.card {
}
}
@include media-breakpoint-down(md) {
.card-deck {
display: block;
.card-link:not(:last-child) {
margin-left: 0;
margin-right: 0;
}
}
}
@include media-breakpoint-up(xs) {
.card-deck .card-link:not(:first-child) {
margin-left: 0;
}
}
.card-header {
background-color: $white;
padding-bottom: 1.5rem;

@ -19,7 +19,7 @@ module PaginatableConcern
),
link: (
render_to_string(
'websites/_next_page.html.erb',
'websites/_next_page',
locals: { websites: ivar },
layout: false
)

@ -31,11 +31,27 @@ class WebsitesController < ApplicationController
@pings = @website.pings.paginate(params).decorate
end
def edit
@website = Website.find(params[:id])
end
def update
@website = Website.find(params[:id])
if @website.update(website_params)
flash[:success] = t('.success', name: @website.name)
redirect_to(root_path)
else
render(:edit)
end
end
private
def website_params
params.require(:website).permit(
:name, :url, :basic_auth_username, :basic_auth_password
:name, :url, :basic_auth_username, :basic_auth_password,
:aws_instance_id, :aws_region
)
end
end

@ -0,0 +1,11 @@
# TranslationsHelper
module TranslationsHelper
def i18n_phrases
{
pagination: {
fetching: t('pagination.fetching'),
failed: t('pagination.failed')
}
}.to_json
end
end

@ -0,0 +1,25 @@
module WebsitesHelper
def options_for_aws_region(selected = nil)
options_for_select(aws_regions, selected)
end
def aws_regions
# http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/
# using-regions-availability-zones.html#concepts-available-regions
[
['US East (N. Virginia) · us-east-1', 'us-east-1'],
['US East (Ohio) · us-east-2', 'us-east-2'],
['US West (N. California) · us-west-1', 'us-west-1'],
['US West (Oregon) · us-west-2', 'us-west-2'],
['Canada (Central) · ca-central-1', 'ca-central-1'],
['EU (Ireland) · eu-west-1', 'eu-west-1'],
['EU (London) · eu-west-1', 'eu-west-2'],
['EU (Frankfurt) · eu-central-1', 'eu-central-1'],
['Asia Pacific (Tokyo) · ap-northeast-1', 'ap-northeast-1'],
['Asia Pacific (Seoul) · ap-northeast-2', 'ap-northeast-2'],
['Asia Pacific (Singapore) · ap-southeast-1', 'ap-southeast-1'],
['Asia Pacific (Mumbai) · ap-south-1', 'ap-south-1'],
['South America (São Paulo) · sa-east-1', 'sa-east-1']
]
end
end

@ -4,6 +4,7 @@ import { namespace } from './utils/namespace';
import CopyToClipboard from './globals/CopyToClipboard';
import Pagination from './globals/Pagination';
import PingChart from './websites/PingChart';
import Polyglot from 'node-polyglot';
class Dispatcher {
constructor() {
@ -23,8 +24,24 @@ class Dispatcher {
break;
}
}
feather() {
feather.replace();
}
translate() {
const phrases = document
.querySelector('[data-behavior="translations"]')
.getAttribute('data-phrases');
window.polyglot = new Polyglot({ phrases: JSON.parse(phrases) });
}
}
document.addEventListener('turbolinks:load', () => {
new Dispatcher().route();
const dispatcher = new Dispatcher();
dispatcher.feather();
dispatcher.route();
dispatcher.translate();
});

@ -1,6 +1,5 @@
import 'whatwg-fetch';
const loadMoreSelector = '[data-behavior="load-more"]';
const paginationWrapperSelector = '[data-behavior="pagination-wrapper"]';
export default class Pagination {
@ -55,7 +54,8 @@ export default class Pagination {
addLoadingText(el) {
this.cachedText = el.textContent;
el.textContent = 'Fetching...';
el.textContent = polyglot.t('pagination.fetching');
el.setAttribute('disabled', true);
}
@ -78,7 +78,7 @@ export default class Pagination {
this.paginationWrapperEl.innerHTML = response.link;
})
.catch(ex => {
console.log('Failed to load next page of results', ex);
console.log(polyglot.t('pagination.failed'), ex);
});
}
}

@ -60,9 +60,8 @@ export default class PingChart {
const { margin, tickSize, axisPadding, width, height } = this.defaults;
this.graph = d3.select(this.selector);
this.chartEl.innerHTML = '';
d3.select('svg').remove();
const svg = (this.svg = this.graph
.append('svg')
.attr('width', width)

@ -1,7 +1,7 @@
module Paginatable
extend ActiveSupport::Concern
SIZE = 12
SIZE = 18
module ClassMethods
def paginate(params)

@ -0,0 +1,42 @@
module Websites
# Rebooter
class Rebooter
attr_reader(:website)
def initialize(website)
@website = website
end
def reboot
website.update_attributes(rebooting: true)
client.instance(website.aws_instance_id).reboot
status = build_status("Rebooting: #{website.name}.")
rescue => e
status = build_status("Failed to reboot #{website.name}: #{e}.")
ensure
status
end
private
def client
Aws.config.update(
region: website.aws_region,
credentials: aws_credentials
)
Aws::EC2::Resource.new
end
def aws_credentials
Aws::Credentials.new(
Setting.first.aws_key,
Setting.first.aws_secret
)
end
def build_status(message)
OpenStruct.new(website: website, message: message)
end
end
end

@ -1,8 +1,17 @@
<div class="page-heading">
<h4 class="page-title"><%= t "devise.invitations.new.header" %></h4>
</div>
<%= link_to("Head back", users_path,
class: "btn btn-secondary btn-sm mt-3") %>
<div class="row">
<div class="col-sm-4 offset-sm-4">
<%= link_to(users_path,
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<i class="mr-3" data-feather="arrow-left"></i>
<h6 class="mb-0">Head back</h6>
</div>
<% end %>
</div>
</div>
<div class="row">

@ -16,5 +16,7 @@
<div class="container">
<div class="mt-4"><%= yield %></div>
</div>
<div data-behavior="translations" data-phrases="<%= i18n_phrases %>"></div>
</body>
</html>

@ -1,6 +1,6 @@
<div class="blankslate">
<h4 class="blankslate-title">
No <%= resource.titleize.pluralize %> have been created yet.
<%= t('.title', resource: resource.pluralize) %>
</h4>
<% if yield.present? %>

@ -1,8 +1,17 @@
<div class="page-heading">
<h4 class="page-title">Here's your team</h4>
</div>
<%= link_to("Invite member", new_user_invitation_path,
class: "btn btn-primary btn-sm mt-3") %>
<div class="row">
<div class="col-sm-4 offset-sm-4">
<%= link_to(new_user_invitation_path,
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<i class="mr-3" data-feather="user-plus"></i>
<h6 class="mb-0">Invite member</h6>
</div>
<% end %>
</div>
</div>
<div class="row">

@ -0,0 +1,53 @@
<%= form_for(website) do |f| %>
<div class="form-group">
<%= f.label(:name) %>
<%= f.text_field(:name,
autofocus: true, autocomplete: :off,
class: "form-control") %>
<%= error_message_on(f.object, :name) %>
</div>
<div class="form-group">
<%= f.label(:url, t('.url')) %>
<%= f.url_field(:url, class: "form-control") %>
<%= error_message_on(f.object, :url) %>
</div>
<div class="hr-sect"><%= t('.optional') %></div>
<div class="form-group">
<%= f.label(:basic_auth_username) %>
<%= f.text_field(:basic_auth_username, class: "form-control") %>
<%= error_message_on(f.object, :basic_auth_username) %>
</div>
<div class="form-group">
<%= f.label(:basic_auth_password) %>
<%= f.text_field(:basic_auth_password, class: "form-control") %>
<%= error_message_on(f.object, :basic_auth_password) %>
</div>
<% if (Setting.global.present? &&
(Setting.global.aws_key.present? && Setting.global.aws_secret.present?)) %>
<div class="hr-sect"><%= t('.aws_info') %></div>
<div class="form-group">
<%= f.label(:aws_instance_id, t('.aws_instance_id')) %>
<%= f.text_field(:aws_instance_id, class: "form-control") %>
<%= error_message_on(f.object, :aws_instance_id) %>
</div>
<div class="form-group">
<%= f.label(:aws_region, t('.aws_region')) %>
<%= f.select(:aws_region,
options_for_aws_region(f.object.aws_region),
{ prompt: t('.aws_region_select') },
{ class: "form-control" }) %>
<%= error_message_on(f.object, :aws_region) %>
</div>
<% end %>
<div class="actions">
<%= f.submit class: "btn btn-primary" %>
</div>
<% end %>

@ -2,6 +2,6 @@
<button class="btn btn-primary btn-block mb-4"
data-url="<%= websites_url(page: websites.next_page) %>"
data-behavior="load-more">
Load more
<%= t('.load_more') %>
</button>
<% end %>

@ -1,11 +1,9 @@
<div class="card-container">
<%= link_to(website_path(website), class: "card") do %>
<div class="card-block">
<h4 class="card-title"><%= website.name %></h4>
<%= link_to(website_path(website), class: "card card-link") do %>
<div class="card-block">
<h4 class="card-title"><%= website.name %></h4>
<div class="hr-sect">Recent Pings</div>
<div class="hr-sect">Recent Pings</div>
<%= render(website.recent_pings) %>
</div>
<% end %>
</div>
<%= render(website.recent_pings) %>
</div>
<% end %>

@ -1,5 +1,5 @@
<div class="page-heading">
<h4 class="page-title">Response Times</h4>
<h4 class="page-title"><%= t('.title') %></h4>
</div>
<div class="row">
@ -7,7 +7,7 @@
<%= link_to(website_path(@website),
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<%= image_tag("icons/arrow-left.svg", class: "mr-3") %>
<i class="mr-3" data-feather="arrow-left"></i>
<h6 class="mb-0"><%= @website.name %></h6>
</div>
<% end %>

@ -0,0 +1,24 @@
<div class="page-heading">
<h4 class="page-title"><%= t(".title") %></h4>
</div>
<div class="row">
<div class="col-sm-4 offset-sm-4">
<%= link_to(website_path(@website),
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<i class="mr-3" data-feather="arrow-left"></i>
<h6 class="mb-0"><%= @website.name %></h6>
</div>
<% end %>
</div>
</div>
<div class="row">
<div class="col-md-6 offset-md-3">
<div class="card">
<div class="card-block">
<%= render("form", website: @website) %>
</div>
</div>
</div>

@ -1,3 +1,19 @@
<div class="page-heading">
<h4 class="page-title"><%= t('.title') %></h4>
</div>
<div class="row">
<div class="col-sm-4 offset-sm-4">
<%= link_to(new_website_path,
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<i class="mr-3" data-feather="link-2"></i>
<h6 class="mb-0"><%= t('.add') %></h6>
</div>
<% end %>
</div>
</div>
<div class="row">
<div class="col-md-12">
<% if @websites.any? %>
@ -13,9 +29,7 @@
</div>
</div>
<% else %>
<%= render("shared/blankslate", resource: "website") do %>
<%= link_to("Add website", new_website_path, class: "btn btn-primary") %>
<% end %>
<%= render("shared/blankslate", resource: t('.resource')) %>
<% end %>
</div>
</div>

@ -1,44 +1,24 @@
<div class="page-heading">
<h4 class="page-title">Let's add a new website</h4>
<h4 class="page-title"><%= t(".title") %></h4>
</div>
<div class="row">
<div class="col-sm-4 offset-sm-4">
<%= link_to(websites_path,
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<i class="mr-3" data-feather="arrow-left"></i>
<h6 class="mb-0"><%= t('.back') %></h6>
</div>
<% end %>
</div>
</div>
<div class="row">
<div class="col-md-6 offset-md-3">
<div class="card">
<div class="card-block">
<%= form_for(@website) do |f| %>
<div class="form-group">
<%= f.label(:name) %>
<%= f.text_field(:name,
autofocus: true, autocomplete: :off,
class: "form-control") %>
<%= error_message_on(f.object, :name) %>
</div>
<div class="form-group">
<%= f.label(:url, "URL") %>
<%= f.url_field(:url, class: "form-control") %>
<%= error_message_on(f.object, :url) %>
</div>
<div class="hr-sect">optional</div>
<div class="form-group">
<%= f.label(:basic_auth_username) %>
<%= f.text_field(:basic_auth_username, class: "form-control") %>
<%= error_message_on(f.object, :basic_auth_username) %>
</div>
<div class="form-group">
<%= f.label(:basic_auth_password) %>
<%= f.text_field(:basic_auth_password, class: "form-control") %>
<%= error_message_on(f.object, :basic_auth_password) %>
</div>
<div class="actions">
<%= f.submit class: "btn btn-primary" %>
</div>
<% end %>
<%= render("form", website: @website) %>
</div>
</div>
</div>

@ -7,8 +7,8 @@
<%= link_to(website_charts_response_time_index_path(@website),
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<%= image_tag("icons/bar-chart.svg", class: "mr-3") %>
<h6 class="mb-0">Response Times</h6>
<i class="mr-3" data-feather="bar-chart"></i>
<h6 class="mb-0"><%= t('.response_times') %></h6>
</div>
<% end %>
</div>
@ -16,8 +16,8 @@
<%= link_to(edit_website_path(@website),
class: "card card-link") do %>
<div class="card-block text-muted text-center d-flex align-items-center justify-content-center">
<%= image_tag("icons/edit.svg", class: "mr-3") %>
<h6 class="mb-0">Edit</h6>
<i class="mr-3" data-feather="edit"></i>
<h6 class="mb-0"><%= t('.edit') %></h6>
</div>
<% end %>
</div>
@ -34,7 +34,7 @@
<%= paginate(@pings) %>
</div>
<% else %>
<%= render("shared/blankslate", resource: "ping") %>
<%= render("shared/blankslate", resource: t('.resource')) %>
<% end %>
</div>
</div>

@ -30,13 +30,48 @@
# available at http://guides.rubyonrails.org/i18n.html.
en:
pagination:
fetching: Fetching...
failed: Failed to load next page of results
shared:
blankslate:
title: No %{resource} have been created yet.
websites:
charts:
response_time:
index:
title: Response Times
create:
success: >
%{name} has been successfully added.
edit:
title: Let's edit your website
form:
aws_info: AWS Information
aws_instance_id: AWS Instance ID
aws_region: AWS Region
aws_region_select: Select a region
optional: Optional
url: URL
index:
add: Add website
resource: website
title: Our websites
new:
back: Back to websites
title: Let's add a new website
next_page:
load_more: Load more
show:
edit: Edit
response_times: Response Times
resource: ping
update:
success: >
%{name} has been successfully updated.
users:
registrations:
new:
disable_registration: >
If you already have an account, please sign in. Otherwise, you
must be invited to join Storm.
websites:
create:
success: >
%{name} has been successfully added.

@ -19,7 +19,7 @@ Rails.application.routes.draw do
resource(:settings, only: %w(edit update))
resources(:users, only: %w(index))
resources(:websites, only: %w(index new create show edit)) do
resources(:websites, only: %w(index new create show edit update)) do
scope(module: :websites) do
namespace(:charts) do
resources(:response_time, only: %w(index), path: 'response-time')

@ -7,6 +7,9 @@ class CreateWebsites < ActiveRecord::Migration[5.1]
t.boolean :active, index: true, default: true
t.string :basic_auth_username
t.string :basic_auth_password
t.string :aws_instance_id
t.string :aws_region
t.boolean :rebooting, default: false
t.timestamps
end

@ -100,6 +100,9 @@ ActiveRecord::Schema.define(version: 20170804190921) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
t.string "aws_instance_id"
t.string "aws_region"
t.boolean "rebooting", default: false
t.index ["active"], name: "index_websites_on_active"
t.index ["deleted_at"], name: "index_websites_on_deleted_at"
t.index ["name"], name: "index_websites_on_name"

@ -17,9 +17,11 @@
"css-loader": "^0.28.4",
"d3": "^4.10.2",
"extract-text-webpack-plugin": "^3.0.0",
"feather-icons": "^3.2.2",
"file-loader": "^0.11.2",
"glob": "^7.1.2",
"js-yaml": "^3.9.0",
"node-polyglot": "^2.2.2",
"node-sass": "^4.5.3",
"path-complete-extname": "^0.1.0",
"postcss-loader": "^2.0.6",

@ -5,6 +5,7 @@ class WebsitesControllerTest < ActionDispatch::IntegrationTest
feature 'as as authenticated user' do
before(:each) do
@user = create(:user)
@website = create(:website)
sign_in(@user)
end
@ -18,6 +19,19 @@ class WebsitesControllerTest < ActionDispatch::IntegrationTest
assert_response(:success)
end
test 'should get edit' do
get(edit_website_path(@website))
assert_response(:success)
end
test 'should patch update' do
assert_no_difference('Website.count') do
patch(website_path(@website), params: params)
assert_not_nil(flash[:success])
assert_redirected_to(root_path)
end
end
test 'should post create' do
assert_difference('Website.count') do
post(websites_path, params: params)

@ -1,5 +1,7 @@
FactoryGirl.define do
factory :setting do
aws_key('aws_key')
aws_secret('aws_secret')
slack_url('127.0.0.1/slack')
end
end

@ -1648,6 +1648,13 @@ deep-extend@~0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
define-properties@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
dependencies:
foreach "^2.0.5"
object-keys "^1.0.8"
defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
@ -1788,6 +1795,24 @@ error-ex@^1.2.0:
dependencies:
is-arrayish "^0.2.1"
es-abstract@^1.5.0:
version "1.8.2"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.8.2.tgz#25103263dc4decbda60e0c737ca32313518027ee"
dependencies:
es-to-primitive "^1.1.1"
function-bind "^1.1.1"
has "^1.0.1"
is-callable "^1.1.3"
is-regex "^1.0.4"
es-to-primitive@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d"
dependencies:
is-callable "^1.1.1"
is-date-object "^1.0.1"
is-symbol "^1.0.1"
es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
version "0.10.24"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.24.tgz#a55877c9924bc0c8d9bd3c2cbe17495ac1709b14"
@ -2011,6 +2036,10 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
feather-icons@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/feather-icons/-/feather-icons-3.2.2.tgz#96c132e4a401d5cc18c03063c87999f47dce442b"
file-loader@^0.11.2:
version "0.11.2"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
@ -2068,6 +2097,12 @@ flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
for-each@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4"
dependencies:
is-function "~1.0.0"
for-in@^0.1.3:
version "0.1.8"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
@ -2088,6 +2123,10 @@ for-own@^1.0.0:
dependencies:
for-in "^1.0.1"
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@ -2154,6 +2193,10 @@ function-bind@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@ -2502,6 +2545,14 @@ is-builtin-module@^1.0.0:
dependencies:
builtin-modules "^1.0.0"
is-callable@^1.1.1, is-callable@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2"
is-date-object@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
is-directory@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
@ -2544,6 +2595,10 @@ is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
is-function@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
@ -2602,6 +2657,12 @@ is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
is-regex@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
dependencies:
has "^1.0.1"
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@ -2612,6 +2673,10 @@ is-svg@^2.0.0:
dependencies:
html-comment-regex "^1.1.0"
is-symbol@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@ -3164,6 +3229,15 @@ node-libs-browser@^2.0.0:
util "^0.10.3"
vm-browserify "0.0.4"
node-polyglot@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/node-polyglot/-/node-polyglot-2.2.2.tgz#1a3f76d7392f836ea0823836ede817e6ea6ec26c"
dependencies:
for-each "^0.3.2"
has "^1.0.1"
string.prototype.trim "^1.1.2"
warning "^3.0.0"
node-pre-gyp@^0.6.36:
version "0.6.36"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
@ -3273,6 +3347,10 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
object-keys@^1.0.8:
version "1.0.11"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
object-path@^0.9.2:
version "0.9.2"
resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.9.2.tgz#0fd9a74fc5fad1ae3968b586bda5c632bd6c05a5"
@ -4661,6 +4739,14 @@ string-width@^2.0.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string.prototype.trim@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea"
dependencies:
define-properties "^1.1.2"
es-abstract "^1.5.0"
function-bind "^1.0.2"
string_decoder@^0.10.25:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@ -4963,6 +5049,12 @@ vm-browserify@0.0.4:
dependencies:
indexof "0.0.1"
warning@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
dependencies:
loose-envify "^1.0.0"
watchpack@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac"