Commit ad5366da authored by Bob Van Landuyt's avatar Bob Van Landuyt

Merge branch '12577-graphql-expose-smaller-design-images' into 'master'

Expose smaller Design Management design images in GraphQL

See merge request gitlab-org/gitlab!26947
parents 60f71a33 dc587e38
...@@ -776,10 +776,15 @@ type Design implements DesignFields & Noteable { ...@@ -776,10 +776,15 @@ type Design implements DesignFields & Noteable {
id: ID! id: ID!
""" """
The URL of the image The URL of the full-sized image
""" """
image: String! image: String!
"""
The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated
"""
imageV432x230: String
""" """
The issue the design belongs to The issue the design belongs to
""" """
...@@ -891,10 +896,15 @@ type DesignAtVersion implements DesignFields { ...@@ -891,10 +896,15 @@ type DesignAtVersion implements DesignFields {
id: ID! id: ID!
""" """
The URL of the image The URL of the full-sized image
""" """
image: String! image: String!
"""
The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated
"""
imageV432x230: String
""" """
The issue the design belongs to The issue the design belongs to
""" """
...@@ -1144,10 +1154,15 @@ interface DesignFields { ...@@ -1144,10 +1154,15 @@ interface DesignFields {
id: ID! id: ID!
""" """
The URL of the image The URL of the full-sized image
""" """
image: String! image: String!
"""
The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated
"""
imageV432x230: String
""" """
The issue the design belongs to The issue the design belongs to
""" """
......
...@@ -2247,7 +2247,7 @@ ...@@ -2247,7 +2247,7 @@
}, },
{ {
"name": "image", "name": "image",
"description": "The URL of the image", "description": "The URL of the full-sized image",
"args": [ "args": [
], ],
...@@ -2263,6 +2263,20 @@ ...@@ -2263,6 +2263,20 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "imageV432x230",
"description": "The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "issue", "name": "issue",
"description": "The issue the design belongs to", "description": "The issue the design belongs to",
...@@ -2583,7 +2597,7 @@ ...@@ -2583,7 +2597,7 @@
}, },
{ {
"name": "image", "name": "image",
"description": "The URL of the image", "description": "The URL of the full-sized image",
"args": [ "args": [
], ],
...@@ -2599,6 +2613,20 @@ ...@@ -2599,6 +2613,20 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "imageV432x230",
"description": "The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "issue", "name": "issue",
"description": "The issue the design belongs to", "description": "The issue the design belongs to",
...@@ -3326,7 +3354,7 @@ ...@@ -3326,7 +3354,7 @@
}, },
{ {
"name": "image", "name": "image",
"description": "The URL of the image", "description": "The URL of the full-sized image",
"args": [ "args": [
], ],
...@@ -3342,6 +3370,20 @@ ...@@ -3342,6 +3370,20 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "imageV432x230",
"description": "The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "issue", "name": "issue",
"description": "The issue the design belongs to", "description": "The issue the design belongs to",
......
...@@ -170,7 +170,8 @@ A single design ...@@ -170,7 +170,8 @@ A single design
| `filename` | String! | The filename of the design | | `filename` | String! | The filename of the design |
| `fullPath` | String! | The full path to the design file | | `fullPath` | String! | The full path to the design file |
| `id` | ID! | The ID of this design | | `id` | ID! | The ID of this design |
| `image` | String! | The URL of the image | | `image` | String! | The URL of the full-sized image |
| `imageV432x230` | String | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated |
| `issue` | Issue! | The issue the design belongs to | | `issue` | Issue! | The issue the design belongs to |
| `notesCount` | Int! | The total count of user-created notes for this design | | `notesCount` | Int! | The total count of user-created notes for this design |
| `project` | Project! | The project the design belongs to | | `project` | Project! | The project the design belongs to |
...@@ -187,7 +188,8 @@ A design pinned to a specific version. The image field reflects the design as of ...@@ -187,7 +188,8 @@ A design pinned to a specific version. The image field reflects the design as of
| `filename` | String! | The filename of the design | | `filename` | String! | The filename of the design |
| `fullPath` | String! | The full path to the design file | | `fullPath` | String! | The full path to the design file |
| `id` | ID! | The ID of this design | | `id` | ID! | The ID of this design |
| `image` | String! | The URL of the image | | `image` | String! | The URL of the full-sized image |
| `imageV432x230` | String | The URL of the design resized to fit within the bounds of 432x230. This will be `null` if the image has not been generated |
| `issue` | Issue! | The issue the design belongs to | | `issue` | Issue! | The issue the design belongs to |
| `notesCount` | Int! | The total count of user-created notes for this design | | `notesCount` | Int! | The total count of user-created notes for this design |
| `project` | Project! | The project the design belongs to | | `project` | Project! | The project the design belongs to |
......
...@@ -12,7 +12,10 @@ module Types ...@@ -12,7 +12,10 @@ module Types
field :issue, Types::IssueType, null: false, description: 'The issue the design belongs to' field :issue, Types::IssueType, null: false, description: 'The issue the design belongs to'
field :filename, GraphQL::STRING_TYPE, null: false, description: 'The filename of the design' field :filename, GraphQL::STRING_TYPE, null: false, description: 'The filename of the design'
field :full_path, GraphQL::STRING_TYPE, null: false, description: 'The full path to the design file' field :full_path, GraphQL::STRING_TYPE, null: false, description: 'The full path to the design file'
field :image, GraphQL::STRING_TYPE, null: false, extras: [:parent], description: 'The URL of the image' field :image, GraphQL::STRING_TYPE, null: false, extras: [:parent], description: 'The URL of the full-sized image'
field :image_v432x230, GraphQL::STRING_TYPE, null: true, extras: [:parent],
description: 'The URL of the design resized to fit within the bounds of 432x230. ' \
'This will be `null` if the image has not been generated'
field :diff_refs, Types::DiffRefsType, field :diff_refs, Types::DiffRefsType,
null: false, null: false,
calls_gitaly: true, calls_gitaly: true,
...@@ -39,6 +42,16 @@ module Types ...@@ -39,6 +42,16 @@ module Types
Gitlab::UrlBuilder.build(design, ref: sha) Gitlab::UrlBuilder.build(design, ref: sha)
end end
def image_v432x230(parent:)
version = cached_stateful_version(parent)
action = design.actions.up_to_version(version).most_recent.first
# A `nil` return value indicates that the image has not been processed
return unless action.image_v432x230.file
Gitlab::UrlBuilder.build(design, ref: version.sha, size: :v432x230)
end
def event(parent:) def event(parent:)
version = cached_stateful_version(parent) version = cached_stateful_version(parent)
......
---
title: Expose smaller sized Design Management design images in GraphQL
merge_request: 26947
author:
type: added
...@@ -6,24 +6,33 @@ describe 'Getting designs related to an issue' do ...@@ -6,24 +6,33 @@ describe 'Getting designs related to an issue' do
include GraphqlHelpers include GraphqlHelpers
include DesignManagementTestHelpers include DesignManagementTestHelpers
let_it_be(:design) { create(:design, :with_file, versions_count: 1) } let_it_be(:design) { create(:design, :with_smaller_image_versions, versions_count: 1) }
let_it_be(:current_user) { design.project.owner } let_it_be(:current_user) { design.project.owner }
let(:design_query) do let(:design_query) do
<<~NODE <<~NODE
designs { designs {
edges { edges {
node { node {
id
filename filename
fullPath
event
image
imageV432x230
} }
} }
} }
NODE NODE
end end
let(:issue) { design.issue } let(:issue) { design.issue }
let(:project) { issue.project } let(:project) { issue.project }
let(:query) { make_query } let(:query) { make_query }
let(:design_collection) do
graphql_data_at(:project, :issue, :design_collection)
end
let(:design_response) do
design_collection.dig('designs', 'edges').first['node']
end
def make_query(dq = design_query) def make_query(dq = design_query)
designs_field = query_graphql_field(:design_collection, {}, dq) designs_field = query_graphql_field(:design_collection, {}, dq)
...@@ -32,12 +41,8 @@ describe 'Getting designs related to an issue' do ...@@ -32,12 +41,8 @@ describe 'Getting designs related to an issue' do
graphql_query_for(:project, { fullPath: project.full_path }, issue_field) graphql_query_for(:project, { fullPath: project.full_path }, issue_field)
end end
let(:design_collection) do def design_image_url(design, ref: nil, size: nil)
graphql_data_at(:project, :issue, :design_collection) Gitlab::UrlBuilder.build(design, ref: ref, size: size)
end
let(:design_response) do
design_collection.dig('designs', 'edges').first['node']
end end
context 'when the feature is not available' do context 'when the feature is not available' do
...@@ -64,10 +69,33 @@ describe 'Getting designs related to an issue' do ...@@ -64,10 +69,33 @@ describe 'Getting designs related to an issue' do
enable_design_management enable_design_management
end end
it 'returns the design filename' do it 'returns the design properties correctly' do
version_sha = design.versions.first.sha
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
expect(design_response['filename']).to eq(design.filename) expect(design_response).to eq(
'id' => design.to_global_id.to_s,
'event' => 'CREATION',
'fullPath' => design.full_path,
'filename' => design.filename,
'image' => design_image_url(design, ref: version_sha),
'imageV432x230' => design_image_url(design, ref: version_sha, size: :v432x230)
)
end
context 'when the v432x230-sized design image has not been processed' do
before do
allow_next_instance_of(DesignManagement::DesignV432x230Uploader) do |uploader|
allow(uploader).to receive(:file).and_return(nil)
end
end
it 'returns nil for the v432x230-sized design image' do
post_graphql(query, current_user: current_user)
expect(design_response['imageV432x230']).to be_nil
end
end end
describe 'pagination' do describe 'pagination' do
...@@ -152,7 +180,7 @@ describe 'Getting designs related to an issue' do ...@@ -152,7 +180,7 @@ describe 'Getting designs related to an issue' do
describe 'viewing a design board at a particular version' do describe 'viewing a design board at a particular version' do
let_it_be(:issue) { design.issue } let_it_be(:issue) { design.issue }
let_it_be(:second_design) { create(:design, :with_file, issue: issue, versions_count: 1) } let_it_be(:second_design, reload: true) { create(:design, :with_smaller_image_versions, issue: issue, versions_count: 1) }
let_it_be(:deleted_design) { create(:design, :with_versions, issue: issue, deleted: true, versions_count: 1) } let_it_be(:deleted_design) { create(:design, :with_versions, issue: issue, deleted: true, versions_count: 1) }
let(:all_versions) { issue.design_versions.ordered.reverse } let(:all_versions) { issue.design_versions.ordered.reverse }
let(:design_query) do let(:design_query) do
...@@ -162,6 +190,7 @@ describe 'Getting designs related to an issue' do ...@@ -162,6 +190,7 @@ describe 'Getting designs related to an issue' do
node { node {
id id
image image
imageV432x230
event event
versions { versions {
edges { edges {
...@@ -179,10 +208,6 @@ describe 'Getting designs related to an issue' do ...@@ -179,10 +208,6 @@ describe 'Getting designs related to an issue' do
design_collection['designs']['edges'] design_collection['designs']['edges']
end end
def image_url(design, sha = nil)
Gitlab::UrlBuilder.build(design, ref: sha)
end
def global_id(object) def global_id(object)
object.to_global_id.to_s object.to_global_id.to_s
end end
...@@ -214,9 +239,15 @@ describe 'Getting designs related to an issue' do ...@@ -214,9 +239,15 @@ describe 'Getting designs related to an issue' do
) )
end end
it 'returns the correct version of the design image' do it 'returns the correct full-sized design image' do
expect(design_nodes).to contain_exactly(
a_hash_including('image' => design_image_url(design, ref: version.sha))
)
end
it 'returns the correct v432x230-sized design image' do
expect(design_nodes).to contain_exactly( expect(design_nodes).to contain_exactly(
a_hash_including('image' => image_url(design, version.sha)) a_hash_including('imageV432x230' => design_image_url(design, ref: version.sha, size: :v432x230))
) )
end end
...@@ -247,10 +278,17 @@ describe 'Getting designs related to an issue' do ...@@ -247,10 +278,17 @@ describe 'Getting designs related to an issue' do
) )
end end
it 'returns the correct versions of the design images' do it 'returns the correct full-sized design images' do
expect(design_nodes).to contain_exactly( expect(design_nodes).to contain_exactly(
a_hash_including('image' => image_url(design, version.sha)), a_hash_including('image' => design_image_url(design, ref: version.sha)),
a_hash_including('image' => image_url(second_design, version.sha)) a_hash_including('image' => design_image_url(second_design, ref: version.sha))
)
end
it 'returns the correct v432x230-sized design images' do
expect(design_nodes).to contain_exactly(
a_hash_including('imageV432x230' => design_image_url(design, ref: version.sha, size: :v432x230)),
a_hash_including('imageV432x230' => design_image_url(second_design, ref: version.sha, size: :v432x230))
) )
end end
...@@ -271,10 +309,11 @@ describe 'Getting designs related to an issue' do ...@@ -271,10 +309,11 @@ describe 'Getting designs related to an issue' do
context 'viewing the last version, when one design was deleted and one was updated' do context 'viewing the last version, when one design was deleted and one was updated' do
let(:version) { all_versions.last } let(:version) { all_versions.last }
let!(:second_design_update) do
create(:design_action, :with_image_v432x230, design: second_design, version: version, event: 'modification')
end
before do before do
second_design.actions.create!(version: version, event: 'modification')
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
end end
...@@ -289,10 +328,17 @@ describe 'Getting designs related to an issue' do ...@@ -289,10 +328,17 @@ describe 'Getting designs related to an issue' do
) )
end end
it 'returns the correct versions of the design images' do it 'returns the correct full-sized design images' do
expect(design_nodes).to contain_exactly(
a_hash_including('image' => design_image_url(design, ref: version.sha)),
a_hash_including('image' => design_image_url(second_design, ref: version.sha))
)
end
it 'returns the correct v432x230-sized design images' do
expect(design_nodes).to contain_exactly( expect(design_nodes).to contain_exactly(
a_hash_including('image' => image_url(design, version.sha)), a_hash_including('imageV432x230' => design_image_url(design, ref: version.sha, size: :v432x230)),
a_hash_including('image' => image_url(second_design, version.sha)) a_hash_including('imageV432x230' => design_image_url(second_design, ref: version.sha, size: :v432x230))
) )
end end
......
...@@ -16,6 +16,7 @@ RSpec.shared_examples 'a GraphQL type with design fields' do ...@@ -16,6 +16,7 @@ RSpec.shared_examples 'a GraphQL type with design fields' do
filename filename
full_path full_path
image image
image_v432x230
diff_refs diff_refs
event event
notes_count notes_count
......
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