Commit 3f9e766e authored by David O'Regan's avatar David O'Regan

Merge branch 'ph/232157/userReadme' into 'master'

Add user README to users profile

See merge request gitlab-org/gitlab!73726
parents 1d03c8b4 0f5eb7e4
...@@ -43,6 +43,8 @@ const onProjectPathChange = ($projectNameInput, $projectPathInput, hasExistingPr ...@@ -43,6 +43,8 @@ const onProjectPathChange = ($projectNameInput, $projectPathInput, hasExistingPr
}; };
const setProjectNamePathHandlers = ($projectNameInput, $projectPathInput) => { const setProjectNamePathHandlers = ($projectNameInput, $projectPathInput) => {
const specialRepo = document.querySelector('.js-user-readme-repo');
// eslint-disable-next-line @gitlab/no-global-event-off // eslint-disable-next-line @gitlab/no-global-event-off
$projectNameInput.off('keyup change').on('keyup change', () => { $projectNameInput.off('keyup change').on('keyup change', () => {
onProjectNameChange($projectNameInput, $projectPathInput); onProjectNameChange($projectNameInput, $projectPathInput);
...@@ -54,6 +56,11 @@ const setProjectNamePathHandlers = ($projectNameInput, $projectPathInput) => { ...@@ -54,6 +56,11 @@ const setProjectNamePathHandlers = ($projectNameInput, $projectPathInput) => {
$projectPathInput.off('keyup change').on('keyup change', () => { $projectPathInput.off('keyup change').on('keyup change', () => {
onProjectPathChange($projectNameInput, $projectPathInput, hasUserDefinedProjectName); onProjectPathChange($projectNameInput, $projectPathInput, hasUserDefinedProjectName);
hasUserDefinedProjectPath = $projectPathInput.val().trim().length > 0; hasUserDefinedProjectPath = $projectPathInput.val().trim().length > 0;
specialRepo.classList.toggle(
'gl-display-none',
$projectPathInput.val() !== $projectPathInput.data('username'),
);
}); });
}; };
......
...@@ -1992,6 +1992,18 @@ class User < ApplicationRecord ...@@ -1992,6 +1992,18 @@ class User < ApplicationRecord
saved saved
end end
def user_project
strong_memoize(:user_project) do
personal_projects.find_by(path: username, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
end
end
def user_readme
strong_memoize(:user_readme) do
user_project&.repository&.readme
end
end
protected protected
# override, from Devise::Validatable # override, from Devise::Validatable
......
...@@ -40,12 +40,17 @@ ...@@ -40,12 +40,17 @@
.form-group.project-path.col-sm-6 .form-group.project-path.col-sm-6
= f.label :path, class: 'label-bold' do = f.label :path, class: 'label-bold' do
%span= _("Project slug") %span= _("Project slug")
= f.text_field :path, placeholder: "my-awesome-project", class: "form-control gl-form-input", required: true, aria: { required: true } = f.text_field :path, placeholder: "my-awesome-project", class: "form-control gl-form-input", required: true, aria: { required: true }, data: { username: current_user.username }
- if current_user.can_create_group? - if current_user.can_create_group?
.form-text.text-muted .form-text.text-muted
- link_start_group_path = '<a href="%{path}">' % { path: new_group_path } - link_start_group_path = '<a href="%{path}">' % { path: new_group_path }
- project_tip = s_('ProjectsNew|Want to house several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}') % { link_start: link_start_group_path, link_end: '</a>' } - project_tip = s_('ProjectsNew|Want to house several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}') % { link_start: link_start_group_path, link_end: '</a>' }
= project_tip.html_safe = project_tip.html_safe
.gl-alert.gl-alert-success.gl-mb-4.gl-display-none.js-user-readme-repo
= sprite_icon('check-circle', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
.gl-alert-body
- help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/profile/index', anchor: 'user-profile-readme') }
= html_escape(_('%{project_path} is a project that you can use to add a README to your GitLab profile. Create a public project and initialize the repository with a README to get started. %{help_link_start}Learn more.%{help_link_end}')) % { project_path: "<strong>#{current_user.username} / #{current_user.username}</strong>".html_safe, help_link_start: help_link_start, help_link_end: '</a>'.html_safe }
.form-group .form-group
= f.label :description, class: 'label-bold' do = f.label :description, class: 'label-bold' do
......
...@@ -9,6 +9,22 @@ ...@@ -9,6 +9,22 @@
%a.js-retry-load{ href: '#' } %a.js-retry-load{ href: '#' }
= s_('UserProfile|Retry') = s_('UserProfile|Retry')
.user-calendar-activities .user-calendar-activities
- if @user.user_readme
.row
.col-12.gl-my-6
.gl-border-gray-100.gl-border-1.gl-border-solid.gl-rounded-small.gl-py-4.gl-px-6
.gl-display-flex
%ol.breadcrumb.gl-breadcrumb-list.gl-mb-4
%li.breadcrumb-item.gl-breadcrumb-item
= link_to @user.username, project_path(@user.user_project)
%span.gl-breadcrumb-separator
= sprite_icon("chevron-right", size: 16)
%li.breadcrumb-item.gl-breadcrumb-item
= link_to @user.user_readme.path, @user.user_project.readme_url
- if current_user == @user
.gl-ml-auto
= link_to _('Edit'), edit_blob_path(@user.user_project, @user.user_project.default_branch, @user.user_readme.path)
= render 'projects/blob/viewer', viewer: @user.user_readme.rich_viewer, load_async: false
.row .row
%div{ class: activity_pane_class } %div{ class: activity_pane_class }
- if can?(current_user, :read_cross_project) - if can?(current_user, :read_cross_project)
......
...@@ -100,6 +100,18 @@ When visiting the public page of a user, you can only see the projects which you ...@@ -100,6 +100,18 @@ When visiting the public page of a user, you can only see the projects which you
If the [public level is restricted](../admin_area/settings/visibility_and_access_controls.md#restrict-visibility-levels), If the [public level is restricted](../admin_area/settings/visibility_and_access_controls.md#restrict-visibility-levels),
user profiles are only visible to signed-in users. user profiles are only visible to signed-in users.
## User profile README
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/232157) in GitLab 14.5.
You can add a README section to your profile that can include more information and formatting than
your profile's bio.
To add a README to your profile:
1. Create a new public project with the same name as your GitLab username.
1. Create a README file inside this project. The file can be any valid [README or index file](../project/repository/index.md#readme-and-index-files).
## Add external accounts to your user profile page ## Add external accounts to your user profile page
You can add links to certain other external accounts you might have, like Skype and Twitter. You can add links to certain other external accounts you might have, like Skype and Twitter.
......
...@@ -815,6 +815,9 @@ msgstr "" ...@@ -815,6 +815,9 @@ msgstr ""
msgid "%{primary} (%{secondary})" msgid "%{primary} (%{secondary})"
msgstr "" msgstr ""
msgid "%{project_path} is a project that you can use to add a README to your GitLab profile. Create a public project and initialize the repository with a README to get started. %{help_link_start}Learn more.%{help_link_end}"
msgstr ""
msgid "%{ref} cannot be added: %{error}" msgid "%{ref} cannot be added: %{error}"
msgstr "" msgstr ""
......
...@@ -21,6 +21,14 @@ RSpec.describe 'User visits their profile' do ...@@ -21,6 +21,14 @@ RSpec.describe 'User visits their profile' do
expect(page).to have_content "This information will appear on your profile" expect(page).to have_content "This information will appear on your profile"
end end
it 'shows user readme' do
create(:project, :repository, :public, path: user.username, namespace: user.namespace)
visit(user_path(user))
expect(find('.file-content')).to have_content('testme')
end
context 'when user has groups' do context 'when user has groups' do
let(:group) do let(:group) do
create :group do |group| create :group do |group|
......
...@@ -6225,4 +6225,31 @@ RSpec.describe User do ...@@ -6225,4 +6225,31 @@ RSpec.describe User do
expect(described_class.get_ids_by_username([user_name])).to match_array([user_id]) expect(described_class.get_ids_by_username([user_name])).to match_array([user_id])
end end
end end
describe 'user_project' do
it 'returns users project matched by username and public visibility' do
user = create(:user)
public_project = create(:project, :public, path: user.username, namespace: user.namespace)
create(:project, namespace: user.namespace)
expect(user.user_project).to eq(public_project)
end
end
describe 'user_readme' do
it 'returns readme from user project' do
user = create(:user)
create(:project, :repository, :public, path: user.username, namespace: user.namespace)
expect(user.user_readme.name).to eq('README.md')
expect(user.user_readme.data).to include('testme')
end
it 'returns nil if project is private' do
user = create(:user)
create(:project, :repository, :private, path: user.username, namespace: user.namespace)
expect(user.user_readme).to be(nil)
end
end
end end
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