diff options
Diffstat (limited to 'app')
5 files changed, 162 insertions, 99 deletions
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue index 28b2c706320..65c1f125b55 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue @@ -3,11 +3,13 @@ import { mapGetters } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; import store from '~/pipelines/stores/test_reports'; import { __ } from '~/locale'; +import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue'; export default { name: 'TestsSuiteTable', components: { Icon, + SmartVirtualList, }, store, props: { @@ -23,6 +25,8 @@ export default { return this.getSuiteTests.length > 0; }, }, + maxShownRows: 30, + typicalRowHeight: 75, }; </script> @@ -34,7 +38,7 @@ export default { </div> </div> - <div v-if="hasSuites" class="test-reports-table js-test-cases-table"> + <div v-if="hasSuites" class="test-reports-table append-bottom-default js-test-cases-table"> <div role="row" class="gl-responsive-table-row table-row-header font-weight-bold fgray"> <div role="rowheader" class="table-section section-20"> {{ __('Class') }} @@ -53,52 +57,58 @@ export default { </div> </div> - <div - v-for="(testCase, index) in getSuiteTests" - :key="index" - class="gl-responsive-table-row rounded align-items-md-start mt-sm-3 js-case-row" + <smart-virtual-list + :length="getSuiteTests.length" + :remain="$options.maxShownRows" + :size="$options.typicalRowHeight" > - <div class="table-section section-20 section-wrap"> - <div role="rowheader" class="table-mobile-header">{{ __('Class') }}</div> - <div class="table-mobile-content pr-md-1">{{ testCase.classname }}</div> - </div> + <div + v-for="(testCase, index) in getSuiteTests" + :key="index" + class="gl-responsive-table-row rounded align-items-md-start mt-xs-3 js-case-row" + > + <div class="table-section section-20 section-wrap"> + <div role="rowheader" class="table-mobile-header">{{ __('Class') }}</div> + <div class="table-mobile-content pr-md-1 text-truncate">{{ testCase.classname }}</div> + </div> - <div class="table-section section-20 section-wrap"> - <div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div> - <div class="table-mobile-content">{{ testCase.name }}</div> - </div> + <div class="table-section section-20 section-wrap"> + <div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div> + <div class="table-mobile-content">{{ testCase.name }}</div> + </div> - <div class="table-section section-10 section-wrap"> - <div role="rowheader" class="table-mobile-header">{{ __('Status') }}</div> - <div class="table-mobile-content text-center"> - <div - class="add-border ci-status-icon d-flex align-items-center justify-content-end justify-content-md-center" - :class="`ci-status-icon-${testCase.status}`" - > - <icon :size="24" :name="testCase.icon" /> + <div class="table-section section-10 section-wrap"> + <div role="rowheader" class="table-mobile-header">{{ __('Status') }}</div> + <div class="table-mobile-content text-center"> + <div + class="add-border ci-status-icon d-flex align-items-center justify-content-end justify-content-md-center" + :class="`ci-status-icon-${testCase.status}`" + > + <icon :size="24" :name="testCase.icon" /> + </div> </div> </div> - </div> - <div class="table-section flex-grow-1"> - <div role="rowheader" class="table-mobile-header">{{ __('Trace'), }}</div> - <div class="table-mobile-content"> - <pre - v-if="testCase.system_output" - class="build-trace build-trace-rounded text-left" - ><code class="bash p-0">{{testCase.system_output}}</code></pre> + <div class="table-section flex-grow-1"> + <div role="rowheader" class="table-mobile-header">{{ __('Trace'), }}</div> + <div class="table-mobile-content"> + <pre + v-if="testCase.system_output" + class="build-trace build-trace-rounded text-left" + ><code class="bash p-0">{{testCase.system_output}}</code></pre> + </div> </div> - </div> - <div class="table-section section-10 section-wrap"> - <div role="rowheader" class="table-mobile-header"> - {{ __('Duration') }} - </div> - <div class="table-mobile-content text-right"> - {{ testCase.formattedTime }} + <div class="table-section section-10 section-wrap"> + <div role="rowheader" class="table-mobile-header"> + {{ __('Duration') }} + </div> + <div class="table-mobile-content text-right pr-sm-1"> + {{ testCase.formattedTime }} + </div> </div> </div> - </div> + </smart-virtual-list> </div> <div v-else> diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue index 96177512e35..6effd6e949d 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue @@ -2,9 +2,13 @@ import { mapGetters } from 'vuex'; import { s__ } from '~/locale'; import store from '~/pipelines/stores/test_reports'; +import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue'; export default { name: 'TestsSummaryTable', + components: { + SmartVirtualList, + }, store, props: { heading: { @@ -24,6 +28,8 @@ export default { this.$emit('row-click', suite); }, }, + maxShownRows: 20, + typicalRowHeight: 55, }; </script> @@ -35,7 +41,7 @@ export default { </div> </div> - <div v-if="hasSuites" class="test-reports-table js-test-suites-table"> + <div v-if="hasSuites" class="test-reports-table append-bottom-default js-test-suites-table"> <div role="row" class="gl-responsive-table-row table-row-header font-weight-bold"> <div role="rowheader" class="table-section section-25 pl-3"> {{ __('Suite') }} @@ -60,66 +66,72 @@ export default { </div> </div> - <div - v-for="(testSuite, index) in getTestSuites" - :key="index" - role="row" - class="gl-responsive-table-row gl-responsive-table-row-clickable test-reports-summary-row rounded cursor-pointer js-suite-row" - @click="tableRowClick(testSuite)" + <smart-virtual-list + :length="getTestSuites.length" + :remain="$options.maxShownRows" + :size="$options.typicalRowHeight" > - <div class="table-section section-25"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Suite') }} - </div> - <div class="table-mobile-content underline cgray pl-3"> - {{ testSuite.name }} + <div + v-for="(testSuite, index) in getTestSuites" + :key="index" + role="row" + class="gl-responsive-table-row gl-responsive-table-row-clickable test-reports-summary-row rounded cursor-pointer js-suite-row" + @click="tableRowClick(testSuite)" + > + <div class="table-section section-25"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Suite') }} + </div> + <div class="table-mobile-content underline cgray pl-3"> + {{ testSuite.name }} + </div> </div> - </div> - <div class="table-section section-25"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Duration') }} + <div class="table-section section-25"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Duration') }} + </div> + <div class="table-mobile-content text-md-left"> + {{ testSuite.formattedTime }} + </div> </div> - <div class="table-mobile-content text-md-left"> - {{ testSuite.formattedTime }} - </div> - </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Failed') }} + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Failed') }} + </div> + <div class="table-mobile-content">{{ testSuite.failed_count }}</div> </div> - <div class="table-mobile-content">{{ testSuite.failed_count }}</div> - </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Errors') }} + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Errors') }} + </div> + <div class="table-mobile-content">{{ testSuite.error_count }}</div> </div> - <div class="table-mobile-content">{{ testSuite.error_count }}</div> - </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Skipped') }} + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Skipped') }} + </div> + <div class="table-mobile-content">{{ testSuite.skipped_count }}</div> </div> - <div class="table-mobile-content">{{ testSuite.skipped_count }}</div> - </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Passed') }} + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Passed') }} + </div> + <div class="table-mobile-content">{{ testSuite.success_count }}</div> </div> - <div class="table-mobile-content">{{ testSuite.success_count }}</div> - </div> - <div class="table-section section-10 text-right pr-md-3"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Total') }} + <div class="table-section section-10 text-right pr-md-3"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Total') }} + </div> + <div class="table-mobile-content">{{ testSuite.total_count }}</div> </div> - <div class="table-mobile-content">{{ testSuite.total_count }}</div> </div> - </div> + </smart-virtual-list> </div> <div v-else> diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb index ccbb1d56030..ea5776534d5 100644 --- a/app/graphql/gitlab_schema.rb +++ b/app/graphql/gitlab_schema.rb @@ -57,13 +57,55 @@ class GitlabSchema < GraphQL::Schema object.to_global_id end + # Find an object by looking it up from its global ID, passed as a string. + # + # This is the composition of 'parse_gid' and 'find_by_gid', see these + # methods for further documentation. def object_from_id(global_id, ctx = {}) + gid = parse_gid(global_id, ctx) + + find_by_gid(gid) + end + + # Find an object by looking it up from its 'GlobalID'. + # + # * For `ApplicationRecord`s, this is equivalent to + # `global_id.model_class.find(gid.model_id)`, but more efficient. + # * For classes that implement `.lazy_find(global_id)`, this class method + # will be called. + # * All other classes will use `GlobalID#find` + def find_by_gid(gid) + if gid.model_class < ApplicationRecord + Gitlab::Graphql::Loaders::BatchModelLoader.new(gid.model_class, gid.model_id).find + elsif gid.model_class.respond_to?(:lazy_find) + gid.model_class.lazy_find(gid.model_id) + else + gid.find + end + end + + # Parse a string to a GlobalID, raising ArgumentError if there are problems + # with it. + # + # Problems that may occur: + # * it may not be syntactically valid + # * it may not match the expected type (see below) + # + # Options: + # * :expected_type [Class] - the type of object this GlobalID should refer to. + # + # e.g. + # + # ``` + # gid = GitlabSchema.parse_gid(my_string, expected_type: ::Project) + # project_id = gid.model_id + # gid.model_class == ::Project + # ``` + def parse_gid(global_id, ctx = {}) expected_type = ctx[:expected_type] gid = GlobalID.parse(global_id) - unless gid - raise Gitlab::Graphql::Errors::ArgumentError, "#{global_id} is not a valid GitLab id." - end + raise Gitlab::Graphql::Errors::ArgumentError, "#{global_id} is not a valid GitLab id." unless gid if expected_type && !gid.model_class.ancestors.include?(expected_type) vars = { global_id: global_id, expected_type: expected_type } @@ -71,13 +113,7 @@ class GitlabSchema < GraphQL::Schema raise Gitlab::Graphql::Errors::ArgumentError, msg end - if gid.model_class < ApplicationRecord - Gitlab::Graphql::Loaders::BatchModelLoader.new(gid.model_class, gid.model_id).find - elsif gid.model_class.respond_to?(:lazy_find) - gid.model_class.lazy_find(gid.model_id) - else - gid.find - end + gid end private diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb index ca93bc15be0..42fa4a6f179 100644 --- a/app/models/clusters/applications/jupyter.rb +++ b/app/models/clusters/applications/jupyter.rb @@ -5,7 +5,7 @@ require 'securerandom' module Clusters module Applications class Jupyter < ApplicationRecord - VERSION = '0.9-174bbd5' + VERSION = '0.9.0-beta.2' self.table_name = 'clusters_applications_jupyter' diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb index 593ce69b0fd..0a09000fff4 100644 --- a/app/models/project_services/external_wiki_service.rb +++ b/app/models/project_services/external_wiki_service.rb @@ -19,15 +19,20 @@ class ExternalWikiService < Service def fields [ - { type: 'text', name: 'external_wiki_url', placeholder: s_('ExternalWikiService|The URL of the external Wiki'), required: true } + { + type: 'text', + name: 'external_wiki_url', + placeholder: s_('ExternalWikiService|The URL of the external Wiki'), + required: true + } ] end def execute(_data) - @response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true) rescue nil - if @response != 200 - nil - end + response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true) + response.body if response.code == 200 + rescue + nil end def self.supported_events |