<commit_before>module ApplicationController::Performance
  extend ActiveSupport::Concern

  # Process changes to performance charts
  def perf_chart_chooser
    assert_privileges("perf_reload")
    @record = identify_tl_or_perf_record
    @perf_record = @record.kind_of?(MiqServer) ? @record.vm : @record # Use related server vm record

    unless params[:task_id] # First time thru, gather options changed by the user
      @perf_options[:typ]        = params[:perf_typ]          if params[:perf_typ]
      @perf_options[:days]       = params[:perf_days]         if params[:perf_days]
      @perf_options[:rt_minutes] = params[:perf_minutes].to_i if params[:perf_minutes]
      @perf_options[:hourly_date] = params[:miq_date_1] if params[:miq_date_1] && @perf_options[:typ] == "Hourly"
      @perf_options[:daily_date]  = params[:miq_date_1] if params[:miq_date_1] && @perf_options[:typ] == "Daily"
      @perf_options[:index]       = params[:chart_idx] == "clear" ? nil : params[:chart_idx] if params[:chart_idx]
      @perf_options[:parent]      = params[:compare_to].blank? ? nil : params[:compare_to] if params.has_key?(:compare_to)
      @perf_options[:compare_vm]  = params[:compare_vm].blank? ? nil : params[:compare_vm] if params.has_key?(:compare_vm)
      if params[:perf_cat]
        if params[:perf_cat] == "<None>"
          @perf_options[:cat_model] = nil
          @perf_options[:cat] = nil
        else
          @perf_options[:cat_model], @perf_options[:cat] = params[:perf_cat].split(":")
        end
      end
      if params[:perf_vmtype]
        @perf_options[:vmtype] = params[:perf_vmtype] == "<All>" ? nil : params[:perf_vmtype]
      end
      if params.has_key?(:time_profile)
        tp = TimeProfile.find(params[:time_profile]) unless params[:time_profile].blank?
        @perf_options[:time_profile] = params[:time_profile].blank? ? nil : params[:time_profile].to_i
        @perf_options[:tz] = @perf_options[:time_profile_tz] = params[:time_profile].blank? ? nil : tp.tz
        @perf_options[:time_profile_days] = params[:time_profile].blank? ? nil : tp.days
      end
    end

    case @perf_options[:chart_type]
    when :performance
      perf_set_or_fix_dates(@perf_options)  unless params[:task_id] # Set dates if first time thru
      unless @temp[:no_util_data]
        perf_gen_data(refresh="n")      # Go generate the task
        return unless @temp[:charts]    # Return if no charts got created (first time thru async rpt gen)
      end
    end

    render :update do |page|
      if @temp[:parent_chart_data]
        page << 'miq_chart_data = ' + {"candu" => @temp[:chart_data], "parent"    => @temp[:parent_chart_data]}.to_json + ';'
      elsif @temp[:compare_vm_chart_data]
        page << 'miq_chart_data = ' + {"candu" => @temp[:chart_data], "comparevm" => @temp[:compare_vm_chart_data]}.to_json + ';'
      else
        page << 'miq_chart_data = ' + {"candu" => @temp[:chart_data]}.to_json + ';'
      end

# Cannot replace button divs that contain dhtmlx toolbars, use code below to turn on/off individual buttons
#     page.replace("view_buttons_div", :partial=>"layouts/view_buttons")  # Don't need to do view or center buttons, just the perf stuff
#     page.replace("center_buttons_div", :partial=>"layouts/center_buttons")
      if ["host","vm","vm_or_template"].include?(params[:controller])
        pfx = params[:controller] == "vm_or_template" ? "vm_" : ""
        if @perf_options[:typ] == "realtime"
          page << "if(center_tb) center_tb.showItem('#{pfx}perf_refresh');"
          page << "if(center_tb) center_tb.showItem('#{pfx}perf_reload');"
          page << "if(center_tb) center_tb.enableItem('#{pfx}perf_refresh');"
          page << "if(center_tb) center_tb.enableItem('#{pfx}perf_reload');"
        else
          page << "if(center_tb) center_tb.hideItem('#{pfx}perf_refresh');"
          page << "if(center_tb) center_tb.hideItem('#{pfx}perf_reload');"
        end
      end

      page.replace("flash_msg_div", :partial=>"layouts/flash_msg")
      page.replace("perf_options_div", :partial=>"layouts/perf_options")
      page.replace("candu_charts_div", :partial=>"layouts/perf_charts",
                  :locals => {:chart_data => @temp[:chart_data], :chart_set => "candu"})
      unless @temp[:no_util_data]
        if @perf_options[:typ] == "Hourly"
          page << "miq_cal_dateFrom = new Date(#{@perf_options[:sdate].year},#{@perf_options[:sdate].month-1},#{@perf_options[:sdate].day});"
          page << "miq_cal_dateTo   = new Date(#{@perf_options[:edate].year},#{@perf_options[:edate].month-1},#{@perf_options[:edate].day});"
        else
          page << "miq_cal_dateFrom = new Date(#{@perf_options[:sdate_daily].year},#{@perf_options[:sdate_daily].month-1},#{@perf_options[:sdate_daily].day});"
          page << "miq_cal_dateTo   = new Date(#{@perf_options[:edate_daily].year},#{@perf_options[:edate_daily].month-1},#{@perf_options[:edate_daily].day});"
        end
        if @perf_options[:skip_days]
          page << "miq_cal_skipDays = '#{@perf_options[:skip_days]}';"
        else
          page << "miq_cal_skipDays = null;"
        end
        page << 'miqBuildCalendar();'
        page << Charting.js_load_statement
      end
      page << 'miqSparkle(false);'
      if request.parameters["controller"] == "storage" && @perf_options[:cat]
        page << javascript_disable_field('perf_typ')
      end
    end
  end

  # Generate a chart with the top CIs for a given timestamp
  def perf_top_chart
    return if perfmenu_click?

    @record = identify_tl_or_perf_record
    @perf_record = @record.kind_of?(MiqServer) ? @record.vm : @record # Use related server vm record
    if params[:menu_choice]
      legend_idx = params[:menu_choice].split("_").last.split("-").first.to_i - 1
      data_idx = params[:menu_choice].split("_").last.split("-")[-2].to_i - 1
      chart_idx = params[:menu_choice].split("_").last.split("-").last.to_i
      cmd, model, typ = params[:menu_choice].split("_").first.split("-")
      report = @sb[:chart_reports].is_a?(Array) ? report = @sb[:chart_reports][chart_idx] : @sb[:chart_reports]
      data_row = report.table.data[data_idx]
      if @perf_options[:cat]
        top_ids = data_row["assoc_ids_#{report.extras[:group_by_tags][legend_idx]}"][model.downcase.to_sym][:on]
      else
        top_ids = data_row["assoc_ids"][model.downcase.to_sym][:on]
      end
      @perf_options[:top_model] = model.singularize.capitalize
      @perf_options[:top_type] = typ        # day or hour
      @perf_options[:top_ts] = data_row["timestamp"].utc
      @perf_options[:top_ids] = top_ids
    end
    @perf_options[:index] = params[:chart_idx] == "clear" ? nil : params[:chart_idx] if params[:chart_idx]
    @showtype = "performance"
    if request.xml_http_request?  # Is this an Ajax request?
      perf_gen_top_data                   # Generate top data
      return unless @charts               # Return if no charts got created (first time thru async rpt gen)
      render :update do |page|
        page << 'miq_chart_data = ' + {"candu" => @chart_data}.to_json + ';'
        page.replace("candu_charts_div",
                     :partial => "layouts/perf_charts",
                     :locals  => {:chart_data => @chart_data, :chart_set => "candu"})
        page << Charting.js_load_statement
        page << 'miqSparkle(false);'
      end
    else
      drop_breadcrumb( {:name=>params[:bc],
                        :url=>url_for(:id=>@perf_record.id,
                                      :action=>"perf_top_chart",
                                      :bc=>params[:bc],
                                      :escape => false)
                        } )
#     @spin_msg = "Generating chart data..."
      @ajax_action = "perf_top_chart"
      render :action=>"show"
    end
  end

  # Send the current chart report data in text, CSV, or PDF
  def perf_download
    report = @sb[:chart_reports].class == Array ? @sb[:chart_reports].first : @sb[:chart_reports] # Get the first or only report
    report = perf_remove_report_cols(report)  # Remove cols that are not in the current chart
    filename = @breadcrumbs.last[:name] + " - " + report.title
    disable_client_cache
    case params[:typ]
    when "txt"
      send_data(report.to_text,
        :filename => "#{filename}.txt" )
    when "csv"
      send_data(report.to_csv,
        :filename => "#{filename}.csv" )
    end
  end

  private ############################

  # Initiate the backend refresh of realtime c&u data
  def perf_refresh_data
    assert_privileges("perf_refresh")
    @record = identify_tl_or_perf_record
    @perf_record = @record.kind_of?(MiqServer) ? @record.vm : @record # Use related server vm record
    @perf_record.perf_capture_realtime_now
    add_flash(_("Refresh of recent C&U data has been initiated"))
  end

  # Correct any date that is out of the date/range or not allowed in a profile
  def perf_set_or_fix_dates(options)
    # Get start/end dates in selected timezone
    tz = options[:time_profile_tz] || options[:tz]  # Use time profile tz or chosen tz, if no profile tz
    s, e = @perf_record.first_and_last_capture
    if s.nil?
      add_flash(_("No Utilization data available"), :warning)
      @temp[:no_util_data] = true
      return
    end
    sdate = s.in_time_zone(tz)
    edate = e.in_time_zone(tz)
    options[:sdate] = sdate
    options[:edate] = edate

    # Eliminate partial start or end days
    sdate_daily = sdate.hour == 00 ? sdate : sdate + 1.day
    options[:sdate_daily] = sdate_daily
    edate_daily = edate.hour < 23 ? edate - 1.day : edate
    options[:edate_daily] = edate_daily

    if options[:hourly_date] && # Need to clear hourly date if not nil so it will be reset below if
      (options[:hourly_date].to_date < sdate.to_date || options[:hourly_date].to_date > edate.to_date ||  # it is out of range
        (options[:typ] == "Hourly" && options[:time_profile] && !options[:time_profile_days].include?(options[:hourly_date].to_date.wday) ) ) # or not in profile
      options[:hourly_date] = nil
    end
    if options[:daily_date] &&
      (options[:daily_date].to_date < sdate_daily.to_date || options[:daily_date].to_date > edate_daily.to_date)
      options[:daily_date] = nil
    end
    options[:hourly_date] ||= [edate.month, edate.day, edate.year].join("/")
    options[:daily_date] ||= [edate_daily.month, edate_daily.day, edate_daily.year].join("/")

    if options[:typ] == "Hourly" && options[:time_profile]              # If hourly and profile in effect, set hourly date to a valid day in the profile
      options[:skip_days] = [0,1,2,3,4,5,6].delete_if{|d| options[:time_profile_days].include?(d)}.join(",")
      hdate = options[:hourly_date].to_date                             # Start at the currently set hourly date
      6.times do                                                        # Go back up to 6 days (try each weekday)<commit_msg>containers: allow realtime metrics to be displayed<commit_after>module ApplicationController::Performance
  extend ActiveSupport::Concern

  # Process changes to performance charts
  def perf_chart_chooser
    assert_privileges("perf_reload")
    @record = identify_tl_or_perf_record
    @perf_record = @record.kind_of?(MiqServer) ? @record.vm : @record # Use related server vm record

    unless params[:task_id] # First time thru, gather options changed by the user
      @perf_options[:typ]        = params[:perf_typ]          if params[:perf_typ]
      @perf_options[:days]       = params[:perf_days]         if params[:perf_days]
      @perf_options[:rt_minutes] = params[:perf_minutes].to_i if params[:perf_minutes]
      @perf_options[:hourly_date] = params[:miq_date_1] if params[:miq_date_1] && @perf_options[:typ] == "Hourly"
      @perf_options[:daily_date]  = params[:miq_date_1] if params[:miq_date_1] && @perf_options[:typ] == "Daily"
      @perf_options[:index]       = params[:chart_idx] == "clear" ? nil : params[:chart_idx] if params[:chart_idx]
      @perf_options[:parent]      = params[:compare_to].blank? ? nil : params[:compare_to] if params.has_key?(:compare_to)
      @perf_options[:compare_vm]  = params[:compare_vm].blank? ? nil : params[:compare_vm] if params.has_key?(:compare_vm)
      if params[:perf_cat]
        if params[:perf_cat] == "<None>"
          @perf_options[:cat_model] = nil
          @perf_options[:cat] = nil
        else
          @perf_options[:cat_model], @perf_options[:cat] = params[:perf_cat].split(":")
        end
      end
      if params[:perf_vmtype]
        @perf_options[:vmtype] = params[:perf_vmtype] == "<All>" ? nil : params[:perf_vmtype]
      end
      if params.has_key?(:time_profile)
        tp = TimeProfile.find(params[:time_profile]) unless params[:time_profile].blank?
        @perf_options[:time_profile] = params[:time_profile].blank? ? nil : params[:time_profile].to_i
        @perf_options[:tz] = @perf_options[:time_profile_tz] = params[:time_profile].blank? ? nil : tp.tz
        @perf_options[:time_profile_days] = params[:time_profile].blank? ? nil : tp.days
      end
    end

    case @perf_options[:chart_type]
    when :performance
      perf_set_or_fix_dates(@perf_options)  unless params[:task_id] # Set dates if first time thru
      unless @temp[:no_util_data]
        perf_gen_data(refresh="n")      # Go generate the task
        return unless @temp[:charts]    # Return if no charts got created (first time thru async rpt gen)
      end
    end

    if @perf_options[:no_rollups]
      add_flash(_("No Hourly or Daily data is available, real time data " \
                  "from the Most Recent Hour is being displayed"), :warning)
    end

    render :update do |page|
      if @temp[:parent_chart_data]
        page << 'miq_chart_data = ' + {"candu" => @temp[:chart_data], "parent"    => @temp[:parent_chart_data]}.to_json + ';'
      elsif @temp[:compare_vm_chart_data]
        page << 'miq_chart_data = ' + {"candu" => @temp[:chart_data], "comparevm" => @temp[:compare_vm_chart_data]}.to_json + ';'
      else
        page << 'miq_chart_data = ' + {"candu" => @temp[:chart_data]}.to_json + ';'
      end

# Cannot replace button divs that contain dhtmlx toolbars, use code below to turn on/off individual buttons
#     page.replace("view_buttons_div", :partial=>"layouts/view_buttons")  # Don't need to do view or center buttons, just the perf stuff
#     page.replace("center_buttons_div", :partial=>"layouts/center_buttons")
      if ["host","vm","vm_or_template"].include?(params[:controller])
        pfx = params[:controller] == "vm_or_template" ? "vm_" : ""
        if @perf_options[:typ] == "realtime"
          page << "if(center_tb) center_tb.showItem('#{pfx}perf_refresh');"
          page << "if(center_tb) center_tb.showItem('#{pfx}perf_reload');"
          page << "if(center_tb) center_tb.enableItem('#{pfx}perf_refresh');"
          page << "if(center_tb) center_tb.enableItem('#{pfx}perf_reload');"
        else
          page << "if(center_tb) center_tb.hideItem('#{pfx}perf_refresh');"
          page << "if(center_tb) center_tb.hideItem('#{pfx}perf_reload');"
        end
      end

      page.replace("flash_msg_div", :partial=>"layouts/flash_msg")
      page.replace("perf_options_div", :partial=>"layouts/perf_options")
      page.replace("candu_charts_div", :partial=>"layouts/perf_charts",
                  :locals => {:chart_data => @temp[:chart_data], :chart_set => "candu"})
      unless @temp[:no_util_data]
        if @perf_options[:typ] == "Hourly"
          page << "miq_cal_dateFrom = new Date(#{@perf_options[:sdate].year},#{@perf_options[:sdate].month-1},#{@perf_options[:sdate].day});"
          page << "miq_cal_dateTo   = new Date(#{@perf_options[:edate].year},#{@perf_options[:edate].month-1},#{@perf_options[:edate].day});"
        else
          page << "miq_cal_dateFrom = new Date(#{@perf_options[:sdate_daily].year},#{@perf_options[:sdate_daily].month-1},#{@perf_options[:sdate_daily].day});"
          page << "miq_cal_dateTo   = new Date(#{@perf_options[:edate_daily].year},#{@perf_options[:edate_daily].month-1},#{@perf_options[:edate_daily].day});"
        end
        if @perf_options[:skip_days]
          page << "miq_cal_skipDays = '#{@perf_options[:skip_days]}';"
        else
          page << "miq_cal_skipDays = null;"
        end
        page << 'miqBuildCalendar();'
        page << Charting.js_load_statement
      end
      page << 'miqSparkle(false);'
      if request.parameters["controller"] == "storage" && @perf_options[:cat]
        page << javascript_disable_field('perf_typ')
      end
    end
  end

  # Generate a chart with the top CIs for a given timestamp
  def perf_top_chart
    return if perfmenu_click?

    @record = identify_tl_or_perf_record
    @perf_record = @record.kind_of?(MiqServer) ? @record.vm : @record # Use related server vm record
    if params[:menu_choice]
      legend_idx = params[:menu_choice].split("_").last.split("-").first.to_i - 1
      data_idx = params[:menu_choice].split("_").last.split("-")[-2].to_i - 1
      chart_idx = params[:menu_choice].split("_").last.split("-").last.to_i
      cmd, model, typ = params[:menu_choice].split("_").first.split("-")
      report = @sb[:chart_reports].is_a?(Array) ? report = @sb[:chart_reports][chart_idx] : @sb[:chart_reports]
      data_row = report.table.data[data_idx]
      if @perf_options[:cat]
        top_ids = data_row["assoc_ids_#{report.extras[:group_by_tags][legend_idx]}"][model.downcase.to_sym][:on]
      else
        top_ids = data_row["assoc_ids"][model.downcase.to_sym][:on]
      end
      @perf_options[:top_model] = model.singularize.capitalize
      @perf_options[:top_type] = typ        # day or hour
      @perf_options[:top_ts] = data_row["timestamp"].utc
      @perf_options[:top_ids] = top_ids
    end
    @perf_options[:index] = params[:chart_idx] == "clear" ? nil : params[:chart_idx] if params[:chart_idx]
    @showtype = "performance"
    if request.xml_http_request?  # Is this an Ajax request?
      perf_gen_top_data                   # Generate top data
      return unless @charts               # Return if no charts got created (first time thru async rpt gen)
      render :update do |page|
        page << 'miq_chart_data = ' + {"candu" => @chart_data}.to_json + ';'
        page.replace("candu_charts_div",
                     :partial => "layouts/perf_charts",
                     :locals  => {:chart_data => @chart_data, :chart_set => "candu"})
        page << Charting.js_load_statement
        page << 'miqSparkle(false);'
      end
    else
      drop_breadcrumb( {:name=>params[:bc],
                        :url=>url_for(:id=>@perf_record.id,
                                      :action=>"perf_top_chart",
                                      :bc=>params[:bc],
                                      :escape => false)
                        } )
#     @spin_msg = "Generating chart data..."
      @ajax_action = "perf_top_chart"
      render :action=>"show"
    end
  end

  # Send the current chart report data in text, CSV, or PDF
  def perf_download
    report = @sb[:chart_reports].class == Array ? @sb[:chart_reports].first : @sb[:chart_reports] # Get the first or only report
    report = perf_remove_report_cols(report)  # Remove cols that are not in the current chart
    filename = @breadcrumbs.last[:name] + " - " + report.title
    disable_client_cache
    case params[:typ]
    when "txt"
      send_data(report.to_text,
        :filename => "#{filename}.txt" )
    when "csv"
      send_data(report.to_csv,
        :filename => "#{filename}.csv" )
    end
  end

  private ############################

  # Initiate the backend refresh of realtime c&u data
  def perf_refresh_data
    assert_privileges("perf_refresh")
    @record = identify_tl_or_perf_record
    @perf_record = @record.kind_of?(MiqServer) ? @record.vm : @record # Use related server vm record
    @perf_record.perf_capture_realtime_now
    add_flash(_("Refresh of recent C&U data has been initiated"))
  end

  # Correct any date that is out of the date/range or not allowed in a profile
  def perf_set_or_fix_dates(options)
    # Get start/end dates in selected timezone
    tz = options[:time_profile_tz] || options[:tz]  # Use time profile tz or chosen tz, if no profile tz
    s, e = @perf_record.first_and_last_capture('hourly')
    if s.nil?
      s, e = @perf_record.first_and_last_capture('realtime')
      if s.nil?
        add_flash(_("No Utilization data available"), :warning)
        @temp[:no_util_data] = true
        return
      end
      options[:typ] = "realtime"
      options[:no_rollups] = true
    end
    sdate = s.in_time_zone(tz)
    edate = e.in_time_zone(tz)
    options[:sdate] = sdate
    options[:edate] = edate

    # Eliminate partial start or end days
    sdate_daily = sdate.hour == 00 ? sdate : sdate + 1.day
    options[:sdate_daily] = sdate_daily
    edate_daily = edate.hour < 23 ? edate - 1.day : edate
    options[:edate_daily] = edate_daily

    if options[:hourly_date] && # Need to clear hourly date if not nil so it will be reset below if
      (options[:hourly_date].to_date < sdate.to_date || options[:hourly_date].to_date > edate.to_date ||  # it is out of range
        (options[:typ] == "Hourly" && options[:time_profile] && !options[:time_profile_days].include?(options[:hourly_date].to_date.wday) ) ) # or not in profile
      options[:hourly_date] = nil
    end
    if options[:daily_date] &&
      (options[:daily_date].to_date < sdate_daily.to_date || options[:daily_date].to_date > edate_daily.to_date)
      options[:daily_date] = nil
    end
    options[:hourly_date] ||= [edate.month, edate.day, edate.year].join("/")
    options[:daily_date] ||= [edate_daily.month, edate_daily.day, edate_daily.year].join("/")

    if options[:typ] == "Hourly" && options[:time_profile]              # If hourly and profile in effect, set hourly date to a valid day in the profile
      options[:skip_days] = [0,1,2,3,4,5,6].delete_if{|d| options[:time_profile_days].include?(d)}.join(",")
      hdate = options[:hourly_date].to_date                             # Start at the currently set hourly date
      6.times do                                                        # Go back up to 6 days (try each weekday)
{'fraction_non_alphanumeric': 0.142343799128599, 'fraction_numerical': 0.002335713964874455, 'mean_word_length': 3.1818181818181817, 'pattern_counts': {'":': 2, '<': 101, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5524891', 'n_tokens_mistral': 7354, 'n_tokens_neox': 7184, 'n_words': 1463}