diff --git a/ee/app/assets/javascripts/analytics/dashboards/components/comparison_table.vue b/ee/app/assets/javascripts/analytics/dashboards/components/comparison_table.vue index 92399e53eac87b8abdd5434cac7a81493907aa74..ff7ea041f339d9f3c08caafbd1fc0f91e2d13ec8 100644 --- a/ee/app/assets/javascripts/analytics/dashboards/components/comparison_table.vue +++ b/ee/app/assets/javascripts/analytics/dashboards/components/comparison_table.vue @@ -71,7 +71,7 @@ export default { <gl-table-lite :fields="dashboardTableFields" :items="tableData" - table-class="gl-my-0" + table-class="gl-my-0 gl-table-fixed" :tbody-tr-attr="rowAttributes" > <template #head()="{ field: { label, start, end } }"> diff --git a/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/project_value_streams_dashboard.yaml b/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/project_value_streams_dashboard.yaml index cb69d22fcfb45a5e61f3a5d785ac06c84a62e186..e7607d784c2b3a048be23975147731e8f0856d23 100644 --- a/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/project_value_streams_dashboard.yaml +++ b/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/project_value_streams_dashboard.yaml @@ -3,19 +3,74 @@ title: Value Streams Dashboard description: Track key DevSecOps metrics throughout the development lifecycle. version: "2" panels: + - visualization: usage_overview + title: Usage overview for %{namespaceName} %{namespaceType} + gridAttributes: + yPos: 0 + xPos: 0 + width: 12 + height: 1 + options: {} - visualization: dora_chart - title: Metrics comparison for %{namespaceName} %{namespaceType} + title: 'Lifecycle metrics: %{namespaceName} (%{namespaceType})' gridAttributes: yPos: 1 xPos: 0 width: 12 - height: 6 + height: 4 options: {} - - visualization: usage_overview - title: Usage overview for %{namespaceName} %{namespaceType} + queryOverrides: + filters: + excludeMetrics: + - deployment_frequency + - lead_time_for_changes + - time_to_restore_service + - change_failure_rate + - vulnerability_critical + - vulnerability_high + - visualization: dora_chart + title: 'DORA metrics: %{namespaceName} (%{namespaceType})' gridAttributes: - yPos: 0 + yPos: 5 xPos: 0 width: 12 - height: 1 + height: 3 + options: {} + queryOverrides: + filters: + excludeMetrics: + - lead_time + - cycle_time + - issues + - issues_completed + - commits + - deploys + - median_time_to_merge + - merge_request_throughput + - contributor_count + - vulnerability_critical + - vulnerability_high + - visualization: dora_chart + title: 'Security metrics: %{namespaceName} (%{namespaceType})' + gridAttributes: + yPos: 8 + xPos: 0 + width: 12 + height: 2 options: {} + queryOverrides: + filters: + excludeMetrics: + - deployment_frequency + - lead_time_for_changes + - time_to_restore_service + - change_failure_rate + - lead_time + - cycle_time + - issues + - issues_completed + - commits + - deploys + - median_time_to_merge + - merge_request_throughput + - contributor_count diff --git a/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/value_streams_dashboard.yaml b/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/value_streams_dashboard.yaml index 515fa3f639c0ac0fa29254742ab67a7740b897ef..2bd49e25376e372c8c41f4417113a4a66268eddd 100644 --- a/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/value_streams_dashboard.yaml +++ b/ee/lib/gitlab/analytics/value_stream_dashboard/dashboards/value_streams_dashboard.yaml @@ -3,26 +3,81 @@ title: Value Streams Dashboard description: Track key DevSecOps metrics throughout the development lifecycle. version: "2" panels: + - visualization: usage_overview + title: Usage overview for %{namespaceName} %{namespaceType} + gridAttributes: + yPos: 0 + xPos: 0 + width: 12 + height: 1 + options: {} - visualization: dora_chart - title: Metrics comparison for %{namespaceName} %{namespaceType} + title: 'Lifecycle metrics: %{namespaceName} (%{namespaceType})' gridAttributes: yPos: 1 xPos: 0 width: 12 - height: 6 + height: 5 options: {} - - visualization: usage_overview - title: Usage overview for %{namespaceName} %{namespaceType} + queryOverrides: + filters: + excludeMetrics: + - deployment_frequency + - lead_time_for_changes + - time_to_restore_service + - change_failure_rate + - vulnerability_critical + - vulnerability_high + - visualization: dora_chart + title: 'DORA metrics: %{namespaceName} (%{namespaceType})' gridAttributes: - yPos: 0 + yPos: 6 xPos: 0 width: 12 - height: 1 + height: 3 + options: {} + queryOverrides: + filters: + excludeMetrics: + - lead_time + - cycle_time + - issues + - issues_completed + - commits + - deploys + - median_time_to_merge + - merge_request_throughput + - contributor_count + - vulnerability_critical + - vulnerability_high + - visualization: dora_chart + title: 'Security metrics: %{namespaceName} (%{namespaceType})' + gridAttributes: + yPos: 9 + xPos: 0 + width: 12 + height: 2 options: {} + queryOverrides: + filters: + excludeMetrics: + - deployment_frequency + - lead_time_for_changes + - time_to_restore_service + - change_failure_rate + - lead_time + - cycle_time + - issues + - issues_completed + - commits + - deploys + - median_time_to_merge + - merge_request_throughput + - contributor_count - visualization: dora_performers_score title: DORA performers score for %{namespaceName} %{namespaceType} gridAttributes: - yPos: 7 + yPos: 11 xPos: 0 width: 12 height: 4 diff --git a/ee/spec/features/groups/analytics/visualizations_spec.rb b/ee/spec/features/groups/analytics/visualizations_spec.rb index ed9c01b551a569b64e80a0a13cdd01c90deb2e31..016f172fde6482e0623c30c29dae457e76c14ff8 100644 --- a/ee/spec/features/groups/analytics/visualizations_spec.rb +++ b/ee/spec/features/groups/analytics/visualizations_spec.rb @@ -32,8 +32,8 @@ visit_group_value_streams_dashboard(group) end - it_behaves_like 'renders metrics comparison table' do - let(:panel_title) { "#{group.name} group" } + it_behaves_like 'renders metrics comparison tables' do + let(:panel_title) { "#{group.name} (group)" } end it_behaves_like 'renders contributor count' @@ -46,8 +46,8 @@ visit_group_value_streams_dashboard(group) end - it_behaves_like 'renders metrics comparison table' do - let(:panel_title) { "#{group.name} group" } + it_behaves_like 'renders metrics comparison tables' do + let(:panel_title) { "#{group.name} (group)" } end it_behaves_like 'does not render contributor count' diff --git a/ee/spec/features/projects/analytics/dashboards_spec.rb b/ee/spec/features/projects/analytics/dashboards_spec.rb index fa092f7f4a1673ef3ae9a836585e28266b0592fb..111b7f5108078c4cd3870c3b7af43089791c0911 100644 --- a/ee/spec/features/projects/analytics/dashboards_spec.rb +++ b/ee/spec/features/projects/analytics/dashboards_spec.rb @@ -114,8 +114,8 @@ visit_project_value_streams_dashboard(project) end - it_behaves_like 'renders metrics comparison table' do - let(:panel_title) { "#{project.name} project" } + it_behaves_like 'renders metrics comparison tables' do + let(:panel_title) { "#{project.name} (project)" } end end diff --git a/ee/spec/models/product_analytics/dashboard_spec.rb b/ee/spec/models/product_analytics/dashboard_spec.rb index c5821fff6bf9727cba30bcba9f08b7130be405d6..5cec69191b08861afde43e0909bf339e96a0fd8a 100644 --- a/ee/spec/models/product_analytics/dashboard_spec.rb +++ b/ee/spec/models/product_analytics/dashboard_spec.rb @@ -268,9 +268,9 @@ it_behaves_like 'returns the value streams dashboard' it 'returns the correct panels' do - expect(dashboard.panels.size).to eq(3) + expect(dashboard.panels.size).to eq(5) expect(dashboard.panels.map { |panel| panel.visualization.type }).to eq( - %w[DORAChart UsageOverview DoraPerformersScore] + %w[UsageOverview DORAChart DORAChart DORAChart DoraPerformersScore] ) end end @@ -281,8 +281,10 @@ it_behaves_like 'returns the value streams dashboard' it 'returns the correct panels' do - expect(dashboard.panels.size).to eq(2) - expect(dashboard.panels.map { |panel| panel.visualization.type }).to eq(%w[DORAChart UsageOverview]) + expect(dashboard.panels.size).to eq(4) + expect(dashboard.panels.map { |panel| panel.visualization.type }).to eq( + %w[UsageOverview DORAChart DORAChart DORAChart] + ) end end end diff --git a/spec/support/shared_examples/features/value_streams_dashboard_shared_examples.rb b/spec/support/shared_examples/features/value_streams_dashboard_shared_examples.rb index 3a9f20ac35c6d72160ee526e7bafdfdb2f4a31a7..acf5e230f8c217ef2d3bee5602aaccf832272584 100644 --- a/spec/support/shared_examples/features/value_streams_dashboard_shared_examples.rb +++ b/spec/support/shared_examples/features/value_streams_dashboard_shared_examples.rb @@ -44,26 +44,46 @@ end end -RSpec.shared_examples 'renders metrics comparison table' do - let(:metric_table) { find_by_testid('panel-dora-chart') } +RSpec.shared_examples 'renders metrics comparison tables' do + let(:metric_tables) { page.all("[data-testid='panel-dora-chart']") } + let(:lifecycle_metrics_table) { metric_tables[0] } + let(:dora_metrics_table) { metric_tables[1] } + let(:security_metrics_table) { metric_tables[2] } + + def expect_row_content(id, name, values) + row = find_by_testid("dora-chart-metric-#{id}") + + expect(row).to be_visible + expect(row).to have_content name + expect(row).to have_content values + end - it "renders the available metrics" do + before do wait_for_all_requests + end - expect(metric_table).to be_visible - expect(metric_table).to have_content format(_("Metrics comparison for %{title}"), title: panel_title) + it 'renders the Lifecycle metrics table' do + expect(lifecycle_metrics_table).to be_visible + expect(lifecycle_metrics_table).to have_content format(_("Lifecycle metrics: %{title}"), title: panel_title) [ - ['lead-time-for-changes', _('Lead time for changes'), '3.0 d 40.0% 1.0 d 66.7% 0.0 d'], - ['time-to-restore-service', _('Time to restore service'), '3.0 d 57.1% 5.0 d 66.7% 0.0 d'], ['lead-time', _('Lead time'), '4.0 d 33.3% 2.0 d 50.0% -'], ['cycle-time', _('Cycle time'), '3.0 d 50.0% 1.0 d 66.7% -'], ['issues', _('Issues created'), '1 66.7% 2 100.0% -'], ['issues-completed', _('Issues closed'), '1 66.7% 2 100.0% -'], ['deploys', _('Deploys'), '10 25.0% 5 50.0% -'], ['merge-request-throughput', _('Merge request throughput'), '1 50.0% 3 200.0% -'], - ['median-time-to-merge', _('Median time to merge'), '- - -'], - ['vulnerability-critical', _('Critical vulnerabilities over time'), '5 3 -'], - ['vulnerability-high', _('High vulnerabilities over time'), '4 2 -'], + ['median-time-to-merge', _('Median time to merge'), '- - -'] + ].each do |id, name, values| + expect_row_content(id, name, values) + end + end + + it 'renders the DORA metrics table' do + expect(dora_metrics_table).to be_visible + expect(dora_metrics_table).to have_content format(_("DORA metrics: %{title}"), title: panel_title) + [ + ['lead-time-for-changes', _('Lead time for changes'), '3.0 d 40.0% 1.0 d 66.7% 0.0 d'], + ['time-to-restore-service', _('Time to restore service'), '3.0 d 57.1% 5.0 d 66.7% 0.0 d'], # The values of these metrics are dependent on the length of the month they are in. Due to the high # flake risk associated with them, we only validate the expected structure of the table row instead @@ -71,11 +91,18 @@ ['deployment-frequency', _('Deployment frequency'), %r{ 0\.\d+/d \d+\.\d% 0\.\d+/d \d+\.\d% 0\.0/d}], ['change-failure-rate', _('Change failure rate'), %r{0\.0% \d+\.\d% \d+\.\d% \d+\.\d% \d+\.\d%}] ].each do |id, name, values| - row = find_by_testid("dora-chart-metric-#{id}") + expect_row_content(id, name, values) + end + end - expect(row).to be_visible - expect(row).to have_content name - expect(row).to have_content values + it 'renders the Security metrics table' do + expect(security_metrics_table).to be_visible + expect(security_metrics_table).to have_content format(_("Security metrics: %{title}"), title: panel_title) + [ + ['vulnerability-critical', _('Critical vulnerabilities over time'), '5 3 -'], + ['vulnerability-high', _('High vulnerabilities over time'), '4 2 -'] + ].each do |id, name, values| + expect_row_content(id, name, values) end end end