-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
beta waitlist #3
base: master
Are you sure you want to change the base?
Changes from 13 commits
3355ff1
31573b9
c334fdf
2809d27
99f070c
23c7b56
3f62dcc
3080b00
dd2e7f0
f754965
2101d71
d788a0c
2dfb25a
8287efe
39fbbe7
13fb53c
aebfada
ec4da18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<%= page_title do %> | ||
<%= icon_tag 'star' %> Projects | ||
<% end %> | ||
|
||
<%= search_form do %> | ||
<%= render 'shared/search_query' %> | ||
<% end %> | ||
|
||
<div class="row dashboard"> | ||
<%= render @projects %> | ||
</div> | ||
|
||
<div class="admin-actions"> | ||
<% if current_user.admin? %> | ||
<div class="pull-right"> | ||
<%= render "locks/button", lock: global_lock, resource: nil, prefix: "Global " %> | ||
<%= link_to "New", new_project_path, class: "btn btn-default" %> | ||
</div> | ||
<% end %> | ||
|
||
<%= paginate @projects %> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
require 'clockwork' | ||
require './config/boot' | ||
require './config/environment' | ||
|
||
include Clockwork | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please ensure we're logging to a place that gets rotated (such as log/production.log) |
||
|
||
require './plugins/deploy_waitlist/lib/samson_deploy_waitlist/waitlist_monitor.rb' | ||
|
||
handler do |job| | ||
puts "Running #{job}" | ||
end | ||
|
||
every(30.seconds, 'deploy_waitlist_monitor') { SamsonDeployWaitlist::WaitlistMonitor.check_your_head } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
class DeployWaitlistController < ApplicationController | ||
|
||
def show | ||
respond_to do |format| | ||
format.html | ||
format.json { render json: current_waitlist.to_json } | ||
end | ||
end | ||
|
||
def add | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want to consider RESTful routes? I think add and remove make sense, but i'm just asking if we have strong opinions either way |
||
Rails.logger.warn("current_waitlist: #{current_waitlist.list}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is good for our debugging, but in a PR to zendesk, i would advise making this debug |
||
current_waitlist.add({ email: deployer, added: now }) | ||
render json: current_waitlist.to_json | ||
end | ||
|
||
def remove | ||
current_waitlist.remove(deployer.to_i) | ||
render json: current_waitlist.to_json | ||
end | ||
|
||
private | ||
|
||
def now | ||
Time.now | ||
end | ||
|
||
def current_waitlist | ||
@waitlist ||= Waitlist.new(project.id, stage.id) | ||
end | ||
|
||
def deployer | ||
params[:deployer] | ||
end | ||
|
||
def stage | ||
Stage.find params[:stage] | ||
end | ||
|
||
def project | ||
Project.find params[:project] | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
class Waitlist | ||
attr_reader :project_id, :stage_id, :list, :metadata | ||
|
||
WAITLIST_KEY = 'deploy_waitlist'.freeze | ||
METADATA_KEY = '.metadata'.freeze | ||
|
||
def initialize(project_id, stage_id) | ||
@project_id = project_id | ||
@stage_id = stage_id | ||
@list = Rails.cache.read(key) || [] | ||
@metadata = Rails.cache.read(metadata_key) || {} | ||
end | ||
|
||
def add(deployer_hash = {}) | ||
@list << deployer_hash | ||
@metadata[:last_updated] = Time.now | ||
@metadata[:head_updated_at] = Time.now if @list.size == 1 | ||
set | ||
end | ||
|
||
def remove(index) | ||
@list.delete_at(index) | ||
@metadata[:last_updated] = Time.now | ||
@metadata[:head_updated_at] = Time.now if (index == 0) | ||
set | ||
end | ||
|
||
# accessors for the view | ||
def created_at | ||
@metadata[:created_at] | ||
end | ||
|
||
def head_updated_at | ||
@metadata[:head_updated_at] | ||
end | ||
|
||
def head_locked? | ||
return false if @list.blank? | ||
stage = Stage.find @stage_id | ||
return false unless stage.lock.present? | ||
stage.lock.user.email == list[0][:email] | ||
end | ||
|
||
def to_json | ||
{ | ||
created_at: created_at, | ||
head_updated_at: head_updated_at, | ||
head_is_locked: head_locked?, | ||
list: list | ||
} | ||
end | ||
|
||
private | ||
|
||
def set | ||
Rails.cache.write(key, @list) | ||
@metadata[:created_at] = Time.now unless @metadata[:created_at] | ||
Rails.cache.write(metadata_key, @metadata) | ||
end | ||
|
||
def key | ||
WAITLIST_KEY + stage_key | ||
end | ||
|
||
def metadata_key | ||
"#{WAITLIST_KEY}.{METADATA_KEY}#{stage_key}" | ||
end | ||
|
||
def stage_key | ||
".project-#{project_id}.stage-#{stage_id}" | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<% | ||
waitlist = Waitlist.new(@project.id, @stage.id) | ||
%> | ||
<div id="waitlist" style="margin-bottom: 20px; margin-top: 20px;"> | ||
<h2 style="margin-bottom: 0px;">Deployment Waitlist <span style="font-size:10px; font-style: italic;" id="createdAt"/></h2> | ||
<div style="margin-bottom: 10px;"> | ||
<span class="glyphicon glyphicon-time"></span> Note: Once you're head of the waitlist, you have <%= SamsonDeployWaitlist::WaitlistMonitor::TIME_TO_LOCK_QUEUE %> | ||
minutes to lock the deployment before you're automatically kicked to the back of the line.</div> | ||
<ol style="width: 60%" id="list"></ol> | ||
<div style="display: none; margin: 25px;" id="empty">Such empty! ¯\_(ツ)_/¯</div> | ||
<button onclick="addUser();"><span class="glyphicon glyphicon-plus"></span> Add Me</button> | ||
</div> | ||
|
||
<script> | ||
var stageId = <%= @stage.id %>; | ||
var projectId = <%= @project.id %>; | ||
var deployer = '<%= current_user.email %>'; | ||
var authenticity_token = '<%= form_authenticity_token %>'; | ||
stage: stageId, | ||
|
||
$( document ).ready(function(){ | ||
$.getScript( "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js", function( data, textStatus, jqxhr ) { | ||
$.getScript("https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.14/moment-timezone-with-data-2012-2022.min.js", function( data, textStatus, jqxhr ) { | ||
drawList(); | ||
}); | ||
}); | ||
}); | ||
|
||
function drawList() { | ||
$.ajax({ | ||
url: "/deploy_waitlist.json?stage=" + stageId + "&project=" + projectId, | ||
}).done(function(wishlist) { | ||
console.log(wishlist); | ||
var createdAt = moment(wishlist.created_at).tz('America/Los_Angeles').format("MMM Do, YYYY h:mm a"); | ||
var headUpdatedAt = moment(wishlist.head_updated_at).fromNow(); | ||
var deployers = wishlist.list; | ||
if (createdAt) { | ||
$("#createdAt").html("created " + createdAt); | ||
} | ||
var list = $(document.createElement('ol')).attr('id','list') | ||
.css({ 'width' : '60%', | ||
'list-style' : 'none', | ||
'padding-left' : '0'}); | ||
if (deployers.length) { | ||
$.each(deployers, function( index, value ) { | ||
$(list).append(listItem(value, index)); | ||
}); | ||
var headSince = $(document.createElement('span')).css({'margin-left' : '10px', | ||
'font-size' : '10px', | ||
'font-weight' : 600}); | ||
$(headSince).append("Head since " + headUpdatedAt) | ||
if (wishlist.head_is_locked) { | ||
$(headSince).prepend('<span class="glyphicon glyphicon-lock"></span> '); | ||
} else { | ||
$(headSince).css('color', 'red'); | ||
} | ||
$(list).find('li').first().append(headSince); | ||
|
||
$("#empty").hide(); | ||
} else { | ||
$("#empty").show(); | ||
} | ||
$("#list").replaceWith(list); | ||
setTimeout(drawList, 3000); | ||
}); | ||
} | ||
|
||
function listItem(deployer, index) { | ||
var item = $(document.createElement('li')); | ||
var added = $(document.createElement('span')).css('margin-left', '10px').css('font-size', '10px'); | ||
$(added).append("Enqueued " + moment(deployer.added).fromNow()); | ||
$(item).append(deployer.email).append(added); | ||
var remove = $(document.createElement('a')); | ||
$(remove).attr('href', '#'); | ||
$(remove).click(function() { | ||
removeUser(index); | ||
}) | ||
$(remove).css({ | ||
'color' : 'red', | ||
'margin-right' : '5px' | ||
}); | ||
$(remove).append('<span class="glyphicon glyphicon-remove"></span>'); | ||
$(item).prepend(remove); | ||
return item; | ||
} | ||
|
||
function addUser() { | ||
$.post( "/deploy_waitlist/add", $.extend({}, postParams(), { deployer: deployer}), function( data ) { | ||
drawList(data); | ||
}); | ||
} | ||
function removeUser(index) { | ||
$.post( "/deploy_waitlist/remove", $.extend({}, postParams(), { deployer: index}), function( data ) { | ||
drawList(data); | ||
}); | ||
} | ||
|
||
function postParams() { | ||
return { | ||
authenticity_token: authenticity_token, | ||
stage: stageId, | ||
project: projectId | ||
} | ||
} | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Samson::Application.routes.draw do | ||
post '/deploy_waitlist/add', to: 'deploy_waitlist#add' | ||
post '/deploy_waitlist/remove', to: 'deploy_waitlist#remove' | ||
get '/deploy_waitlist', to: 'deploy_waitlist#show' | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have we considered using periodical, which is already built in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, but only because not familiar with it.
embarassed--google search coming up dry. can you add link?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/zendesk/samson/blob/40aa50583db4b9b636d52e751b424e2ef4dfa04d/config/initializers/periodical.rb