diff --git a/app/components/pajamas/avatar_component.rb b/app/components/pajamas/avatar_component.rb
index 423934b6887..0821818103a 100644
--- a/app/components/pajamas/avatar_component.rb
+++ b/app/components/pajamas/avatar_component.rb
@@ -1,16 +1,21 @@
# frozen_string_literal: true
module Pajamas
+ AvatarEmail = Struct.new(:email) do
+ def name
+ email
+ end
+ end
class AvatarComponent < Pajamas::Component
include Gitlab::Utils::StrongMemoize
- # @param record [User, Project, Group]
+ # @param item [User, Project, Group, AvatarEmail]
# @param alt [String] text for the alt tag
# @param class [String] custom CSS class(es)
# @param size [Integer] size in pixel
# @param [Hash] avatar_options
- def initialize(record, alt: nil, class: "", size: 64, avatar_options: {})
- @record = record
+ def initialize(item, alt: nil, class: "", size: 64, avatar_options: {})
+ @item = item
@alt = alt
@class = binding.local_variable_get(:class)
@size = filter_attribute(size.to_i, SIZE_OPTIONS, default: 64)
@@ -23,11 +28,11 @@ module Pajamas
def avatar_classes
classes = ["gl-avatar", "gl-avatar-s#{@size}", @class]
- classes.push("gl-avatar-circle") if @record.is_a?(User)
+ classes.push("gl-avatar-circle") if @item.is_a?(User) || @item.is_a?(AvatarEmail)
unless src
classes.push("gl-avatar-identicon")
- classes.push("gl-avatar-identicon-bg#{((@record.id || 0) % 7) + 1}")
+ classes.push("gl-avatar-identicon-bg#{((@item.id || 0) % 7) + 1}")
end
classes.join(' ')
@@ -35,7 +40,7 @@ module Pajamas
def src
strong_memoize(:src) do
- if @record.is_a?(User)
+ if @item.is_a?(User)
# Users show a gravatar instead of an identicon. Also avatars of
# blocked users are only shown if the current_user is an admin.
# To not duplicate this logic, we are using existing helpers here.
@@ -44,9 +49,11 @@ module Pajamas
rescue StandardError
nil
end
- helpers.avatar_icon_for_user(@record, @size, current_user: current_user)
- elsif @record.try(:avatar_url)
- "#{@record.avatar_url}?width=#{@size}"
+ helpers.avatar_icon_for_user(@item, @size, current_user: current_user)
+ elsif @item.is_a?(AvatarEmail)
+ helpers.avatar_icon_for_email(@item.email, @size)
+ elsif @item.try(:avatar_url)
+ "#{@item.avatar_url}?width=#{@size}"
end
end
end
@@ -59,11 +66,11 @@ module Pajamas
end
def alt
- @alt || @record.name
+ @alt || @item.name
end
def initial
- @record.name[0, 1].upcase
+ @item.name[0, 1].upcase
end
end
end
diff --git a/app/graphql/resolvers/ml/find_models_resolver.rb b/app/graphql/resolvers/ml/find_models_resolver.rb
new file mode 100644
index 00000000000..b9901100e22
--- /dev/null
+++ b/app/graphql/resolvers/ml/find_models_resolver.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Ml
+ class FindModelsResolver < Resolvers::BaseResolver
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
+
+ type ::Types::Ml::ModelType.connection_type, null: true
+
+ argument :name, GraphQL::Types::String,
+ required: false,
+ description: 'Search for names that include the string.'
+
+ argument :order_by, ::Types::Ml::ModelsOrderByEnum,
+ required: false,
+ description: 'Ordering column. Default is created_at.'
+
+ argument :sort, ::Types::SortDirectionEnum,
+ required: false,
+ description: 'Ordering column. Default is desc.'
+
+ def resolve(**args)
+ return unless current_user.can?(:read_model_registry, object)
+
+ find_params = {
+ name: args[:name],
+ order_by: args[:order_by].to_s,
+ sort: args[:sort].to_s
+ }
+
+ ::Projects::Ml::ModelFinder.new(object, find_params).execute
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/ml/model_links_type.rb b/app/graphql/types/ml/model_links_type.rb
new file mode 100644
index 00000000000..9d18efb2e17
--- /dev/null
+++ b/app/graphql/types/ml/model_links_type.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Types
+ module Ml
+ # rubocop: disable Graphql/AuthorizeTypes -- authorization in ModelDetailsResolver
+ class ModelLinksType < BaseObject
+ graphql_name 'MLModelLinks'
+ description 'Represents links to perform actions on the model'
+
+ present_using ::Ml::ModelPresenter
+
+ field :show_path, GraphQL::Types::String,
+ null: true, description: 'Path to the details page of the model.', method: :path
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/ml/model_type.rb b/app/graphql/types/ml/model_type.rb
index ca63918b370..e677b37547a 100644
--- a/app/graphql/types/ml/model_type.rb
+++ b/app/graphql/types/ml/model_type.rb
@@ -7,10 +7,21 @@ module Types
graphql_name 'MlModel'
description 'Machine learning model in the model registry'
+ connection_type_class Types::LimitedCountableConnectionType
+
field :id, ::Types::GlobalIDType[::Ml::Model], null: false, description: 'ID of the model.'
field :name, ::GraphQL::Types::String, null: false, description: 'Name of the model.'
+ field :created_at, Types::TimeType, null: false, description: 'Date of creation.'
+
+ field :latest_version, ::Types::Ml::ModelVersionType, null: true, description: 'Latest version of the model.'
+
+ field :version_count, ::GraphQL::Types::Int, null: true, description: 'Count of versions in the model.'
+
+ field :_links, ::Types::Ml::ModelLinksType, null: false, method: :itself,
+ description: 'Map of links to perform actions on the model.'
+
field :versions, ::Types::Ml::ModelVersionType.connection_type, null: true,
description: 'Versions of the model.'
diff --git a/app/graphql/types/ml/model_version_links_type.rb b/app/graphql/types/ml/model_version_links_type.rb
index 142f62bfad2..a8497334fc6 100644
--- a/app/graphql/types/ml/model_version_links_type.rb
+++ b/app/graphql/types/ml/model_version_links_type.rb
@@ -11,6 +11,9 @@ module Types
field :show_path, GraphQL::Types::String,
null: true, description: 'Path to the details page of the model version.', method: :path
+
+ field :package_path, GraphQL::Types::String,
+ null: true, description: 'Path to the package of the model version.', method: :package_path
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/ml/models_order_by_enum.rb b/app/graphql/types/ml/models_order_by_enum.rb
new file mode 100644
index 00000000000..db96a2e2d7d
--- /dev/null
+++ b/app/graphql/types/ml/models_order_by_enum.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ module Ml
+ class ModelsOrderByEnum < BaseEnum
+ graphql_name 'MlModelsOrderBy'
+ description 'Values for ordering machine learning models by a specific field'
+
+ value 'NAME', 'Ordered by name.', value: :name
+ value 'CREATED_AT', 'Ordered by creation time.', value: :created_at
+ value 'UPDATED_AT', 'Ordered by update time.', value: :updated_at
+ value 'ID', 'Ordered by id.', value: :id
+ end
+ end
+end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 8e84605cb05..68a55687419 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -663,6 +663,12 @@ module Types
null: true,
resolver: Resolvers::Analytics::CycleAnalytics::ValueStreamsResolver
+ field :ml_models, ::Types::Ml::ModelType.connection_type,
+ null: true,
+ alpha: { milestone: '16.8' },
+ description: 'Finds machine learning models',
+ resolver: Resolvers::Ml::FindModelsResolver
+
def timelog_categories
object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories)
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index bf21eca8857..2471c0bdb29 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -2194,6 +2194,8 @@ class MergeRequest < ApplicationRecord
attr_accessor :skip_fetch_ref
def merge_base_pipelines
+ return ::Ci::Pipeline.none unless actual_head_pipeline
+
target_branch_pipelines_for(sha: actual_head_pipeline.target_sha)
end
diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml
index c86993f5b77..47ab2d5f4be 100644
--- a/app/views/shared/members/_member.html.haml
+++ b/app/views/shared/members/_member.html.haml
@@ -49,7 +49,7 @@
= _("Expires %{preposition} %{expires_at}").html_safe % { expires_at: time_ago_with_tooltip(member.expires_at), preposition: preposition }
- else
- = image_tag avatar_icon_for_email(member.invite_email, 40), class: "avatar s40 flex-shrink-0 flex-grow-0", alt: ''
+ = render Pajamas::AvatarComponent.new(Pajamas::AvatarEmail.new(member.invite_email), size: 32, class: 'gl-mr-3 flex-shrink-0 flex-grow-0')
.user-info
.member= member.invite_email
.cgray
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 3701abbc237..ee44d76a773 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -11801,6 +11801,43 @@ The edge type for [`MlCandidate`](#mlcandidate).
| `cursor` | [`String!`](#string) | A cursor for use in pagination. |
| `node` | [`MlCandidate`](#mlcandidate) | The item at the end of the edge. |
+#### `MlModelConnection`
+
+The connection type for [`MlModel`](#mlmodel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `edges` | [`[MlModelEdge]`](#mlmodeledge) | A list of edges. |
+| `nodes` | [`[MlModel]`](#mlmodel) | A list of nodes. |
+| `pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+##### Fields with arguments
+
+###### `MlModelConnection.count`
+
+Limited count of collection. Returns limit + 1 for counts greater than the limit.
+
+Returns [`Int!`](#int).
+
+####### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `limit` | [`Int`](#int) | Limit value to be applied to the count query. Default is 1000. |
+
+#### `MlModelEdge`
+
+The edge type for [`MlModel`](#mlmodel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| `node` | [`MlModel`](#mlmodel) | The item at the end of the edge. |
+
#### `MlModelVersionConnection`
The connection type for [`MlModelVersion`](#mlmodelversion).
@@ -21288,6 +21325,16 @@ Represents links to perform actions on the candidate.
| `artifactPath` | [`String`](#string) | Path to the artifact. |
| `showPath` | [`String`](#string) | Path to the details page of the candidate. |
+### `MLModelLinks`
+
+Represents links to perform actions on the model.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `showPath` | [`String`](#string) | Path to the details page of the model. |
+
### `MLModelVersionLinks`
Represents links to perform actions on the model version.
@@ -21296,6 +21343,7 @@ Represents links to perform actions on the model version.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| `packagePath` | [`String`](#string) | Path to the package of the model version. |
| `showPath` | [`String`](#string) | Path to the details page of the model version. |
### `MavenMetadata`
@@ -22923,9 +22971,13 @@ Machine learning model in the model registry.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| `_links` | [`MLModelLinks!`](#mlmodellinks) | Map of links to perform actions on the model. |
| `candidates` | [`MlCandidateConnection`](#mlcandidateconnection) | Version candidates of the model. (see [Connections](#connections)) |
+| `createdAt` | [`Time!`](#time) | Date of creation. |
| `id` | [`MlModelID!`](#mlmodelid) | ID of the model. |
+| `latestVersion` | [`MlModelVersion`](#mlmodelversion) | Latest version of the model. |
| `name` | [`String!`](#string) | Name of the model. |
+| `versionCount` | [`Int`](#int) | Count of versions in the model. |
| `versions` | [`MlModelVersionConnection`](#mlmodelversionconnection) | Versions of the model. (see [Connections](#connections)) |
### `MlModelVersion`
@@ -25103,6 +25155,28 @@ four standard [pagination arguments](#connection-pagination-arguments):
| `timeframe` | [`Timeframe`](#timeframe) | List items overlapping the given timeframe. |
| `title` | [`String`](#string) | Title of the milestone. |
+##### `Project.mlModels`
+
+Finds machine learning models.
+
+WARNING:
+**Introduced** in 16.8.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`MlModelConnection`](#mlmodelconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, and `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `name` | [`String`](#string) | Search for names that include the string. |
+| `orderBy` | [`MlModelsOrderBy`](#mlmodelsorderby) | Ordering column. Default is created_at. |
+| `sort` | [`SortDirectionEnum`](#sortdirectionenum) | Ordering column. Default is desc. |
+
##### `Project.nestedEnvironments`
Environments for this project with nested folders, can only be resolved for one project in any single request.
@@ -30820,6 +30894,17 @@ Milestone ID wildcard values.
| `STARTED` | Milestone assigned is open and started (start date <= today). |
| `UPCOMING` | Milestone assigned is due in the future (due date > today). |
+### `MlModelsOrderBy`
+
+Values for ordering machine learning models by a specific field.
+
+| Value | Description |
+| ----- | ----------- |
+| `CREATED_AT` | Ordered by creation time. |
+| `ID` | Ordered by id. |
+| `NAME` | Ordered by name. |
+| `UPDATED_AT` | Ordered by update time. |
+
### `MoveType`
The position to which the adjacent object should be moved.
diff --git a/doc/development/code_suggestions/index.md b/doc/development/code_suggestions/index.md
index 409efc41fc2..f282dbb1223 100644
--- a/doc/development/code_suggestions/index.md
+++ b/doc/development/code_suggestions/index.md
@@ -52,5 +52,5 @@ with the deployed staging Model Gateway. To do this:
```
1. Restart the GDK.
-1. Ensure you followed the necessary [steps to enable the Code Suggestions feature](../../user/project/repository/code_suggestions/self_managed.md#gitlab-163-and-later).
+1. Ensure you followed the necessary [steps to enable the Code Suggestions feature](../../user/project/repository/code_suggestions/self_managed.md).
1. Test out the Code Suggestions feature by opening the Web IDE for a project.
diff --git a/doc/user/analytics/analytics_dashboards.md b/doc/user/analytics/analytics_dashboards.md
index 0699be4e0ad..76acba44682 100644
--- a/doc/user/analytics/analytics_dashboards.md
+++ b/doc/user/analytics/analytics_dashboards.md
@@ -226,7 +226,7 @@ You can define different charts, and add visualization options to some of them:
- Line chart, with the options listed in the [ECharts documentation](https://echarts.apache.org/en/option.html).
- Column chart, with the options listed in the [ECharts documentation](https://echarts.apache.org/en/option.html).
-- Data table, with the only option to render `links` (array of objects, each with `text` and `href` properties to specify the dimensions to be used in links). See [example](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/validators/json_schemas/analytics_visualization.json?ref_type=heads#L112)).
+- Data table.
- Single stat, with the only option to set `decimalPlaces` (number, default value is 0).
To define a chart for your dashboards:
diff --git a/doc/user/application_security/vulnerability_report/index.md b/doc/user/application_security/vulnerability_report/index.md
index 23454bf387a..c5806ed6124 100644
--- a/doc/user/application_security/vulnerability_report/index.md
+++ b/doc/user/application_security/vulnerability_report/index.md
@@ -133,6 +133,10 @@ The content of the Project filter depends on the current level:
### Activity filter
+> Introduced in GitLab 16.7 [with a flag](../../../administration/feature_flags.md) named `activity_filter_has_remediations`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default the Solution Available filter is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `activity_filter_has_remediations`. On GitLab.com, this feature is not available. This feature is not ready for production use.
The activity filter behaves differently from the other filters. You can select only one value in
each category. To remove a filter, from the activity filter dropdown list select the filter you want to remove.
@@ -149,6 +153,9 @@ Selection behavior when using the activity filter:
- **Merge request**
- **Has merge request**: Vulnerabilities with one or more associated merge requests.
- **Does not have merge request**: Vulnerabilities without an associated merge request.
+- **Solution available**
+ - **Has a solution**: Vulnerabilities with an available solution.
+ - **Does not have a solution**: Vulnerabilities without an available solution.
## View details of a vulnerability
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 81f15227c8c..dfcbc8a171d 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -163,7 +163,7 @@ To lock an issue or merge request:
1. On the left sidebar, select **Search or go to** and find your project.
1. For merge requests, select **Code > Merge requests**, and find your merge request.
1. For issues, select **Plan > Issues**, and find your issue.
-1. On the upper-right corner, select **Merge request actions** or **Issue actions** (**{ellipsis_v}**), then select **Lock discussion**.
+1. In the upper-right corner, select **Merge request actions** or **Issue actions** (**{ellipsis_v}**), then select **Lock discussion**.
A system note is added to the page details.
diff --git a/doc/user/product_analytics/index.md b/doc/user/product_analytics/index.md
index 75e44471f92..9c2826855fa 100644
--- a/doc/user/product_analytics/index.md
+++ b/doc/user/product_analytics/index.md
@@ -150,6 +150,8 @@ The `cube_analytics` data type connects to the Cube instance defined when [produ
All filters and queries are sent to the Cube instance and the returned data is processed by the
product analytics data source to be rendered by the appropriate visualizations.
+Data table visualizations from `cube_analytics` have an additional configuration option for rendering `links` (array of objects, each with `text` and `href` properties to specify the dimensions to be used in links. If `href` contains multiple dimensions, values are joined into a single URL). See [example](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/validators/json_schemas/analytics_visualization.json?ref_type=heads#L112)).
+
### Filling missing data
- Introduced in GitLab 16.3 behind the [feature flag](../../administration/feature_flags.md) named `product_analytics_dashboards`. Disabled by default.
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 6cc5f7c5039..de8ab4b25e9 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -321,20 +321,14 @@ To access your **Followers** and **Following** tabs:
## Enable Code Suggestions **(FREE SAAS)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1 as [Beta](../../policy/experiment-beta-support.md#beta).
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139916) in GitLab 16.8. Available to a percentage of users.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139916) in GitLab 16.8. UI user setting removed.
-A percentage of users can use Code Suggestions without any additional configuration.
+If Code Suggestions is
+[enabled for your top-level group](../group/manage.md#enable-code-suggestions-for-a-group),
+you can use Code Suggestions after you
+[configure a supported IDE extension](../project/repository/code_suggestions/index.md#supported-editor-extensions).
-If the following options are available to you, it means you are **not** part of the percentage of users
-and you must manually enable Code Suggestions for your account:
-
-1. On the left sidebar, select your avatar.
-1. Select **Preferences**.
-1. Select the **Enable Code Suggestions** checkbox.
-1. Select **Save changes**.
-
-NOTE:
-If Code Suggestions are disabled [for any groups that you belong to](../../user/group/manage.md#enable-code-suggestions-for-a-group), then you cannot enable them for yourself. (Your setting has no effect.)
+If Code Suggestions are disabled [for all the groups that you belong to](../../user/group/manage.md#enable-code-suggestions-for-a-group), then you cannot enable them for yourself.
## Integrate your GitLab instance with third-party services
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index 832c1ad63f6..ae7afd35af4 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -355,7 +355,7 @@ To delete an issue:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
-1. On the upper-right corner, select **Issue actions** (**{ellipsis_v}**).
+1. In the upper-right corner, select **Issue actions** (**{ellipsis_v}**).
1. Select **Delete issue**.
Alternatively:
@@ -377,7 +377,7 @@ To promote an issue to an epic:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
-1. On the upper-right corner, select **Issue actions** (**{ellipsis_v}**).
+1. In the upper-right corner, select **Issue actions** (**{ellipsis_v}**).
1. Select **Promote to epic**.
Alternatively, you can use the `/promote` [quick action](../quick_actions.md#issues-merge-requests-and-epics).
diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md
index 72d482edb1a..eeb5be2fab6 100644
--- a/doc/user/project/repository/branches/index.md
+++ b/doc/user/project/repository/branches/index.md
@@ -35,7 +35,7 @@ To create a new branch from the GitLab UI:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
-1. On the upper-right corner, select **New branch**.
+1. In the upper-right corner, select **New branch**.
1. Enter a **Branch name**.
1. In **Create from**, select the base of your branch: an existing branch, an existing
tag, or a commit SHA.
@@ -283,7 +283,7 @@ To do this:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
-1. On the upper right corner of the page, select **More** **{ellipsis_v}**.
+1. In the upper right corner of the page, select **More** **{ellipsis_v}**.
1. Select **Delete merged branches**.
1. In the dialog, enter the word `delete` to confirm, then select **Delete merged branches**.
diff --git a/doc/user/project/repository/code_suggestions/index.md b/doc/user/project/repository/code_suggestions/index.md
index 61b6d3724cd..cc036ae00d8 100644
--- a/doc/user/project/repository/code_suggestions/index.md
+++ b/doc/user/project/repository/code_suggestions/index.md
@@ -147,3 +147,10 @@ Code Suggestions do not prevent you from writing code in your IDE.
## Feedback
Let us know about your Code Suggestions experience in [issue 435783](https://gitlab.com/gitlab-org/gitlab/-/issues/435783).
+
+## Troubleshooting
+
+### Disable Code Suggestions
+
+Individual users can disable Code Suggestions by disabling the feature in their
+[installed IDE editor extension](index.md#supported-editor-extensions).
diff --git a/doc/user/project/repository/code_suggestions/saas.md b/doc/user/project/repository/code_suggestions/saas.md
index 52b023445d5..78355ccb11f 100644
--- a/doc/user/project/repository/code_suggestions/saas.md
+++ b/doc/user/project/repository/code_suggestions/saas.md
@@ -20,7 +20,7 @@ Learn about [data usage when using Code Suggestions](index.md#code-suggestions-d
## Enable Code Suggestions
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1 as [Beta](../../../../policy/experiment-beta-support.md#beta).
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139916) in GitLab 16.8. Available to a percentage of users.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139916) in GitLab 16.8. UI user setting removed.
A group owner must
[enable Code Suggestions for your top-level group](../../../group/manage.md#enable-code-suggestions-for-a-group).
@@ -35,16 +35,10 @@ Prerequisites:
- You must have configured Code Suggestions in a
[supported IDE editor extension](index.md#supported-editor-extensions).
-- Code Suggestions must be enabled for:
- - [The top-level group](../../../group/manage.md#enable-code-suggestions-for-a-group).
- - [Your own account](../../../profile/preferences.md#enable-code-suggestions), if your
- account is not part of the percentage rollout.
+- Code Suggestions must be enabled for [the top-level group](../../../group/manage.md#enable-code-suggestions-for-a-group).
To use Code Suggestions:
-1. Determine if your user account is part of the percentage rollout. See
- [Enable Code Suggestions](../../../profile/preferences.md#enable-code-suggestions)
- for more information.
1. Author your code. As you type, suggestions are displayed.
Code Suggestions provide code snippets or complete the current line, depending on the cursor position.
1. Describe the requirements in natural language. Be concise and specific. Code Suggestions generates functions and code snippets as appropriate.
diff --git a/doc/user/project/repository/code_suggestions/self_managed.md b/doc/user/project/repository/code_suggestions/self_managed.md
index 8c3c4aadc71..7bc5ea9346b 100644
--- a/doc/user/project/repository/code_suggestions/self_managed.md
+++ b/doc/user/project/repository/code_suggestions/self_managed.md
@@ -28,16 +28,19 @@ Learn about [data usage when using Code Suggestions](index.md#code-suggestions-d
## Enable Code Suggestions on self-managed GitLab
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10653) in GitLab 16.1 as [Beta](../../../../policy/experiment-beta-support.md#beta).
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139916) in GitLab 16.8. Available to a percentage of users.
+> - [Enabled self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139916) in GitLab 16.8.
When you enable Code Suggestions for your self-managed instance, you:
- Agree to the [GitLab testing agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
- Acknowledge that GitLab sends data from the instance, including personal data, to GitLab.com infrastructure.
-How you enable Code Suggestions for your instance differs depending on your version of GitLab.
+How you enable Code Suggestions for your instance differs depending on your
+version of GitLab. This setting is visible only in self-managed GitLab instances.
-### GitLab 16.3 and later **(PREMIUM)**
+::Tabs
+
+:::TabTitle GitLab 16.3 and later **(PREMIUM)**
Prerequisites:
@@ -53,17 +56,12 @@ To enable Code Suggestions for your self-managed GitLab instance:
In GitLab 16.3, you do not need to enter anything into the **Personal access token** field.
In GitLab 16.4 and later, there is no **Personal access token** field.
1. Select **Save changes**.
-
-This setting is visible only in self-managed GitLab instances.
-
-WARNING:
-In GitLab 16.2 and earlier, if you clear the **Turn on Code Suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
-
-To make sure Code Suggestions works immediately, you must [manually synchronize your subscription](#manually-synchronize-your-subscription).
+1. To make sure Code Suggestions works immediately, you must
+ [manually synchronize your subscription](#manually-synchronize-your-subscription).
The users in your instance can now use Code Suggestions.
-### GitLab 16.2 and earlier
+:::TabTitle GitLab 16.2 and earlier
FLAG:
On self-managed GitLab 16.0 and earlier, GitLab Duo Code Suggestions is not available. To use this feature, you must have GitLab 16.1 or later. For optimal performance and full feature access, you should upgrade to GitLab 16.3 or later, which supports cloud licensing.
@@ -75,7 +73,7 @@ Prerequisites:
- You have a [GitLab SaaS account](https://gitlab.com/users/sign_up). You do not need to have a GitLab SaaS subscription.
NOTE:
-If you do not have a customer success manager, you cannot participate in the free trial of Code Suggestions on self-managed GitLab. Upgrade to GitLab 16.3 to [perform self-service onboarding](#gitlab-163-and-later).
+If you do not have a customer success manager, you cannot participate in the free trial of Code Suggestions on self-managed GitLab. Upgrade to GitLab 16.3 or later to perform self-service onboarding.
Then, you will:
@@ -83,7 +81,7 @@ Then, you will:
1. Enable Code Suggestions for the instance.
1. [Request early access](#request-access-to-code-suggestions) to the Code Suggestions Beta.
-#### Enable Code Suggestions for your SaaS account
+### Enable Code Suggestions for your SaaS account
To enable Code Suggestions for your GitLab SaaS account:
@@ -94,7 +92,7 @@ To enable Code Suggestions for your GitLab SaaS account:
1. In the **Code Suggestions** section, select **Enable Code Suggestions**.
1. Select **Save changes**.
-#### Enable Code Suggestions for the instance
+### Enable Code Suggestions for the instance
To enable Code Suggestions for your self-managed GitLab instance:
@@ -110,7 +108,7 @@ This setting is visible only in self-managed GitLab instances.
WARNING:
If you clear the **Turn on Code Suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
-#### Request access to Code Suggestions
+### Request access to Code Suggestions
GitLab provisions access on a customer-by-customer basis for Code Suggestions
on self-managed instances. To request access, contact your customer success manager.
@@ -120,7 +118,7 @@ Your customer success manager then provisions access by commenting on [issue 415
After GitLab has provisioned access to Code Suggestions for your instance,
the users in your instance can now enable Code Suggestions.
-### Configure network and proxy settings
+## Configure network and proxy settings
Configure any firewalls to allow outbound connections to `https://codesuggestions.gitlab.com/`.
@@ -128,7 +126,7 @@ If your GitLab instance uses an HTTP proxy server to access the internet, ensure
the server is configured to allow outbound connections, including the
[`gitlab_workhorse` environment variable](https://docs.gitlab.com/omnibus/settings/environment-variables.html).
-### Upgrade GitLab
+## Upgrade GitLab
In GitLab 16.3 and later, GitLab is enforcing the cloud licensing requirement for Code Suggestions:
@@ -142,7 +140,7 @@ to continue having early access to Code Suggestions, you must:
1. Make sure you have the latest version of your [IDE extension](index.md#supported-editor-extensions).
1. [Manually synchronize your subscription](#manually-synchronize-your-subscription).
-#### Manually synchronize your subscription
+### Manually synchronize your subscription
You must [manually synchronize your subscription](../../../../subscriptions/self_managed/index.md#manually-synchronize-your-subscription-details) if either:
@@ -151,6 +149,8 @@ You must [manually synchronize your subscription](../../../../subscriptions/self
Without the manual synchronization, it might take up to 24 hours to active Code Suggestions on your instance.
+::EndTabs
+
## Use Code Suggestions
Prerequisites:
diff --git a/doc/user/project/repository/code_suggestions/troubleshooting.md b/doc/user/project/repository/code_suggestions/troubleshooting.md
index 22398395c2c..067831d3fa9 100644
--- a/doc/user/project/repository/code_suggestions/troubleshooting.md
+++ b/doc/user/project/repository/code_suggestions/troubleshooting.md
@@ -14,7 +14,6 @@ If Code Suggestions are not displayed, and you have [installed a supported IDE e
In GitLab, ensure Code Suggestions is enabled:
-- [For your user account](../../../profile/preferences.md#enable-code-suggestions).
- [For **all** top-level groups your account belongs to](../../../group/manage.md#enable-code-suggestions-for-a-group). If you don't have a role that lets you view the top-level group's settings, contact a group owner.
### Code Suggestions not displayed in VS Code or GitLab WebIDE
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a2feeeedf89..172d1f3d9aa 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -51119,6 +51119,16 @@ msgstr ""
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{count} match"
+msgid_plural "Tracing|%{count} matches"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Tracing|%{count} span"
+msgid_plural "Tracing|%{count} spans"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Tracing|%{ms} ms"
msgstr ""
diff --git a/spec/components/pajamas/avatar_component_spec.rb b/spec/components/pajamas/avatar_component_spec.rb
index d59ef390fad..9c1a40ad5b5 100644
--- a/spec/components/pajamas/avatar_component_spec.rb
+++ b/spec/components/pajamas/avatar_component_spec.rb
@@ -5,16 +5,25 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group) }
+ let_it_be(:email) { Pajamas::AvatarEmail.new('kitty@cat.com') }
let(:options) { {} }
before do
- render_inline(described_class.new(record, **options))
+ render_inline(described_class.new(item, **options))
end
describe "avatar shape" do
context "for a User" do
- let(:record) { user }
+ let(:item) { user }
+
+ it "has a circle shape" do
+ expect(page).to have_css ".gl-avatar.gl-avatar-circle"
+ end
+ end
+
+ context "for an Email" do
+ let(:item) { email }
it "has a circle shape" do
expect(page).to have_css ".gl-avatar.gl-avatar-circle"
@@ -22,7 +31,7 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do
end
context "for a Project" do
- let(:record) { project }
+ let(:item) { project }
it "has default shape (rect)" do
expect(page).to have_css ".gl-avatar"
@@ -31,7 +40,7 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do
end
context "for a Group" do
- let(:record) { group }
+ let(:item) { group }
it "has default shape (rect)" do
expect(page).to have_css ".gl-avatar"
@@ -42,11 +51,11 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do
describe "avatar image" do
context "when it has an uploaded image" do
- let(:record) { project }
+ let(:item) { project }
before do
- allow(record).to receive(:avatar_url).and_return "/example.png"
- render_inline(described_class.new(record, **options))
+ allow(item).to receive(:avatar_url).and_return "/example.png"
+ render_inline(described_class.new(item, **options))
end
it "uses the avatar_url as image src" do
@@ -73,14 +82,14 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do
end
context "when a project or group has no uploaded image" do
- let(:record) { project }
+ let(:item) { project }
- it "uses an identicon with the record's initial" do
- expect(page).to have_css "div.gl-avatar.gl-avatar-identicon", text: record.name[0].upcase
+ it "uses an identicon with the item's initial" do
+ expect(page).to have_css "div.gl-avatar.gl-avatar-identicon", text: item.name[0].upcase
end
- context "when the record has no id" do
- let(:record) { build :group }
+ context "when the item has no id" do
+ let(:item) { build :group }
it "uses an identicon with default background color" do
expect(page).to have_css "div.gl-avatar.gl-avatar-identicon-bg1"
@@ -89,16 +98,34 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do
end
context "when a user has no uploaded image" do
- let(:record) { user }
+ let(:item) { user }
it "uses a gravatar" do
expect(rendered_content).to match /gravatar\.com/
end
end
+
+ context "when an email has no linked user" do
+ context "when the email is blank" do
+ let(:item) { Pajamas::AvatarEmail.new('') }
+
+ it "uses the default avatar" do
+ expect(rendered_content).to match /no_avatar/
+ end
+ end
+
+ context "when the email is not blank" do
+ let(:item) { email }
+
+ it "uses a agravatar" do
+ expect(rendered_content).to match /gravatar\.com/
+ end
+ end
+ end
end
describe "options" do
- let(:record) { user }
+ let(:item) { user }
describe "alt" do
context "with a value" do
@@ -110,8 +137,8 @@ RSpec.describe Pajamas::AvatarComponent, type: :component do
end
context "without a value" do
- it "uses the record's name as alt text" do
- expect(page).to have_css ".gl-avatar[alt='#{record.name}']"
+ it "uses the item's name as alt text" do
+ expect(page).to have_css ".gl-avatar[alt='#{item.name}']"
end
end
end
diff --git a/spec/graphql/resolvers/ml/find_models_resolver_spec.rb b/spec/graphql/resolvers/ml/find_models_resolver_spec.rb
new file mode 100644
index 00000000000..ce85dd62515
--- /dev/null
+++ b/spec/graphql/resolvers/ml/find_models_resolver_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Ml::FindModelsResolver, feature_category: :mlops do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:models) { create_list(:ml_models, 2, project: project) }
+ let_it_be(:model_in_another_project) { create(:ml_models) }
+ let_it_be(:user) { project.owner }
+
+ let(:args) { { name: 'model', orderBy: 'CREATED_AT', sort: 'desc', invalid: 'blah' } }
+ let(:read_model_registry) { true }
+
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?)
+ .with(user, :read_model_registry, project)
+ .and_return(read_model_registry)
+ end
+
+ subject(:resolve_models) do
+ force(resolve(described_class, obj: project, ctx: { current_user: user }, args: args))&.to_a
+ end
+
+ context 'when user is allowed and model exists' do
+ it { is_expected.to eq(models.reverse) }
+
+ it 'only passes name, sort_by and order to finder' do
+ expect(::Projects::Ml::ModelFinder).to receive(:new)
+ .with(project, { name: 'model', order_by: 'created_at',
+sort: 'desc' })
+ .and_call_original
+
+ resolve_models
+ end
+ end
+
+ context 'when user does not have permission' do
+ let(:read_model_registry) { false }
+
+ it { is_expected.to be_nil }
+ end
+ end
+end
diff --git a/spec/graphql/types/ml/model_links_type_spec.rb b/spec/graphql/types/ml/model_links_type_spec.rb
new file mode 100644
index 00000000000..e33102c8f7f
--- /dev/null
+++ b/spec/graphql/types/ml/model_links_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['MLModelLinks'], feature_category: :mlops do
+ it 'has the expected fields' do
+ expected_fields = %w[showPath]
+
+ expect(described_class).to include_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ml/model_type_spec.rb b/spec/graphql/types/ml/model_type_spec.rb
index ee0473ccafe..79edea29eb8 100644
--- a/spec/graphql/types/ml/model_type_spec.rb
+++ b/spec/graphql/types/ml/model_type_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe GitlabSchema.types['MlModel'], feature_category: :mlops do
specify { expect(described_class.description).to eq('Machine learning model in the model registry') }
it 'includes all the package fields' do
- expected_fields = %w[id name versions candidates]
+ expected_fields = %w[id name versions candidates version_count _links created_at latest_version]
expect(described_class).to include_graphql_fields(*expected_fields)
end
diff --git a/spec/graphql/types/ml/model_version_links_type_spec.rb b/spec/graphql/types/ml/model_version_links_type_spec.rb
index d2a11643c35..63083b441e3 100644
--- a/spec/graphql/types/ml/model_version_links_type_spec.rb
+++ b/spec/graphql/types/ml/model_version_links_type_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['MLModelVersionLinks'], feature_category: :mlops do
it 'has the expected fields' do
- expected_fields = %w[showPath]
+ expected_fields = %w[showPath packagePath]
expect(described_class).to include_graphql_fields(*expected_fields)
end
diff --git a/spec/graphql/types/ml/models_order_by_enum_spec.rb b/spec/graphql/types/ml/models_order_by_enum_spec.rb
new file mode 100644
index 00000000000..211e073e8c1
--- /dev/null
+++ b/spec/graphql/types/ml/models_order_by_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['MlModelsOrderBy'], feature_category: :mlops do
+ specify { expect(described_class.graphql_name).to eq('MlModelsOrderBy') }
+
+ it 'exposes all the existing order by types' do
+ expect(described_class.values.keys).to match_array(%w[CREATED_AT ID UPDATED_AT NAME])
+ end
+end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 3965312316b..f97ec4514f9 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe GitlabSchema.types['Project'], feature_category: :groups_and_proj
recent_issue_boards ci_config_path_or_default packages_cleanup_policy ci_variables
timelog_categories fork_targets branch_rules ci_config_variables pipeline_schedules languages
incident_management_timeline_event_tags visible_forks inherited_ci_variables autocomplete_users
- ci_cd_settings detailed_import_status value_streams
+ ci_cd_settings detailed_import_status value_streams ml_models
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -532,6 +532,13 @@ RSpec.describe GitlabSchema.types['Project'], feature_category: :groups_and_proj
it { is_expected.to have_graphql_type(Types::IncidentManagement::TimelineEventTagType) }
end
+ describe 'mlModels field' do
+ subject { described_class.fields['mlModels'] }
+
+ it { is_expected.to have_graphql_type(Types::Ml::ModelType.connection_type) }
+ it { is_expected.to have_graphql_resolver(Resolvers::Ml::FindModelsResolver) }
+ end
+
describe 'agent_configurations' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/container_repositories_spec.rb b/spec/requests/api/graphql/project/container_repositories_spec.rb
index c86d3bdd14c..2307409c383 100644
--- a/spec/requests/api/graphql/project/container_repositories_spec.rb
+++ b/spec/requests/api/graphql/project/container_repositories_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
- let(:excluded_fields) { %w[pipeline jobs productAnalyticsState] }
+ let(:excluded_fields) { %w[pipeline jobs productAnalyticsState mlModels] }
let(:container_repositories_fields) do
<<~GQL
edges {
@@ -155,7 +155,7 @@ RSpec.describe 'getting container repositories in a project', feature_category:
it_behaves_like 'handling graphql network errors with the container registry'
it_behaves_like 'not hitting graphql network errors with the container registry' do
- let(:excluded_fields) { %w[pipeline jobs tags tagsCount productAnalyticsState] }
+ let(:excluded_fields) { %w[pipeline jobs tags tagsCount productAnalyticsState mlModels] }
end
it 'returns the total count of container repositories' do
diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb
index 23be9fa5286..96933505838 100644
--- a/spec/requests/api/graphql/project/merge_request_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'getting merge request information nested in a project', feature_
# we exclude Project.pipeline because it needs arguments,
# codequalityReportsComparer because it is behind a feature flag
# and runners because the user is not an admin and therefore has no access
- let(:excluded) { %w[jobs pipeline runners codequalityReportsComparer] }
+ let(:excluded) { %w[jobs pipeline runners codequalityReportsComparer mlModels] }
let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: excluded) }
before do
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index 913316c8622..0cdddeaa84a 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -157,7 +157,7 @@ module LoginHelpers
mock_auth_hash(provider, uid, email, response_object: response_object)
end
- def configure_mock_auth(provider, uid, email, response_object: nil, additional_info: {}, name: 'mockuser')
+ def configure_mock_auth(provider, uid, email, response_object: nil, additional_info: {}, name: 'mockuser', groups: [])
# The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing.
@@ -180,7 +180,8 @@ module LoginHelpers
name: 'mockuser',
email: email,
image: 'mock_user_thumbnail_url'
- }
+ },
+ 'groups' => groups
}
),
response_object: response_object
@@ -188,9 +189,9 @@ module LoginHelpers
}).merge(additional_info) { |_, old_hash, new_hash| old_hash.merge(new_hash) }
end
- def mock_auth_hash(provider, uid, email, additional_info: {}, response_object: nil, name: 'mockuser')
+ def mock_auth_hash(provider, uid, email, additional_info: {}, response_object: nil, name: 'mockuser', groups: [])
configure_mock_auth(
- provider, uid, email, additional_info: additional_info, response_object: response_object, name: name
+ provider, uid, email, additional_info: additional_info, response_object: response_object, name: name, groups: groups
)
original_env_config_omniauth_auth = Rails.application.env_config['omniauth.auth']