/// <summary> /// Loads summary box in the right upper corner. /// </summary> private void LoadSummaryBox() { lnkTest.HRef = DocumentURLProvider.GetUrl(ABTest.ABTestOriginalPage); lnkTest.InnerText = ShortenUrl(ABTest.ABTestOriginalPage, MAX_LINK_LENGTH); lnkTest.Target = "_blank"; // If Visitors conversion methodology selected, use "Visitors" instead of "Visits" if (drpCountingMethodology.SelectedValue == "absessionconversionfirst") { lblVisits.ResourceString = "abtesting.overview.summary.visitors"; } lblStatus.Text = ABTestStatusEvaluator.GetFormattedStatus(TestStatus).ToString(); int visits = VariantsStatisticsData.Sum(d => d.Value.Visits); int conversions = VariantsStatisticsData.Sum(d => d.Value.ConversionsCount); lblTotalVisitors.Text = String.Format("{0:N0}", visits); lblTotalConversions.Text = String.Format("{0:N0}", conversions); if (TestStatus == ABTestStatusEnum.Finished) { txtDuration.ResourceString = "abtesting.daysrun"; } DateTime start = ABTest.ABTestOpenFrom; DateTime finish = GetFinishDateOrToday(); lblDuration.Text = (finish - start).Days.ToString(); }
/// <summary> /// Ensures statistics data for specific AB variant. /// </summary> /// <param name="variantName">Variant name</param> private void EnsureVariantStatisticsData(string variantName) { if (!VariantsStatisticsData.ContainsKey(variantName)) { // Select both abvisitfirst and abvisitreturn by default string visitType = "abvisit%"; // If counting methodology is set to visitor conversion, select abvisitfirst only string countingMethodology = drpCountingMethodology.Items[mDrpCountingMethodologyIndex].Value; if (countingMethodology == "absessionconversionfirst") { visitType = "abvisitfirst"; } string conversionsCodename = countingMethodology + ";" + ABTest.ABTestName + ";" + variantName; string visitsCodename = visitType + ";" + ABTest.ABTestName + ";" + variantName; // Get conversions count and value DataRow conversions = GetHits(conversionsCodename, "Sum(HitsCount), Sum(HitsValue)", mDrpCultureValue, GetConversionCondition()); int conversionsCount = ValidationHelper.GetInteger(conversions[0], 0); double conversionsValue = ValidationHelper.GetDouble(conversions[1], 0); // Get visits count int visits = ValidationHelper.GetInteger(GetHits(visitsCodename, "Sum(HitsCount)", mDrpCultureValue)[0], 0); // Add statistics data VariantsStatisticsData.Add(variantName, new ABVariantStatisticsData(conversionsCount, conversionsValue, visits)); // Add conversion rate intervals if ((VariantPerformanceCalculator != null) && (visits > 0) && (conversionsCount <= visits)) { ABConversionRateIntervals.Add(variantName, VariantPerformanceCalculator.GetConversionRateInterval(conversionsCount, visits)); } } }
/// <summary> /// Loads summary box in the right upper corner. /// </summary> private void LoadSummaryBox() { var selectionParameters = new NodeSelectionParameters { AliasPath = ABTest.ABTestOriginalPage, CultureCode = ABTest.ABTestCulture, SiteName = SiteContext.CurrentSiteName, SelectOnlyPublished = true, CombineWithDefaultCulture = false }; var node = new TreeProvider().SelectSingleNode(selectionParameters); var shortUrl = ShortenUrl(ABTest.ABTestOriginalPage); var encodedShortUrl = HTMLHelper.HTMLEncode(shortUrl); if (node == null) { lblTest.Text = encodedShortUrl; lblTest.Visible = true; } else { lnkTest.HRef = DocumentURLProvider.GetAbsoluteLiveSiteURL(node); lnkTest.InnerText = encodedShortUrl; lnkTest.Target = "_blank"; lnkTest.Visible = true; } // If Visitors conversion methodology selected, use "Visitors" instead of "Visits" if (drpCountingMethodology.SelectedValue == ABTestConstants.ABSESSIONCONVERSION_FIRST) { lblVisits.ResourceString = "abtesting.overview.summary.visitors"; } lblStatus.Text = ABTestStatusEvaluator.GetFormattedStatus(TestStatus).ToString(); int visits = VariantsStatisticsData.Sum(d => d.Value.Visits); int conversions = VariantsStatisticsData.Sum(d => d.Value.ConversionsCount); lblTotalVisitors.Text = String.Format("{0:N0}", visits); lblTotalConversions.Text = String.Format("{0:N0}", conversions); if (TestStatus == ABTestStatusEnum.Finished) { txtDuration.ResourceString = "abtesting.daysrun"; } DateTime start = ABTest.ABTestOpenFrom; DateTime finish = GetFinishDate(); lblDuration.Text = (finish - start).Days.ToString(); }
/// <summary> /// Ensures statistics data for specific AB variant. /// </summary> /// <param name="variantGuid">Variant GUID</param> private void EnsureVariantStatisticsData(Guid variantGuid) { if (!VariantsStatisticsData.ContainsKey(variantGuid)) { // Select both abvisitfirst and abvisitreturn by default string visitType = "abvisit%"; // If counting methodology is set to visitor conversion, select abvisitfirst only string countingMethodology = drpCountingMethodology.Items[drpCountingMethodologyIndex].Value; if (countingMethodology == ABTestConstants.ABSESSIONCONVERSION_FIRST) { visitType = "abvisitfirst"; } string conversionsCodename = countingMethodology + ";" + ABTest.ABTestName + ";" + variantGuid; string visitsCodename = visitType + ";" + ABTest.ABTestName + ";" + variantGuid; string conversion = ValidationHelper.GetString(drpConversions.SelectedValue, string.Empty); var testConversions = ABTest.ABTestConversionConfiguration.ABTestConversions.Select(c => c.ConversionName); // Get conversions count and value DataRow conversions = GetHits(conversionsCodename, "Sum(HitsCount), Sum(HitsValue)", null, GetConversionCondition(conversion, testConversions)); int conversionsCount = ValidationHelper.GetInteger(conversions[0], 0); double conversionsValue = ValidationHelper.GetDouble(conversions[1], 0); // Get visits count int visits = ValidationHelper.GetInteger(GetHits(visitsCodename, "Sum(HitsCount)", null)[0], 0); // Add statistics data VariantsStatisticsData.Add(variantGuid, new ABVariantStatisticsData(conversionsCount, conversionsValue, visits)); // Add conversion rate intervals if ((VariantPerformanceCalculator != null) && (visits > 0) && (conversionsCount <= visits)) { ABConversionRateIntervals.Add(variantGuid, VariantPerformanceCalculator.GetConversionRateInterval(conversionsCount, visits)); } } }
protected object gridElem_OnExternalDataBound(object sender, string sourceName, object parameter) { if (!RequestHelper.IsPostBack()) { return(string.Empty); } // Handle the grid action first because it doesn't require access to VariantsStatisticsData if (sourceName == "selectwinner") { var gridViewRow = parameter as GridViewRow; if (gridViewRow != null) { var dataRowView = gridViewRow.DataItem as DataRowView; if (dataRowView != null) { var img = sender as CMSGridActionButton; if (img != null) { // Check permissions to select winner if (!IsUserAuthorizedToManageTest) { img.Enabled = false; img.ToolTip = GetString("abtesting.selectwinner.permission.tooltip"); } else { var winner = GetTestWinner(); if (winner != null) { string variantName = (ValidationHelper.GetString(dataRowView["ABVariantName"], "")); if (variantName == winner.ABVariantName) { // Disable action image for the winning variant img.Enabled = false; } else { // Hide action image for other variants img.Visible = false; } } } } } } return(string.Empty); } string currentVariantName = parameter.ToString(); if (String.IsNullOrEmpty(currentVariantName) || (OriginalVariant == null) || !VariantsStatisticsData.ContainsKey(currentVariantName)) { return(string.Empty); } var variantData = VariantsStatisticsData[currentVariantName]; switch (sourceName) { case "name": var variant = ABVariants.FirstOrDefault(v => v.ABVariantName == currentVariantName); if (variant != null) { var link = new HtmlAnchor(); link.InnerText = ResHelper.LocalizeString(variant.ABVariantDisplayName); link.HRef = DocumentURLProvider.GetUrl(variant.ABVariantPath); link.Target = "_blank"; return(link); } break; case "conversionsovervisits": return(variantData.ConversionsCount + " / " + variantData.Visits); case "chancetobeatoriginal": if ((currentVariantName != OriginalVariant.ABVariantName) && (VariantPerformanceCalculator != null) && (variantData.Visits > 0)) { double chanceToBeatOriginal = VariantPerformanceCalculator.GetChanceToBeatOriginal(variantData.ConversionsCount, variantData.Visits); // Check whether the variant is most probably winning already and mark the row green if ((chanceToBeatOriginal >= WINNING_VARIANT_MIN_CHANCETOBEAT) && (variantData.ConversionsCount >= WINNING_VARIANT_MIN_CONVERSIONS)) { AddCSSToParentControl(sender as WebControl, "winning-variant-row"); } return(String.Format("{0:P2}", chanceToBeatOriginal)); } break; case "conversionrate": if ((VariantPerformanceCalculator != null) && (variantData.Visits > 0) && ABConversionRateIntervals.ContainsKey(currentVariantName) && ABConversionRateIntervals.ContainsKey(OriginalVariant.ABVariantName)) { // Render the picture representing how the challenger variant is performing against the original variant return(new ABConversionRateIntervalVisualizer( mMinConversionRateLowerBound, mConversionRateRange, ABConversionRateIntervals[currentVariantName], ABConversionRateIntervals[OriginalVariant.ABVariantName])); } break; case "conversionvalue": return(variantData.ConversionsValue); case "averageconversionvalue": return(String.Format("{0:#.##}", variantData.AverageConversionValue)); case "improvement": if ((currentVariantName != OriginalVariant.ABVariantName) && VariantsStatisticsData.ContainsKey(OriginalVariant.ABVariantName)) { var originalData = VariantsStatisticsData[OriginalVariant.ABVariantName]; switch (drpSuccessMetric.SelectedValue) { case "conversioncount": if (!originalData.ConversionsCount.Equals(0)) { return(GetPercentageImprovementPanel((variantData.ConversionsCount / (double)originalData.ConversionsCount) - 1)); } break; case "conversionvalue": if (!originalData.ConversionsValue.Equals(0)) { return(GetPercentageImprovementPanel((variantData.ConversionsValue / originalData.ConversionsValue) - 1)); } break; case "conversionrate": if (!originalData.ConversionRate.Equals(0)) { return(GetPercentageImprovementPanel((variantData.ConversionRate / originalData.ConversionRate) - 1)); } break; case "averageconversionvalue": if (!originalData.AverageConversionValue.Equals(0)) { return(GetPercentageImprovementPanel((variantData.AverageConversionValue / originalData.AverageConversionValue) - 1)); } break; } } break; } return(string.Empty); }
protected object gridElem_OnExternalDataBound(object sender, string sourceName, object parameter) { // Handle the grid action first because it doesn't require access to VariantsStatisticsData if (sourceName == "selectwinner") { if (parameter is GridViewRow gridViewRow && gridViewRow.DataItem is DataRowView dataRowView) { var action = sender as CMSAccessibleButtonBase; var variantGuid = ValidationHelper.GetGuid(dataRowView["ABVariantGUID"], Guid.Empty); InitializeGridAction(action, variantGuid); } return(string.Empty); } var currentVariantGuid = ValidationHelper.GetGuid(parameter, Guid.Empty); if (currentVariantGuid == Guid.Empty || (OriginalVariant == null) || !VariantsStatisticsData.ContainsKey(currentVariantGuid)) { return(string.Empty); } var variantData = VariantsStatisticsData[currentVariantGuid]; switch (sourceName) { case "name": var variant = ABVariants.FirstOrDefault(v => v.ABVariantGUID == currentVariantGuid); if (variant != null) { return(HTMLHelper.HTMLEncode(ResHelper.LocalizeString(variant.ABVariantDisplayName))); } break; case METRIC_CONVERSIONS_OVER_VISITS: return(variantData.ConversionsCount + " / " + variantData.Visits); case METRIC_CHANCE_TO_BEAT_ORIGINAL: if ((currentVariantGuid != OriginalVariant.ABVariantGUID) && (VariantPerformanceCalculator != null) && (variantData.Visits > 0)) { double chanceToBeatOriginal = VariantPerformanceCalculator.GetChanceToBeatOriginal(variantData.ConversionsCount, variantData.Visits); // Check whether the variant is most probably winning already and mark the row green if ((chanceToBeatOriginal >= WINNING_VARIANT_MIN_CHANCETOBEAT) && (variantData.ConversionsCount >= WINNING_VARIANT_MIN_CONVERSIONS)) { AddCSSToParentControl(sender as WebControl, "winning-variant-row"); } return(String.Format("{0:P2}", chanceToBeatOriginal)); } break; case METRIC_CONVERSION_RATE: if ((VariantPerformanceCalculator != null) && (variantData.Visits > 0) && ABConversionRateIntervals.ContainsKey(currentVariantGuid) && ABConversionRateIntervals.ContainsKey(OriginalVariant.ABVariantGUID)) { // Render the picture representing how the challenger variant is performing against the original variant return(new ABConversionRateIntervalVisualizer( mMinConversionRateLowerBound, mConversionRateRange, ABConversionRateIntervals[currentVariantGuid], ABConversionRateIntervals[OriginalVariant.ABVariantGUID])); } break; case METRIC_CONVERSION_VALUE: return(variantData.ConversionsValue); case METRIC_AVG_CONVERSION_VALUE: return(String.Format("{0:#.##}", variantData.AverageConversionValue)); case "improvement": if ((currentVariantGuid != OriginalVariant.ABVariantGUID) && VariantsStatisticsData.ContainsKey(OriginalVariant.ABVariantGUID)) { var originalData = VariantsStatisticsData[OriginalVariant.ABVariantGUID]; switch (drpSuccessMetric.SelectedValue) { case METRIC_CONVERSION_COUNT: if (!originalData.ConversionsCount.Equals(0)) { return(GetPercentageImprovementPanel((variantData.ConversionsCount / (double)originalData.ConversionsCount) - 1)); } break; case METRIC_CONVERSION_VALUE: if (!originalData.ConversionsValue.Equals(0)) { return(GetPercentageImprovementPanel((variantData.ConversionsValue / originalData.ConversionsValue) - 1)); } break; case METRIC_CONVERSION_RATE: if (!originalData.ConversionRate.Equals(0)) { return(GetPercentageImprovementPanel((variantData.ConversionRate / originalData.ConversionRate) - 1)); } break; case METRIC_AVG_CONVERSION_VALUE: if (!originalData.AverageConversionValue.Equals(0)) { return(GetPercentageImprovementPanel((variantData.AverageConversionValue / originalData.AverageConversionValue) - 1)); } break; } } break; } return(string.Empty); }