From: Jan Provaznik jprovazn@redhat.com
This patch significantly cleanups template UI backend. Drops most of hacks made for package selction in beta1, though there is still metagroup support (will be removed with new UI design).
I think this is a good base for future rework of views (while we get it from design team). I also moved build actions into separate controller (BuildsController). Note that you should run 'rake dc:prepare_repos' if you don't use pulp. --- src/app/controllers/builds_controller.rb | 90 ++++++ src/app/controllers/templates_controller.rb | 298 +++++++------------ src/app/models/template.rb | 72 ++++-- src/app/util/image_descriptor_xml.rb | 41 ++-- src/app/util/repository_manager.rb | 149 +++------- .../util/repository_manager/abstract_repository.rb | 4 + .../util/repository_manager/comps_repository.rb | 78 +++--- src/app/util/repository_manager/pulp_repository.rb | 23 +- src/app/views/builds/index.haml | 89 ++++++ src/app/views/builds/new.haml | 55 ++++ src/app/views/templates/_collections.haml | 11 +- src/app/views/templates/_form.haml | 122 ++++++++ src/app/views/templates/_hidden_fields.haml | 4 +- .../views/templates/_local_content_to_bundle.haml | 21 ++ src/app/views/templates/_managed_content.haml | 15 +- src/app/views/templates/_metagroup_packages.haml | 14 +- src/app/views/templates/_metagroups.haml | 13 + .../views/templates/_preboot_configuration.haml | 11 + src/app/views/templates/_search_packages.haml | 45 +++ src/app/views/templates/_searched_packages.haml | 43 --- src/app/views/templates/_software_selection.haml | 39 +++ src/app/views/templates/build_form.haml | 55 ---- src/app/views/templates/builds.haml | 89 ------ src/app/views/templates/collections.haml | 1 + src/app/views/templates/content_selection.haml | 56 ---- src/app/views/templates/edit.haml | 6 + src/app/views/templates/index.haml | 2 +- src/app/views/templates/metagroup_packages.haml | 1 + src/app/views/templates/new.haml | 162 +----------- src/app/views/templates/search_packages.haml | 1 + src/config/navigation.rb | 6 +- src/config/routes.rb | 10 +- src/features/step_definitions/general_steps.rb | 3 + src/features/step_definitions/template_steps.rb | 13 +- src/features/support/paths.rb | 6 +- src/features/template.feature | 67 +++-- src/spec/controllers/builds_controller_spec.rb | 37 +++ src/spec/controllers/templates_controller_spec.rb | 27 +-- src/spec/factories/template.rb | 25 +-- src/spec/models/template_spec.rb | 2 +- src/spec/utils/repository_manager_spec.rb | 20 ++- 41 files changed, 917 insertions(+), 909 deletions(-) create mode 100644 src/app/controllers/builds_controller.rb create mode 100644 src/app/views/builds/index.haml create mode 100644 src/app/views/builds/new.haml create mode 100644 src/app/views/templates/_form.haml create mode 100644 src/app/views/templates/_local_content_to_bundle.haml create mode 100644 src/app/views/templates/_metagroups.haml create mode 100644 src/app/views/templates/_preboot_configuration.haml create mode 100644 src/app/views/templates/_search_packages.haml delete mode 100644 src/app/views/templates/_searched_packages.haml create mode 100644 src/app/views/templates/_software_selection.haml delete mode 100644 src/app/views/templates/build_form.haml delete mode 100644 src/app/views/templates/builds.haml create mode 100644 src/app/views/templates/collections.haml delete mode 100644 src/app/views/templates/content_selection.haml create mode 100644 src/app/views/templates/edit.haml create mode 100644 src/app/views/templates/metagroup_packages.haml create mode 100644 src/app/views/templates/search_packages.haml create mode 100644 src/features/step_definitions/general_steps.rb create mode 100644 src/spec/controllers/builds_controller_spec.rb
diff --git a/src/app/controllers/builds_controller.rb b/src/app/controllers/builds_controller.rb new file mode 100644 index 0000000..820f28b --- /dev/null +++ b/src/app/controllers/builds_controller.rb @@ -0,0 +1,90 @@ +class BuildsController < ApplicationController + before_filter :require_user + + def section_id + 'build' + end + + def index + require_privilege(Privilege::IMAGE_VIEW) + order = get_order('templates.name') + @running_images = Image.all(:include => :template, :conditions => ['status IN (?)', Image::ACTIVE_STATES], :order => order) + @completed_images = Image.all(:include => :template, :conditions => {:status => Image::STATE_COMPLETE}, :order => order) + @failed_images = Image.all(:include => :template, :conditions => {:status => Image::STATE_FAILED}, :order => order) + end + + def new + raise "select template to build" unless id = params[:template_id] + @tpl = Template.find(id) + @all_targets = Image.available_targets + end + + def create + if params[:cancel] + redirect_to templates_path + return + end + + @tpl = Template.find(params[:template_id]) + @all_targets = Image.available_targets + + if params[:targets].blank? + flash.now[:warning] = 'You need to check at least one provider format' + render :action => 'new' + return + end + + @tpl.upload_template unless @tpl.uploaded + errors = {} + params[:targets].each do |target| + # FIXME: for beta release we check explicitly that provider and provider + # account exists + unless provider = Provider.find_by_cloud_type(target) + flash_error('Error while trying to build image', + 'no provider account' => "There is no provider of '#{target}' type, \ +you can add provider on <a href="#{url_for :controller => 'provider'}">the providers page.</a>") + render :action => 'new' and return + end + if provider.cloud_accounts.empty? + flash_error('Error while trying to build image', + 'no provider account' => "There is no provider account for '#{target}' \ +provider, you can add account on <a href="#{url_for :controller => 'provider', \ +:action => 'accounts', :id => provider.id}">the provider accounts page</a>") + render :action => 'new' and return + end + begin + Image.build(@tpl, target) + rescue + errors[target] = $!.message + end + end + if errors.empty? + redirect_to builds_path + else + flash_error('Error while trying to build image', errors) + render :action => 'new' + end + end + + def edit + end + + def update + end + + private + + # TODO: DRY this, is used in templates controller too + def get_order(default) + @order_dir = params[:order_dir] == 'desc' ? 'desc' : 'asc' + @order_field = params[:order_field] || default + "#{@order_field} #{@order_dir}" + end + + def flash_error(summary, errs) + flash.now[:error] ||= {} + flash.now[:error][:summary] = summary + flash.now[:error][:failures] ||= {} + flash.now[:error][:failures].merge!(errs) + end +end diff --git a/src/app/controllers/templates_controller.rb b/src/app/controllers/templates_controller.rb index 12df295..403e6c3 100644 --- a/src/app/controllers/templates_controller.rb +++ b/src/app/controllers/templates_controller.rb @@ -2,7 +2,12 @@ require 'util/repository_manager'
class TemplatesController < ApplicationController before_filter :require_user - before_filter :check_permission, :except => [:index, :builds] + before_filter :check_permission, :except => :index + layout :layout + + def layout + return "aggregator" unless request.xhr? + end
def section_id 'build' @@ -18,31 +23,29 @@ class TemplatesController < ApplicationController ) end
- def action + def index_action if params[:new_template] - redirect_to :action => 'new' + redirect_to new_template_path elsif params[:assembly] - redirect_to :action => 'assembly' + redirect_to assembly_template_path(:id => params[:ids].to_a.first) elsif params[:deployment_definition] - redirect_to :action => 'deployment_definition' + redirect_to deployment_definition_template_path(:id => params[:ids].to_a.first) elsif params[:delete] - redirect_to :action => 'delete', :ids => params[:ids].to_a + redirect_to destroy_multiple_templates_path(:ids => params[:ids].to_a) elsif params[:edit] - begin - redirect_to :action => 'new', :id => get_selected_id - rescue - flash[:notice] = "No template selected" - redirect_to :action => 'index' + if id = get_selected_id + redirect_to edit_template_path(:id => id) + else + redirect_to templates_path end elsif params[:build] - begin - redirect_to :action => 'build_form', 'template_id' => get_selected_id - rescue - flash[:notice] = "No template selected" - redirect_to :action => 'index' + if id = get_selected_id + redirect_to new_build_path(:template_id => id) + else + redirect_to templates_path end else - raise "Unknown action" + raise 'Unknown action' end end
@@ -51,183 +54,122 @@ class TemplatesController < ApplicationController def dispatch if params[:save] create - elsif params[:cancel] - redirect_to :action => 'index' - + redirect_to templates_path elsif params[:add_software_form] - content_selection - + collections + elsif params[:collections] + collections elsif pkg = params.keys.find { |k| k =~ /^remove_package_(.*)$/ } # actually remove the package from list params[:packages].delete($1) if params[:packages] new - elsif params[:add_selected] new - elsif params[:cancel_add_software] - params[:packages] = params[:selected_packages] + params[:selected_packages] = params[:packages] + params[:selected_groups] = params[:groups] + params[:cached_packages] = [] new - - elsif params.include?('show_metagroup') - @metagroup = params['show_metagroup'] - content_selection - - elsif not params[:package_search].blank? - content_selection - + elsif params.include?('metagroup_packages') + metagroup_packages + elsif params[:package_search] + search_packages + else + raise "unknown action" end end
- # FIXME at some point split edit/update out from new/create - # to conform to web standards def new # can't use @template variable - is used by compass (or something other) - @id = params[:id] - @tpl = @id.blank? ? Template.new : Template.find(@id) - @tpl.attributes = params[:tpl] unless params[:tpl].nil? - get_selected_packages(@tpl) + @tpl = Template.new(params[:tpl]) + @repository_manager = RepositoryManager.new(:repositories => params[:repository] || @tpl.platform) + @tpl.add_software(params[:packages].to_a + params[:selected_packages].to_a + params[:cached_packages].to_a, + params[:groups].to_a + params[:selected_groups].to_a) render :action => :new end
- def create - @id = params[:tpl][:id] - @tpl = @id.blank? || @id == "" ? Template.new(params[:tpl]) : Template.find(@id) - - @tpl.xml.clear_packages - - params[:groups].to_a.each { |group| @tpl.xml.add_group(group) } - params[:packages].to_a.each { |pkg| @tpl.xml.add_package(pkg) } - - # this is crazy, but we have most attrs in xml and also in model, - # synchronize it at first to xml - @tpl.update_xml_attributes(params[:tpl]) + def edit + @tpl = Template.find(params[:id]) + @tpl.attributes = params[:tpl] unless params[:tpl].blank? + @repository_manager = RepositoryManager.new(:repositories => params[:repository] || @tpl.platform) + render :action => :edit + end
+ def create + @tpl = Template.new(params[:tpl]) + @tpl.packages = params[:packages] if @tpl.save flash[:notice] = "Template saved." @tpl.set_complete - redirect_to :action => 'index' + redirect_to templates_path else - get_selected_packages(@tpl) + @repository_manager = RepositoryManager.new(:repositories => params[:repository] || @tpl.platform) render :action => 'new' end end
- def content_selection - @repository_manager = RepositoryManager.new - @id = params[:id] - @tpl = @id.blank? ? Template.new : Template.find(@id) - @tpl.attributes = params[:tpl] unless params[:tpl].nil? - @packages = [] - @packages += params[:packages].collect{ |p| { :name => p } } unless params[:packages].blank? - @packages += params[:selected_packages].collect{ |p| { :name => p } } unless params[:selected_packages].blank? - @groups = @repository_manager.all_groups_with_tagged_selected_packages(@packages, params[:repository] || @tpl.platform) - @embed = params[:embed] - @categories = @repository_manager.categories(params[:tpl] ? params[:tpl][:platform] : nil) - @metagroups = @repository_manager.metagroups + def update + @tpl = Template.find(params[:id]) + @tpl.packages = []
- if not params[:package_search].blank? - @page = get_page - @cached_packages = params[:cached_packages].to_a - @searched_packages = @repository_manager.search_package(params[:package_search], - params[:repository] || @tpl.platform).paginate(:page => @page, - :per_page => 60) - elsif not @metagroup.blank? - if @metagroup == 'Collections' - # TODO: if we remember selected groups, this could be done much more simply - @collections = @repository_manager.all_groups_with_tagged_selected_packages(@packages, params[:repository] || @tpl.platform) - else - @metagroup_packages = @repository_manager.metagroup_packages_with_tagged_selected_packages(@metagroup, @packages, params[:repository] || @tpl.platform) - end + if @tpl.update_attributes(params[:tpl]) + @tpl.set_complete + flash[:notice] = "Template updated." + redirect_to templates_path else - @collections = @repository_manager.all_groups_with_tagged_selected_packages(@packages, params[:repository] || @tpl.platform) - end - if request.xhr? - if @metagroup_packages - render :partial => 'metagroup_packages' and return - end - if @searched_packages - render :partial => 'searched_packages' and return - end - if @collections and @metagroup - render :partial => 'collections' and return - end + @repository_manager = RepositoryManager.new(:repositories => params[:repository] || @tpl.platform) + render :action => 'edit' end + end
- if @embed - render :layout => false + def search_packages + set_package_vars + @page = get_page + @cached_packages = params[:cached_packages].to_a + params[:selected_packages].to_a + @searched_packages = params[:package_search].empty? ? [] : @repository_manager.search_package( + params[:package_search]).paginate(:page => @page, :per_page => 60) + if request.xhr? + render :partial => 'search_packages' else - render :action => :content_selection + render :search_packages end end
- def managed_content - get_selected_packages - render :layout => false - end - - def build_form - raise "select template to build" unless id = params[:template_id] - @tpl = Template.find(id) - @all_targets = Image.available_targets - end - - def build - if params[:cancel] - redirect_to :action => 'index' - return - end - - @tpl = Template.find(params[:template_id]) - @all_targets = Image.available_targets - - if params[:targets].blank? - flash.now[:warning] = 'You need to check at least one provider format' - render :action => 'build_form' - return + def metagroup_packages + set_package_vars + @metagroup_packages = @repository_manager.metagroup_packages(params[:metagroup_packages]) + if request.xhr? + render :partial => 'metagroup_packages' + else + render :metagroup_packages end + end
- @tpl.upload_template unless @tpl.uploaded - params[:targets].each do |target| - # FIXME: for beta release we check explicitly that provider and provider - # account exists - unless provider = Provider.find_by_cloud_type(target) - flash_error("There is no provider of '#{target}' type, you can add provider \ -on <a href="#{url_for :controller => 'providers'}">the providers page.</a>") - render :action => 'build_form' and return - end - if provider.cloud_accounts.empty? - flash_error("There is no provider account for '#{target}' provider, you can \ -add account on <a href="#{url_for :controller => 'providers', \ -:action => 'accounts', :id => provider.id}">the provider accounts page</a>") - render :action => 'build_form' and return - end - begin - Image.build(@tpl, target) - rescue - flash.now[:error] ||= {} - flash.now[:error][:failures] ||= {} - flash.now[:error][:failures][target] = $!.message - end - end - if flash[:error] and not flash[:error][:failures].blank? - flash[:error][:summary] = 'Error while trying to build image' - render :action => 'build_form' + def collections + set_package_vars + @collections = @repository_manager.groups + if request.xhr? + render :partial => 'collections' else - redirect_to :action => 'builds' + render :collections end end
- def builds - order = get_order('templates.name') - @running_images = Image.all(:include => :template, :conditions => ['status IN (?)', Image::ACTIVE_STATES], :order => order) - @completed_images = Image.all(:include => :template, :conditions => {:status => Image::STATE_COMPLETE}, :order => order) - @failed_images = Image.all(:include => :template, :conditions => {:status => Image::STATE_FAILED}, :order => order) - require_privilege(Privilege::IMAGE_VIEW) + def content_selection + set_package_vars(true) + @collections = @repository_manager.groups + render :collections end
- def delete + def managed_content + @tpl = params[:template_id].blank? ? Template.new : Template.find(params[:template_id]) + @tpl.add_software(params[:packages].to_a + params[:selected_packages].to_a, + params[:groups].to_a + params[:selected_groups].to_a) + render :layout => false + end + + def destroy_multiple ids = params[:ids].to_a if ids.empty? flash[:notice] = "No Template Selected" @@ -242,12 +184,10 @@ add account on <a href="#{url_for :controller => 'providers', \ if errs.empty? flash[:notice] = 'Template deleted' else - flash[:error] ||= {} - flash[:error][:summary] = 'Error while deleting template' - (flash[:error][:failures] ||= {}).merge!(errs) + flash_error('Error while deleting template', errs) end end - redirect_to :action => 'index' + redirect_to templates_path end
def assembly @@ -259,17 +199,27 @@ add account on <a href="#{url_for :controller => 'providers', \
private
+ def set_package_vars(set_all = false) + @tpl = params[:id].blank? ? Template.new : Template.find(params[:id]) + @tpl.attributes = params[:tpl] unless params[:tpl].nil? + @repository_manager = RepositoryManager.new(:repositories => params[:repository] || @tpl.platform) + @groups = @repository_manager.groups + @categories = @repository_manager.categories if not request.xhr? or set_all + @metagroups = @repository_manager.metagroups if not request.xhr? or set_all + @tpl.add_software(params[:packages].to_a, params[:groups].to_a) + end + def get_order(default) @order_dir = params[:order_dir] == 'desc' ? 'desc' : 'asc' @order_field = params[:order_field] || default "#{@order_field} #{@order_dir}" end
- def flash_error(msg) + def flash_error(summary, errs) flash.now[:error] ||= {} - flash.now[:error][:summary] = 'Error while trying to build image' + flash.now[:error][:summary] = summary flash.now[:error][:failures] ||= {} - flash.now[:error][:failures]['no provider account'] = msg + flash.now[:error][:failures].merge!(errs) end
def check_permission @@ -279,40 +229,12 @@ add account on <a href="#{url_for :controller => 'providers', \ def get_selected_id ids = params[:ids].to_a if ids.size != 1 - raise "No Template Selected" if ids.empty? - raise "You can select only one template" if ids.size > 1 + flash[:warning] = ids.empty? ? 'No Template Selected' : 'You can select only one template' + return end return ids.first end
- def get_selected_packages(tpl=nil) - @repository_manager = RepositoryManager.new - @groups = @repository_manager.all_groups(params[:repository]) - - if not params[:packages].blank? or not params[:selected_packages].blank? or not params[:cached_packages].blank? - @selected_packages = params[:packages].to_a + params[:selected_packages].to_a - elsif !tpl.nil? - @selected_packages = tpl.xml.packages.collect { |p| p[:name] } - else - @selected_packages = [] - end - - if params[:collections].to_s == 'true' or not request.xhr? - [:selected_groups, :groups].each do |pg| - if params[pg] - params[pg].each { |grp| - fg = @groups.find { |gk, gv| gk == grp } - fg[1][:packages].each { |pk, pv| - @selected_packages << pk - } unless fg.nil? - } - end - end - end - - @selected_packages.uniq! - end - def get_page if params[:page] == 'Previous' return params[:old_page].to_i - 1 diff --git a/src/app/models/template.rb b/src/app/models/template.rb index e1e9df2..74bf208 100644 --- a/src/app/models/template.rb +++ b/src/app/models/template.rb @@ -4,7 +4,8 @@ require 'typhoeus' class Template < ActiveRecord::Base has_many :images, :dependent => :destroy has_many :instances - before_validation :update_attrs + before_validation :generate_uuid + before_save :update_xml before_destroy :no_instances?
WAREHOUSE_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/image_warehouse.yml") @@ -27,19 +28,6 @@ class Template < ActiveRecord::Base true end
- def update_xml_attributes(opts = {}) - xml.name = opts[:name] if opts[:name] - xml.description = opts[:summary] if opts[:summary] - if plat = opts[:platform] - xml.platform = plat - xml.platform_version = platforms[plat]['version'].to_s - xml.architecture = platforms[plat]['architecture'] - end - self[:xml] = xml.to_xml - @xml = nil - update_attrs - end - def xml @xml ||= ImageDescriptorXML.new(self[:xml].to_s) end @@ -54,14 +42,18 @@ class Template < ActiveRecord::Base end end
- def update_attrs + def generate_uuid # TODO: generate real uuid here, e.g. with some ruby uuid generator - self.uuid ||= "#{xml.name}-#{Time.now.to_f.to_s}" - self.name = xml.name - self.summary = xml.description - self.platform = xml.platform - self.platform_version = xml.platform_version - self.architecture = xml.architecture + self.uuid ||= "#{self.name}-#{Time.now.to_f.to_s}" + end + + def update_xml + xml.name = self.name + xml.description = self.summary + xml.platform = self.platform + xml.platform_version = self.platform_version + xml.architecture = self.architecture + write_attribute(:xml, xml.to_s) end
def providers @@ -83,4 +75,42 @@ class Template < ActiveRecord::Base def platforms @platforms ||= YAML.load_file("#{RAILS_ROOT}/config/image_descriptor_platform_repositories.yml") end + + def add_packages(packages) + packages.to_a.each {|pkg| xml.add_package(pkg)} + end + + def add_groups(groups) + groups.to_a.each {|pkg| xml.add_group(pkg)} + end + + def add_software(packages, groups) + add_packages(packages) + add_groups(groups) + end + + def platform=(plat) + write_attribute(:platform, plat) + self.platform_version = platforms[plat]['version'].to_s + self.architecture = platforms[plat]['architecture'] + end + + # packages and groups are virtual attributes + def packages + xml.packages + end + + def packages=(packages) + xml.clear_packages + packages.to_a.each {|pkg| xml.add_package(pkg)} + end + + def groups + xml.groups + end + + def groups=(groups) + xml.clear_groups + groups.to_a.each {|group| xml.add_group(group)} + end end diff --git a/src/app/util/image_descriptor_xml.rb b/src/app/util/image_descriptor_xml.rb index 034d943..e9f71d9 100644 --- a/src/app/util/image_descriptor_xml.rb +++ b/src/app/util/image_descriptor_xml.rb @@ -52,7 +52,7 @@ class ImageDescriptorXML # platform # update: we don't add platform repo, image builder chooses right one from OS # name, but we add all other repos - recreate_repo_nodes + #recreate_repo_nodes get_or_create_node('os')['name'] = str end
@@ -109,28 +109,28 @@ class ImageDescriptorXML end
def packages - packages = [] - @root.xpath('/image/packages/package').each do |s| - packages << {:name => s.at_xpath('.//name').text} + @root.xpath('/image/packages/package').map do |s| + s.at_xpath('.//name').text + end + end + + def groups + @root.xpath('/image/groups/group').map do |s| + s.at_xpath('.//name').text end - return packages end
def add_package(pkg) pkgs_node = get_or_create_node('packages') - unless older = packages.find {|p| p[:name] == pkg} - add_package_node(pkgs_node, pkg) - end + add_package_node(pkgs_node, pkg) unless packages.include?(pkg) end
def add_group(gname) - unless group = repository_manager.all_groups[gname] - raise "group #{gname} not found in repositories" - end - group[:packages].each do |p, info| - next if info[:type] == 'optional' - add_package(p) - end + #unless group = repository_manager.groups.find(gname) + # raise "group #{gname} not found in repositories" + #end + node = get_or_create_node('groups') + add_group_node(node, gname) unless groups.include?(gname) end
def remove_package(package) @@ -145,12 +145,17 @@ class ImageDescriptorXML @root.xpath('/image/packages').each { |s| s.remove } end
+ def clear_groups + @root.xpath('/image/groups').each { |s| s.remove } + end + private
def add_group_node(parent, group) - n = Nokogiri::XML::Node.new('group', @doc) - n.content = group - parent << n + pnode = get_or_create_node('group', parent) + n = Nokogiri::XML::Node.new('name', @doc) + n.content = name + pnode << n end
def recreate_repo_nodes diff --git a/src/app/util/repository_manager.rb b/src/app/util/repository_manager.rb index 382f48d..8ada489 100644 --- a/src/app/util/repository_manager.rb +++ b/src/app/util/repository_manager.rb @@ -28,141 +28,63 @@ class RepositoryManager @config = opts[:config] || load_config @config = [ @config ] if Hash === @config @repositories = get_repositories + @selected_repositories = get_selected_repositories(opts[:repositories]) end
- def all_groups(repository = nil) - unless @all_groups - @all_groups = {} - repositories.each do |r| - next if repository and repository != 'all' and repository != r.id - r.groups.each do |group, data| - if @all_groups[group] - @all_groups[group][:packages].merge!(data[:packages]) - else - @all_groups[group] = data - end - end - end - end - return @all_groups + def groups + @groups ||= @selected_repositories.map {|repo| repo.groups}.flatten end
- def packages(repository = nil) + def packages + @packages ||= @selected_repositories.map {|repo| repo.packages}.flatten end
- def categories(repository = nil) - unless @all_categories - @all_categories = {} - repositories.each do |r| - next if repository and repository != 'all' and repository != r.id - r.categories.each do |id, data| - if @all_categories[id] - @all_categories[id][:groups] += data[:groups] - else - @all_categories[id] = data - end - end - end + def categories + @categories ||= @selected_repositories.map {|repo| repo.categories}.flatten + end + + def repositories_hash + res = {} + @repositories.each do |r| + res[r.id] = r end - return @all_categories + res end
- def packages(repository = nil) - unless @packages - @packages = [] - repositories.each do |r| - next if repository and repository != 'all' and repository != r.id - @packages += r.packages - end + def search_package(str) + @selected_repositories.map {|repo| repo.search_package(str)}.flatten + end + + # TODO (remove): this is temporary solution for categorizing packages + def metagroup_packages(category) + res = [] + grps = groups + metagroups[category].to_a.each do |entry| + gname = entry[1] + cat = categories.find{|t| t[:id] == entry[0]} + group = grps.find{|g| g[:id] == gname} + next unless cat and cat[:groups].include?(gname) and group + next if res.find{|g| g[:name] == gname} + res << {:name => gname, :packages => group[:packages].keys} end - return @packages + res end
- # TODO: this is temporary solution for categorizing packages + # TODO (remove): this is temporary solution for categorizing packages def metagroups unless @metagroups @metagroups = {} File.readlines('config/image_descriptor_package_metagroups.conf').each do |line| group, entries_str = line.chomp.split('=') next unless group and entries_str - @metagroups[group] = entries_str.split(',') + @metagroups[group] = entries_str.split(',').map {|entry| entry.split(';')} end end @metagroups end
- def metagroup_packages(category, repository = nil) - res = {} - groups = all_groups(repository) - metagroups[category].to_a.each do |entry| - cat, group = entry.split(';') - next unless c = categories[cat] and c[:groups].include?(group) and groups[group] - res[group] = {:packages => groups[group][:packages].keys} - end - res - end - - def metagroup_packages_with_tagged_selected_packages(category, pkgs, repository = nil) - mgroups = metagroup_packages(category, repository) - mgroups.each_value do |group| - missing = false - group[:packages].each do |pkg| - unless pkgs.find {|p| p[:name] == pkg} - missing = true - break - end - end - next if missing - group[:selected] = true - end - mgroups - end - - def all_groups_with_tagged_selected_packages(pkgs, repository = nil) - groups = all_groups(repository) - groups.each_value do |group| - pkgs.each do |pkg| - next unless p = group[:packages][pkg[:name]] - p[:selected] = true - end - group[:selected] = is_group_selected(group) - end - return groups - end - - def repositories_hash - res = {} - @repositories.each do |r| - res[r.id] = r - end - res - end - - def search_package(str, repository = nil) - packages(repository).select {|p| p =~ /#{Regexp.escape(str)}/i} - end - private
- # returns true if all non-optional packages are selected - # (if there are only non-optional packages in the group, - # all packages must be selected) - def is_group_selected(group) - all = true - all_nonopt = true - only_opt = true - group[:packages].each_value do |pkg| - all = false unless pkg[:selected] - if pkg[:type] != 'optional' - only_opt = false - if !pkg[:selected] - all_nonopt = false - end - end - end - return only_opt ? all : all_nonopt - end - def load_config YAML.load_file("#{RAILS_ROOT}/config/image_descriptor_package_repositories.yml") end @@ -178,4 +100,11 @@ class RepositoryManager end return repositories end + + def get_selected_repositories(repos) + return @repositories if repos.blank? + repos.map do |repo| + @repositories.find {|r| r.id == repo} or raise "repository '#{repo}' not found" + end + end end diff --git a/src/app/util/repository_manager/abstract_repository.rb b/src/app/util/repository_manager/abstract_repository.rb index 5400ae1..7b73926 100644 --- a/src/app/util/repository_manager/abstract_repository.rb +++ b/src/app/util/repository_manager/abstract_repository.rb @@ -8,4 +8,8 @@ class AbstractRepository @yumurl = conf['yumurl'] || conf['baseurl'] @type = conf['type'] end + + def search_package(what) + packages.select {|p| p[:name] =~ /#{Regexp.escape(what)}/i} + end end diff --git a/src/app/util/repository_manager/comps_repository.rb b/src/app/util/repository_manager/comps_repository.rb index 6a90f14..494fbac 100644 --- a/src/app/util/repository_manager/comps_repository.rb +++ b/src/app/util/repository_manager/comps_repository.rb @@ -19,58 +19,55 @@ class CompsRepository < AbstractRepository end
def packages - pkgs = [] - groups.each_value do |g| - pkgs += g[:packages].keys - end - pkgs.uniq + @packages ||= load_data[:packages] end
def prepare_repo - grps = {} - @all_pkgs = pkg_names - group_nodes.each do |g| - pkgs = group_packages(g) - next if pkgs.empty? - name = g.at_xpath('name').text - id = g.at_xpath('id').text - grps[id] = { - :name => name, + Dir.mkdir(@cache_dir) unless File.directory?(@cache_dir) + File.open(@cache_file, 'w') do |f| + Marshal.dump({ + :packages => get_packages, + :groups => get_groups, + :categories => get_categories + }, f) + end + end + + private + + def get_packages + packages = package_nodes.map do |node| + { + #:id => node.at_xpath('./xmlns:id/child::text()').text, + :name => node.at_xpath('./xmlns:name/child::text()').text, :repository_id => @id, - :packages => pkgs } end + end
- other = {} - @all_pkgs.each do |pkg, val| - other[pkg] = {:type => 'optional'} if val != :listed - end - if other.size > 0 - name = 'unsorted' - grps[name] = { - :name => name, + def get_groups + group_nodes.map do |g| + pkgs = group_packages(g) + next if pkgs.empty? + { + :id => g.at_xpath('id').text, + :name => g.at_xpath('name').text, :repository_id => @id, - :packages => other + :packages => pkgs } end + end
- categories = {} - category_nodes.each do |cat| - id = cat.at_xpath('id').text - categories[id] = { + def get_categories + category_nodes.map do |cat| + { + :id => cat.at_xpath('id').text, :name => cat.at_xpath('name').text, :groups => cat.xpath('./grouplist/groupid').map {|g| g.text} } end - - Dir.mkdir(@cache_dir) unless File.directory?(@cache_dir) - File.open(@cache_file, 'w') do |f| - Marshal.dump({:groups => grps, :categories => categories}, f) - end end
- private - def load_data unless @load_data begin @@ -100,14 +97,9 @@ class CompsRepository < AbstractRepository xml.xpath('/comps/category') end
- def pkg_names - pkgs = {} + def package_nodes xml = Nokogiri::XML(primary_xml) - xml.xpath('/xmlns:metadata/xmlns:package').each do |node| - next unless name = node.at_xpath('./xmlns:name/child::text()') - pkgs[name.text] = true - end - return pkgs + xml.xpath('/xmlns:metadata/xmlns:package') end
def download_xml(url) @@ -146,8 +138,6 @@ class CompsRepository < AbstractRepository pkgs = {} group_node.xpath('packagelist/packagereq').each do |p| pkg_name = p.text - next unless val = @all_pkgs[pkg_name] - val = :listed (pkgs[pkg_name] ||= {})[:type] = p.attr('type') end return pkgs diff --git a/src/app/util/repository_manager/pulp_repository.rb b/src/app/util/repository_manager/pulp_repository.rb index 051bc47..b232d7f 100644 --- a/src/app/util/repository_manager/pulp_repository.rb +++ b/src/app/util/repository_manager/pulp_repository.rb @@ -35,41 +35,36 @@ class PulpRepository < AbstractRepository end
def groups - groups = {} - WrappedRestClient.get(@groups_url, HTTP_OPTS).each do |id, info| + WrappedRestClient.get(@groups_url, HTTP_OPTS).map do |id, info| pkgs = {} info['default_package_names'].each {|p| pkgs[p] = {:type => 'default'}} info['optional_package_names'].each {|p| pkgs[p] = {:type => 'optional'}} info['mandatory_package_names'].each {|p| pkgs[p] = {:type => 'mandatory'}} next if pkgs.empty? - name = info['name'] - groups[info['id']] = { + { + :id => id, :name => info['name'], :description => info['description'].to_s, :repository_id => @id, :packages => pkgs, } - end - return groups + end.compact end
def categories - categories = {} - WrappedRestClient.get(@categories_url, HTTP_OPTS).each do |id, info| - categories[info['id']] = { + WrappedRestClient.get(@categories_url, HTTP_OPTS).map do |id, info| + { + :id => id, :name => info['name'], :groups => info['packagegroupids'], } end - return categories end
def packages - packages = [] - WrappedRestClient.get(@packages_url, HTTP_OPTS).each do |info| - packages << info['name'] + WrappedRestClient.get(@packages_url, HTTP_OPTS).map do |info| + {:name => info['name']} end - return packages end
private diff --git a/src/app/views/builds/index.haml b/src/app/views/builds/index.haml new file mode 100644 index 0000000..0d2d5ce --- /dev/null +++ b/src/app/views/builds/index.haml @@ -0,0 +1,89 @@ +- columns = [ | + {:name => 'NAME', :sort_attr => 'templates.name'}, | + {:name => 'OS', :sort_attr => 'templates.platform'}, | + {:name => 'VERSION', :sort_attr => 'templates.platform_version'}, | + {:name => 'ARCH', :sort_attr => 'templates.architecture'}, | + {:name => 'STATUS', :sort_attr => 'status'}, | +] | + +- form_tag :action => "" do + .actionsidebar.grid_3 + %dl + %dt Build Job Actions + %dd + %h5 JOB QUEUE + %ul + %li.delete + %span + = submit_tag "Cancel Job", :name => "job_details", :disabled => true, :class => "icon" + %li.show + %span + = submit_tag "Show Job Details", :name => "job_details", :disabled => true, :class => "icon" + %li.show + %span + = submit_tag "Show Job Log", :name => "job_log", :disabled => true, :class => "icon" + %li.clear + %span + = submit_tag "Clear Job History", :name => "job_history", :disabled => true, :class => "icon" + + .grid_13 + %h1 Status + %section.wrap.status + %label.grid_4.alpha Image Warehouse Status: + .grid_3.suffix_6.omega + %span.good + Green + + %label.grid_4.alpha Total Builds in Queue: + .grid_3.suffix_6.omega + = @running_images.size + + %label.grid_4.alpha Number of VM's Building: + .grid_3.suffix_6.omega + = @running_images.select {|i| i.status == Image::STATE_BUILDING}.size + + %h1 Running + + %table + = sortable_table_header(columns) + %tbody + - if @running_images.empty? + %tr + %td{:colspan => 5} No Images + - else + - @running_images.each do |img| + %tr + %td= img.template.name + %td= img.template.platform + %td= img.template.platform_version + %td= img.template.architecture + %td= img.status + + - unless @failed_images.empty? + %h1 Failed + %table + = sortable_table_header(columns) + %tbody + - @failed_images.each do |img| + %tr + %td= img.template.name + %td= img.template.platform + %td= img.template.platform_version + %td= img.template.architecture + %td= img.status + + %h1 Completed + %table + = sortable_table_header(columns) + %tbody + - if @completed_images.empty? + %tr + %td{:colspan => 5} No Images + - else + - @completed_images.each do |img| + %tr + %td= img.template.name + %td= img.template.platform + %td= img.template.platform_version + %td= img.template.architecture + %td OK diff --git a/src/app/views/builds/new.haml b/src/app/views/builds/new.haml new file mode 100644 index 0000000..4cddb6f --- /dev/null +++ b/src/app/views/builds/new.haml @@ -0,0 +1,55 @@ +%h2 BUILD REQUEST +- form_tag :action => 'create' do + = hidden_field_tag :template_id, @tpl.id + %h3 Deployment Definition + %fieldset.clearfix + = label_tag :deploy_name, 'Deployment Definition Name:', :class => 'grid_4' + = text_field_tag 'deploy_name', 'Deployment Name', :disabled => true, :class => 'grid_3' + = text_field_tag 'deploy_description', 'Deployment Description', :disabled => true, :class => 'grid_3' + %fieldset.clearfix + .prefix_4.grid_6 + = check_box_tag 'use_for_machine', 1, true, :disabled => true + = label_tag 'use_for_machine', 'Use for Machine Definition Name and Description' + %fieldset.clearfix + .grid_7 + = file_field :templates, :choose_logo, :value => 'Choose Logo', :disabled => true + = text_field :templates, :logo_text, :value => 'Logo Text (5 characters)', :disabled => true, :class => "grid_3" + + %fieldset.clearfix + %label.grid_4{:for => :template_group} + Template Category: + .grid_3 + = select_tag(:template_group, options_for_select([['User Private', 1]])) + + %h3 Deployment Options + %fieldset.clearfix + .grid_6 + %label OS: + = @tpl.platform + .grid_3 + Hardware Profile + .grid_3.suffix_3 + Locale + %fieldset.clearfix + .grid_3 + %label OS Version: + = @tpl.platform_version + .grid_3.ra + %label Global Settings: + .grid_3 + Small + .grid_3 + Any + .grid_3 + = submit_tag "Config", :name => "config", :disabled => true + %h3 Build Options + %label Choose Provider Format: + %section.clearfix.gap + %ul.block + - @all_targets.each do |target_id, target| + %li + = check_box_tag 'targets[]', target_id, false + = label_tag 'targets[]', target['name'] + + = submit_tag "Submit to Build", :name => "build" + = submit_tag "Cancel", :name => "cancel" diff --git a/src/app/views/templates/_collections.haml b/src/app/views/templates/_collections.haml index 4623f6f..98ce959 100644 --- a/src/app/views/templates/_collections.haml +++ b/src/app/views/templates/_collections.haml @@ -1,9 +1,8 @@ -= hidden_field_tag :collections, true - %ul.collections - - @collections.keys.sort.each do |id| + - @collections.each do |c| %li - - selected = @collections[id][:selected] ? true : false - = check_box_tag 'groups[]', id, selected, {:disabled => selected, :id => "group_#{id}", :class => "#{selected ? 'selected' : ''}"} - = label_tag "group_#{id}", @collections[id][:name] + /- selected = c[:selected] ? true : false + - selected = false + = check_box_tag 'groups[]', c[:id], selected, {:disabled => selected, :id => "group_#{c[:id]}", :class => "#{selected ? 'selected' : ''}"} + = label_tag "group_#{c[:id]}", c[:name] = render :partial => 'addbuttons' diff --git a/src/app/views/templates/_form.haml b/src/app/views/templates/_form.haml new file mode 100644 index 0000000..dff9811 --- /dev/null +++ b/src/app/views/templates/_form.haml @@ -0,0 +1,122 @@ +:javascript + $(document).ready(function() { + var $content_container = $('#managed_content'); + var $sel_pkg_container = $('#package_selection_list'); + var $submit = $('#add_software_button'); + $submit.click(function(e) { + e.preventDefault(); + $submit.hide(); + var data = { + 'packages[]': $("input[name='packages[]']").map(function() {return $(this).val()}).get(), + 'repository': $("select[name='tpl[platform]']").val() || '' + } + var url = '#{url_for :action => 'content_selection', :id => @id}'; + //$content_container.empty().show(); + $sel_pkg_container.empty().show().addClass('loading'); + $sel_pkg_container.load(url, data, function(){ + $sel_pkg_container.removeClass('loading'); + var $groups = $('.softwaregroups .disclosure', this); + //search + $("input[name='package_search']").keypress(function(event) { + if (event.keyCode == '13') { + event.preventDefault(); + $("input[name=package_search] ~ button").click(); + } + }); + $("input[name=package_search] ~ button").click(function(event) { + event.preventDefault(); + var data = { + 'packages[]': $("input:text[name='packages[]']").map(function() {return $(this).val()}).get(), + 'package_search': $("input[name='package_search']").val(), + 'repository': $("select[name='tpl[platform]']").val() + }; + var url = '#{url_for :action => 'search_packages', :id => @id}'; + $('#metagrouppackages').empty().addClass('loading'); + $('#metagrouppackages').load(url, data, function() { + $('#metagrouppackages').removeClass('loading'); + }); + }); + }); + }); + //removing packages from the list + $('.remove_package').live('click', function (e) { + e.preventDefault(); + $(this).parent().hide(300, function () { + $(this).remove(); + }); + }); + //displaying extended package info and actions + $('.dropdown').hide(); + $('.packagename').live('click', function () { + var dropdowncontent = $(this).siblings('.dropdown').html(), + $dropdown = $("#dropdown"); + $('.packagewrap').removeClass('selected'); + $(this).parent().addClass('selected'); + $dropdown.empty().html(dropdowncontent).css({ + 'top': $(this).positionAncestor('#content').top + 17, + 'left': $(this).positionAncestor('#content').left - 4 + }).show(); + }); + //catch #content clicks and hide the #dropdown if it's not within it + $("#content").click(function (e) { + if(!e.target.id === 'dropdown' || !$(e.target).closest("#dropdown").length) { + $("#dropdown").hide(); + $('.packagewrap').removeClass('selected'); + } + }); + // select correct package repo when we change platform + $("select[name='tpl[platform]']").change(function() { + if ($submit.is(':hidden')) { + $submit.trigger('click'); + } + }); + // add selected pkgs/groups + $('#do_add_software').live('click', function(e) { + e.preventDefault(); + var $button = $(this).clone(); + var label = "<span id='do_add_software' class='loading fl'>Adding Packages</span>"; + var url = '#{url_for :action => 'managed_content'}'; + var new_pkgs = $("input:checked[name='selected_packages[]']").map(function() {return $(this).val()}).get(); + var old_pkgs = $("input:hidden[name='packages[]']").map(function() {return $(this).val()}).get() + var cached_pkgs = $("input:hidden[name='cached_packages[]']").map(function() {return $(this).val()}).get() + var data = { + 'selected_packages[]': old_pkgs.concat(new_pkgs.concat(cached_pkgs)), + 'selected_groups[]': $("input:checked[name='groups[]']").map(function() {return $(this).val()}).get(), + 'collections': $("input:hidden[name=collections]").val(), + 'template_id' : '#{@id.nil? ? nil : @id}' + }; + $(this).replaceWith(label); + $('#managed_content').load(url, data, function(){ + $("input:checked[name='groups[]']").attr('disabled', 'disabled'); + $("input:checked[name='packages[]']").attr('disabled', 'disabled'); + // $('#add_software_button').show(); + $('.dropdown').hide(); + $('#do_add_software').replaceWith($button); + }); + }); + // hide sw selection panel + $('#cancel_add_software').live('click', function(e) { + e.preventDefault(); + $('#package_selection_list').hide(); + $('#add_software_button').show(); + $('.dropdown').hide(); + }); + }); + += error_messages_for :tpl, :object_name => 'template' += render :partial => 'basics' += render :partial => 'local_content_to_bundle' + +#managed_content + = render :partial => 'managed_content' + +.clearfix + .grid_16.alpha.omega + = submit_tag "Add Software", :name => "add_software_form", :id => "add_software_button", :class => "iconbutton" + +#package_selection_list{:style => 'display: none'} + += render :partial => 'preboot_configuration' + += submit_tag "Save", :name => "save", :class => "formbutton" += submit_tag "Cancel", :name => "cancel", :class => "formbutton" diff --git a/src/app/views/templates/_hidden_fields.haml b/src/app/views/templates/_hidden_fields.haml index 3fcab65..5709087 100644 --- a/src/app/views/templates/_hidden_fields.haml +++ b/src/app/views/templates/_hidden_fields.haml @@ -1,8 +1,8 @@ -- # the template fields as hidden form inputs -<input type="hidden" id="id" name="id" value="#{@id}" /> = hidden_field :tpl, :id = hidden_field :tpl, :name = hidden_field :tpl, :summary = hidden_field :tpl, :platform = hidden_field :tpl, :platform_version = hidden_field :tpl, :architecture +- @tpl.packages.each do |p| + = hidden_field_tag "packages[]", p, :id => "package_#{p}" diff --git a/src/app/views/templates/_local_content_to_bundle.haml b/src/app/views/templates/_local_content_to_bundle.haml new file mode 100644 index 0000000..109ce20 --- /dev/null +++ b/src/app/views/templates/_local_content_to_bundle.haml @@ -0,0 +1,21 @@ +%h3.disabled.gap Local Content to Bundle +%fieldset.clearfix + = label_tag :local_bundle_name, 'Local:', :class => "disabled grid_2 alpha" + = text_field_tag 'local_bundle_name[]', 'Bundle Name', :disabled => true, :class => "grid_8" + .grid_6.omega + %button{:type => 'button', :disabled => 'disabled'} Browse + %button{:type => 'button', :disabled => 'disabled'} Config + %button{:type => 'button', :disabled => 'disabled'} Metadata + ( + %a{:href => '#'} Remove + ) + .grid_2.alpha + + = text_field_tag 'local_bundle_name[]', 'Bundle Name', :disabled => true, :class => "grid_8" + .grid_6.omega + %button{:type => 'button', :disabled => 'disabled'} Browse + %button{:type => 'button', :disabled => 'disabled'} Config + %button{:type => 'button', :disabled => 'disabled'} Metadata + ( + %a{:href => '#'} Remove + ) diff --git a/src/app/views/templates/_managed_content.haml b/src/app/views/templates/_managed_content.haml index 86b076f..5b9f13a 100644 --- a/src/app/views/templates/_managed_content.haml +++ b/src/app/views/templates/_managed_content.haml @@ -1,20 +1,21 @@ #selected_packages %h3.gap Managed Content to Bundle .grid_16.alpha.omega - - if @selected_packages.empty? + - if @tpl.packages.empty? No selected packages - else - - repos = @repository_manager.repositories_hash - - @selected_packages.sort.each do |pkg| - - pkg_group = @groups.keys.find {|g| @groups[g][:packages][pkg]} + /- repos = @repository_manager.repositories_hash + - @tpl.packages.sort.each do |pkg| + /- pkg_group = @groups.keys.find {|g| @groups[g][:packages][pkg]} .packagewrap %a.packagename{:id => "package_#{pkg}"}=pkg = hidden_field_tag 'packages[]', pkg, :id => "package_#{pkg}" = submit_tag "Remove", :name => "remove_package_#{pkg}", :id => "remove_package_#{pkg}", :class => 'remove_package' .dropdown - %section - Repository: - %label= (pkg_group and repo = repos[@groups[pkg_group][:repository_id]]) ? repo.name.to_s : ' ' + / we don't display repository for now, it's pretty difficult with current design + /%section + / Repository: + / %label= (pkg_group and repo = repos[@groups[pkg_group][:repository_id]]) ? repo.name.to_s : ' ' %fieldset.nomargin %button{:disabled => true} Browse %button{:disabled => true} Config diff --git a/src/app/views/templates/_metagroup_packages.haml b/src/app/views/templates/_metagroup_packages.haml index c709f97..3e83d34 100644 --- a/src/app/views/templates/_metagroup_packages.haml +++ b/src/app/views/templates/_metagroup_packages.haml @@ -4,16 +4,16 @@ %h4 = "#{@metagroup} Packages" %ul.metagrouppackages - - @metagroup_packages.keys.sort.each do |group| + - @metagroup_packages.sort {|a, b| a[:name] <=> b[:name]}.each do |group| %li - - selected = !@metagroup_packages[group][:selected].nil? + - selected = false %h5 - = check_box_tag 'groups[]', group, selected, {:disabled => selected, :id => "group_#{group}", :class => "softwaregroups #{selected ? 'selected' : ''}"} - = label_tag "group_#{group}", group + = check_box_tag 'selected_groups[]', group[:id], selected, {:disabled => selected, :id => "group_#{group[:id]}", :class => "softwaregroups #{selected ? 'selected' : ''}"} + = label_tag "group_#{group[:id]}", group[:name] %ul - - @metagroup_packages[group][:packages].each do |pkg| + - group[:packages].each do |pkg| %li - selected = @packages.to_a.find {|p| p[:name] == pkg} - = check_box_tag 'packages[]', pkg, selected, {:disabled => selected, :id => "pkg_#{group}_#{pkg}"} - = label_tag "pkg_#{group}_#{pkg}", pkg + = check_box_tag 'selected_packages[]', pkg, selected, {:disabled => selected, :id => "pkg_#{group[:name]}_#{pkg}"} + = label_tag "pkg_#{group[:name]}_#{pkg}", pkg = render :partial => 'addbuttons' diff --git a/src/app/views/templates/_metagroups.haml b/src/app/views/templates/_metagroups.haml new file mode 100644 index 0000000..b4fcf3f --- /dev/null +++ b/src/app/views/templates/_metagroups.haml @@ -0,0 +1,13 @@ +%fieldset.clearfix + .search.grid_4.alpha + %input{:type => "search", :placeholder => "Search for package", :name => 'package_search', :value => params[:package_search], :id => 'package_search'} + %button.action{:id => 'package_search_button'} + .grid_8 + %a.grid_4.omega Advanced Search + +%ul.metagroups{:class => 'packagegroupsidebar grid_4 alpha'} + %li + = submit_tag 'Collections', :name => 'collections', :id => 'collections', :class => 'icon' + - @metagroups.keys.sort.each do |cat| + %li + = submit_tag cat, :name => "metagroup_packages", :class => 'icon' diff --git a/src/app/views/templates/_preboot_configuration.haml b/src/app/views/templates/_preboot_configuration.haml new file mode 100644 index 0000000..79ae839 --- /dev/null +++ b/src/app/views/templates/_preboot_configuration.haml @@ -0,0 +1,11 @@ +%h3.clear.gap Preboot Configuration +%fieldset.clearfix + .grid_4.alpha + = radio_button_tag :configure_via_script, 'no', :disabled => true + = label_tag :configure_via_script, 'Configure Via Script' + = file_field_tag 'script_file', :disabled => true, :class => 'grid_12 omega' +%fieldset.clearfix + .grid_4.alpha + = radio_button_tag :configure_via_script, 'no', :disabled => true + = label_tag :configure_via_script, 'Configure Via Script' + = file_field_tag 'script_file', :disabled => true, :class => 'grid_12 omega' diff --git a/src/app/views/templates/_search_packages.haml b/src/app/views/templates/_search_packages.haml new file mode 100644 index 0000000..873f2ab --- /dev/null +++ b/src/app/views/templates/_search_packages.haml @@ -0,0 +1,45 @@ +:javascript + $(document).ready(function() { + $('.pagination input[type=submit]').click(function(e) { + e.preventDefault(); + var url = '#{url_for :action => 'dispatch', :id => @id}'; + var old_pkgs = $("input:hidden[name='cached_packages[]']").map(function() {return $(this).val()}).get(); + var new_pkgs = $("input:checked[name='selected_packages[]']").map(function() {return $(this).val()}).get(); + var data = { + 'selected_packages[]': $("input:hidden[name='packages[]']").map(function() {return $(this).val()}).get(), + 'cached_packages[]': old_pkgs.concat(new_pkgs), + 'selected_groups[]': $("input:checked[name='groups[]']").map(function() {return $(this).val()}).get(), + 'package_search': $("input[name='package_search']").val(), + 'old_page': '#{@page}', + 'template_id' : '#{@id.nil? ? nil : @id}', + 'page': $(this).val(), + 'repository': $("select[name='tpl[platform]']").val() + }; + $('#metagrouppackages').empty().addClass('loading'); + $('#metagrouppackages').load(url, data, function() { + $('#metagrouppackages').removeClass('loading'); + }) + }); + }); + +- @cached_packages.uniq.each do |pkg| + = hidden_field_tag 'cached_packages[]', pkg + +- if params[:package_search].empty? + Search string is empty. +-else + %h4 + = "Search Results for '#{params[:package_search]}'" + %ul.searchedpackages + - @searched_packages.sort {|a, b| a [:name] <=> b[:name]}.each do |pkg| + %li + - selected = (@packages.to_a.find {|p| p[:name] == pkg[:name]} or @cached_packages.include?(pkg[:name])) + - disabled = @tpl.packages.include?(pkg[:name]) + = check_box_tag 'selected_packages[]', pkg[:name], selected, {:disabled => disabled, :id => "pkg_#{pkg[:name]}"} + = label_tag "pkg_#{pkg[:name]}", pkg[:name] + .pageinfo + = page_entries_info @searched_packages, :entry_name => 'package' + = will_paginate @searched_packages, :params => {:package_search => params[:package_search]}, :renderer => TemplatesHelper::ButtonPaginationRenderer.new, :previous_label => 'Previous', :next_label => 'Next' + + + = render :partial => 'addbuttons' diff --git a/src/app/views/templates/_searched_packages.haml b/src/app/views/templates/_searched_packages.haml deleted file mode 100644 index 6533f1a..0000000 --- a/src/app/views/templates/_searched_packages.haml +++ /dev/null @@ -1,43 +0,0 @@ -:javascript - $(document).ready(function() { - $('.pagination input[type=submit]').click(function(e) { - e.preventDefault(); - var url = '#{url_for :action => 'dispatch', :id => @id}'; - var old_pkgs = $("input:hidden[name='cached_packages[]']").map(function() {return $(this).val()}).get(); - var new_pkgs = $("input:checked[name='packages[]']").map(function() {return $(this).val()}).get(); - var data = { - 'selected_packages[]': $("input:hidden[name='packages[]']").map(function() {return $(this).val()}).get(), - 'cached_packages[]': old_pkgs.concat(new_pkgs), - 'selected_groups[]': $("input:checked[name='groups[]']").map(function() {return $(this).val()}).get(), - 'package_search': $("input[name='package_search']").val(), - 'old_page': '#{@page}', - 'template_id' : '#{@id.nil? ? nil : @id}', - 'page': $(this).val(), - 'repository': $("select[name='tpl[platform]']").val() - }; - $('#metagrouppackages').empty().addClass('loading'); - $('#metagrouppackages').load(url, data, function() { - $('#metagrouppackages').removeClass('loading'); - Aggregator.hook_selected_packages(); - }) - }); - }); - -- @cached_packages.uniq.each do |pkg| - = hidden_field_tag 'cached_packages[]', pkg - -%h4 - = "Search Results for '#{params[:package_search]}'" -%ul.searchedpackages - - @searched_packages.sort.each do |pkg| - %li - - selected = (@packages.to_a.find {|p| p[:name] == pkg} or @cached_packages.include?(pkg)) - - disabled = params[:selected_packages].to_a.include?(pkg) - = check_box_tag 'packages[]', pkg, selected, {:disabled => disabled, :id => "pkg_#{pkg}"} - = label_tag "pkg_#{pkg}", pkg -.pageinfo - = page_entries_info @searched_packages, :entry_name => 'package' -= will_paginate @searched_packages, :params => {:package_search => params[:package_search]}, :renderer => TemplatesHelper::ButtonPaginationRenderer.new, :previous_label => 'Previous', :next_label => 'Next' - - -= render :partial => 'addbuttons' diff --git a/src/app/views/templates/_software_selection.haml b/src/app/views/templates/_software_selection.haml new file mode 100644 index 0000000..79bbe1e --- /dev/null +++ b/src/app/views/templates/_software_selection.haml @@ -0,0 +1,39 @@ +:javascript + $(document).ready(function() { + var $metagrouppackages = $('#metagrouppackages'); + $('.metagroups input').click(function(e) { + e.preventDefault(); + var data = { + 'repository': $("select[name='tpl[platform]']").val(), + 'packages[]': $("input:hidden[name='packages[]']").map(function() {return $(this).val()}).get() + }; + if ($(this).attr('name') == 'collections') { + var url = '#{url_for :action => 'collections', :id => @id}'; + } else { + var url = '#{url_for :action => 'metagroup_packages', :id => @id}'; + data.metagroup_packages = e.currentTarget.value; + } + $metagrouppackages.empty().addClass('loading'); + $metagrouppackages.load(url, data, function() { + $metagrouppackages.removeClass('loading'); + //select all packages in collection + $(".softwaregroups").click(function() { + if ($(this).attr("checked") === true) { + $(this).parent().siblings("ul").find("input[type='checkbox']").attr("checked","checked"); + } else { + $(this).parent().siblings("ul").find("input[type='checkbox']").removeAttr("checked"); + } + }); + }); + }); + }); + +.grid_16 + %h4 Managed Content Selection + + - form_tag :action => 'dispatch' do + - unless request.xhr? + = render :partial => 'hidden_fields' + = render :partial => 'metagroups' + #metagrouppackages.grid_12.omega.gap + = render :partial => view diff --git a/src/app/views/templates/build_form.haml b/src/app/views/templates/build_form.haml deleted file mode 100644 index 7084f39..0000000 --- a/src/app/views/templates/build_form.haml +++ /dev/null @@ -1,55 +0,0 @@ -%h2 BUILD REQUEST -- form_tag :action => 'build' do - = hidden_field_tag :template_id, @tpl.id - %h3 Deployment Definition - %fieldset.clearfix - = label_tag :deploy_name, 'Deployment Definition Name:', :class => 'grid_4' - = text_field_tag 'deploy_name', 'Deployment Name', :disabled => true, :class => 'grid_3' - = text_field_tag 'deploy_description', 'Deployment Description', :disabled => true, :class => 'grid_3' - %fieldset.clearfix - .prefix_4.grid_6 - = check_box_tag 'use_for_machine', 1, true, :disabled => true - = label_tag 'use_for_machine', 'Use for Machine Definition Name and Description' - %fieldset.clearfix - .grid_7 - = file_field :templates, :choose_logo, :value => 'Choose Logo', :disabled => true - = text_field :templates, :logo_text, :value => 'Logo Text (5 characters)', :disabled => true, :class => "grid_3" - - %fieldset.clearfix - %label.grid_4{:for => :template_group} - Template Category: - .grid_3 - = select_tag(:template_group, options_for_select([['User Private', 1]])) - - %h3 Deployment Options - %fieldset.clearfix - .grid_6 - %label OS: - = @tpl.platform - .grid_3 - Hardware Profile - .grid_3.suffix_3 - Locale - %fieldset.clearfix - .grid_3 - %label OS Version: - = @tpl.platform_version - .grid_3.ra - %label Global Settings: - .grid_3 - Small - .grid_3 - Any - .grid_3 - = submit_tag "Config", :name => "config", :disabled => true - %h3 Build Options - %label Choose Provider Format: - %section.clearfix.gap - %ul.block - - @all_targets.each do |target_id, target| - %li - = check_box_tag 'targets[]', target_id, false - = label_tag 'targets[]', target['name'] - - = submit_tag "Submit to Build", :name => "build" - = submit_tag "Cancel", :name => "cancel" diff --git a/src/app/views/templates/builds.haml b/src/app/views/templates/builds.haml deleted file mode 100644 index 0d2d5ce..0000000 --- a/src/app/views/templates/builds.haml +++ /dev/null @@ -1,89 +0,0 @@ -- columns = [ | - {:name => 'NAME', :sort_attr => 'templates.name'}, | - {:name => 'OS', :sort_attr => 'templates.platform'}, | - {:name => 'VERSION', :sort_attr => 'templates.platform_version'}, | - {:name => 'ARCH', :sort_attr => 'templates.architecture'}, | - {:name => 'STATUS', :sort_attr => 'status'}, | -] | - -- form_tag :action => "" do - .actionsidebar.grid_3 - %dl - %dt Build Job Actions - %dd - %h5 JOB QUEUE - %ul - %li.delete - %span - = submit_tag "Cancel Job", :name => "job_details", :disabled => true, :class => "icon" - %li.show - %span - = submit_tag "Show Job Details", :name => "job_details", :disabled => true, :class => "icon" - %li.show - %span - = submit_tag "Show Job Log", :name => "job_log", :disabled => true, :class => "icon" - %li.clear - %span - = submit_tag "Clear Job History", :name => "job_history", :disabled => true, :class => "icon" - - .grid_13 - %h1 Status - %section.wrap.status - %label.grid_4.alpha Image Warehouse Status: - .grid_3.suffix_6.omega - %span.good - Green - - %label.grid_4.alpha Total Builds in Queue: - .grid_3.suffix_6.omega - = @running_images.size - - %label.grid_4.alpha Number of VM's Building: - .grid_3.suffix_6.omega - = @running_images.select {|i| i.status == Image::STATE_BUILDING}.size - - %h1 Running - - %table - = sortable_table_header(columns) - %tbody - - if @running_images.empty? - %tr - %td{:colspan => 5} No Images - - else - - @running_images.each do |img| - %tr - %td= img.template.name - %td= img.template.platform - %td= img.template.platform_version - %td= img.template.architecture - %td= img.status - - - unless @failed_images.empty? - %h1 Failed - %table - = sortable_table_header(columns) - %tbody - - @failed_images.each do |img| - %tr - %td= img.template.name - %td= img.template.platform - %td= img.template.platform_version - %td= img.template.architecture - %td= img.status - - %h1 Completed - %table - = sortable_table_header(columns) - %tbody - - if @completed_images.empty? - %tr - %td{:colspan => 5} No Images - - else - - @completed_images.each do |img| - %tr - %td= img.template.name - %td= img.template.platform - %td= img.template.platform_version - %td= img.template.architecture - %td OK diff --git a/src/app/views/templates/collections.haml b/src/app/views/templates/collections.haml new file mode 100644 index 0000000..a899c85 --- /dev/null +++ b/src/app/views/templates/collections.haml @@ -0,0 +1 @@ += render :partial => 'software_selection', :locals => {:view => 'collections'} diff --git a/src/app/views/templates/content_selection.haml b/src/app/views/templates/content_selection.haml deleted file mode 100644 index 689c33d..0000000 --- a/src/app/views/templates/content_selection.haml +++ /dev/null @@ -1,56 +0,0 @@ -:javascript - $(document).ready(function() { - var $metagrouppackages = $('#metagrouppackages'); - $('.metagroups input[name="show_metagroup"]').click(function(e) { - e.preventDefault(); - var data = { - 'show_metagroup': e.currentTarget.value, - 'repository': $("select[name='tpl[platform]']").val(), - 'packages[]': $("input:hidden[name='packages[]']").map(function() {return $(this).val()}).get() - }; - var url = '#{url_for :action => 'dispatch', :id => @id}'; - $metagrouppackages.empty().addClass('loading'); - $metagrouppackages.load(url, data, function() { - $metagrouppackages.removeClass('loading'); - Aggregator.hook_selected_packages(); - //select all packages in collection - $(".softwaregroups").click(function() { - if ($(this).attr("checked") === true) { - $(this).parent().siblings("ul").find("input[type='checkbox']").attr("checked","checked"); - } else { - $(this).parent().siblings("ul").find("input[type='checkbox']").removeAttr("checked"); - } - }); - }); - }); - Aggregator.hook_selected_packages(); - }); - -.grid_16 - %h4 Managed Content Selection - - - form_tag :action => "dispatch" do - - unless @embed - = render :partial => 'hidden_fields' - - @packages.each do |p| - <input type="hidden" id="selected_package_#{p[:name]}" name="selected_packages[]" value="#{p[:name]}" /> - %fieldset.clearfix - .search.grid_4.alpha - %input{:type => "search", :placeholder => "Search for package", :name => 'package_search', :value => params[:package_search]} - %button.action - .grid_8 - %a.grid_4.omega Advanced Search - - %ul.metagroups{:class => 'packagegroupsidebar grid_4 alpha'} - %li - = submit_tag 'Collections', :name => 'show_metagroup', :id => 'collections', :class => 'icon' - - @metagroups.keys.sort.each do |cat| - %li - = submit_tag cat, :name => "show_metagroup", :class => 'icon' - #metagrouppackages.grid_12.omega.gap - - if @collections - = render :partial => 'collections' - - elsif @searched_packages - = render :partial => 'searched_packages' - - else - = render :partial => 'metagroup_packages' diff --git a/src/app/views/templates/edit.haml b/src/app/views/templates/edit.haml new file mode 100644 index 0000000..a2fece4 --- /dev/null +++ b/src/app/views/templates/edit.haml @@ -0,0 +1,6 @@ +#dropdown +.grid_16 + %h2 Edit Template + - form_for @tpl, :url => {:action => 'dispatch'} do + = hidden_field_tag :id, @tpl.id + = render :partial => 'form' diff --git a/src/app/views/templates/index.haml b/src/app/views/templates/index.haml index 0d4c515..38b32de 100644 --- a/src/app/views/templates/index.haml +++ b/src/app/views/templates/index.haml @@ -1,4 +1,4 @@ -- form_tag(:action => 'action') do +- form_tag(:action => 'index_action') do .actionsidebar.grid_3 %dl %dt Actions diff --git a/src/app/views/templates/metagroup_packages.haml b/src/app/views/templates/metagroup_packages.haml new file mode 100644 index 0000000..9703663 --- /dev/null +++ b/src/app/views/templates/metagroup_packages.haml @@ -0,0 +1 @@ += render :partial => 'software_selection', :locals => {:view => 'metagroup_packages'} diff --git a/src/app/views/templates/new.haml b/src/app/views/templates/new.haml index 669babb..9ae8525 100644 --- a/src/app/views/templates/new.haml +++ b/src/app/views/templates/new.haml @@ -1,161 +1,5 @@ -:javascript - $(document).ready(function() { - var $content_container = $('#managed_content'); - var $sel_pkg_container = $('#package_selection_list'); - var $submit = $('#add_software_button'); - $submit.click(function(e) { - e.preventDefault(); - $submit.hide(); - var data = { - 'packages[]': $("input[name='packages[]']").map(function() {return $(this).val()}).get(), - 'repository': $("select[name='tpl[platform]']").val() || '' - } - var url = '#{url_for :action => 'content_selection', :embed => true, :id => @id}'; - //$content_container.empty().show(); - $sel_pkg_container.empty().show().addClass('loading'); - $sel_pkg_container.load(url, data, function(){ - $sel_pkg_container.removeClass('loading'); - var $groups = $('.softwaregroups .disclosure', this); - //search - $("input[name='package_search']").keypress(function(event) { - if (event.keyCode == '13') { - event.preventDefault(); - $("input[name=package_search] ~ button").click(); - } - }); - $("input[name=package_search] ~ button").click(function(event) { - event.preventDefault(); - var data = { - 'packages[]': $("input:text[name='packages[]']").map(function() {return $(this).val()}).get(), - 'package_search': $("input[name='package_search']").val(), - 'repository': $("select[name='tpl[platform]']").val() - }; - var url = '#{url_for :action => 'dispatch', :id => @id}'; - $('#metagrouppackages').empty().addClass('loading'); - $('#metagrouppackages').load(url, data, function() { - $('#metagrouppackages').removeClass('loading'); - Aggregator.hook_selected_packages(); - }); - }); - }); - }); - //removing packages from the list - $('.remove_package').live('click', function (e) { - e.preventDefault(); - $(this).parent().hide(300, function () { - $(this).remove(); - }); - }); - //displaying extended package info and actions - $('.dropdown').hide(); - $('.packagename').live('click', function () { - var dropdowncontent = $(this).siblings('.dropdown').html(), - $dropdown = $("#dropdown"); - $('.packagewrap').removeClass('selected'); - $(this).parent().addClass('selected'); - $dropdown.empty().html(dropdowncontent).css({ - 'top': $(this).positionAncestor('#content').top + 17, - 'left': $(this).positionAncestor('#content').left - 4 - }).show(); - }); - //catch #content clicks and hide the #dropdown if it's not within it - $("#content").click(function (e) { - if(!e.target.id === 'dropdown' || !$(e.target).closest("#dropdown").length) { - $("#dropdown").hide(); - $('.packagewrap').removeClass('selected'); - } - }); - // select correct package repo when we change platform - $("select[name='tpl[platform]']").change(function() { - if ($submit.is(':hidden')) { - $submit.trigger('click'); - } - }); - Aggregator.hook_selected_packages = function() { - $('#do_add_software').live('click', function(e) { - e.preventDefault(); - var $button = $(this).clone(); - var label = "<span id='do_add_software' class='loading fl'>Adding Packages</span>"; - var url = '#{url_for :action => 'managed_content'}'; - var new_pkgs = $("input:checked[name='packages[]']").map(function() {return $(this).val()}).get(); - var old_pkgs = $("input:hidden[name='packages[]']").map(function() {return $(this).val()}).get() - var cached_pkgs = $("input:hidden[name='cached_packages[]']").map(function() {return $(this).val()}).get() - var data = { - 'selected_packages[]': old_pkgs.concat(new_pkgs.concat(cached_pkgs)), - 'selected_groups[]': $("input:checked[name='groups[]']").map(function() {return $(this).val()}).get(), - 'cached_packages[]': $("input:text[name='cached[]']").map(function() {return $(this).val()}).get(), - 'collections': $("input:hidden[name=collections]").val(), - 'template_id' : '#{@id.nil? ? nil : @id}' - }; - $(this).replaceWith(label); - $('#managed_content').load(url, data, function(){ - $("input:checked[name='groups[]']").attr('disabled', 'disabled'); - $("input:checked[name='packages[]']").attr('disabled', 'disabled'); - $('#add_software_button').show(); - $('.dropdown').hide(); - $('#do_add_software').replaceWith($button); - }); - }); - $('#cancel_add_software').click(function(e) { - e.preventDefault(); - $('#package_selection_list').hide(); - $('#add_software_button').show(); - $('.dropdown').hide(); - }); - } - }); - #dropdown .grid_16 - %h2 Template - - form_for @tpl, :url => { :action => "dispatch" } do - <input type="hidden" id="id" name="id" value="#{@id}" /> - = hidden_field :tpl, :id - = error_messages_for :tpl, :object_name => 'template' - = render :partial => 'basics' - - %h3.disabled.gap Local Content to Bundle - %fieldset.clearfix - = label_tag :local_bundle_name, 'Local:', :class => "disabled grid_2 alpha" - = text_field_tag 'local_bundle_name[]', 'Bundle Name', :disabled => true, :class => "grid_8" - .grid_6.omega - %button{:type => 'button', :disabled => 'disabled'} Browse - %button{:type => 'button', :disabled => 'disabled'} Config - %button{:type => 'button', :disabled => 'disabled'} Metadata - ( - %a{:href => '#'} Remove - ) - .grid_2.alpha - - = text_field_tag 'local_bundle_name[]', 'Bundle Name', :disabled => true, :class => "grid_8" - .grid_6.omega - %button{:type => 'button', :disabled => 'disabled'} Browse - %button{:type => 'button', :disabled => 'disabled'} Config - %button{:type => 'button', :disabled => 'disabled'} Metadata - ( - %a{:href => '#'} Remove - ) - - #managed_content - = render :partial => 'managed_content' - - .clearfix - .grid_16.alpha.omega - = submit_tag "Add Software", :name => "add_software_form", :id => "add_software_button", :class => "iconbutton" - - #package_selection_list{:style => 'display: none'} - - %h3.clear.gap Preboot Configuration - %fieldset.clearfix - .grid_4.alpha - = radio_button_tag :configure_via_script, 'no', :disabled => true - = label_tag :configure_via_script, 'Configure Via Script' - = file_field_tag 'script_file', :disabled => true, :class => 'grid_12 omega' - %fieldset.clearfix - .grid_4.alpha - = radio_button_tag :configure_via_script, 'no', :disabled => true - = label_tag :configure_via_script, 'Configure Via Script' - = file_field_tag 'script_file', :disabled => true, :class => 'grid_12 omega' - - = submit_tag "Save", :name => "save", :class => "formbutton" - = submit_tag "Cancel", :name => "cancel", :class => "formbutton" + %h2 New Template + - form_for @tpl, :url => {:action => 'dispatch'} do + = render :partial => 'form' diff --git a/src/app/views/templates/search_packages.haml b/src/app/views/templates/search_packages.haml new file mode 100644 index 0000000..94e30f5 --- /dev/null +++ b/src/app/views/templates/search_packages.haml @@ -0,0 +1 @@ += render :partial => 'software_selection', :locals => {:view => 'search_packages'} diff --git a/src/config/navigation.rb b/src/config/navigation.rb index 95d5e05..27b44cf 100644 --- a/src/config/navigation.rb +++ b/src/config/navigation.rb @@ -30,10 +30,8 @@ SimpleNavigation::Configuration.run do |navigation| second_level.item :assistance_requests, t(:assistance_requests), '#', :class => 'disabled' end first_level.item :define, t(:define), '#', :class => 'build' do |second_level| - # TODO: currently we exclude /templates/builds (next tab), but - # we could have special controller for builds in future - second_level.item :deployables, t(:deployables), {:controller => 'templates'}, :highlights_on => /(/templates$|/templates/(?!builds))/ - second_level.item :builds, t(:builds), :controller => 'templates', :action => 'builds' + second_level.item :deployables, t(:deployables), {:controller => 'templates'}, :highlights_on => //templates/ + second_level.item :builds, t(:builds), :controller => 'builds', :action => 'index' second_level.item :images, t(:images), '#', :class => 'disabled' end first_level.item :runtime, t(:runtime), '#', :class => 'runtime' do |second_level| diff --git a/src/config/routes.rb b/src/config/routes.rb index 931c97f..146e16f 100644 --- a/src/config/routes.rb +++ b/src/config/routes.rb @@ -46,7 +46,7 @@ ActionController::Routing::Routes.draw do |map|
map.dashboard '/dashboard', :controller => 'dashboard' map.instance '/instances', :controller => 'instances' - map.templates '/templates', :controller => 'templates' + # map.templates '/templates', :controller => 'templates' map.settings '/settings', :controller => 'settings' map.root :dashboard
@@ -57,6 +57,14 @@ ActionController::Routing::Routes.draw do |map| end map.destroy_providers_account '/providers/:provider_id/accounts/:id/destroy', :controller => 'cloud_accounts', :action => 'destroy', :conditions => { :method => :get }
+ map.resources :templates, :collection => { :destroy_multiple => :get }, + :member => { + :assembly => :get, + :deployment_definition => :get, + :action => :get, + } + map.resources :builds + # Allow downloading Web Service WSDL as a file with an extension # instead of a file named 'wsdl' map.connect ':controller/service.wsdl', :action => 'wsdl' diff --git a/src/features/step_definitions/general_steps.rb b/src/features/step_definitions/general_steps.rb new file mode 100644 index 0000000..df1f588 --- /dev/null +++ b/src/features/step_definitions/general_steps.rb @@ -0,0 +1,3 @@ +Then /^I should see an input "([^"]*)"$/ do |value| + response.should have_selector("form input[value=#{value}]") +end diff --git a/src/features/step_definitions/template_steps.rb b/src/features/step_definitions/template_steps.rb index 65b89c1..894bf0a 100644 --- a/src/features/step_definitions/template_steps.rb +++ b/src/features/step_definitions/template_steps.rb @@ -17,8 +17,7 @@ Given /^There is a mock pulp repository$/ do end
Given /^there is a "([^"]*)" template$/ do |name| - @template = Factory.build :template - @template.xml.name = name + @template = Factory.build :template, :name => name @template.save! end
@@ -27,14 +26,13 @@ Given /^there is a package group$/ do end
Given /^no package is selected$/ do - @template.xml.packages = [] + @template.packages = [] end
Given /^there is one selected package$/ do pkg = RepositoryManager.new.all_packages.first - @template.xml.packages = [] - @template.xml.add_package(pkg['name'], nil) - @template.save_xml! + @template.packages = [pkg['name']] + @template.save! end
# "I jump" is used instead of "I am" because "I am" is already defined in @@ -72,8 +70,7 @@ Then /^I should see "([^"]*)" followed by "([^"]*)"$/ do |arg1, arg2| end
Given /^there is a "([^"]*)" build$/ do |arg1| - template = Factory.build :template - template.xml.name = arg1 + template = Factory.build :template, :name => arg1 template.save! image = Factory.build(:image, :template => template) image.save! diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb index e948161..1c73ffa 100644 --- a/src/features/support/paths.rb +++ b/src/features/support/paths.rb @@ -66,16 +66,16 @@ module NavigationHelpers url_for :action => 'new', :controller => 'permissions', :only_path => true
when /the new template page/ - url_for :action => 'new', :controller => 'templates', :only_path => true + url_for new_template_path
when /the template builds page/ - url_for :action => 'builds', :controller => 'templates', :only_path => true + url_for builds_path
when /the templates page/ templates_path
when /the create template page/ - url_for :action => 'create', :controller => 'templates', :only_path => true + url_for create_template_path
when /the self service settings page/ url_for :action => 'self_service', :controller => 'settings', :only_path => true diff --git a/src/features/template.feature b/src/features/template.feature index 3404638..4ce0151 100644 --- a/src/features/template.feature +++ b/src/features/template.feature @@ -21,27 +21,38 @@ Feature: Manage Templates And I should see "Template saved" And I should see "mocktemplate"
- Scenario: Add group and remove package to/from the template - Given I am on the templates page - When I press "Template" - Then I should be on the new template page - When I fill in the following: - | tpl_name | mocktemplate | - And I press "Add Software" - Then I should see "Managed Content Selection" - When I press "Collections" - And I check "group_deltacloud" + Scenario: Add a searched package to a new template + Given I am on the new template page + When I press "Add Software" + And I fill in "package_search" with "libdeltacloud" + And I press "package_search_button" + Then I should see "libdeltacloud" + When I check "libdeltacloud" And I press "Add Selected" - Then I should see "Managed Content to Bundle" - And the "tpl[name]" field by name should contain "mocktemplate" - And the page should contain "#package_libdeltacloud" selector - When I press "remove_package_libdeltacloud" - Then I should see "Managed Content to Bundle" - And the page should not contain "#package_libdeltacloud" selector - When I press "Save" - Then I should be on the templates page - And I should see "Template saved" - And I should see "mocktemplate" + Then I should see "New Template" + And I should see "libdeltacloud" + + #Scenario: Add group and remove package to/from the template + # Given I am on the templates page + # When I press "Template" + # Then I should be on the new template page + # When I fill in the following: + # | tpl_name | mocktemplate | + # And I press "Add Software" + # Then I should see "Managed Content Selection" + # When I press "Collections" + # And I check "group_deltacloud" + # And I press "Add Selected" + # Then I should see "Managed Content to Bundle" + # And the "tpl[name]" field by name should contain "mocktemplate" + # And the page should contain "#package_libdeltacloud" selector + # When I press "remove_package_libdeltacloud" + # Then I should see "Managed Content to Bundle" + # And the page should not contain "#package_libdeltacloud" selector + # When I press "Save" + # Then I should be on the templates page + # And I should see "Template saved" + # And I should see "mocktemplate"
Scenario: Sorting templates Given there is a "mock1" template @@ -60,3 +71,19 @@ Feature: Manage Templates Then I should see "mock1" followed by "mock2" When I follow "Name" Then I should see "mock2" followed by "mock1" + + Scenario: Search software with empty string + Given I am on the new template page + When I press "Add Software" + And I fill in "package_search" with "" + And I press "package_search_button" + Then I should see "Search string is empty" + + Scenario: Show software selection + Given I am on the new template page + And I press "Add Software" + Then I should see an input "Collections" + # test that we see a metagroup + Then I should see an input "admin-tools" + # test that we see a collection (collections are loaded by default) + And I should see an input "deltacloud" diff --git a/src/spec/controllers/builds_controller_spec.rb b/src/spec/controllers/builds_controller_spec.rb new file mode 100644 index 0000000..ef4f3d4 --- /dev/null +++ b/src/spec/controllers/builds_controller_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe BuildsController do + fixtures :all + before(:each) do + @admin_permission = Factory :admin_permission + @admin = @admin_permission.user + @tuser = Factory :tuser + activate_authlogic + end + + context "when a user has permission to build templates" do + #FIXME: The following functionality needs to come out of the controller + + before(:each) do + UserSession.create(@admin) + @template = Factory.create(:template) + hydra = Typhoeus::Hydra.hydra + hydra.stub(:put, %r{http://localhost:9090/templates/.*%7D).and_return( + Typhoeus::Response.new(:code => 200)) + Factory.create(:mock_cloud_account) + Factory.create(:mock_provider) + end + + it "should create a new Image" do + lambda do + post :create, :template_id => @template.id, :targets => ["mock"] + end.should change(Image, :count).by(1) + end + + it "should create a new ReplicatedImage" do + lambda do + post :create, :template_id => @template.id, :targets => ["mock"] + end.should change(ReplicatedImage, :count).by(1) + end + end +end diff --git a/src/spec/controllers/templates_controller_spec.rb b/src/spec/controllers/templates_controller_spec.rb index 6e23609..0ead1b0 100644 --- a/src/spec/controllers/templates_controller_spec.rb +++ b/src/spec/controllers/templates_controller_spec.rb @@ -13,7 +13,7 @@ describe TemplatesController do it "should allow a user with image_modify permission to create new template" do UserSession.create(@admin) lambda do - post :create, :tpl => { :name => 'template', :platform => 'fedora', :platform_version => '11', :architecture => '64-bit' } + post :create, :tpl => { :name => 'template', :platform => 'fedora' } end.should change(Template, :count).by(1) response.should redirect_to(templates_path) end @@ -23,29 +23,4 @@ describe TemplatesController do get :new response.should_not render_template("new") end - - context "when a user has permission to build templates" do - #FIXME: The following functionality needs to come out of the controller - - before(:each) do - UserSession.create(@admin) - @template = Factory.create(:template) - hydra = Typhoeus::Hydra.hydra - hydra.stub(:put, %r{http://localhost:9090/templates/.*%7D).and_return( - Typhoeus::Response.new(:code => 200)) - Factory.create(:mock_cloud_account) - end - - it "should create a new Image" do - lambda do - post :build, :template_id => @template.id, :targets => ["mock"] - end.should change(Image, :count).by(1) - end - - it "should create a new ReplicatedImage" do - lambda do - post :build, :template_id => @template.id, :targets => ["mock"] - end.should change(ReplicatedImage, :count).by(1) - end - end end diff --git a/src/spec/factories/template.rb b/src/spec/factories/template.rb index 7130370..0305147 100644 --- a/src/spec/factories/template.rb +++ b/src/spec/factories/template.rb @@ -1,25 +1,4 @@ -Factory.sequence :template_name do |n| - "template#{n}" -end - Factory.define :template do |i| - i.xml { %Q{ -<image> - <name>#{Factory.next :template_name}</name> - <repos> - <repo>https://localhost/pulp/repos/jboss2</repo> - </repos> - <os name="Fedora" version="13" architecture="64-bit"/> - <description/> - <services/> - <groups> - <group>JBoss Core Packages</group> - </groups> - <packages> - <package><name>jboss-as5</name><group>JBoss Core Packages</group></package> - <package><name>jboss-jgroups</name><group>JBoss Core Packages</group></package> - </packages> -</image> - } -} + i.sequence(:name) { |n| "template#{n}" } + i.platform 'fedora' end diff --git a/src/spec/models/template_spec.rb b/src/spec/models/template_spec.rb index 407657f..406febd 100644 --- a/src/spec/models/template_spec.rb +++ b/src/spec/models/template_spec.rb @@ -19,7 +19,7 @@ describe Template do
it "should not be valid if template name is too long" do t = Factory.build(:template) - t.xml.name = ('a' * 256) + t.name = ('a' * 256) t.valid?.should be_false t.errors[:name].should_not be_nil t.errors[:name].should =~ /^is too long.*/ diff --git a/src/spec/utils/repository_manager_spec.rb b/src/spec/utils/repository_manager_spec.rb index c2da511..98ff157 100644 --- a/src/spec/utils/repository_manager_spec.rb +++ b/src/spec/utils/repository_manager_spec.rb @@ -8,6 +8,8 @@ describe RepositoryManager do '../fixtures/packagegroups.json')) @packages_json = File.read(File.join(File.dirname(__FILE__), '../fixtures/packages.json')) + @packagegroupcategories_json = File.read(File.join(File.dirname(__FILE__), + '../fixtures/packagegroupcategories.json')) end
before(:each) do @@ -18,6 +20,8 @@ describe RepositoryManager do Typhoeus::Response.new(:code => 200, :body => @packagegroups_json)) hydra.stub(:get, "http://pulptest/repositories/fedora/packages/%22).and_return( Typhoeus::Response.new(:code => 200, :body => @packages_json)) + hydra.stub(:get, "http://pulptest/repositories/fedora/packagegroupcategories/%22).and_return( + Typhoeus::Response.new(:code => 200, :body => @packagegroupcategories_json))
@rmanager = RepositoryManager.new(:config => [{ 'baseurl' => 'http://pulptest', @@ -26,13 +30,23 @@ describe RepositoryManager do }]) end
- it "should return a list of repositories" do + it 'should return a list of repositories' do @rmanager.repositories.should have(1).items @rmanager.repositories.first.id.should eql('fedora') end
- it "should return a list of packagegroups" do + it 'should return a list of packagegroups' do rep = @rmanager.repositories.first - rep.groups.keys.sort.should == ["deltacloud"] + rep.groups.first[:id].should == 'deltacloud' + end + + it 'should return a list of categories' do + @rmanager.categories.should have(1).items + @rmanager.categories.first[:id].should eql('base-system') + end + + it "should return a list of packages" do + @rmanager.packages.should have(2).items + @rmanager.packages.first[:name].should eql('libdeltacloud') end end