Commit a1f735cc authored by Alex Kalderimis's avatar Alex Kalderimis

Merge branch 'show-gitpod-button' into 'master'

Show Gitpod button and pipeline editor buttons

See merge request gitlab-org/gitlab!81902
parents 65d402df 209af09b
...@@ -14,6 +14,8 @@ import WebIdeLink from '~/vue_shared/components/web_ide_link.vue'; ...@@ -14,6 +14,8 @@ import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
import CodeIntelligence from '~/code_navigation/components/app.vue'; import CodeIntelligence from '~/code_navigation/components/app.vue';
import getRefMixin from '../mixins/get_ref'; import getRefMixin from '../mixins/get_ref';
import blobInfoQuery from '../queries/blob_info.query.graphql'; import blobInfoQuery from '../queries/blob_info.query.graphql';
import userInfoQuery from '../queries/user_info.query.graphql';
import applicationInfoQuery from '../queries/application_info.query.graphql';
import { DEFAULT_BLOB_INFO, TEXT_FILE_TYPE, LFS_STORAGE } from '../constants'; import { DEFAULT_BLOB_INFO, TEXT_FILE_TYPE, LFS_STORAGE } from '../constants';
import BlobButtonGroup from './blob_button_group.vue'; import BlobButtonGroup from './blob_button_group.vue';
import ForkSuggestion from './fork_suggestion.vue'; import ForkSuggestion from './fork_suggestion.vue';
...@@ -40,6 +42,18 @@ export default { ...@@ -40,6 +42,18 @@ export default {
}, },
}, },
apollo: { apollo: {
gitpodEnabled: {
query: applicationInfoQuery,
error() {
this.displayError();
},
},
currentUser: {
query: userInfoQuery,
error() {
this.displayError();
},
},
project: { project: {
query: blobInfoQuery, query: blobInfoQuery,
variables() { variables() {
...@@ -81,7 +95,9 @@ export default { ...@@ -81,7 +95,9 @@ export default {
isBinary: false, isBinary: false,
isLoadingLegacyViewer: false, isLoadingLegacyViewer: false,
activeViewerType: SIMPLE_BLOB_VIEWER, activeViewerType: SIMPLE_BLOB_VIEWER,
project: DEFAULT_BLOB_INFO, project: DEFAULT_BLOB_INFO.project,
gitpodEnabled: DEFAULT_BLOB_INFO.gitpodEnabled,
currentUser: DEFAULT_BLOB_INFO.currentUser,
}; };
}, },
computed: { computed: {
...@@ -226,22 +242,18 @@ export default { ...@@ -226,22 +242,18 @@ export default {
:edit-url="blobInfo.editBlobPath" :edit-url="blobInfo.editBlobPath"
:web-ide-url="blobInfo.ideEditPath" :web-ide-url="blobInfo.ideEditPath"
:needs-to-fork="showForkSuggestion" :needs-to-fork="showForkSuggestion"
:show-pipeline-editor-button="Boolean(blobInfo.pipelineEditorPath)"
:pipeline-editor-url="blobInfo.pipelineEditorPath"
:gitpod-url="blobInfo.gitpodBlobUrl"
:show-gitpod-button="gitpodEnabled"
:gitpod-enabled="currentUser && currentUser.gitpodEnabled"
:user-preferences-gitpod-path="currentUser && currentUser.preferencesGitpodPath"
:user-profile-enable-gitpod-path="currentUser && currentUser.profileEnableGitpodPath"
is-blob is-blob
disable-fork-modal disable-fork-modal
@edit="editBlob" @edit="editBlob"
/> />
<gl-button
v-if="blobInfo.pipelineEditorPath"
class="gl-mr-3"
category="secondary"
variant="confirm"
data-testid="pipeline-editor"
:href="blobInfo.pipelineEditorPath"
>
{{ $options.i18n.pipelineEditor }}
</gl-button>
<blob-button-group <blob-button-group
v-if="isLoggedIn && !blobInfo.archived" v-if="isLoggedIn && !blobInfo.archived"
:path="path" :path="path"
......
...@@ -27,6 +27,12 @@ export const PDF_MAX_PAGE_LIMIT = 50; ...@@ -27,6 +27,12 @@ export const PDF_MAX_PAGE_LIMIT = 50;
export const ROW_APPEAR_DELAY = 150; export const ROW_APPEAR_DELAY = 150;
export const DEFAULT_BLOB_INFO = { export const DEFAULT_BLOB_INFO = {
gitpodEnabled: false,
currentUser: {
gitpodEnabled: false,
preferencesGitpodPath: null,
profileEnableGitpodPath: null,
},
userPermissions: { userPermissions: {
pushCode: false, pushCode: false,
downloadCode: false, downloadCode: false,
...@@ -49,6 +55,7 @@ export const DEFAULT_BLOB_INFO = { ...@@ -49,6 +55,7 @@ export const DEFAULT_BLOB_INFO = {
tooLarge: false, tooLarge: false,
path: '', path: '',
editBlobPath: '', editBlobPath: '',
gitpodBlobUrl: '',
ideEditPath: '', ideEditPath: '',
forkAndEditPath: '', forkAndEditPath: '',
ideForkAndEditPath: '', ideForkAndEditPath: '',
......
...@@ -28,6 +28,7 @@ query getBlobInfo( ...@@ -28,6 +28,7 @@ query getBlobInfo(
language language
path path
editBlobPath editBlobPath
gitpodBlobUrl
ideEditPath ideEditPath
forkAndEditPath forkAndEditPath
ideForkAndEditPath ideForkAndEditPath
......
query getUserInfo {
currentUser {
id
gitpodEnabled
preferencesGitpodPath
profileEnableGitpodPath
}
}
...@@ -150,6 +150,10 @@ module Types ...@@ -150,6 +150,10 @@ module Types
resolver: Resolvers::TopicsResolver, resolver: Resolvers::TopicsResolver,
description: "Find project topics." description: "Find project topics."
field :gitpod_enabled, GraphQL::Types::Boolean,
null: true,
description: "Whether Gitpod is enabled in application settings."
def design_management def design_management
DesignManagementObject.new(nil) DesignManagementObject.new(nil)
end end
...@@ -194,6 +198,10 @@ module Types ...@@ -194,6 +198,10 @@ module Types
Gitlab::CurrentSettings.current_application_settings Gitlab::CurrentSettings.current_application_settings
end end
def gitpod_enabled
application_settings.gitpod_enabled
end
def query_complexity def query_complexity
context.query context.query
end end
......
...@@ -77,6 +77,9 @@ module Types ...@@ -77,6 +77,9 @@ module Types
field :pipeline_editor_path, GraphQL::Types::String, null: true, field :pipeline_editor_path, GraphQL::Types::String, null: true,
description: 'Web path to edit .gitlab-ci.yml file.' description: 'Web path to edit .gitlab-ci.yml file.'
field :gitpod_blob_url, GraphQL::Types::String, null: true,
description: 'URL to the blob within Gitpod.'
field :find_file_path, GraphQL::Types::String, null: true, field :find_file_path, GraphQL::Types::String, null: true,
description: 'Web path to find file.' description: 'Web path to find file.'
......
...@@ -116,6 +116,15 @@ module Types ...@@ -116,6 +116,15 @@ module Types
complexity: 5, complexity: 5,
resolver: ::Resolvers::TimelogResolver resolver: ::Resolvers::TimelogResolver
field :gitpod_enabled, GraphQL::Types::Boolean, null: true,
description: 'Whether Gitpod is enabled at the user level.'
field :preferences_gitpod_path, GraphQL::Types::String, null: true,
description: 'Web path to the Gitpod section within user preferences.'
field :profile_enable_gitpod_path, GraphQL::Types::String, null: true,
description: 'Web path to enable Gitpod for the user.'
definition_methods do definition_methods do
def resolve_type(object, context) def resolve_type(object, context)
# in the absense of other information, we cannot tell - just default to # in the absense of other information, we cannot tell - just default to
......
...@@ -62,6 +62,12 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated ...@@ -62,6 +62,12 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
project_ci_pipeline_editor_path(project, branch_name: blob.commit_id) if can_collaborate_with_project?(project) && blob.path == project.ci_config_path_or_default project_ci_pipeline_editor_path(project, branch_name: blob.commit_id) if can_collaborate_with_project?(project) && blob.path == project.ci_config_path_or_default
end end
def gitpod_blob_url
return unless Gitlab::CurrentSettings.gitpod_enabled && !current_user.nil? && current_user.gitpod_enabled
"#{Gitlab::CurrentSettings.gitpod_url}##{url_helpers.project_tree_url(project, tree_join(blob.commit_id, blob.path || ''))}"
end
def find_file_path def find_file_path
url_helpers.project_find_file_path(project, ref_qualified_path) url_helpers.project_find_file_path(project, ref_qualified_path)
end end
......
...@@ -11,6 +11,14 @@ class UserPresenter < Gitlab::View::Presenter::Delegated ...@@ -11,6 +11,14 @@ class UserPresenter < Gitlab::View::Presenter::Delegated
should_be_private? ? ProjectMember.none : user.project_members should_be_private? ? ProjectMember.none : user.project_members
end end
def preferences_gitpod_path
profile_preferences_path(anchor: 'user_gitpod_enabled') if application_gitpod_enabled?
end
def profile_enable_gitpod_path
profile_path(user: { gitpod_enabled: true }) if application_gitpod_enabled?
end
private private
def can?(*args) def can?(*args)
...@@ -20,4 +28,8 @@ class UserPresenter < Gitlab::View::Presenter::Delegated ...@@ -20,4 +28,8 @@ class UserPresenter < Gitlab::View::Presenter::Delegated
def should_be_private? def should_be_private?
!Ability.allowed?(current_user, :read_user_profile, user) !Ability.allowed?(current_user, :read_user_profile, user)
end end
def application_gitpod_enabled?
Gitlab::CurrentSettings.gitpod_enabled
end
end end
...@@ -157,6 +157,12 @@ Returns [`GeoNode`](#geonode). ...@@ -157,6 +157,12 @@ Returns [`GeoNode`](#geonode).
| ---- | ---- | ----------- | | ---- | ---- | ----------- |
| <a id="querygeonodename"></a>`name` | [`String`](#string) | Name of the Geo node. Defaults to the current Geo node name. | | <a id="querygeonodename"></a>`name` | [`String`](#string) | Name of the Geo node. Defaults to the current Geo node name. |
### `Query.gitpodEnabled`
Whether Gitpod is enabled in application settings.
Returns [`Boolean`](#boolean).
### `Query.group` ### `Query.group`
Find a group. Find a group.
...@@ -12447,6 +12453,7 @@ A user assigned to a merge request. ...@@ -12447,6 +12453,7 @@ A user assigned to a merge request.
| <a id="mergerequestassigneebot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. | | <a id="mergerequestassigneebot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| <a id="mergerequestassigneecallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) | | <a id="mergerequestassigneecallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| <a id="mergerequestassigneeemail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). | | <a id="mergerequestassigneeemail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
| <a id="mergerequestassigneegitpodenabled"></a>`gitpodEnabled` | [`Boolean`](#boolean) | Whether Gitpod is enabled at the user level. |
| <a id="mergerequestassigneegroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. | | <a id="mergerequestassigneegroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. |
| <a id="mergerequestassigneegroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) | | <a id="mergerequestassigneegroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) |
| <a id="mergerequestassigneeid"></a>`id` | [`ID!`](#id) | ID of the user. | | <a id="mergerequestassigneeid"></a>`id` | [`ID!`](#id) | ID of the user. |
...@@ -12454,6 +12461,8 @@ A user assigned to a merge request. ...@@ -12454,6 +12461,8 @@ A user assigned to a merge request.
| <a id="mergerequestassigneemergerequestinteraction"></a>`mergeRequestInteraction` | [`UserMergeRequestInteraction`](#usermergerequestinteraction) | Details of this user's interactions with the merge request. | | <a id="mergerequestassigneemergerequestinteraction"></a>`mergeRequestInteraction` | [`UserMergeRequestInteraction`](#usermergerequestinteraction) | Details of this user's interactions with the merge request. |
| <a id="mergerequestassigneename"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. | | <a id="mergerequestassigneename"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. |
| <a id="mergerequestassigneenamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. | | <a id="mergerequestassigneenamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. |
| <a id="mergerequestassigneepreferencesgitpodpath"></a>`preferencesGitpodPath` | [`String`](#string) | Web path to the Gitpod section within user preferences. |
| <a id="mergerequestassigneeprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="mergerequestassigneeprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) | | <a id="mergerequestassigneeprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="mergerequestassigneepublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. | | <a id="mergerequestassigneepublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="mergerequestassigneestate"></a>`state` | [`UserState!`](#userstate) | State of the user. | | <a id="mergerequestassigneestate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
...@@ -12708,6 +12717,7 @@ A user assigned to a merge request as a reviewer. ...@@ -12708,6 +12717,7 @@ A user assigned to a merge request as a reviewer.
| <a id="mergerequestreviewerbot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. | | <a id="mergerequestreviewerbot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| <a id="mergerequestreviewercallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) | | <a id="mergerequestreviewercallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| <a id="mergerequestrevieweremail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). | | <a id="mergerequestrevieweremail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
| <a id="mergerequestreviewergitpodenabled"></a>`gitpodEnabled` | [`Boolean`](#boolean) | Whether Gitpod is enabled at the user level. |
| <a id="mergerequestreviewergroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. | | <a id="mergerequestreviewergroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. |
| <a id="mergerequestreviewergroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) | | <a id="mergerequestreviewergroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) |
| <a id="mergerequestreviewerid"></a>`id` | [`ID!`](#id) | ID of the user. | | <a id="mergerequestreviewerid"></a>`id` | [`ID!`](#id) | ID of the user. |
...@@ -12715,6 +12725,8 @@ A user assigned to a merge request as a reviewer. ...@@ -12715,6 +12725,8 @@ A user assigned to a merge request as a reviewer.
| <a id="mergerequestreviewermergerequestinteraction"></a>`mergeRequestInteraction` | [`UserMergeRequestInteraction`](#usermergerequestinteraction) | Details of this user's interactions with the merge request. | | <a id="mergerequestreviewermergerequestinteraction"></a>`mergeRequestInteraction` | [`UserMergeRequestInteraction`](#usermergerequestinteraction) | Details of this user's interactions with the merge request. |
| <a id="mergerequestreviewername"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. | | <a id="mergerequestreviewername"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. |
| <a id="mergerequestreviewernamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. | | <a id="mergerequestreviewernamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. |
| <a id="mergerequestreviewerpreferencesgitpodpath"></a>`preferencesGitpodPath` | [`String`](#string) | Web path to the Gitpod section within user preferences. |
| <a id="mergerequestreviewerprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="mergerequestreviewerprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) | | <a id="mergerequestreviewerprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="mergerequestreviewerpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. | | <a id="mergerequestreviewerpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="mergerequestreviewerstate"></a>`state` | [`UserState!`](#userstate) | State of the user. | | <a id="mergerequestreviewerstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
...@@ -15073,6 +15085,7 @@ Returns [`Tree`](#tree). ...@@ -15073,6 +15085,7 @@ Returns [`Tree`](#tree).
| <a id="repositoryblobfindfilepath"></a>`findFilePath` | [`String`](#string) | Web path to find file. | | <a id="repositoryblobfindfilepath"></a>`findFilePath` | [`String`](#string) | Web path to find file. |
| <a id="repositoryblobforkandeditpath"></a>`forkAndEditPath` | [`String`](#string) | Web path to edit this blob using a forked project. | | <a id="repositoryblobforkandeditpath"></a>`forkAndEditPath` | [`String`](#string) | Web path to edit this blob using a forked project. |
| <a id="repositoryblobforkandviewpath"></a>`forkAndViewPath` | [`String`](#string) | Web path to view this blob using a forked project. | | <a id="repositoryblobforkandviewpath"></a>`forkAndViewPath` | [`String`](#string) | Web path to view this blob using a forked project. |
| <a id="repositoryblobgitpodbloburl"></a>`gitpodBlobUrl` | [`String`](#string) | URL to the blob within Gitpod. |
| <a id="repositoryblobhistorypath"></a>`historyPath` | [`String`](#string) | Web path to blob history page. | | <a id="repositoryblobhistorypath"></a>`historyPath` | [`String`](#string) | Web path to blob history page. |
| <a id="repositoryblobid"></a>`id` | [`ID!`](#id) | ID of the blob. | | <a id="repositoryblobid"></a>`id` | [`ID!`](#id) | ID of the blob. |
| <a id="repositoryblobideeditpath"></a>`ideEditPath` | [`String`](#string) | Web path to edit this blob in the Web IDE. | | <a id="repositoryblobideeditpath"></a>`ideEditPath` | [`String`](#string) | Web path to edit this blob in the Web IDE. |
...@@ -16028,12 +16041,15 @@ Core represention of a GitLab user. ...@@ -16028,12 +16041,15 @@ Core represention of a GitLab user.
| <a id="usercorebot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. | | <a id="usercorebot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| <a id="usercorecallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) | | <a id="usercorecallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| <a id="usercoreemail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). | | <a id="usercoreemail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
| <a id="usercoregitpodenabled"></a>`gitpodEnabled` | [`Boolean`](#boolean) | Whether Gitpod is enabled at the user level. |
| <a id="usercoregroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. | | <a id="usercoregroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. |
| <a id="usercoregroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) | | <a id="usercoregroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) |
| <a id="usercoreid"></a>`id` | [`ID!`](#id) | ID of the user. | | <a id="usercoreid"></a>`id` | [`ID!`](#id) | ID of the user. |
| <a id="usercorelocation"></a>`location` | [`String`](#string) | Location of the user. | | <a id="usercorelocation"></a>`location` | [`String`](#string) | Location of the user. |
| <a id="usercorename"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. | | <a id="usercorename"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. |
| <a id="usercorenamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. | | <a id="usercorenamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. |
| <a id="usercorepreferencesgitpodpath"></a>`preferencesGitpodPath` | [`String`](#string) | Web path to the Gitpod section within user preferences. |
| <a id="usercoreprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="usercoreprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) | | <a id="usercoreprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="usercorepublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. | | <a id="usercorepublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="usercorestate"></a>`state` | [`UserState!`](#userstate) | State of the user. | | <a id="usercorestate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
...@@ -19515,12 +19531,15 @@ Implementations: ...@@ -19515,12 +19531,15 @@ Implementations:
| <a id="userbot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. | | <a id="userbot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
| <a id="usercallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) | | <a id="usercallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
| <a id="useremail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). | | <a id="useremail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
| <a id="usergitpodenabled"></a>`gitpodEnabled` | [`Boolean`](#boolean) | Whether Gitpod is enabled at the user level. |
| <a id="usergroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. | | <a id="usergroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. |
| <a id="usergroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) | | <a id="usergroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) |
| <a id="userid"></a>`id` | [`ID!`](#id) | ID of the user. | | <a id="userid"></a>`id` | [`ID!`](#id) | ID of the user. |
| <a id="userlocation"></a>`location` | [`String`](#string) | Location of the user. | | <a id="userlocation"></a>`location` | [`String`](#string) | Location of the user. |
| <a id="username"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. | | <a id="username"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. |
| <a id="usernamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. | | <a id="usernamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. |
| <a id="userpreferencesgitpodpath"></a>`preferencesGitpodPath` | [`String`](#string) | Web path to the Gitpod section within user preferences. |
| <a id="userprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
| <a id="userprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) | | <a id="userprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
| <a id="userpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. | | <a id="userpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
| <a id="userstate"></a>`state` | [`UserState!`](#userstate) | State of the user. | | <a id="userstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
...@@ -19,14 +19,14 @@ RSpec.describe 'User views pipeline editor button on root ci config file', :js d ...@@ -19,14 +19,14 @@ RSpec.describe 'User views pipeline editor button on root ci config file', :js d
project.repository.create_file(user, project.ci_config_path_or_default, 'test', message: 'testing', branch_name: 'master') project.repository.create_file(user, project.ci_config_path_or_default, 'test', message: 'testing', branch_name: 'master')
visit project_blob_path(project, File.join('master', '.my-config.yml')) visit project_blob_path(project, File.join('master', '.my-config.yml'))
expect(page).to have_content('Pipeline Editor') expect(page).to have_content('Edit in pipeline editor')
end end
it 'does not shows the Pipeline Editor button' do it 'does not shows the Pipeline Editor button' do
project.repository.create_file(user, '.my-sub-config.yml', 'test', message: 'testing', branch_name: 'master') project.repository.create_file(user, '.my-sub-config.yml', 'test', message: 'testing', branch_name: 'master')
visit project_blob_path(project, File.join('master', '.my-sub-config.yml')) visit project_blob_path(project, File.join('master', '.my-sub-config.yml'))
expect(page).not_to have_content('Pipeline Editor') expect(page).not_to have_content('Edit in pipeline editor')
end end
end end
...@@ -36,7 +36,7 @@ RSpec.describe 'User views pipeline editor button on root ci config file', :js d ...@@ -36,7 +36,7 @@ RSpec.describe 'User views pipeline editor button on root ci config file', :js d
end end
it 'does not shows the Pipeline Editor button' do it 'does not shows the Pipeline Editor button' do
visit project_blob_path(project, File.join('master', '.my-config.yml')) visit project_blob_path(project, File.join('master', '.my-config.yml'))
expect(page).not_to have_content('Pipeline Editor') expect(page).not_to have_content('Edit in pipeline editor')
end end
end end
end end
...@@ -18,6 +18,8 @@ import DownloadViewer from '~/repository/components/blob_viewers/download_viewer ...@@ -18,6 +18,8 @@ import DownloadViewer from '~/repository/components/blob_viewers/download_viewer
import EmptyViewer from '~/repository/components/blob_viewers/empty_viewer.vue'; import EmptyViewer from '~/repository/components/blob_viewers/empty_viewer.vue';
import SourceViewer from '~/vue_shared/components/source_viewer/source_viewer.vue'; import SourceViewer from '~/vue_shared/components/source_viewer/source_viewer.vue';
import blobInfoQuery from '~/repository/queries/blob_info.query.graphql'; import blobInfoQuery from '~/repository/queries/blob_info.query.graphql';
import userInfoQuery from '~/repository/queries/user_info.query.graphql';
import applicationInfoQuery from '~/repository/queries/application_info.query.graphql';
import CodeIntelligence from '~/code_navigation/components/app.vue'; import CodeIntelligence from '~/code_navigation/components/app.vue';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import { isLoggedIn } from '~/lib/utils/common_utils'; import { isLoggedIn } from '~/lib/utils/common_utils';
...@@ -27,6 +29,8 @@ import { ...@@ -27,6 +29,8 @@ import {
simpleViewerMock, simpleViewerMock,
richViewerMock, richViewerMock,
projectMock, projectMock,
userInfoMock,
applicationInfoMock,
userPermissionsMock, userPermissionsMock,
propsMock, propsMock,
refMock, refMock,
...@@ -38,6 +42,8 @@ jest.mock('~/lib/utils/common_utils'); ...@@ -38,6 +42,8 @@ jest.mock('~/lib/utils/common_utils');
let wrapper; let wrapper;
let mockResolver; let mockResolver;
let userInfoMockResolver;
let applicationInfoMockResolver;
const mockAxios = new MockAdapter(axios); const mockAxios = new MockAdapter(axios);
...@@ -77,7 +83,19 @@ const createComponent = async (mockData = {}, mountFn = shallowMount) => { ...@@ -77,7 +83,19 @@ const createComponent = async (mockData = {}, mountFn = shallowMount) => {
data: { isBinary, project }, data: { isBinary, project },
}); });
const fakeApollo = createMockApollo([[blobInfoQuery, mockResolver]]); userInfoMockResolver = jest.fn().mockResolvedValue({
data: { ...userInfoMock },
});
applicationInfoMockResolver = jest.fn().mockResolvedValue({
data: { ...applicationInfoMock },
});
const fakeApollo = createMockApollo([
[blobInfoQuery, mockResolver],
[userInfoQuery, userInfoMockResolver],
[applicationInfoQuery, applicationInfoMockResolver],
]);
wrapper = extendedWrapper( wrapper = extendedWrapper(
mountFn(BlobContentViewer, { mountFn(BlobContentViewer, {
...@@ -107,7 +125,6 @@ describe('Blob content viewer component', () => { ...@@ -107,7 +125,6 @@ describe('Blob content viewer component', () => {
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findBlobHeader = () => wrapper.findComponent(BlobHeader); const findBlobHeader = () => wrapper.findComponent(BlobHeader);
const findWebIdeLink = () => wrapper.findComponent(WebIdeLink); const findWebIdeLink = () => wrapper.findComponent(WebIdeLink);
const findPipelineEditor = () => wrapper.findByTestId('pipeline-editor');
const findBlobContent = () => wrapper.findComponent(BlobContent); const findBlobContent = () => wrapper.findComponent(BlobContent);
const findBlobButtonGroup = () => wrapper.findComponent(BlobButtonGroup); const findBlobButtonGroup = () => wrapper.findComponent(BlobButtonGroup);
const findForkSuggestion = () => wrapper.findComponent(ForkSuggestion); const findForkSuggestion = () => wrapper.findComponent(ForkSuggestion);
...@@ -290,6 +307,13 @@ describe('Blob content viewer component', () => { ...@@ -290,6 +307,13 @@ describe('Blob content viewer component', () => {
editUrl: editBlobPath, editUrl: editBlobPath,
webIdeUrl: ideEditPath, webIdeUrl: ideEditPath,
showEditButton: true, showEditButton: true,
showGitpodButton: applicationInfoMock.gitpodEnabled,
gitpodEnabled: userInfoMock.currentUser.gitpodEnabled,
showPipelineEditorButton: true,
gitpodUrl: simpleViewerMock.gitpodBlobUrl,
pipelineEditorUrl: simpleViewerMock.pipelineEditorPath,
userPreferencesGitpodPath: userInfoMock.currentUser.preferencesGitpodPath,
userProfileEnableGitpodPath: userInfoMock.currentUser.profileEnableGitpodPath,
}); });
}); });
...@@ -313,15 +337,6 @@ describe('Blob content viewer component', () => { ...@@ -313,15 +337,6 @@ describe('Blob content viewer component', () => {
}); });
}); });
it('renders Pipeline Editor button for .gitlab-ci files', async () => {
const pipelineEditorPath = 'some/path/.gitlab-ce';
const blob = { ...simpleViewerMock, pipelineEditorPath };
await createComponent({ blob, inject: { BlobContent: true, BlobReplace: true } }, mount);
expect(findPipelineEditor().exists()).toBe(true);
expect(findPipelineEditor().attributes('href')).toBe(pipelineEditorPath);
});
describe('blob header binary file', () => { describe('blob header binary file', () => {
it('passes the correct isBinary value when viewing a binary file', async () => { it('passes the correct isBinary value when viewing a binary file', async () => {
await createComponent({ blob: richViewerMock, isBinary: true }); await createComponent({ blob: richViewerMock, isBinary: true });
......
...@@ -9,6 +9,7 @@ export const simpleViewerMock = { ...@@ -9,6 +9,7 @@ export const simpleViewerMock = {
path: 'some_file.js', path: 'some_file.js',
webPath: 'some_file.js', webPath: 'some_file.js',
editBlobPath: 'some_file.js/edit', editBlobPath: 'some_file.js/edit',
gitpodBlobUrl: 'https://gitpod.io#path/to/blob.js',
ideEditPath: 'some_file.js/ide/edit', ideEditPath: 'some_file.js/ide/edit',
forkAndEditPath: 'some_file.js/fork/edit', forkAndEditPath: 'some_file.js/fork/edit',
ideForkAndEditPath: 'some_file.js/fork/ide', ideForkAndEditPath: 'some_file.js/fork/ide',
...@@ -25,7 +26,7 @@ export const simpleViewerMock = { ...@@ -25,7 +26,7 @@ export const simpleViewerMock = {
externalStorage: 'lfs', externalStorage: 'lfs',
rawPath: 'some_file.js', rawPath: 'some_file.js',
replacePath: 'some_file.js/replace', replacePath: 'some_file.js/replace',
pipelineEditorPath: '', pipelineEditorPath: 'path/to/pipeline/editor',
simpleViewer: { simpleViewer: {
fileType: 'text', fileType: 'text',
tooLarge: false, tooLarge: false,
...@@ -70,6 +71,17 @@ export const projectMock = { ...@@ -70,6 +71,17 @@ export const projectMock = {
}, },
}; };
export const userInfoMock = {
currentUser: {
id: '123',
gitpodEnabled: true,
preferencesGitpodPath: '/-/profile/preferences#user_gitpod_enabled',
profileEnableGitpodPath: '/-/profile?user%5Bgitpod_enabled%5D=true',
},
};
export const applicationInfoMock = { gitpodEnabled: true };
export const propsMock = { path: 'some_file.js', projectPath: 'some/path' }; export const propsMock = { path: 'some_file.js', projectPath: 'some/path' };
export const refMock = 'default-ref'; export const refMock = 'default-ref';
......
...@@ -34,6 +34,9 @@ RSpec.describe GitlabSchema.types['MergeRequestReviewer'] do ...@@ -34,6 +34,9 @@ RSpec.describe GitlabSchema.types['MergeRequestReviewer'] do
namespace namespace
timelogs timelogs
groups groups
gitpodEnabled
preferencesGitpodPath
profileEnableGitpodPath
] ]
expect(described_class).to have_graphql_fields(*expected_fields) expect(described_class).to have_graphql_fields(*expected_fields)
......
...@@ -29,6 +29,7 @@ RSpec.describe GitlabSchema.types['Query'] do ...@@ -29,6 +29,7 @@ RSpec.describe GitlabSchema.types['Query'] do
timelogs timelogs
board_list board_list
topics topics
gitpod_enabled
] ]
expect(described_class).to have_graphql_fields(*expected_fields).at_least expect(described_class).to have_graphql_fields(*expected_fields).at_least
......
...@@ -25,6 +25,7 @@ RSpec.describe Types::Repository::BlobType do ...@@ -25,6 +25,7 @@ RSpec.describe Types::Repository::BlobType do
:raw_path, :raw_path,
:replace_path, :replace_path,
:pipeline_editor_path, :pipeline_editor_path,
:gitpod_blob_url,
:find_file_path, :find_file_path,
:blame_path, :blame_path,
:history_path, :history_path,
......
...@@ -39,6 +39,9 @@ RSpec.describe GitlabSchema.types['User'] do ...@@ -39,6 +39,9 @@ RSpec.describe GitlabSchema.types['User'] do
namespace namespace
timelogs timelogs
groups groups
gitpodEnabled
preferencesGitpodPath
profileEnableGitpodPath
] ]
expect(described_class).to have_graphql_fields(*expected_fields) expect(described_class).to have_graphql_fields(*expected_fields)
......
...@@ -71,6 +71,40 @@ RSpec.describe BlobPresenter do ...@@ -71,6 +71,40 @@ RSpec.describe BlobPresenter do
end end
end end
context 'Gitpod' do
let(:gitpod_url) { "https://gitpod.io" }
let(:gitpod_application_enabled) { true }
let(:gitpod_user_enabled) { true }
before do
allow(user).to receive(:gitpod_enabled).and_return(gitpod_user_enabled)
allow(Gitlab::CurrentSettings).to receive(:gitpod_enabled).and_return(gitpod_application_enabled)
allow(Gitlab::CurrentSettings).to receive(:gitpod_url).and_return(gitpod_url)
end
context 'Gitpod enabled for application and user' do
describe '#gitpod_blob_url' do
it { expect(presenter.gitpod_blob_url).to eq("#{gitpod_url}##{"http://localhost/#{project.full_path}/-/tree/#{blob.commit_id}/#{blob.path}"}") }
end
end
context 'Gitpod disabled at application level' do
let(:gitpod_application_enabled) { false }
describe '#gitpod_blob_url' do
it { expect(presenter.gitpod_blob_url).to eq(nil) }
end
end
context 'Gitpod disabled at user level' do
let(:gitpod_user_enabled) { false }
describe '#gitpod_blob_url' do
it { expect(presenter.gitpod_blob_url).to eq(nil) }
end
end
end
describe '#find_file_path' do describe '#find_file_path' do
it { expect(presenter.find_file_path).to eq("/#{project.full_path}/-/find_file/HEAD/files/ruby/regex.rb") } it { expect(presenter.find_file_path).to eq("/#{project.full_path}/-/find_file/HEAD/files/ruby/regex.rb") }
end end
......
...@@ -14,4 +14,36 @@ RSpec.describe UserPresenter do ...@@ -14,4 +14,36 @@ RSpec.describe UserPresenter do
describe '#web_url' do describe '#web_url' do
it { expect(presenter.web_url).to eq("http://localhost/#{user.username}") } it { expect(presenter.web_url).to eq("http://localhost/#{user.username}") }
end end
context 'Gitpod' do
let(:gitpod_url) { "https://gitpod.io" }
let(:gitpod_application_enabled) { true }
before do
allow(Gitlab::CurrentSettings).to receive(:gitpod_enabled).and_return(gitpod_application_enabled)
allow(Gitlab::CurrentSettings).to receive(:gitpod_url).and_return(gitpod_url)
end
context 'Gitpod enabled for application' do
describe '#preferences_gitpod_path' do
it { expect(presenter.preferences_gitpod_path).to eq("/-/profile/preferences#user_gitpod_enabled") }
end
describe '#profile_enable_gitpod_path' do
it { expect(presenter.profile_enable_gitpod_path).to eq("/-/profile?user%5Bgitpod_enabled%5D=true") }
end
end
context 'Gitpod disabled for application' do
let(:gitpod_application_enabled) { false }
describe '#preferences_gitpod_path' do
it { expect(presenter.preferences_gitpod_path).to eq(nil) }
end
describe '#profile_enable_gitpod_path' do
it { expect(presenter.profile_enable_gitpod_path).to eq(nil) }
end
end
end
end end
...@@ -11,6 +11,30 @@ RSpec.describe 'Query' do ...@@ -11,6 +11,30 @@ RSpec.describe 'Query' do
let(:current_user) { developer } let(:current_user) { developer }
describe 'gitpodEnabled field' do
let(:gitpod_enabled) { true }
let(:gitpod_enabled_query) do
<<~GRAPHQL
{ gitpodEnabled }
GRAPHQL
end
before do
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:gitpod_enabled).and_return(gitpod_enabled)
post_graphql(gitpod_enabled_query)
end
context 'When Gitpod is enabled for the application' do
it { expect(graphql_data).to include('gitpodEnabled' => true) }
end
context 'When Gitpod is disabled for the application' do
let(:gitpod_enabled) { false }
it { expect(graphql_data).to include('gitpodEnabled' => false) }
end
end
describe '.designManagement' do describe '.designManagement' do
include DesignManagementTestHelpers include DesignManagementTestHelpers
......
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