Skip to content

Commit

Permalink
webui cookbook/index show multiple versions filtered by environment
Browse files Browse the repository at this point in the history
The cookbook index page shows the latest version of all cookbooks in
the currently selected environment.  User can expand the view to see
latest five versions and then click 'view all' to see all versions for
a given cookbook.
  • Loading branch information
Seth Falcon committed Feb 14, 2011
1 parent e5557d9 commit f986803
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 27 deletions.
73 changes: 54 additions & 19 deletions chef-server-webui/app/controllers/cookbooks.rb
Expand Up @@ -2,7 +2,8 @@
# Author:: Adam Jacob (<adam@opscode.com>)
# Author:: Christopher Brown (<cb@opscode.com>)
# Author:: Nuo Yan (<nuo@opscode.com>)
# Copyright:: Copyright (c) 2008 Opscode, Inc.
# Author:: Seth Falcon (<seth@opscode.com>)
# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -30,24 +31,37 @@ class Cookbooks < Application
attr_reader :cookbook_id
def params_helper
@cookbook_id = params[:id] || params[:cookbook_id]
@num_versions = params[:num_versions] || 6
end

def index
@cl = begin
if session[:environment]
result = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("environments/#{session[:environment]}/cookbooks")
else
result = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("cookbooks")
end
result.inject({}) do |res, (cookbook, data)|
res[cookbook] = data["versions"].first["version"]
res
end
rescue => e
Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}")
@_message = {:error => $!}
{}
def fetch_cookbook_versions(num_versions=6)
url = if session[:environment]
"environments/#{session[:environment]}/cookbooks"
else
"cookbooks"
end
# we want to display at most 5 versions, but we ask for 6. This
# tells us if we should display a show all button or not.
url += "?num_versions=#{num_versions}"
begin
result = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest(url)
result.inject({}) do |ans, (name, cb)|
cb["versions"].each do |v|
v["url"] = url(:show_specific_version_cookbook, :cookbook_id => name,
:cb_version => v["version"])
end
ans[name] = cb["versions"]
ans
end
rescue => e
Chef::Log.error("#{e}\n#{e.backtrace.join("\n")}")
@_message = {:error => $!}
{}
end
end

def index
@cl = fetch_cookbook_versions(6)
display @cl
end

Expand Down Expand Up @@ -82,8 +96,8 @@ def show
# provides :json, for the javascript on the environments web form.
def cb_versions
provides :json
@versions = {cookbook_id => get_versions}
display @versions
all_books = fetch_cookbook_versions(@num_versions)
display({ cookbook_id => all_books[cookbook_id] })
end

def recipe_files
Expand Down Expand Up @@ -112,10 +126,31 @@ def library_files
display @lib_files
end

def more_versions_link(cookbook)
link_to("+", "JavaScript:void(0);",
:title => "show other versions of #{cookbook}",
:data => cookbook,
:class => "cookbook_version_toggle")
end

def all_versions_link(cookbook)
link_to("show all", "JavaScript:void(0);",
:class => "show_all",
:id => "#{cookbook}_show_all",
:data => cookbook,
:title => "show all versions of #{cookbook}")
end

private

def get_versions
Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("cookbooks/#{cookbook_id}")[cookbook_id].sort!{|x,y| y <=> x }
# FIXME: Chef API needs a /environments/ENV/cookbooks/BOOK endpoint.
url = if session[:environment]
"environments/#{session[:environment]}/cookbooks/#{cookbook_id}"
else
"cookbooks/#{cookbook_id}"
end
Chef::REST.new(Chef::Config[:chef_server_url]).get_rest(url)[cookbook_id].sort!{|x,y| y <=> x }
end

end
25 changes: 18 additions & 7 deletions chef-server-webui/app/views/cookbooks/index.html.haml
Expand Up @@ -3,13 +3,24 @@
%h2.title
Cookbooks
.inner
%table.table
%table.table#cookbook_version_table
%thead
%tr
%th.first Cookbook Name
%th.last Version
%tbody
- @cl.each do |cookbook, version|
%th Cookbook
%th Latest Version
%th Other Versions
%tbody.cookbook_versions
- @cl.each do |cookbook, versions|
%tr
%td= link_to cookbook, url(:show_specific_version_cookbook, :cookbook_id => cookbook, :cb_version => version)
%td= version
%td= cookbook
%td
%ul.cookbook_versions{ :id => "#{cookbook}_versions" }
- versions[0..4].each_with_index do |v, i|
- klass = i > 0 ? "other_version" : "latest_version"
%li{ :class => klass }
= link_to(v["version"], v["url"])
- if versions.length > 5
= all_versions_link(cookbook)
%td.show_more
= versions.length > 1 ? more_versions_link(cookbook) : ""
= js_include_tag "cookbook_versions"
106 changes: 106 additions & 0 deletions chef-server-webui/public/javascripts/cookbook_versions.js
@@ -0,0 +1,106 @@
// function cookbook_versions_show_more() {
// var cookbook = this.attributes["data"].textContent;
// // do AJAX here and get back something like this:
// var extra_versions = [{version : "0.0.1", url : "/cookbooks/" + cookbook + "/0.0.1/"},
// {version : "0.0.3", url : "/cookbooks/" + cookbook + "/0.0.3"}];

// // NOTE: we're going to try not caching and will repeat ajax calls
// // on repeated click because the data could have changed on the
// // server. We can revisit if this feels wrong for real-world UX
// var version_list = $("#" + cookbook + "_versions");
// var tmp_list = $('<ol/>');
// $.each(extra_versions, function(i, x) {
// var link = $('<a/>').attr("href", x.url).text(x.version);
// var item = $('<li/>').append(link);
// tmp_list.append(item);
// });
// version_list.html(tmp_list.html());
// $(this).unbind("click");
// $(this).click(cookbook_versions_show_less);
// return false;
// }
function cookbook_versions_show_more() {
var cookbook = $(this).attr("data");
var version_list = $("#" + cookbook + "_versions");
if (version_list.children().length == 1) {
return;
}
version_list.children('.other_version').show();
$("#" + cookbook + "_show_all").show();
$(this).unbind("click");
$(this).html("&#8211;"); // FIXME: set css class here, to determine icon image
$(this).click(cookbook_versions_show_less);
}

function cookbook_versions_show_less() {
console.log($(this));
var cookbook = $(this).attr("data");
var version_list = $("#" + cookbook + "_versions");
version_list.children('.other_version').hide();
version_list.children('.all_version').hide();
$("#" + cookbook + "_show_all").hide();
$(this).unbind("click");
$(this).text("+"); // FIXME: set css class here, to determine icon image
$(this).click(cookbook_versions_show_more);
}

function cookbook_versions_show_all() {
var self = $(this);
var cookbook = self.attr("data");
var version_list = $("#" + cookbook + "_versions");
var all_versions = version_list.children('.all_version');
if (all_versions.length > 0) {
all_versions.show();
self.hide();
return;
}
var callback = function(data, textStatus, jqXHR) {
var all_versions = $('<ol/>');
console.log("got " + data[cookbook].length + " items for " + cookbook);
for (var i in data[cookbook]) {
var v = data[cookbook][i];
klass = "all_version";
if (i == 0) {
klass = "latest_version";
}
else if (i < 5) {
klass = "other_version";
}
var link = $('<a/>').attr("href", v.url).text(v.version);
var item = $('<li/>').addClass(klass).append(link);
all_versions.append(item);
}
version_list.html(all_versions.html());
self.hide();
}
$.ajax({
url : "/cookbooks/" + cookbook + "?num_versions=all",
dataType: "json",
success : callback,
error : function(jqXHR, textStatus, errorThrown) {
// FIXME
console.log(textStatus);
}
})
}

function fetch_all_versions0(cookbook) {
$.ajax({
url : "/cookbooks/" + cookbook,
dataType: "json",
success : function(data, textStatus, jqXHR) {
console.log(data);
},
error : function(jqXHR, textStatus, errorThrown) {
console.log(textStatus);
}

})
}

$(document).ready(function() {
$('td.show_more a').click(cookbook_versions_show_more);
$('td.show_more a').each(cookbook_versions_show_less);
$('a.show_all').click(cookbook_versions_show_all);
})

20 changes: 19 additions & 1 deletion chef-server-webui/public/stylesheets/chef.css
Expand Up @@ -313,4 +313,22 @@ h1 label {

.cookbook_version_constraints_cb_name{
width:80%;
}
}

a.cookbook_version_toggle{
text-decoration:none;
font-weight:bold;
font-size: 24px;
}

ul.cookbook_versions{
list-style-type:none;
}

#cookbook_version_table{
width: auto;
}

tbody.cookbook_versions td {
vertical-align:top;
}

0 comments on commit f986803

Please sign in to comment.