Commit c966c762 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch 'nfriend-implement-startup-queries-for-releases-page' into 'master'

Update the Releases page to make use of startup queries

See merge request gitlab-org/gitlab!63914
parents e512b4cb efb7212f
<script>
import { GlButton } from '@gitlab/ui';
import allReleasesQuery from 'shared_queries/releases/all_releases.query.graphql';
import createFlash from '~/flash';
import { historyPushState, getParameterByName } from '~/lib/utils/common_utils';
import { scrollUp } from '~/lib/utils/scroll_utils';
import { setUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import { PAGE_SIZE, DEFAULT_SORT } from '~/releases/constants';
import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql';
import { convertAllReleasesGraphQLResponse } from '~/releases/util';
import ReleaseBlock from './release_block.vue';
import ReleaseSkeletonLoader from './release_skeleton_loader.vue';
......
fragment Release on Release {
__typename
name
tagName
tagPath
......@@ -7,15 +8,20 @@ fragment Release on Release {
createdAt
upcomingRelease
assets {
__typename
count
sources {
__typename
nodes {
__typename
format
url
}
}
links {
__typename
nodes {
__typename
id
name
url
......@@ -26,13 +32,16 @@ fragment Release on Release {
}
}
evidences {
__typename
nodes {
__typename
filepath
collectedAt
sha
}
}
links {
__typename
editUrl
selfUrl
openedIssuesUrl
......@@ -42,22 +51,27 @@ fragment Release on Release {
closedMergeRequestsUrl
}
commit {
__typename
sha
webUrl
title
}
author {
__typename
webUrl
avatarUrl
username
}
milestones {
__typename
nodes {
__typename
id
title
description
webPath
stats {
__typename
totalIssuesCount
closedIssuesCount
}
......
#import "../fragments/release.fragment.graphql"
# This query is identical to
# `app/graphql/queries/releases/all_releases.query.graphql`.
# These two queries should be kept in sync.
# When the `releases_index_apollo_client` feature flag is
# removed, this query should be removed entirely.
query allReleases(
$fullPath: ID!
$first: Int
......@@ -9,11 +15,14 @@ query allReleases(
$sort: ReleaseSort
) {
project(fullPath: $fullPath) {
__typename
releases(first: $first, last: $last, before: $before, after: $after, sort: $sort) {
__typename
nodes {
...Release
}
pageInfo {
__typename
startCursor
hasPreviousPage
hasNextPage
......
# This query is identical to
# `app/assets/javascripts/releases/graphql/queries/all_releases.query.graphql`.
# These two queries should be kept in sync.
query allReleases(
$fullPath: ID!
$first: Int
$last: Int
$before: String
$after: String
$sort: ReleaseSort
) {
project(fullPath: $fullPath) {
__typename
releases(first: $first, last: $last, before: $before, after: $after, sort: $sort) {
__typename
nodes {
__typename
name
tagName
tagPath
descriptionHtml
releasedAt
createdAt
upcomingRelease
assets {
__typename
count
sources {
__typename
nodes {
__typename
format
url
}
}
links {
__typename
nodes {
__typename
id
name
url
directAssetUrl
linkType
external
}
}
}
evidences {
__typename
nodes {
__typename
filepath
collectedAt
sha
}
}
links {
__typename
editUrl
selfUrl
openedIssuesUrl
closedIssuesUrl
openedMergeRequestsUrl
mergedMergeRequestsUrl
closedMergeRequestsUrl
}
commit {
__typename
sha
webUrl
title
}
author {
__typename
webUrl
avatarUrl
username
}
milestones {
__typename
nodes {
__typename
id
title
description
webPath
stats {
__typename
totalIssuesCount
closedIssuesCount
}
}
}
}
pageInfo {
__typename
startCursor
hasPreviousPage
hasNextPage
endCursor
}
}
}
}
......@@ -4,6 +4,10 @@ module ReleasesHelper
IMAGE_PATH = 'illustrations/releases.svg'
DOCUMENTATION_PATH = 'user/project/releases/index'
# This needs to be kept in sync with the constant in
# app/assets/javascripts/releases/constants.js
DEFAULT_SORT = 'RELEASED_AT_DESC'
def illustration
image_path(IMAGE_PATH)
end
......@@ -25,6 +29,19 @@ module ReleasesHelper
end
end
# For simplicity, only optimize non-paginated requests
def use_startup_query_for_index_page?
params[:before].nil? && params[:after].nil?
end
def index_page_startup_query_variables
{
fullPath: @project.full_path,
sort: DEFAULT_SORT,
first: 1
}
end
def data_for_show_page
{
project_id: @project.id,
......
- page_title _('Releases')
- if use_startup_query_for_index_page?
- add_page_startup_graphql_call('releases/all_releases', index_page_startup_query_variables)
#js-releases-page{ data: data_for_releases_page }
......@@ -14,9 +14,14 @@ RSpec.describe 'User views releases', :js do
let_it_be(:maintainer) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:internal_link) { create(:release_link, release: release_v1, name: 'An internal link', url: "#{project.web_url}/-/jobs/1/artifacts/download", filepath: nil) }
let_it_be(:internal_link_with_redirect) { create(:release_link, release: release_v1, name: 'An internal link with a redirect', url: "#{project.web_url}/-/jobs/2/artifacts/download", filepath: '/binaries/linux-amd64' ) }
let_it_be(:external_link) { create(:release_link, release: release_v1, name: 'An external link', url: "https://example.com/an/external/link", filepath: nil) }
before do
project.add_maintainer(maintainer)
project.add_guest(guest)
stub_default_url_options(host: 'localhost')
end
shared_examples 'releases index page' do
......@@ -25,6 +30,8 @@ RSpec.describe 'User views releases', :js do
sign_in(maintainer)
visit project_releases_path(project)
wait_for_requests
end
it 'sees the release' do
......@@ -35,38 +42,18 @@ RSpec.describe 'User views releases', :js do
end
end
context 'when there is a link as an asset' do
let!(:release_link) { create(:release_link, release: release_v1, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{release_link.filepath}" }
it 'renders the correct links', :aggregate_failures do
page.within("##{release_v1.tag} .js-assets-list") do
external_link_indicator_selector = '[data-testid="external-link-indicator"]'
it 'sees the link' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
end
end
expect(page).to have_link internal_link.name, href: internal_link.url
expect(find_link(internal_link.name)).not_to have_css(external_link_indicator_selector)
context 'when there is a link redirect' do
let!(:release_link) { create(:release_link, release: release_v1, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
expect(page).to have_link internal_link_with_redirect.name, href: Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{internal_link_with_redirect.filepath}"
expect(find_link(internal_link_with_redirect.name)).not_to have_css(external_link_indicator_selector)
it 'sees the link', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329301' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
end
end
end
context 'when url points to external resource' do
let(:url) { 'http://google.com/download' }
it 'sees that the link is external resource', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329302' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_css('[data-testid="external-link-indicator"]')
end
end
expect(page).to have_link external_link.name, href: external_link.url
expect(find_link(external_link.name)).to have_css(external_link_indicator_selector)
end
end
......
......@@ -5,6 +5,7 @@ Object {
"data": Array [
Object {
"_links": Object {
"__typename": "ReleaseLinks",
"closedIssuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.2&scope=all&state=closed",
"closedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.2&scope=all&state=closed",
"editUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.2/edit",
......@@ -19,24 +20,29 @@ Object {
"links": Array [],
"sources": Array [
Object {
"__typename": "ReleaseSource",
"format": "zip",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.2/releases-project-v1.2.zip",
},
Object {
"__typename": "ReleaseSource",
"format": "tar.gz",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.2/releases-project-v1.2.tar.gz",
},
Object {
"__typename": "ReleaseSource",
"format": "tar.bz2",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.2/releases-project-v1.2.tar.bz2",
},
Object {
"__typename": "ReleaseSource",
"format": "tar",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.2/releases-project-v1.2.tar",
},
],
},
"author": Object {
"__typename": "UserCore",
"avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon",
"username": "administrator",
"webUrl": "http://localhost/administrator",
......@@ -57,6 +63,7 @@ Object {
},
Object {
"_links": Object {
"__typename": "ReleaseLinks",
"closedIssuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=closed",
"closedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=closed",
"editUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/edit",
......@@ -70,6 +77,7 @@ Object {
"count": 8,
"links": Array [
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/awesome-app-3",
"external": true,
"id": "gid://gitlab/Releases::Link/13",
......@@ -78,6 +86,7 @@ Object {
"url": "https://example.com/image",
},
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/awesome-app-2",
"external": true,
"id": "gid://gitlab/Releases::Link/12",
......@@ -86,6 +95,7 @@ Object {
"url": "https://example.com/package",
},
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/awesome-app-1",
"external": false,
"id": "gid://gitlab/Releases::Link/11",
......@@ -94,6 +104,7 @@ Object {
"url": "http://localhost/releases-namespace/releases-project/runbook",
},
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/linux-amd64",
"external": true,
"id": "gid://gitlab/Releases::Link/10",
......@@ -104,24 +115,29 @@ Object {
],
"sources": Array [
Object {
"__typename": "ReleaseSource",
"format": "zip",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.zip",
},
Object {
"__typename": "ReleaseSource",
"format": "tar.gz",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.gz",
},
Object {
"__typename": "ReleaseSource",
"format": "tar.bz2",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.bz2",
},
Object {
"__typename": "ReleaseSource",
"format": "tar",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar",
},
],
},
"author": Object {
"__typename": "UserCore",
"avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon",
"username": "administrator",
"webUrl": "http://localhost/administrator",
......@@ -134,6 +150,7 @@ Object {
"descriptionHtml": "<p data-sourcepos=\\"1:1-1:33\\" dir=\\"auto\\">Best. Release. <strong>Ever.</strong> <gl-emoji title=\\"rocket\\" data-name=\\"rocket\\" data-unicode-version=\\"6.0\\">🚀</gl-emoji></p>",
"evidences": Array [
Object {
"__typename": "ReleaseEvidence",
"collectedAt": "2018-12-03T00:00:00Z",
"filepath": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/evidences/1.json",
"sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
......@@ -141,6 +158,7 @@ Object {
],
"milestones": Array [
Object {
"__typename": "Milestone",
"description": "The 12.3 milestone",
"id": "gid://gitlab/Milestone/123",
"issueStats": Object {
......@@ -153,6 +171,7 @@ Object {
"webUrl": "/releases-namespace/releases-project/-/milestones/1",
},
Object {
"__typename": "Milestone",
"description": "The 12.4 milestone",
"id": "gid://gitlab/Milestone/124",
"issueStats": Object {
......@@ -173,6 +192,7 @@ Object {
},
],
"paginationInfo": Object {
"__typename": "PageInfo",
"endCursor": "eyJyZWxlYXNlZF9hdCI6IjIwMTgtMTItMTAgMDA6MDA6MDAuMDAwMDAwMDAwIFVUQyIsImlkIjoiMSJ9",
"hasNextPage": false,
"hasPreviousPage": false,
......@@ -247,6 +267,7 @@ exports[`releases/util.js convertOneReleaseGraphQLResponse matches snapshot 1`]
Object {
"data": Object {
"_links": Object {
"__typename": "ReleaseLinks",
"closedIssuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=closed",
"closedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=closed",
"editUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/edit",
......@@ -260,6 +281,7 @@ Object {
"count": 8,
"links": Array [
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/awesome-app-3",
"external": true,
"id": "gid://gitlab/Releases::Link/13",
......@@ -268,6 +290,7 @@ Object {
"url": "https://example.com/image",
},
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/awesome-app-2",
"external": true,
"id": "gid://gitlab/Releases::Link/12",
......@@ -276,6 +299,7 @@ Object {
"url": "https://example.com/package",
},
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/awesome-app-1",
"external": false,
"id": "gid://gitlab/Releases::Link/11",
......@@ -284,6 +308,7 @@ Object {
"url": "http://localhost/releases-namespace/releases-project/runbook",
},
Object {
"__typename": "ReleaseAssetLink",
"directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/downloads/binaries/linux-amd64",
"external": true,
"id": "gid://gitlab/Releases::Link/10",
......@@ -294,24 +319,29 @@ Object {
],
"sources": Array [
Object {
"__typename": "ReleaseSource",
"format": "zip",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.zip",
},
Object {
"__typename": "ReleaseSource",
"format": "tar.gz",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.gz",
},
Object {
"__typename": "ReleaseSource",
"format": "tar.bz2",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.bz2",
},
Object {
"__typename": "ReleaseSource",
"format": "tar",
"url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar",
},
],
},
"author": Object {
"__typename": "UserCore",
"avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon",
"username": "administrator",
"webUrl": "http://localhost/administrator",
......@@ -324,6 +354,7 @@ Object {
"descriptionHtml": "<p data-sourcepos=\\"1:1-1:33\\" dir=\\"auto\\">Best. Release. <strong>Ever.</strong> <gl-emoji title=\\"rocket\\" data-name=\\"rocket\\" data-unicode-version=\\"6.0\\">🚀</gl-emoji></p>",
"evidences": Array [
Object {
"__typename": "ReleaseEvidence",
"collectedAt": "2018-12-03T00:00:00Z",
"filepath": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/evidences/1.json",
"sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
......@@ -331,6 +362,7 @@ Object {
],
"milestones": Array [
Object {
"__typename": "Milestone",
"description": "The 12.3 milestone",
"id": "gid://gitlab/Milestone/123",
"issueStats": Object {
......@@ -343,6 +375,7 @@ Object {
"webUrl": "/releases-namespace/releases-project/-/milestones/1",
},
Object {
"__typename": "Milestone",
"description": "The 12.4 milestone",
"id": "gid://gitlab/Milestone/124",
"issueStats": Object {
......
......@@ -3,6 +3,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import allReleasesQuery from 'shared_queries/releases/all_releases.query.graphql';
import createFlash from '~/flash';
import { historyPushState } from '~/lib/utils/common_utils';
import ReleasesIndexApolloClientApp from '~/releases/components/app_index_apollo_client.vue';
......@@ -12,7 +13,6 @@ import ReleasesEmptyState from '~/releases/components/releases_empty_state.vue';
import ReleasesPaginationApolloClient from '~/releases/components/releases_pagination_apollo_client.vue';
import ReleasesSortApolloClient from '~/releases/components/releases_sort_apollo_client.vue';
import { PAGE_SIZE, CREATED_ASC, DEFAULT_SORT } from '~/releases/constants';
import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql';
Vue.use(VueApollo);
......
......@@ -97,4 +97,42 @@ RSpec.describe ReleasesHelper do
end
end
end
describe 'startup queries' do
describe 'use_startup_query_for_index_page?' do
it 'allows startup queries for non-paginated requests' do
allow(helper).to receive(:params).and_return({ unrelated_query_param: 'value' })
expect(helper.use_startup_query_for_index_page?).to be(true)
end
it 'disallows startup queries for requests paginated with a "before" cursor' do
allow(helper).to receive(:params).and_return({ unrelated_query_param: 'value', before: 'cursor' })
expect(helper.use_startup_query_for_index_page?).to be(false)
end
it 'disallows startup queries for requests paginated with an "after" cursor' do
allow(helper).to receive(:params).and_return({ unrelated_query_param: 'value', after: 'cursor' })
expect(helper.use_startup_query_for_index_page?).to be(false)
end
end
describe '#index_page_startup_query_variables' do
let_it_be(:project) { build(:project, namespace: create(:group)) }
before do
helper.instance_variable_set(:@project, project)
end
it 'returns the correct GraphQL variables for the startup query' do
expect(helper.index_page_startup_query_variables).to eq({
fullPath: project.full_path,
sort: 'RELEASED_AT_DESC',
first: 1
})
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment