This patch creates the shell for much of what the cloud ui will become. It is focused on layout (lightly fedora themed), accessibility, and 'bookmarkability'. This layout uses no javascript (that will be used to enhance interactivity in a future patch). It also introduces the idea of using a simple table rather than the more conplex js/json we use in the admin side. Plan here is to gradually enhance this as needed to make more interactive. CSS was kept separate from admin CSS to facilitate theming by users/deployments. Controllers are designed (even though large parts are stubbed) to be 'skinny' and leverage as much as possible the new service api. There are a few readonly AR calls that in near future could easily be moved to service layer to be even simpler calls. They are kept separate from admin things so they can be as simple as possible as well a making it conceivable that one could deploy the cloud part of the app without also deplying admin (perhaps one wants to deply that elsewhere). For now this would have to be done manually, but perhaps in future we can setup the service layer/ar classes to be a separate rpm that two different wuis (admin/cloud) could call into, enhancing modularity. Signed-off-by: Jason Guiditta <jguiditt at redhat.com> --- src/app/controllers/cloud/cloud_controller.rb | 35 ++++ src/app/controllers/cloud/dashboard_controller.rb | 24 +++ src/app/controllers/cloud/instance_controller.rb | 95 +++++++++++ src/app/helpers/cloud/cloud_helper.rb | 21 +++ src/app/helpers/cloud/dashboard_helper.rb | 21 +++ src/app/helpers/cloud/instance_helper.rb | 38 +++++ src/app/views/cloud/dashboard/index.rhtml | 2 + src/app/views/cloud/instance/_list.rhtml | 34 ++++ src/app/views/cloud/instance/_show.rhtml | 47 ++++++ src/app/views/cloud/instance/create.rhtml | 2 + src/app/views/cloud/instance/destroy.rhtml | 2 + src/app/views/cloud/instance/edit.rhtml | 2 + src/app/views/cloud/instance/index.rhtml | 23 +++ src/app/views/cloud/instance/new.rhtml | 2 + src/app/views/cloud/instance/show.rhtml | 5 + src/app/views/cloud/instance/update.rhtml | 2 + src/app/views/layouts/cloud/cloud.rhtml | 55 +++++++ src/public/images/icon_failed_11px.png | Bin 0 -> 374 bytes src/public/images/icon_queued_11px.png | Bin 0 -> 429 bytes src/public/images/icon_startup_11px.png | Bin 0 -> 458 bytes src/public/images/icon_unknown_11px.png | Bin 0 -> 421 bytes src/public/images/icon_warning_11px.png | Bin 0 -> 343 bytes src/public/stylesheets/cloud/layout.css | 166 ++++++++++++++++++++ src/test/functional/cloud/cloud_controller_test.rb | 8 + .../functional/cloud/dashboard_controller_test.rb | 8 + .../functional/cloud/instance_controller_test.rb | 23 +++ 26 files changed, 615 insertions(+), 0 deletions(-) create mode 100644 src/app/controllers/cloud/cloud_controller.rb create mode 100644 src/app/controllers/cloud/dashboard_controller.rb create mode 100644 src/app/controllers/cloud/instance_controller.rb create mode 100644 src/app/helpers/cloud/cloud_helper.rb create mode 100644 src/app/helpers/cloud/dashboard_helper.rb create mode 100644 src/app/helpers/cloud/instance_helper.rb create mode 100644 src/app/views/cloud/dashboard/index.rhtml create mode 100644 src/app/views/cloud/instance/_list.rhtml create mode 100644 src/app/views/cloud/instance/_show.rhtml create mode 100644 src/app/views/cloud/instance/create.rhtml create mode 100644 src/app/views/cloud/instance/destroy.rhtml create mode 100644 src/app/views/cloud/instance/edit.rhtml create mode 100644 src/app/views/cloud/instance/index.rhtml create mode 100644 src/app/views/cloud/instance/new.rhtml create mode 100644 src/app/views/cloud/instance/show.rhtml create mode 100644 src/app/views/cloud/instance/update.rhtml create mode 100644 src/app/views/layouts/cloud/cloud.rhtml create mode 100644 src/public/images/icon_failed_11px.png create mode 100644 src/public/images/icon_queued_11px.png create mode 100644 src/public/images/icon_startup_11px.png create mode 100644 src/public/images/icon_unknown_11px.png create mode 100644 src/public/images/icon_warning_11px.png create mode 100644 src/public/stylesheets/cloud/layout.css create mode 100644 src/test/functional/cloud/cloud_controller_test.rb create mode 100644 src/test/functional/cloud/dashboard_controller_test.rb create mode 100644 src/test/functional/cloud/instance_controller_test.rb diff --git a/src/app/controllers/cloud/cloud_controller.rb b/src/app/controllers/cloud/cloud_controller.rb new file mode 100644 index 0000000..154d15d --- /dev/null +++ b/src/app/controllers/cloud/cloud_controller.rb @@ -0,0 +1,35 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class Cloud::CloudController < ApplicationController + include VmService + + layout 'cloud/cloud' + + before_filter :set_vars + + protected + + + # NOTE: This probably will/should be moved to use set_perms in + # ApplicationService once that is ready to go. + def set_vars + @user = get_login_user + end +end diff --git a/src/app/controllers/cloud/dashboard_controller.rb b/src/app/controllers/cloud/dashboard_controller.rb new file mode 100644 index 0000000..8fd0f02 --- /dev/null +++ b/src/app/controllers/cloud/dashboard_controller.rb @@ -0,0 +1,24 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class Cloud::DashboardController < Cloud::CloudController + def index + end + +end diff --git a/src/app/controllers/cloud/instance_controller.rb b/src/app/controllers/cloud/instance_controller.rb new file mode 100644 index 0000000..a4d0fd8 --- /dev/null +++ b/src/app/controllers/cloud/instance_controller.rb @@ -0,0 +1,95 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + + +class Cloud::InstanceController < Cloud::CloudController + + before_filter :handle_form + + def index + list + end + + def list + page = find_in_params_or_default(:page, 1) + order = find_in_params_or_default(:sort,"vms.id") + @vms = Vm.paged_with_perms(@user, + Privilege::VIEW, + # NOTE: maybe this ^^ part could be taken care of behind the scenes? + # Also, needs to be changed to a cloud priv + page, order) + @actions = VmTask.get_vm_actions + show + end + + def show + ids = params[:ids] + task_page = find_in_params_or_default(:task_page, 1) + task_order = find_in_params_or_default(:task_order, "tasks.id") + @vm_details = Vm.find(ids) if ids + if @vm_details + @tasks = VmTask.paginate(:conditions => ["task_target_id in (:ids)",{:ids => ids}], + :per_page => 5, :page => task_page, :order => task_order) + end + end + + # TODO: implement + def create + end + + # TODO: implement + def update + end + + # TODO: implement + def destroy + end + + # TODO: implement + def new + end + + # TODO: implement + def edit + end + + private + +# Pass in the symbol for the param key you want, and an optional default value + def find_in_params_or_default(key, default=nil) + return params[key] && params[key] != "" ? params[key] : default + end + +# This redirects the user to a get url if they are just trying to view details for one or more +# instances. +# TODO: if the user is trying to submit an acton on selected instances, call the service +# layer and display the :flash (might still want to do :get redirect to keep pagination/sorting +# correct. + def handle_form + case params[:submit_for_list] + when "Show Selected" + params.delete(:submit_for_list) + redirect_to :action => "index", :params => params + return +# Do this if we have submitted an action on one or more vms. +# svc_vm_action(params[:ids], params[:vm_action], params[:action_args]) + end + end + +end diff --git a/src/app/helpers/cloud/cloud_helper.rb b/src/app/helpers/cloud/cloud_helper.rb new file mode 100644 index 0000000..9ec71da --- /dev/null +++ b/src/app/helpers/cloud/cloud_helper.rb @@ -0,0 +1,21 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +module Cloud::CloudHelper +end diff --git a/src/app/helpers/cloud/dashboard_helper.rb b/src/app/helpers/cloud/dashboard_helper.rb new file mode 100644 index 0000000..713f3a9 --- /dev/null +++ b/src/app/helpers/cloud/dashboard_helper.rb @@ -0,0 +1,21 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +module Cloud::DashboardHelper +end diff --git a/src/app/helpers/cloud/instance_helper.rb b/src/app/helpers/cloud/instance_helper.rb new file mode 100644 index 0000000..2db0529 --- /dev/null +++ b/src/app/helpers/cloud/instance_helper.rb @@ -0,0 +1,38 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +module Cloud::InstanceHelper +# TODO: add checking to make sure this is a symbol, possibly as simple as adding a +# to_sym, just not sure what happens if it is already a symbol + def sort_td_class_helper(param, key = :sort) + result = 'sortup' if params[key] == param + result = 'sortdown' if params[key] == param + " DESC" + return result + end + + # pass in an optional symbol for the key you want to use + # TODO: add checking to make sure this is a symbol, possibly as simple as adding a + # to_sym, just not sure what happens if it is already a symbol + def sort_link_helper(text, param, key = :sort) + param += " DESC" if params[key] == param + param_list = params.clone + param_list[key] == param ? param_list[key] = param += " DESC": param_list[key] = param + link_to(text, :action => 'index', :params => param_list) + end +end diff --git a/src/app/views/cloud/dashboard/index.rhtml b/src/app/views/cloud/dashboard/index.rhtml new file mode 100644 index 0000000..de94fa4 --- /dev/null +++ b/src/app/views/cloud/dashboard/index.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Dashboard#index</h1> +<p>Find me in app/views/cloud/dashboard/index.html.erb</p> diff --git a/src/app/views/cloud/instance/_list.rhtml b/src/app/views/cloud/instance/_list.rhtml new file mode 100644 index 0000000..1fa46de --- /dev/null +++ b/src/app/views/cloud/instance/_list.rhtml @@ -0,0 +1,34 @@ +<%= hidden_field_tag 'page', params[:page] %> +<%= hidden_field_tag 'sort', params[:sort] %> +<table> + <thead> + <th scope="col"><div> </div></th> + <th scope="col"> + <div class="sortable <%= sort_td_class_helper "description" %>"> + <%= sort_link_helper "Instance", "description" %> + </div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "provisioning" %>"> + <div><%= sort_link_helper "Profile", "provisioning" %></div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "state" %>"> + <div><%= sort_link_helper "State", "state" %></div> + </th> + <th scope="col"><div>IP Address</div></th> + <th scope="col"><div>Load</div></th> + </thead> + <tbody> + <% @vms.each { |vm| %> + <% checked = (params[:ids] != nil && params[:ids].include?(vm.id.to_s)) ? 'checked' : nil %> + <tr class="<%= cycle("even", "odd") -%><%if checked%> selected<%end%>" > + <td class="center"><div><%= check_box_tag "ids[]", "#{vm.id}", checked -%></div></td> + <td><div><%= vm.description %></div></td> + <td><div><%= vm.provisioning %></div></td> <!-- TODO: possibly add default output value for this? --> + <td><div class="state-container instance-<%= vm.state %>"><%= vm.state.capitalize %></div></td> + <td><div>N/A</div></td> + <td><div>N/A</div></td> + </tr> + <% } %> + </tbody> +</table> +<%= will_paginate @vms, :sort => params[:sort] %> \ No newline at end of file diff --git a/src/app/views/cloud/instance/_show.rhtml b/src/app/views/cloud/instance/_show.rhtml new file mode 100644 index 0000000..001286e --- /dev/null +++ b/src/app/views/cloud/instance/_show.rhtml @@ -0,0 +1,47 @@ + <div> + <div id="detail_header"> + <%= submit_tag 'Show Selected', :id => 'submit_for_list', :name => 'submit_for_list' %> + </form> + <% if @vm_details %> + <h3> + <% if @vm_details.size == 1 %> + <%=@vm_details[0].description%> + <% else %> + <%= @vm_details.size %> instances selected + <% end %> + </h3> + <% end %> + </div> +<% if @vm_details %> + <div id="graph">Placeholder for graph widget</div> + <table> + <thead> + <th scope="col"> + <div class="sortable <%= sort_td_class_helper "action", :task_order %>"> + <%= sort_link_helper "Task", "action", :task_order %> + </div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "state", :task_order %>"> + <div><%= sort_link_helper "State", "state", :task_order %></div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "vms.description", :task_order %>"> + <div><%= sort_link_helper "Instance", "vms.description", :task_order %></div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "time_started", :task_order %>"> + <div><%= sort_link_helper "Started", "time_started", :task_order %></div> + </th> + </thead> + <tbody> + <%@tasks.each { |task| %> + <tr class="<%= cycle("even", "odd") -%>"> + <td><div><%= task.action %></div></td> + <td><div class="state-container task-<%= task.state %>"><%= task.state.capitalize %></div></td> + <td><div><%= task.vm.description %></div></td> + <td><div><%= task.created_at %> </div></td> + </tr> + <% } %> + </tbody> + </table> + <%= will_paginate @tasks, :param_name => 'task_page' %> +<% end %> + </div> \ No newline at end of file diff --git a/src/app/views/cloud/instance/create.rhtml b/src/app/views/cloud/instance/create.rhtml new file mode 100644 index 0000000..b608264 --- /dev/null +++ b/src/app/views/cloud/instance/create.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#create</h1> +<p>Find me in app/views/cloud/instance/create.html.erb</p> diff --git a/src/app/views/cloud/instance/destroy.rhtml b/src/app/views/cloud/instance/destroy.rhtml new file mode 100644 index 0000000..8322a5a --- /dev/null +++ b/src/app/views/cloud/instance/destroy.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#destroy</h1> +<p>Find me in app/views/cloud/instance/destroy.html.erb</p> diff --git a/src/app/views/cloud/instance/edit.rhtml b/src/app/views/cloud/instance/edit.rhtml new file mode 100644 index 0000000..b7517a5 --- /dev/null +++ b/src/app/views/cloud/instance/edit.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#edit</h1> +<p>Find me in app/views/cloud/instance/edit.html.erb</p> diff --git a/src/app/views/cloud/instance/index.rhtml b/src/app/views/cloud/instance/index.rhtml new file mode 100644 index 0000000..218bd8c --- /dev/null +++ b/src/app/views/cloud/instance/index.rhtml @@ -0,0 +1,23 @@ +<div id="toolbar_nav"> + <!-- TODO: Make each li a submit button with same styling as current li. + Handlng of this will be implemented in InstanceController::handle_form + --> + <ul> + <li>New Instance</li> + <li> + Actions + <ul> + <% @actions.each {|action| %> + <li><%= image_tag action[2]%><%= action[0] %></li> + <% } %> + </ul> + </li> + </ul> +</div> +<form action="<%= url_for({:action => 'index'})%>" method="post"> <%# This form tag is terminated in _show.rhtml %> + <div id="list-view"> + <%= render :partial => 'list' %> + </div> + <div id="detail-view"> + <%= render :partial => 'show' %> + </div> \ No newline at end of file diff --git a/src/app/views/cloud/instance/new.rhtml b/src/app/views/cloud/instance/new.rhtml new file mode 100644 index 0000000..6f91d27 --- /dev/null +++ b/src/app/views/cloud/instance/new.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#new</h1> +<p>Find me in app/views/cloud/instance/new.html.erb</p> diff --git a/src/app/views/cloud/instance/show.rhtml b/src/app/views/cloud/instance/show.rhtml new file mode 100644 index 0000000..8e44308 --- /dev/null +++ b/src/app/views/cloud/instance/show.rhtml @@ -0,0 +1,5 @@ +<!-- TODO: Get new mockup from jeremy perry of what else + gets displayed if we are in the 'drilldown view' +--> + +<%= render :partial => 'show' %> \ No newline at end of file diff --git a/src/app/views/cloud/instance/update.rhtml b/src/app/views/cloud/instance/update.rhtml new file mode 100644 index 0000000..6c88fb5 --- /dev/null +++ b/src/app/views/cloud/instance/update.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#update</h1> +<p>Find me in app/views/cloud/instance/update.html.erb</p> diff --git a/src/app/views/layouts/cloud/cloud.rhtml b/src/app/views/layouts/cloud/cloud.rhtml new file mode 100644 index 0000000..b891bf2 --- /dev/null +++ b/src/app/views/layouts/cloud/cloud.rhtml @@ -0,0 +1,55 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + +<head> + <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> + <title><%= yield :title -%></title> + <link rel="stylesheet" type="text/css" href="http://fedoraproject.org/static/css/fedora.css" /> + <%= stylesheet_link_tag 'cloud/layout' %> + <%= yield :scripts -%> + </head> + + <body> + <div id="head"> + <!-- Header stuff! --> + <div id="login-box"> + Hi, <%= @user %> + | <%= link_to 'Log out', { :controller => "/login", :action => "logout"}%> + <%= link_to image_tag("Help_16.png"), + {:controller => 'help', :action => @help_section, :anchor => @anchor}, + :id=>"help-link", :popup => true, :title => "Help" %> + </div> + <div id="nav"> + <ul class="toolbar"> + <li> + <%+ link_to_unless(controller.controller_name == 'dashboard', "Dashboard", { :controller => 'cloud/dashboard' }) do |name| + link_to(name, { :controller => 'cloud/dashboard'}, :class => 'current') + end + %> + </li> + <li> + <%+ link_to_unless(controller.controller_name == 'instance', "Instances", { :controller => 'cloud/instance' }) do |name| + link_to(name, { :controller => 'cloud/instance'}, :class => 'current') + end + %> + </li> + <!-- Enable this once we have a profile view. + <li> + <%+ link_to_unless(controller.controller_name == 'profile', "Profiles", { :controller => 'cloud/profile' }) do |name| + link_to(name, { :controller => 'cloud/profile'}, :class => 'current') + end + %> + </li>--> + </ul> + </div> + </div> + <div id="content"> + <%= yield %> + </div> + </body> +</html> diff --git a/src/public/images/icon_failed_11px.png b/src/public/images/icon_failed_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..a8022652ab0172e5ce91eb0a4429cce496d92a6f GIT binary patch literal 374 zcmV-+0g3*JP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz7)eAyRCwBSQM*dSP!K({1}nF)3>FpzI|~u*L=eQS@&SThk?-&~_5)HyE5TyHMJ((L3wB#r*k|sY at g%!(qu{_WGiM&>&Rkhs zo&#_QBy)JdAO|EBU`fAZ;?5nl2x~sBE{NfpTH$}0Q13?;V-}-T77cN&`wx$uU11Ss zv7*hA5Ul8WNz;i-XJUvOY$XMYHDCGii<kHyYIB|^sv+HgTw*;rXuuFBW10ljcI(vp ze(KBd(T^{EEw3};<g#fLp$X7V6(_H6=rB%iT1*uhw3MgpAY<?QkaG9*3}5s4-}4=E z!B8_lAz#%Of6iw8JNtL=&QfpPj(6bZ3p1aZ**1S`&&|djv1CllZ_NFf7T*F404n*b UH}$I_cK`qY07*qoM6N<$f}Hi8umAu6 literal 0 HcmV?d00001 diff --git a/src/public/images/icon_queued_11px.png b/src/public/images/icon_queued_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..bd99c71acb11fb0308d26760110e66d470317cc8 GIT binary patch literal 429 zcmV;e0aE^nP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzPf0{URCwB4Q9WzIP!zpStpyhyoW(j6 z)5W>P2<8W<jazU{aCPq7rTqg5u7z%bQ^i3M`v*G3+5b=~B=6pyr%fxpaNfx~?{ITJ zl!%at at p#+ at xqt&$Kn$#aSr~@z#*;IL?*}8zda5-~G;?b>bc+mzHi0$`e1Bwo`Tc(1 z7U5 at MX@W_Zsn_e#X0yS!n0u8)Zszm(M=niMH%Zebm@<?~C4xq^T8;YsKD5NVyM-i4 z9QqfPN`>wR19BXPJkO(Yxol*|n5{pX0_2$4wrvW6;O8$1DIv?4W6Yza&N45TONye1 zz77YvC=@a|&Nmv3Yjl1KP=>d~f|OE}Lk8Br`fL8GUjM|n?$CMFh!_`L7K>!&&!=gC z^-i-qDI<2f-4V)tK)KDV?z7kdkL&gNMP(c8*qt`IIBigrC5mE2vcmIhyWJi)_$|Ny X31G at EBP7mw00000NkvXXu0mjfll#5W literal 0 HcmV?d00001 diff --git a/src/public/images/icon_startup_11px.png b/src/public/images/icon_startup_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..1b8769fc7af754de05c442a63fed404b5e744e29 GIT binary patch literal 458 zcmV;*0X6=KP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzY)M2xRCwAnQM*b5Q4l?IlL!$+3t#vs zG_dSyVW9++Xc0 at FEDAybR(^nWswg)8fS{cu+Nix2K}2i>3oX`0BKSZ{1uJ*&_3TYt zILw at L&kVCOvT>S3^UD!FktaMNAZo-JaUB~}(^w=9h)rT_-~VliW0M~=-=VZdPHQO{ z19!>Wf;Nq6V+59Kap@^B=4ci_(lm~2!ReYo6p1xcvwV59%-k0Eib-D6Fy8Oux?W|c zM&~Hxp!FlG(-R}F!U$eS(%qK9&GRWujo%0(g`4_`)uT|z#Zydzn0$UeAv>^&xNz+- zZO6zCu2|i6ju0f=#gxOjCp%huF)=s~krY0@>X;rbVkT3--RlMJ-!5UaI!?HAsUL1& z>f!yWv!`tcv(7pS6Wi!(cX0P|j_Pe02J%SHt}N`O*-eVvSc$4D60hz5PD})kFtWo~ zNouVqnTkN3DfnD;o{<-nfDbjU`%K~sGWio=0FQs4hHXF@$N&HU07*qoM6N<$f;C{m AI{*Lx literal 0 HcmV?d00001 diff --git a/src/public/images/icon_unknown_11px.png b/src/public/images/icon_unknown_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..1e7fda4dc5793502e90cfabff60ea32eb35abaae GIT binary patch literal 421 zcmV;W0b2fvP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzM at d9MRCwAnQL$>mP!v74<U52~hXjOx zvy)p#Gl)aK!a{{+E>x+b{Q_q{AyWnkK_N>V9qrb3?0fO{yk`uY3%U24^X at xO*6UBS z-;hX%5fKqJkr7)WcZA?_xd5t95Tt;FQ2vT9F+^igc_i<R*aX%#LpD<Z!cM1y at p$Zy z+3)wLstP~fzo9}?nw{>fH3<cwwbm2Mvc$(~g~4Eee!maS(O4T=(<F4ZBXL$Ni}!`w z0^RPtcUM&ynz%Xpqreyw-N>%=dJmXPCMb#mhr<ExL?;qR<eY2D;+uRronp7!dE)u} z<?QL<hjn28Os0ZZ+WgYj)UR?4<l1X}vcNQkIr?})H&`wgo-luzdr|9rq<9<fra3oa zj at S5RvuE#$)|K3&%bA<xBsX-BjfkE&;0p?0P~D|#u90z<E!F-7{{<KTM8={uf|Zq& P00000NkvXXu0mjf6ZgH1 literal 0 HcmV?d00001 diff --git a/src/public/images/icon_warning_11px.png b/src/public/images/icon_warning_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..44700c87cc1440335f186fbda793c633924ef6de GIT binary patch literal 343 zcmV-d0jU0oP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy`AI}URCwBqkikmBKomvqdvqpNQ>v53 zl~xzVojd6__z{BN&_y7Afqt7yx1#7yG|9$7n^0zalWdaOf)^gcefMyg8G61$Pw|Yh z#k+e5&*}dA$vt*6#)hf_>B$W@=VsP}<7>)P2osC|HG=VeC%np$9$qqdW^t5o<F~?- zE6Vgfj2^aL at 5u~d{QeJIl}N{@VwbIVD_}h3X5WLOgfkULs}`sOd++yA(zcWTy6~8a z_<~JvKyaNqdRHxg{MD8}UoPTkDy^D~QWDi at Cb(S#a at v}toiLExbM!W+VsggvFv2d? pONac!mV<Q-^Z8=&51C&91^^~AOG{24q`m+E002ovPDHLkV1lujmu&z5 literal 0 HcmV?d00001 diff --git a/src/public/stylesheets/cloud/layout.css b/src/public/stylesheets/cloud/layout.css new file mode 100644 index 0000000..60b5c91 --- /dev/null +++ b/src/public/stylesheets/cloud/layout.css @@ -0,0 +1,166 @@ +/* ------ General Layout ------ */ + +.toolbar {text-align:left;} + +.current, .toolbar a:hover { + border-bottom: 5px solid #5599B8; +} + +.toolbar a { + text-decoration: none; +} + +#nav {height:1em;padding-top:1ex;} + +#nav a {display: inline-block;} + +#head {height:50px;} + +#login-box { + text-align:right; + /* + TODO: put this back in with a real logo when we have one. + background: url('../../images/logo_cumulus.png') left top no-repeat; + */ +} + +#content {margin-left:18px;} + +#content table{width:100%;} + +#content table tr.odd {background:#eef2f2;} + +#content table tr:hover {background: #729FCF; color: #FFFFFF;} + +#content table th, #content table td { + border:1px solid #AAAAAA; + padding:0; + text-align:left; +} + +#content table th {background-color: #F0F0F0;} + +#content table div { + padding: 0.4ex; +} + +#content table th a { + display: block; + text-decoration: none; +} + +.sortup { + background: #F0F0F0 url('../../images/Sort_up_11.png') top center no-repeat !important; +} + +.sortdown { + background: #F0F0F0 url('../../images/Sort_down_11.png') top center no-repeat !important; +} + +.sortable:hover {background-color: #DDDDDD !important;} + +.selected {background: #337ACC !important; color: #FFFFFF;} + +.center {text-align:center;} + +.pagination {padding-top: 1ex;} + +#list-view {} + +#detail-view { + border-top: 3px solid #AAAAAA; + margin-top: 2ex; +} + +#graph { + border: 1px solid #AAAAAA; + margin-bottom: 1.5ex; + height: 15ex; +} + +#submit_for_list { + float: right; + background: none; + border: 0; + color: #337ACC; + cursor: pointer; +} + +#detail_header { + background-color: #F0F0F0; + height: 10ex; + margin-bottom: 1.5ex; +} + +/* ----- Backgrounds for states ----- */ +.state-container { + margin-left:5px; + text-indent:10px; +} + +.task-canceled {background:url(../../images/icon-canceled-11px.png) left center no-repeat;} +.task-failed {background:url(../../images/icon-failed-11px.png) left center no-repeat;} +.task-finished {background:url(../../images/icon-finished-11px.png) left center no-repeat;} +.task-paused {background:url(../../images/icon-paused-11px.png) left center no-repeat;} +.task-queued {background:url(../../images/icon-queued-11px.png) left center no-repeat;} +.task-running {background:url(../../images/icon-running-11px.png) left center no-repeat;} +.instance-unreachable {background:url(../../images/icon_unknown_11px.png) left center no-repeat;} +.instance-stopped {background:url(../../images/icon_stop_11px.png) left center no-repeat;} +.instance-suspended {background:url(../../images/icon_suspend_11px.png) left center no-repeat;} +.instance-saved {background:url(../../images/icon_save_11px.png) left center no-repeat;} +.instance-create_failed {background:url(../../images/icon_failed_11px.png) left center no-repeat;} +.instance-invalid {background:url(../../images/icon_warning_11px.png) left center no-repeat;} +.instance-pending {background:url(../../images/icon_queued_11px.png) left center no-repeat;} +.instance-running {background:url(../../images/icon_start_11px.png) left center no-repeat;} +.instance-creating {background:url(../../images/icon_startup_11px.png) left center no-repeat;} + + +/* ----- Toolbar Navigation -------- */ +#toolbar_nav { + background: #F0F0F0; +} + +#toolbar_nav img { + margin: 0; +} + +#toolbar_nav ul{ + list-style: none; +} + +#toolbar_nav li { + display: inline-block; + position: relative; + color: #666666; + padding: 0 1ex; +} +#toolbar_nav li:hover { + background: #337ACC; + color: #FFFFFF; + cursor: pointer; +} + +#toolbar_nav li.current { /* This is not really needed right now, but will be useful when we add filters. */ + background: #4B95B8; +} + +#toolbar_nav li ul { + display: none; + position: absolute; + top: 1em; + left: 0; + background: #F0F0F0; +} + +#toolbar_nav li ul li { + display: block; + white-space: nowrap; + padding-right: 1ex; +} + +#toolbar_nav li > ul { + top: auto; + left: auto; +} + +#toolbar_nav li:hover ul {display: block;} \ No newline at end of file diff --git a/src/test/functional/cloud/cloud_controller_test.rb b/src/test/functional/cloud/cloud_controller_test.rb new file mode 100644 index 0000000..864400c --- /dev/null +++ b/src/test/functional/cloud/cloud_controller_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class Cloud::CloudControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/src/test/functional/cloud/dashboard_controller_test.rb b/src/test/functional/cloud/dashboard_controller_test.rb new file mode 100644 index 0000000..3ddb6ca --- /dev/null +++ b/src/test/functional/cloud/dashboard_controller_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class Cloud::DashboardControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/src/test/functional/cloud/instance_controller_test.rb b/src/test/functional/cloud/instance_controller_test.rb new file mode 100644 index 0000000..213d2e0 --- /dev/null +++ b/src/test/functional/cloud/instance_controller_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class Cloud::InstanceControllerTest < ActionController::TestCase + fixtures :vms, :tasks + def setup + @controller = Cloud::InstanceController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_should_show_index + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:vms) + assert_not_nil assigns(:user) + end + + def test_should_redirect_if_request_for_selected + post(:index,{:submit_for_list => 'Show Selected'}) + assert_response :redirect + end +end -- 1.6.0.6
Jason Guiditta
2009-May-19 14:26 UTC
[Ovirt-devel] [PATCH server] REBASE Cloud UI V1 (readonly).
This patch creates the shell for much of what the cloud ui will become. It is focused on layout (lightly fedora themed), accessibility, and 'bookmarkability'. This layout uses no javascript (that will be used to enhance interactivity in a future patch). It also introduces the idea of using a simple table rather than the more conplex js/json we use in the admin side. Plan here is to gradually enhance this as needed to make more interactive. CSS was kept separate from admin CSS to facilitate theming by users/deployments. Controllers are designed (even though large parts are stubbed) to be 'skinny' and leverage as much as possible the new service api. There are a few readonly AR calls that in near future could easily be moved to service layer to be even simpler calls. They are kept separate from admin things so they can be as simple as possible as well a making it conceivable that one could deploy the cloud part of the app without also deplying admin (perhaps one wants to deply that elsewhere). For now this would have to be done manually, but perhaps in future we can setup the service layer/ar classes to be a separate rpm that two different wuis (admin/cloud) could call into, enhancing modularity. Signed-off-by: Jason Guiditta <jguiditt at redhat.com> --- src/app/controllers/cloud/cloud_controller.rb | 35 ++++ src/app/controllers/cloud/dashboard_controller.rb | 24 +++ src/app/controllers/cloud/instance_controller.rb | 95 +++++++++++ src/app/helpers/cloud/cloud_helper.rb | 21 +++ src/app/helpers/cloud/dashboard_helper.rb | 21 +++ src/app/helpers/cloud/instance_helper.rb | 38 +++++ src/app/views/cloud/dashboard/index.rhtml | 2 + src/app/views/cloud/instance/_list.rhtml | 34 ++++ src/app/views/cloud/instance/_show.rhtml | 47 ++++++ src/app/views/cloud/instance/create.rhtml | 2 + src/app/views/cloud/instance/destroy.rhtml | 2 + src/app/views/cloud/instance/edit.rhtml | 2 + src/app/views/cloud/instance/index.rhtml | 23 +++ src/app/views/cloud/instance/new.rhtml | 2 + src/app/views/cloud/instance/show.rhtml | 5 + src/app/views/cloud/instance/update.rhtml | 2 + src/app/views/layouts/cloud/cloud.rhtml | 55 +++++++ src/public/images/icon_failed_11px.png | Bin 0 -> 374 bytes src/public/images/icon_queued_11px.png | Bin 0 -> 429 bytes src/public/images/icon_startup_11px.png | Bin 0 -> 458 bytes src/public/images/icon_unknown_11px.png | Bin 0 -> 421 bytes src/public/images/icon_warning_11px.png | Bin 0 -> 343 bytes src/public/stylesheets/cloud/layout.css | 166 ++++++++++++++++++++ src/test/functional/cloud/cloud_controller_test.rb | 8 + .../functional/cloud/dashboard_controller_test.rb | 8 + .../functional/cloud/instance_controller_test.rb | 23 +++ 26 files changed, 615 insertions(+), 0 deletions(-) create mode 100644 src/app/controllers/cloud/cloud_controller.rb create mode 100644 src/app/controllers/cloud/dashboard_controller.rb create mode 100644 src/app/controllers/cloud/instance_controller.rb create mode 100644 src/app/helpers/cloud/cloud_helper.rb create mode 100644 src/app/helpers/cloud/dashboard_helper.rb create mode 100644 src/app/helpers/cloud/instance_helper.rb create mode 100644 src/app/views/cloud/dashboard/index.rhtml create mode 100644 src/app/views/cloud/instance/_list.rhtml create mode 100644 src/app/views/cloud/instance/_show.rhtml create mode 100644 src/app/views/cloud/instance/create.rhtml create mode 100644 src/app/views/cloud/instance/destroy.rhtml create mode 100644 src/app/views/cloud/instance/edit.rhtml create mode 100644 src/app/views/cloud/instance/index.rhtml create mode 100644 src/app/views/cloud/instance/new.rhtml create mode 100644 src/app/views/cloud/instance/show.rhtml create mode 100644 src/app/views/cloud/instance/update.rhtml create mode 100644 src/app/views/layouts/cloud/cloud.rhtml create mode 100644 src/public/images/icon_failed_11px.png create mode 100644 src/public/images/icon_queued_11px.png create mode 100644 src/public/images/icon_startup_11px.png create mode 100644 src/public/images/icon_unknown_11px.png create mode 100644 src/public/images/icon_warning_11px.png create mode 100644 src/public/stylesheets/cloud/layout.css create mode 100644 src/test/functional/cloud/cloud_controller_test.rb create mode 100644 src/test/functional/cloud/dashboard_controller_test.rb create mode 100644 src/test/functional/cloud/instance_controller_test.rb diff --git a/src/app/controllers/cloud/cloud_controller.rb b/src/app/controllers/cloud/cloud_controller.rb new file mode 100644 index 0000000..154d15d --- /dev/null +++ b/src/app/controllers/cloud/cloud_controller.rb @@ -0,0 +1,35 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class Cloud::CloudController < ApplicationController + include VmService + + layout 'cloud/cloud' + + before_filter :set_vars + + protected + + + # NOTE: This probably will/should be moved to use set_perms in + # ApplicationService once that is ready to go. + def set_vars + @user = get_login_user + end +end diff --git a/src/app/controllers/cloud/dashboard_controller.rb b/src/app/controllers/cloud/dashboard_controller.rb new file mode 100644 index 0000000..8fd0f02 --- /dev/null +++ b/src/app/controllers/cloud/dashboard_controller.rb @@ -0,0 +1,24 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class Cloud::DashboardController < Cloud::CloudController + def index + end + +end diff --git a/src/app/controllers/cloud/instance_controller.rb b/src/app/controllers/cloud/instance_controller.rb new file mode 100644 index 0000000..a4d0fd8 --- /dev/null +++ b/src/app/controllers/cloud/instance_controller.rb @@ -0,0 +1,95 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + + +class Cloud::InstanceController < Cloud::CloudController + + before_filter :handle_form + + def index + list + end + + def list + page = find_in_params_or_default(:page, 1) + order = find_in_params_or_default(:sort,"vms.id") + @vms = Vm.paged_with_perms(@user, + Privilege::VIEW, + # NOTE: maybe this ^^ part could be taken care of behind the scenes? + # Also, needs to be changed to a cloud priv + page, order) + @actions = VmTask.get_vm_actions + show + end + + def show + ids = params[:ids] + task_page = find_in_params_or_default(:task_page, 1) + task_order = find_in_params_or_default(:task_order, "tasks.id") + @vm_details = Vm.find(ids) if ids + if @vm_details + @tasks = VmTask.paginate(:conditions => ["task_target_id in (:ids)",{:ids => ids}], + :per_page => 5, :page => task_page, :order => task_order) + end + end + + # TODO: implement + def create + end + + # TODO: implement + def update + end + + # TODO: implement + def destroy + end + + # TODO: implement + def new + end + + # TODO: implement + def edit + end + + private + +# Pass in the symbol for the param key you want, and an optional default value + def find_in_params_or_default(key, default=nil) + return params[key] && params[key] != "" ? params[key] : default + end + +# This redirects the user to a get url if they are just trying to view details for one or more +# instances. +# TODO: if the user is trying to submit an acton on selected instances, call the service +# layer and display the :flash (might still want to do :get redirect to keep pagination/sorting +# correct. + def handle_form + case params[:submit_for_list] + when "Show Selected" + params.delete(:submit_for_list) + redirect_to :action => "index", :params => params + return +# Do this if we have submitted an action on one or more vms. +# svc_vm_action(params[:ids], params[:vm_action], params[:action_args]) + end + end + +end diff --git a/src/app/helpers/cloud/cloud_helper.rb b/src/app/helpers/cloud/cloud_helper.rb new file mode 100644 index 0000000..9ec71da --- /dev/null +++ b/src/app/helpers/cloud/cloud_helper.rb @@ -0,0 +1,21 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +module Cloud::CloudHelper +end diff --git a/src/app/helpers/cloud/dashboard_helper.rb b/src/app/helpers/cloud/dashboard_helper.rb new file mode 100644 index 0000000..713f3a9 --- /dev/null +++ b/src/app/helpers/cloud/dashboard_helper.rb @@ -0,0 +1,21 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +module Cloud::DashboardHelper +end diff --git a/src/app/helpers/cloud/instance_helper.rb b/src/app/helpers/cloud/instance_helper.rb new file mode 100644 index 0000000..2db0529 --- /dev/null +++ b/src/app/helpers/cloud/instance_helper.rb @@ -0,0 +1,38 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Jason Guiditta <jguiditt at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +module Cloud::InstanceHelper +# TODO: add checking to make sure this is a symbol, possibly as simple as adding a +# to_sym, just not sure what happens if it is already a symbol + def sort_td_class_helper(param, key = :sort) + result = 'sortup' if params[key] == param + result = 'sortdown' if params[key] == param + " DESC" + return result + end + + # pass in an optional symbol for the key you want to use + # TODO: add checking to make sure this is a symbol, possibly as simple as adding a + # to_sym, just not sure what happens if it is already a symbol + def sort_link_helper(text, param, key = :sort) + param += " DESC" if params[key] == param + param_list = params.clone + param_list[key] == param ? param_list[key] = param += " DESC": param_list[key] = param + link_to(text, :action => 'index', :params => param_list) + end +end diff --git a/src/app/views/cloud/dashboard/index.rhtml b/src/app/views/cloud/dashboard/index.rhtml new file mode 100644 index 0000000..de94fa4 --- /dev/null +++ b/src/app/views/cloud/dashboard/index.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Dashboard#index</h1> +<p>Find me in app/views/cloud/dashboard/index.html.erb</p> diff --git a/src/app/views/cloud/instance/_list.rhtml b/src/app/views/cloud/instance/_list.rhtml new file mode 100644 index 0000000..1fa46de --- /dev/null +++ b/src/app/views/cloud/instance/_list.rhtml @@ -0,0 +1,34 @@ +<%= hidden_field_tag 'page', params[:page] %> +<%= hidden_field_tag 'sort', params[:sort] %> +<table> + <thead> + <th scope="col"><div> </div></th> + <th scope="col"> + <div class="sortable <%= sort_td_class_helper "description" %>"> + <%= sort_link_helper "Instance", "description" %> + </div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "provisioning" %>"> + <div><%= sort_link_helper "Profile", "provisioning" %></div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "state" %>"> + <div><%= sort_link_helper "State", "state" %></div> + </th> + <th scope="col"><div>IP Address</div></th> + <th scope="col"><div>Load</div></th> + </thead> + <tbody> + <% @vms.each { |vm| %> + <% checked = (params[:ids] != nil && params[:ids].include?(vm.id.to_s)) ? 'checked' : nil %> + <tr class="<%= cycle("even", "odd") -%><%if checked%> selected<%end%>" > + <td class="center"><div><%= check_box_tag "ids[]", "#{vm.id}", checked -%></div></td> + <td><div><%= vm.description %></div></td> + <td><div><%= vm.provisioning %></div></td> <!-- TODO: possibly add default output value for this? --> + <td><div class="state-container instance-<%= vm.state %>"><%= vm.state.capitalize %></div></td> + <td><div>N/A</div></td> + <td><div>N/A</div></td> + </tr> + <% } %> + </tbody> +</table> +<%= will_paginate @vms, :sort => params[:sort] %> \ No newline at end of file diff --git a/src/app/views/cloud/instance/_show.rhtml b/src/app/views/cloud/instance/_show.rhtml new file mode 100644 index 0000000..001286e --- /dev/null +++ b/src/app/views/cloud/instance/_show.rhtml @@ -0,0 +1,47 @@ + <div> + <div id="detail_header"> + <%= submit_tag 'Show Selected', :id => 'submit_for_list', :name => 'submit_for_list' %> + </form> + <% if @vm_details %> + <h3> + <% if @vm_details.size == 1 %> + <%=@vm_details[0].description%> + <% else %> + <%= @vm_details.size %> instances selected + <% end %> + </h3> + <% end %> + </div> +<% if @vm_details %> + <div id="graph">Placeholder for graph widget</div> + <table> + <thead> + <th scope="col"> + <div class="sortable <%= sort_td_class_helper "action", :task_order %>"> + <%= sort_link_helper "Task", "action", :task_order %> + </div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "state", :task_order %>"> + <div><%= sort_link_helper "State", "state", :task_order %></div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "vms.description", :task_order %>"> + <div><%= sort_link_helper "Instance", "vms.description", :task_order %></div> + </th> + <th scope="col" class="sortable <%= sort_td_class_helper "time_started", :task_order %>"> + <div><%= sort_link_helper "Started", "time_started", :task_order %></div> + </th> + </thead> + <tbody> + <%@tasks.each { |task| %> + <tr class="<%= cycle("even", "odd") -%>"> + <td><div><%= task.action %></div></td> + <td><div class="state-container task-<%= task.state %>"><%= task.state.capitalize %></div></td> + <td><div><%= task.vm.description %></div></td> + <td><div><%= task.created_at %> </div></td> + </tr> + <% } %> + </tbody> + </table> + <%= will_paginate @tasks, :param_name => 'task_page' %> +<% end %> + </div> \ No newline at end of file diff --git a/src/app/views/cloud/instance/create.rhtml b/src/app/views/cloud/instance/create.rhtml new file mode 100644 index 0000000..b608264 --- /dev/null +++ b/src/app/views/cloud/instance/create.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#create</h1> +<p>Find me in app/views/cloud/instance/create.html.erb</p> diff --git a/src/app/views/cloud/instance/destroy.rhtml b/src/app/views/cloud/instance/destroy.rhtml new file mode 100644 index 0000000..8322a5a --- /dev/null +++ b/src/app/views/cloud/instance/destroy.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#destroy</h1> +<p>Find me in app/views/cloud/instance/destroy.html.erb</p> diff --git a/src/app/views/cloud/instance/edit.rhtml b/src/app/views/cloud/instance/edit.rhtml new file mode 100644 index 0000000..b7517a5 --- /dev/null +++ b/src/app/views/cloud/instance/edit.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#edit</h1> +<p>Find me in app/views/cloud/instance/edit.html.erb</p> diff --git a/src/app/views/cloud/instance/index.rhtml b/src/app/views/cloud/instance/index.rhtml new file mode 100644 index 0000000..218bd8c --- /dev/null +++ b/src/app/views/cloud/instance/index.rhtml @@ -0,0 +1,23 @@ +<div id="toolbar_nav"> + <!-- TODO: Make each li a submit button with same styling as current li. + Handlng of this will be implemented in InstanceController::handle_form + --> + <ul> + <li>New Instance</li> + <li> + Actions + <ul> + <% @actions.each {|action| %> + <li><%= image_tag action[2]%><%= action[0] %></li> + <% } %> + </ul> + </li> + </ul> +</div> +<form action="<%= url_for({:action => 'index'})%>" method="post"> <%# This form tag is terminated in _show.rhtml %> + <div id="list-view"> + <%= render :partial => 'list' %> + </div> + <div id="detail-view"> + <%= render :partial => 'show' %> + </div> \ No newline at end of file diff --git a/src/app/views/cloud/instance/new.rhtml b/src/app/views/cloud/instance/new.rhtml new file mode 100644 index 0000000..6f91d27 --- /dev/null +++ b/src/app/views/cloud/instance/new.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#new</h1> +<p>Find me in app/views/cloud/instance/new.html.erb</p> diff --git a/src/app/views/cloud/instance/show.rhtml b/src/app/views/cloud/instance/show.rhtml new file mode 100644 index 0000000..8e44308 --- /dev/null +++ b/src/app/views/cloud/instance/show.rhtml @@ -0,0 +1,5 @@ +<!-- TODO: Get new mockup from jeremy perry of what else + gets displayed if we are in the 'drilldown view' +--> + +<%= render :partial => 'show' %> \ No newline at end of file diff --git a/src/app/views/cloud/instance/update.rhtml b/src/app/views/cloud/instance/update.rhtml new file mode 100644 index 0000000..6c88fb5 --- /dev/null +++ b/src/app/views/cloud/instance/update.rhtml @@ -0,0 +1,2 @@ +<h1>Cloud::Instance#update</h1> +<p>Find me in app/views/cloud/instance/update.html.erb</p> diff --git a/src/app/views/layouts/cloud/cloud.rhtml b/src/app/views/layouts/cloud/cloud.rhtml new file mode 100644 index 0000000..b891bf2 --- /dev/null +++ b/src/app/views/layouts/cloud/cloud.rhtml @@ -0,0 +1,55 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + +<head> + <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> + <title><%= yield :title -%></title> + <link rel="stylesheet" type="text/css" href="http://fedoraproject.org/static/css/fedora.css" /> + <%= stylesheet_link_tag 'cloud/layout' %> + <%= yield :scripts -%> + </head> + + <body> + <div id="head"> + <!-- Header stuff! --> + <div id="login-box"> + Hi, <%= @user %> + | <%= link_to 'Log out', { :controller => "/login", :action => "logout"}%> + <%= link_to image_tag("Help_16.png"), + {:controller => 'help', :action => @help_section, :anchor => @anchor}, + :id=>"help-link", :popup => true, :title => "Help" %> + </div> + <div id="nav"> + <ul class="toolbar"> + <li> + <%+ link_to_unless(controller.controller_name == 'dashboard', "Dashboard", { :controller => 'cloud/dashboard' }) do |name| + link_to(name, { :controller => 'cloud/dashboard'}, :class => 'current') + end + %> + </li> + <li> + <%+ link_to_unless(controller.controller_name == 'instance', "Instances", { :controller => 'cloud/instance' }) do |name| + link_to(name, { :controller => 'cloud/instance'}, :class => 'current') + end + %> + </li> + <!-- Enable this once we have a profile view. + <li> + <%+ link_to_unless(controller.controller_name == 'profile', "Profiles", { :controller => 'cloud/profile' }) do |name| + link_to(name, { :controller => 'cloud/profile'}, :class => 'current') + end + %> + </li>--> + </ul> + </div> + </div> + <div id="content"> + <%= yield %> + </div> + </body> +</html> diff --git a/src/public/images/icon_failed_11px.png b/src/public/images/icon_failed_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..a8022652ab0172e5ce91eb0a4429cce496d92a6f GIT binary patch literal 374 zcmV-+0g3*JP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz7)eAyRCwBSQM*dSP!K({1}nF)3>FpzI|~u*L=eQS@&SThk?-&~_5)HyE5TyHMJ((L3wB#r*k|sY at g%!(qu{_WGiM&>&Rkhs zo&#_QBy)JdAO|EBU`fAZ;?5nl2x~sBE{NfpTH$}0Q13?;V-}-T77cN&`wx$uU11Ss zv7*hA5Ul8WNz;i-XJUvOY$XMYHDCGii<kHyYIB|^sv+HgTw*;rXuuFBW10ljcI(vp ze(KBd(T^{EEw3};<g#fLp$X7V6(_H6=rB%iT1*uhw3MgpAY<?QkaG9*3}5s4-}4=E z!B8_lAz#%Of6iw8JNtL=&QfpPj(6bZ3p1aZ**1S`&&|djv1CllZ_NFf7T*F404n*b UH}$I_cK`qY07*qoM6N<$f}Hi8umAu6 literal 0 HcmV?d00001 diff --git a/src/public/images/icon_queued_11px.png b/src/public/images/icon_queued_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..bd99c71acb11fb0308d26760110e66d470317cc8 GIT binary patch literal 429 zcmV;e0aE^nP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzPf0{URCwB4Q9WzIP!zpStpyhyoW(j6 z)5W>P2<8W<jazU{aCPq7rTqg5u7z%bQ^i3M`v*G3+5b=~B=6pyr%fxpaNfx~?{ITJ zl!%at at p#+ at xqt&$Kn$#aSr~@z#*;IL?*}8zda5-~G;?b>bc+mzHi0$`e1Bwo`Tc(1 z7U5 at MX@W_Zsn_e#X0yS!n0u8)Zszm(M=niMH%Zebm@<?~C4xq^T8;YsKD5NVyM-i4 z9QqfPN`>wR19BXPJkO(Yxol*|n5{pX0_2$4wrvW6;O8$1DIv?4W6Yza&N45TONye1 zz77YvC=@a|&Nmv3Yjl1KP=>d~f|OE}Lk8Br`fL8GUjM|n?$CMFh!_`L7K>!&&!=gC z^-i-qDI<2f-4V)tK)KDV?z7kdkL&gNMP(c8*qt`IIBigrC5mE2vcmIhyWJi)_$|Ny X31G at EBP7mw00000NkvXXu0mjfll#5W literal 0 HcmV?d00001 diff --git a/src/public/images/icon_startup_11px.png b/src/public/images/icon_startup_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..1b8769fc7af754de05c442a63fed404b5e744e29 GIT binary patch literal 458 zcmV;*0X6=KP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzY)M2xRCwAnQM*b5Q4l?IlL!$+3t#vs zG_dSyVW9++Xc0 at FEDAybR(^nWswg)8fS{cu+Nix2K}2i>3oX`0BKSZ{1uJ*&_3TYt zILw at L&kVCOvT>S3^UD!FktaMNAZo-JaUB~}(^w=9h)rT_-~VliW0M~=-=VZdPHQO{ z19!>Wf;Nq6V+59Kap@^B=4ci_(lm~2!ReYo6p1xcvwV59%-k0Eib-D6Fy8Oux?W|c zM&~Hxp!FlG(-R}F!U$eS(%qK9&GRWujo%0(g`4_`)uT|z#Zydzn0$UeAv>^&xNz+- zZO6zCu2|i6ju0f=#gxOjCp%huF)=s~krY0@>X;rbVkT3--RlMJ-!5UaI!?HAsUL1& z>f!yWv!`tcv(7pS6Wi!(cX0P|j_Pe02J%SHt}N`O*-eVvSc$4D60hz5PD})kFtWo~ zNouVqnTkN3DfnD;o{<-nfDbjU`%K~sGWio=0FQs4hHXF@$N&HU07*qoM6N<$f;C{m AI{*Lx literal 0 HcmV?d00001 diff --git a/src/public/images/icon_unknown_11px.png b/src/public/images/icon_unknown_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..1e7fda4dc5793502e90cfabff60ea32eb35abaae GIT binary patch literal 421 zcmV;W0b2fvP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzM at d9MRCwAnQL$>mP!v74<U52~hXjOx zvy)p#Gl)aK!a{{+E>x+b{Q_q{AyWnkK_N>V9qrb3?0fO{yk`uY3%U24^X at xO*6UBS z-;hX%5fKqJkr7)WcZA?_xd5t95Tt;FQ2vT9F+^igc_i<R*aX%#LpD<Z!cM1y at p$Zy z+3)wLstP~fzo9}?nw{>fH3<cwwbm2Mvc$(~g~4Eee!maS(O4T=(<F4ZBXL$Ni}!`w z0^RPtcUM&ynz%Xpqreyw-N>%=dJmXPCMb#mhr<ExL?;qR<eY2D;+uRronp7!dE)u} z<?QL<hjn28Os0ZZ+WgYj)UR?4<l1X}vcNQkIr?})H&`wgo-luzdr|9rq<9<fra3oa zj at S5RvuE#$)|K3&%bA<xBsX-BjfkE&;0p?0P~D|#u90z<E!F-7{{<KTM8={uf|Zq& P00000NkvXXu0mjf6ZgH1 literal 0 HcmV?d00001 diff --git a/src/public/images/icon_warning_11px.png b/src/public/images/icon_warning_11px.png new file mode 100644 index 0000000000000000000000000000000000000000..44700c87cc1440335f186fbda793c633924ef6de GIT binary patch literal 343 zcmV-d0jU0oP)<h;3K|Lk000e1NJLTq000XB000XJ1^@s6sjPP<0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy`AI}URCwBqkikmBKomvqdvqpNQ>v53 zl~xzVojd6__z{BN&_y7Afqt7yx1#7yG|9$7n^0zalWdaOf)^gcefMyg8G61$Pw|Yh z#k+e5&*}dA$vt*6#)hf_>B$W@=VsP}<7>)P2osC|HG=VeC%np$9$qqdW^t5o<F~?- zE6Vgfj2^aL at 5u~d{QeJIl}N{@VwbIVD_}h3X5WLOgfkULs}`sOd++yA(zcWTy6~8a z_<~JvKyaNqdRHxg{MD8}UoPTkDy^D~QWDi at Cb(S#a at v}toiLExbM!W+VsggvFv2d? pONac!mV<Q-^Z8=&51C&91^^~AOG{24q`m+E002ovPDHLkV1lujmu&z5 literal 0 HcmV?d00001 diff --git a/src/public/stylesheets/cloud/layout.css b/src/public/stylesheets/cloud/layout.css new file mode 100644 index 0000000..60b5c91 --- /dev/null +++ b/src/public/stylesheets/cloud/layout.css @@ -0,0 +1,166 @@ +/* ------ General Layout ------ */ + +.toolbar {text-align:left;} + +.current, .toolbar a:hover { + border-bottom: 5px solid #5599B8; +} + +.toolbar a { + text-decoration: none; +} + +#nav {height:1em;padding-top:1ex;} + +#nav a {display: inline-block;} + +#head {height:50px;} + +#login-box { + text-align:right; + /* + TODO: put this back in with a real logo when we have one. + background: url('../../images/logo_cumulus.png') left top no-repeat; + */ +} + +#content {margin-left:18px;} + +#content table{width:100%;} + +#content table tr.odd {background:#eef2f2;} + +#content table tr:hover {background: #729FCF; color: #FFFFFF;} + +#content table th, #content table td { + border:1px solid #AAAAAA; + padding:0; + text-align:left; +} + +#content table th {background-color: #F0F0F0;} + +#content table div { + padding: 0.4ex; +} + +#content table th a { + display: block; + text-decoration: none; +} + +.sortup { + background: #F0F0F0 url('../../images/Sort_up_11.png') top center no-repeat !important; +} + +.sortdown { + background: #F0F0F0 url('../../images/Sort_down_11.png') top center no-repeat !important; +} + +.sortable:hover {background-color: #DDDDDD !important;} + +.selected {background: #337ACC !important; color: #FFFFFF;} + +.center {text-align:center;} + +.pagination {padding-top: 1ex;} + +#list-view {} + +#detail-view { + border-top: 3px solid #AAAAAA; + margin-top: 2ex; +} + +#graph { + border: 1px solid #AAAAAA; + margin-bottom: 1.5ex; + height: 15ex; +} + +#submit_for_list { + float: right; + background: none; + border: 0; + color: #337ACC; + cursor: pointer; +} + +#detail_header { + background-color: #F0F0F0; + height: 10ex; + margin-bottom: 1.5ex; +} + +/* ----- Backgrounds for states ----- */ +.state-container { + margin-left:5px; + text-indent:10px; +} + +.task-canceled {background:url(../../images/icon-canceled-11px.png) left center no-repeat;} +.task-failed {background:url(../../images/icon-failed-11px.png) left center no-repeat;} +.task-finished {background:url(../../images/icon-finished-11px.png) left center no-repeat;} +.task-paused {background:url(../../images/icon-paused-11px.png) left center no-repeat;} +.task-queued {background:url(../../images/icon-queued-11px.png) left center no-repeat;} +.task-running {background:url(../../images/icon-running-11px.png) left center no-repeat;} +.instance-unreachable {background:url(../../images/icon_unknown_11px.png) left center no-repeat;} +.instance-stopped {background:url(../../images/icon_stop_11px.png) left center no-repeat;} +.instance-suspended {background:url(../../images/icon_suspend_11px.png) left center no-repeat;} +.instance-saved {background:url(../../images/icon_save_11px.png) left center no-repeat;} +.instance-create_failed {background:url(../../images/icon_failed_11px.png) left center no-repeat;} +.instance-invalid {background:url(../../images/icon_warning_11px.png) left center no-repeat;} +.instance-pending {background:url(../../images/icon_queued_11px.png) left center no-repeat;} +.instance-running {background:url(../../images/icon_start_11px.png) left center no-repeat;} +.instance-creating {background:url(../../images/icon_startup_11px.png) left center no-repeat;} + + +/* ----- Toolbar Navigation -------- */ +#toolbar_nav { + background: #F0F0F0; +} + +#toolbar_nav img { + margin: 0; +} + +#toolbar_nav ul{ + list-style: none; +} + +#toolbar_nav li { + display: inline-block; + position: relative; + color: #666666; + padding: 0 1ex; +} +#toolbar_nav li:hover { + background: #337ACC; + color: #FFFFFF; + cursor: pointer; +} + +#toolbar_nav li.current { /* This is not really needed right now, but will be useful when we add filters. */ + background: #4B95B8; +} + +#toolbar_nav li ul { + display: none; + position: absolute; + top: 1em; + left: 0; + background: #F0F0F0; +} + +#toolbar_nav li ul li { + display: block; + white-space: nowrap; + padding-right: 1ex; +} + +#toolbar_nav li > ul { + top: auto; + left: auto; +} + +#toolbar_nav li:hover ul {display: block;} \ No newline at end of file diff --git a/src/test/functional/cloud/cloud_controller_test.rb b/src/test/functional/cloud/cloud_controller_test.rb new file mode 100644 index 0000000..864400c --- /dev/null +++ b/src/test/functional/cloud/cloud_controller_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class Cloud::CloudControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/src/test/functional/cloud/dashboard_controller_test.rb b/src/test/functional/cloud/dashboard_controller_test.rb new file mode 100644 index 0000000..3ddb6ca --- /dev/null +++ b/src/test/functional/cloud/dashboard_controller_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class Cloud::DashboardControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/src/test/functional/cloud/instance_controller_test.rb b/src/test/functional/cloud/instance_controller_test.rb new file mode 100644 index 0000000..213d2e0 --- /dev/null +++ b/src/test/functional/cloud/instance_controller_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class Cloud::InstanceControllerTest < ActionController::TestCase + fixtures :vms, :tasks + def setup + @controller = Cloud::InstanceController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + def test_should_show_index + get :index + assert_response :success + assert_template 'index' + assert_not_nil assigns(:vms) + assert_not_nil assigns(:user) + end + + def test_should_redirect_if_request_for_selected + post(:index,{:submit_for_list => 'Show Selected'}) + assert_response :redirect + end +end -- 1.6.0.6