Commit 209af09b authored by Jacques Erasmus's avatar Jacques Erasmus Committed by Alex Kalderimis

Display Gitpod and pipeline editor buttons

Displays Gitpod and Pipeline editor buttons in the consolidated dropdown
parent 1c3f6164
...@@ -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