summaryrefslogtreecommitdiff
path: root/app/graphql/types/design_management/design_fields.rb
blob: c3a35cfe1ad601cc4f8353c7e7e217bd21457003 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# frozen_string_literal: true

module Types
  module DesignManagement
    module DesignFields
      include BaseInterface

      field_class Types::BaseField

      field :id, GraphQL::Types::ID, description: 'ID of this design.', null: false
      field :project, Types::ProjectType, null: false, description: 'Project the design belongs to.'
      field :issue, Types::IssueType, null: false, description: 'Issue the design belongs to.'
      field :filename, GraphQL::Types::String, null: false, description: 'Filename of the design.'
      field :full_path, GraphQL::Types::String, null: false, description: 'Full path to the design file.'
      field :image, GraphQL::Types::String, null: false, extras: [:parent], description: 'URL of the full-sized image.'
      field :image_v432x230, GraphQL::Types::String, 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,
            null: false,
            calls_gitaly: true,
            extras: [:parent],
            description: 'Diff refs for this design.'
      field :event, Types::DesignManagement::DesignVersionEventEnum,
            null: false,
            extras: [:parent],
            description: 'How this design was changed in the current version.'
      field :notes_count,
            GraphQL::Types::Int,
            null: false,
            method: :user_notes_count,
            description: 'Total count of user-created notes for this design.'

      def diff_refs(parent:)
        version = cached_stateful_version(parent)
        version.diff_refs
      end

      def image(parent:)
        sha = cached_stateful_version(parent).sha

        Gitlab::UrlBuilder.build(design, ref: sha)
      end

      def image_v432x230(parent:)
        Gitlab::Graphql::Lazy.with_value(lazy_action(parent)) do |action|
          # A `nil` return value indicates that the image has not been processed
          next unless action&.image_v432x230&.file

          Gitlab::UrlBuilder.build(action.design, ref: action.version.sha, size: :v432x230)
        end
      end

      def event(parent:)
        version = cached_stateful_version(parent)

        action = cached_actions_for_version(version)[design.id]

        action&.event || ::Types::DesignManagement::DesignVersionEventEnum::NONE
      end

      def cached_actions_for_version(version)
        Gitlab::SafeRequestStore.fetch(['DesignFields', 'actions_for_version', version.id]) do
          version.actions.index_by(&:design_id)
        end
      end

      def project
        ::Gitlab::Graphql::Loaders::BatchModelLoader.new(::Project, design.project_id).find
      end

      def issue
        ::Gitlab::Graphql::Loaders::BatchModelLoader.new(::Issue, design.issue_id).find
      end

      private

      def lazy_action(parent)
        version = cached_stateful_version(parent)

        BatchLoader::GraphQL.for([version, design]).batch do |ids, loader|
          by_version = ids.group_by(&:first).transform_values { _1.map(&:second) }
          designs_by_id = ids.map(&:second).index_by(&:id)

          by_version.each do |v, designs|
            actions = ::DesignManagement::Action.most_recent.up_to_version(v).by_design(designs).with_version
            actions.each do |action|
              action.design = designs_by_id[action.design_id] # eliminate duplicate load
              loader.call([v, action.design], action)
            end
          end
        end
      end
    end
  end
end