Commit ff67e3ed authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 7071f9bf
/* eslint-disable func-names, no-var, no-else-return, consistent-return, one-var, no-return-assign, no-unused-expressions, no-sequences */ /* eslint-disable func-names, no-var, no-else-return, consistent-return, one-var, no-return-assign */
import $ from 'jquery'; import $ from 'jquery';
...@@ -9,40 +9,29 @@ const viewModes = ['two-up', 'swipe']; ...@@ -9,40 +9,29 @@ const viewModes = ['two-up', 'swipe'];
export default class ImageFile { export default class ImageFile {
constructor(file) { constructor(file) {
this.file = file; this.file = file;
this.requestImageInfo( this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), () =>
$('.two-up.view .frame.deleted img', this.file), this.requestImageInfo($('.two-up.view .frame.added img', this.file), () => {
(function(_this) { this.initViewModes();
return function() {
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), () => { // Load two-up view after images are loaded
_this.initViewModes(); // so that we can display the correct width and height information
const $images = $('.two-up.view img', this.file);
// Load two-up view after images are loaded
// so that we can display the correct width and height information $images.waitForImages(() => {
const $images = $('.two-up.view img', _this.file); this.initView('two-up');
});
$images.waitForImages(() => { }),
_this.initView('two-up');
});
});
};
})(this),
); );
} }
initViewModes() { initViewModes() {
const viewMode = viewModes[0]; const viewMode = viewModes[0];
$('.view-modes', this.file).removeClass('hide'); $('.view-modes', this.file).removeClass('hide');
$('.view-modes-menu', this.file).on( $('.view-modes-menu', this.file).on('click', 'li', event => {
'click', if (!$(event.currentTarget).hasClass('active')) {
'li', return this.activateViewMode(event.currentTarget.className);
(function(_this) { }
return function(event) { });
if (!$(event.currentTarget).hasClass('active')) {
return _this.activateViewMode(event.currentTarget.className);
}
};
})(this),
);
return this.activateViewMode(viewMode); return this.activateViewMode(viewMode);
} }
...@@ -51,15 +40,10 @@ export default class ImageFile { ...@@ -51,15 +40,10 @@ export default class ImageFile {
.removeClass('active') .removeClass('active')
.filter(`.${viewMode}`) .filter(`.${viewMode}`)
.addClass('active'); .addClass('active');
return $(`.view:visible:not(.${viewMode})`, this.file).fadeOut( return $(`.view:visible:not(.${viewMode})`, this.file).fadeOut(200, () => {
200, $(`.view.${viewMode}`, this.file).fadeIn(200);
(function(_this) { return this.initView(viewMode);
return function() { });
$(`.view.${viewMode}`, _this.file).fadeIn(200);
return _this.initView(viewMode);
};
})(this),
);
} }
initView(viewMode) { initView(viewMode) {
...@@ -103,22 +87,18 @@ export default class ImageFile { ...@@ -103,22 +87,18 @@ export default class ImageFile {
.on('touchmove', dragMove); .on('touchmove', dragMove);
} }
prepareFrames(view) { static prepareFrames(view) {
var maxHeight, maxWidth; var maxHeight, maxWidth;
maxWidth = 0; maxWidth = 0;
maxHeight = 0; maxHeight = 0;
$('.frame', view) $('.frame', view)
.each( .each((index, frame) => {
(function() { var height, width;
return function(index, frame) { width = $(frame).width();
var height, width; height = $(frame).height();
width = $(frame).width(); maxWidth = width > maxWidth ? width : maxWidth;
height = $(frame).height(); return (maxHeight = height > maxHeight ? height : maxHeight);
maxWidth = width > maxWidth ? width : maxWidth; })
return (maxHeight = height > maxHeight ? height : maxHeight);
};
})(this),
)
.css({ .css({
width: maxWidth, width: maxWidth,
height: maxHeight, height: maxHeight,
...@@ -128,104 +108,95 @@ export default class ImageFile { ...@@ -128,104 +108,95 @@ export default class ImageFile {
views = { views = {
'two-up': function() { 'two-up': function() {
return $('.two-up.view .wrap', this.file).each( return $('.two-up.view .wrap', this.file).each((index, wrap) => {
(function(_this) { $('img', wrap).each(function() {
return function(index, wrap) { var currentWidth;
$('img', wrap).each(function() { currentWidth = $(this).width();
var currentWidth; if (currentWidth > availWidth / 2) {
currentWidth = $(this).width(); return $(this).width(availWidth / 2);
if (currentWidth > availWidth / 2) { }
return $(this).width(availWidth / 2); });
} return this.requestImageInfo($('img', wrap), (width, height) => {
}); $('.image-info .meta-width', wrap).text(`${width}px`);
return _this.requestImageInfo($('img', wrap), (width, height) => { $('.image-info .meta-height', wrap).text(`${height}px`);
$('.image-info .meta-width', wrap).text(`${width}px`); return $('.image-info', wrap).removeClass('hide');
$('.image-info .meta-height', wrap).text(`${height}px`); });
return $('.image-info', wrap).removeClass('hide'); });
});
};
})(this),
);
}, },
swipe() { swipe() {
var maxHeight, maxWidth; var maxHeight, maxWidth;
maxWidth = 0; maxWidth = 0;
maxHeight = 0; maxHeight = 0;
return $('.swipe.view', this.file).each( return $('.swipe.view', this.file).each((index, view) => {
(function(_this) { var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding;
return function(index, view) { const ref = ImageFile.prepareFrames(view);
var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref; [maxWidth, maxHeight] = ref;
(ref = _this.prepareFrames(view)), ([maxWidth, maxHeight] = ref); $swipeFrame = $('.swipe-frame', view);
$swipeFrame = $('.swipe-frame', view); $swipeWrap = $('.swipe-wrap', view);
$swipeWrap = $('.swipe-wrap', view); $swipeBar = $('.swipe-bar', view);
$swipeBar = $('.swipe-bar', view);
$swipeFrame.css({
$swipeFrame.css({ width: maxWidth + 16,
width: maxWidth + 16, height: maxHeight + 28,
height: maxHeight + 28, });
}); $swipeWrap.css({
$swipeWrap.css({ width: maxWidth + 1,
width: maxWidth + 1, height: maxHeight + 2,
height: maxHeight + 2, });
}); // Set swipeBar left position to match image frame
// Set swipeBar left position to match image frame $swipeBar.css({
$swipeBar.css({ left: 1,
left: 1, });
});
wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
this.initDraggable($swipeBar, wrapPadding, (e, left) => {
_this.initDraggable($swipeBar, wrapPadding, (e, left) => { if (left > 0 && left < $swipeFrame.width() - wrapPadding * 2) {
if (left > 0 && left < $swipeFrame.width() - wrapPadding * 2) { $swipeWrap.width(maxWidth + 1 - left);
$swipeWrap.width(maxWidth + 1 - left); $swipeBar.css('left', left);
$swipeBar.css('left', left); }
} });
}); });
};
})(this),
);
}, },
'onion-skin': function() { 'onion-skin': function() {
var dragTrackWidth, maxHeight, maxWidth; var dragTrackWidth, maxHeight, maxWidth;
maxWidth = 0; maxWidth = 0;
maxHeight = 0; maxHeight = 0;
dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width(); dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width();
return $('.onion-skin.view', this.file).each( return $('.onion-skin.view', this.file).each((index, view) => {
(function(_this) { var $frame, $track, $dragger, $frameAdded, framePadding;
return function(index, view) {
var $frame, $track, $dragger, $frameAdded, framePadding, ref; const ref = ImageFile.prepareFrames(view);
(ref = _this.prepareFrames(view)), ([maxWidth, maxHeight] = ref); [maxWidth, maxHeight] = ref;
$frame = $('.onion-skin-frame', view); $frame = $('.onion-skin-frame', view);
$frameAdded = $('.frame.added', view); $frameAdded = $('.frame.added', view);
$track = $('.drag-track', view); $track = $('.drag-track', view);
$dragger = $('.dragger', $track); $dragger = $('.dragger', $track);
$frame.css({ $frame.css({
width: maxWidth + 16, width: maxWidth + 16,
height: maxHeight + 28, height: maxHeight + 28,
}); });
$('.swipe-wrap', view).css({ $('.swipe-wrap', view).css({
width: maxWidth + 1, width: maxWidth + 1,
height: maxHeight + 2, height: maxHeight + 2,
}); });
$dragger.css({ $dragger.css({
left: dragTrackWidth, left: dragTrackWidth,
}); });
$frameAdded.css('opacity', 1); $frameAdded.css('opacity', 1);
framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10); framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
_this.initDraggable($dragger, framePadding, (e, left) => { this.initDraggable($dragger, framePadding, (e, left) => {
var opacity = left / dragTrackWidth; var opacity = left / dragTrackWidth;
if (opacity >= 0 && opacity <= 1) { if (opacity >= 0 && opacity <= 1) {
$dragger.css('left', left); $dragger.css('left', left);
$frameAdded.css('opacity', opacity); $frameAdded.css('opacity', opacity);
} }
}); });
}; });
})(this),
);
}, },
}; };
...@@ -235,14 +206,7 @@ export default class ImageFile { ...@@ -235,14 +206,7 @@ export default class ImageFile {
if (domImg.complete) { if (domImg.complete) {
return callback.call(this, domImg.naturalWidth, domImg.naturalHeight); return callback.call(this, domImg.naturalWidth, domImg.naturalHeight);
} else { } else {
return img.on( return img.on('load', () => callback.call(this, domImg.naturalWidth, domImg.naturalHeight));
'load',
(function(_this) {
return function() {
return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight);
};
})(this),
);
} }
} }
} }
......
/* eslint-disable no-new */
import AbuseReports from './abuse_reports'; import AbuseReports from './abuse_reports';
import UsersSelect from '~/users_select';
document.addEventListener('DOMContentLoaded', () => new AbuseReports()); document.addEventListener('DOMContentLoaded', () => {
new AbuseReports();
new UsersSelect();
});
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
line-height: $line-height-base; line-height: $line-height-base;
position: relative; position: relative;
min-height: $modal-body-height; min-height: $modal-body-height;
padding: #{2 * $grid-size} #{6 * $grid-size} #{2 * $grid-size} #{2 * $grid-size}; padding: #{2 * $grid-size};
text-align: left; text-align: left;
white-space: normal; white-space: normal;
...@@ -70,9 +70,9 @@ ...@@ -70,9 +70,9 @@
margin: 0; margin: 0;
} }
.btn + .btn:not(.dropdown-toggle-split),
.btn + .btn-group, .btn + .btn-group,
.btn-group + .btn { .btn-group + .btn,
.btn-group + .btn-group {
margin-left: $grid-size; margin-left: $grid-size;
} }
...@@ -83,13 +83,6 @@ ...@@ -83,13 +83,6 @@
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
flex-direction: column; flex-direction: column;
.btn + .btn:not(.dropdown-toggle-split),
.btn + .btn-group,
.btn-group + .btn {
margin-left: 0;
margin-top: $grid-size;
}
.btn-group .btn + .btn { .btn-group .btn + .btn {
margin-left: -1px; margin-left: -1px;
margin-top: 0; margin-top: 0;
......
...@@ -274,6 +274,12 @@ ...@@ -274,6 +274,12 @@
height: 24px; height: 24px;
} }
.git-clone-holder {
.btn {
height: auto;
}
}
.dropdown-toggle, .dropdown-toggle,
.clone-dropdown-btn { .clone-dropdown-btn {
.fa { .fa {
......
...@@ -131,7 +131,6 @@ ...@@ -131,7 +131,6 @@
.modal-security-report-dast { .modal-security-report-dast {
.modal-dialog { .modal-dialog {
width: $modal-lg;
max-width: $modal-lg; max-width: $modal-lg;
} }
......
# frozen_string_literal: true # frozen_string_literal: true
class Admin::AbuseReportsController < Admin::ApplicationController class Admin::AbuseReportsController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def index def index
@abuse_reports = AbuseReport.order(id: :desc).page(params[:page]) @abuse_reports = AbuseReportsFinder.new(params).execute
@abuse_reports = @abuse_reports.includes(:user, :reporter)
end end
# rubocop: enable CodeReuse/ActiveRecord
def destroy def destroy
abuse_report = AbuseReport.find(params[:id]) abuse_report = AbuseReport.find(params[:id])
......
# frozen_string_literal: true
class AbuseReportsFinder
attr_reader :params
def initialize(params = {})
@params = params
end
def execute
reports = AbuseReport.all
reports = reports.by_user(params[:user_id]) if params[:user_id].present?
reports.with_order_id_desc
.with_users
.page(params[:page])
end
end
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
class AbuseReport < ApplicationRecord class AbuseReport < ApplicationRecord
include CacheMarkdownField include CacheMarkdownField
include Sortable
cache_markdown_field :message, pipeline: :single_line cache_markdown_field :message, pipeline: :single_line
...@@ -13,6 +14,9 @@ class AbuseReport < ApplicationRecord ...@@ -13,6 +14,9 @@ class AbuseReport < ApplicationRecord
validates :message, presence: true validates :message, presence: true
validates :user_id, uniqueness: { message: 'has already been reported' } validates :user_id, uniqueness: { message: 'has already been reported' }
scope :by_user, -> (user) { where(user_id: user) }
scope :with_users, -> { includes(:reporter, :user) }
# For CacheMarkdownField # For CacheMarkdownField
alias_method :author, :reporter alias_method :author, :reporter
......
...@@ -6,11 +6,14 @@ class AwardEmoji < ApplicationRecord ...@@ -6,11 +6,14 @@ class AwardEmoji < ApplicationRecord
include Participable include Participable
include GhostUser include GhostUser
include Importable
belongs_to :awardable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations belongs_to :awardable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
belongs_to :user belongs_to :user
validates :awardable, :user, presence: true validates :user, presence: true
validates :awardable, presence: true, unless: :importing?
validates :name, presence: true, inclusion: { in: Gitlab::Emoji.emojis_names } validates :name, presence: true, inclusion: { in: Gitlab::Emoji.emojis_names }
validates :name, uniqueness: { scope: [:user, :awardable_type, :awardable_id] }, unless: :ghost_user? validates :name, uniqueness: { scope: [:user, :awardable_type, :awardable_id] }, unless: :ghost_user?
......
- page_title 'Abuse Reports' - page_title _('Abuse Reports')
%h3.page-title Abuse Reports
%hr %h3.page-title= _('Abuse Reports')
.row-content-block.second-block
= form_tag admin_abuse_reports_path, method: :get, class: 'filter-form' do
.filter-categories.flex-fill
.filter-item.inline
= dropdown_tag(user_dropdown_label(params[:user_id], 'User'),
options: { toggle_class: 'js-filter-submit js-user-search',
title: _('Filter by user'), filter: true, filterInput: 'input#user-search',
dropdown_class: 'dropdown-menu-selectable dropdown-menu-user js-filter-submit',
placeholder: _('Search users'),
data: { current_user: true, field_name: 'user_id' }})
.abuse-reports .abuse-reports
- if @abuse_reports.present? - if @abuse_reports.present?
.table-holder .table-holder
......
...@@ -13,5 +13,11 @@ ...@@ -13,5 +13,11 @@
- @project.pages_domains.each do |domain| - @project.pages_domains.each do |domain|
%p %p
= external_link(domain.url, domain.url) = external_link(domain.url, domain.url)
- unless @project.public_pages?
.card-footer.alert-warning
- help_page = help_page_path('/user/project/pages/pages_access_control')
- link_start = '<a href="%{url}" target="_blank" class="alert-link" rel="noopener noreferrer">'.html_safe % { url: help_page }
- link_end = '</a>'.html_safe
= s_('GitLabPages|Access Control is enabled for this Pages website; only authorized users will be able to access it. To make your website publicly available, navigate to your project\'s %{strong_start}Settings > General > Visibility%{strong_end} and select %{strong_start}Everyone%{strong_end} in pages section. Read the %{link_start}documentation%{link_end} for more information.').html_safe % { link_start: link_start, link_end: link_end, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
.card-footer.alert-primary .card-footer.alert-primary
= s_('GitLabPages|It may take up to 30 minutes before the site is available after the first deployment.') = s_('GitLabPages|It may take up to 30 minutes before the site is available after the first deployment.')
- page_title 'Pages' - page_title 'Pages'
%h3.page-title.with-button - if @project.pages_enabled?
= s_('GitLabPages|Pages') %h3.page-title.with-button
= s_('GitLabPages|Pages')
- if can?(current_user, :update_pages, @project) && (Gitlab.config.pages.external_http || Gitlab.config.pages.external_https) - if can?(current_user, :update_pages, @project) && (Gitlab.config.pages.external_http || Gitlab.config.pages.external_https)
= link_to new_project_pages_domain_path(@project), class: 'btn btn-success float-right', title: s_('GitLabPages|New Domain') do = link_to new_project_pages_domain_path(@project), class: 'btn btn-success float-right', title: s_('GitLabPages|New Domain') do
= s_('GitLabPages|New Domain') = s_('GitLabPages|New Domain')
%p.light %p.light
= s_('GitLabPages|With GitLab Pages you can host your static websites on GitLab. Combined with the power of GitLab CI and the help of GitLab Runner you can deploy static pages for your individual projects, your user or your group.') = s_('GitLabPages|With GitLab Pages you can host your static websites on GitLab. Combined with the power of GitLab CI and the help of GitLab Runner you can deploy static pages for your individual projects, your user or your group.')
- if Gitlab.config.pages.external_https - if Gitlab.config.pages.external_https
= render 'https_only' = render 'https_only'
%hr.clearfix %hr.clearfix
= render 'access' = render 'access'
= render 'use' = render 'use'
- if Gitlab.config.pages.external_http || Gitlab.config.pages.external_https - if Gitlab.config.pages.external_http || Gitlab.config.pages.external_https
= render 'list' = render 'list'
- else
= render 'no_domains'
= render 'destroy'
- else - else
= render 'no_domains' .bs-callout.bs-callout-warning
= render 'destroy' = s_('GitLabPages|GitLab Pages are disabled for this project. You can enable them on your project\'s %{strong_start}Settings > General > Visibility%{strong_end} page.').html_safe % { strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
---
title: Add ability to reorder projects on operations dashboard
merge_request: 18855
author:
type: added
---
title: Fixes mobile styling issues on security modals
merge_request: 19391
author:
type: fixed
---
title: Add warnings about pages access control settings
merge_request: 19067
author:
type: added
---
title: Hide repeated trial offers on self-hosted instances
merge_request: 19511
author:
type: changed
---
title: Fix import of snippets having `award_emoji` (Project Export/Import)
merge_request: 19690
author:
type: fixed
---
title: Removed IIFEs from image_file.js
merge_request: 19548
author: nuwe1
type: other
---
title: Handle new Container Scanning report format
merge_request: 19123
author:
type: changed
---
title: Add user filtering to abuse reports page
merge_request: 19365
author:
type: changed
# frozen_string_literal: true
class AddLicenseDetailsToApplicationSettings < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :application_settings, :license_trial_ends_on, :date, null: true
end
end
...@@ -345,6 +345,7 @@ ActiveRecord::Schema.define(version: 2019_11_05_140942) do ...@@ -345,6 +345,7 @@ ActiveRecord::Schema.define(version: 2019_11_05_140942) do
t.boolean "pendo_enabled", default: false, null: false t.boolean "pendo_enabled", default: false, null: false
t.string "pendo_url", limit: 255 t.string "pendo_url", limit: 255
t.integer "deletion_adjourned_period", default: 7, null: false t.integer "deletion_adjourned_period", default: 7, null: false
t.date "license_trial_ends_on"
t.boolean "eks_integration_enabled", default: false, null: false t.boolean "eks_integration_enabled", default: false, null: false
t.string "eks_account_id", limit: 128 t.string "eks_account_id", limit: 128
t.string "eks_access_key_id", limit: 128 t.string "eks_access_key_id", limit: 128
......
...@@ -142,6 +142,106 @@ and expect something like: ...@@ -142,6 +142,106 @@ and expect something like:
By running the command above, `primary` should be `true` when executed in By running the command above, `primary` should be `true` when executed in
the **primary** node, and `false` on any **secondary** node. the **primary** node, and `false` on any **secondary** node.
## Fixing errors found when running the Geo check rake task
When running this rake task, you may see errors if the nodes are not properly configured:
```sh
sudo gitlab-rake gitlab:geo:check
```
1. Rails did not provide a password when connecting to the database
```text
Checking Geo ...
GitLab Geo is available ... Exception: fe_sendauth: no password supplied
GitLab Geo is enabled ... Exception: fe_sendauth: no password supplied
...
Checking Geo ... Finished
```
- Ensure that you have the `gitlab_rails['db_password']` set to the plain text-password used when creating the hash for `postgresql['sql_user_password']`.
1. Rails is unable to connect to the database
```text
Checking Geo ...
GitLab Geo is available ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
GitLab Geo is enabled ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
...
Checking Geo ... Finished
```
- Ensure that you have the IP address of the rails node included in `postgresql['md5_auth_cidr_addresses']`.
- Ensure that you have included the subnet mask on the IP address: `postgresql['md5_auth_cidr_addresses'] = ['1.1.1.1/32']`.
1. Rails has supplied the incorrect password
```text
Checking Geo ...
GitLab Geo is available ... Exception: FATAL: password authentication failed for user "gitlab"
FATAL: password authentication failed for user "gitlab"
GitLab Geo is enabled ... Exception: FATAL: password authentication failed for user "gitlab"
FATAL: password authentication failed for user "gitlab"
...
Checking Geo ... Finished
```
- Verify the correct password is set for `gitlab_rails['db_password']` that was used when creating the hash in `postgresql['sql_user_password']` by running `gitlab-ctl pg-password-md5 gitlab` and entering the password.
1. Check returns not a secondary node
```text
Checking Geo ...
GitLab Geo is available ... yes
GitLab Geo is enabled ... yes
GitLab Geo secondary database is correctly configured ... not a secondary node
Database replication enabled? ... not a secondary node
...
Checking Geo ... Finished
```
- Ensure that you have added the secondary node in the admin area of the primary node.
- Ensure that you entered the `external_url` or `gitlab_rails['geo_node_name']` when adding the secondary node in the admin are of the primary node.
- Prior to GitLab 12.4, edit the secondary node in the admin area of the primary node and ensure that there is a trailing `/` in the `Name` field.
1. Check returns Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist
```text
Checking Geo ...
GitLab Geo is available ... no
Try fixing it:
Upload a new license that includes the GitLab Geo feature
For more information see:
https://about.gitlab.com/features/gitlab-geo/
GitLab Geo is enabled ... Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist
LINE 8: WHERE a.attrelid = '"geo_nodes"'::regclass
^
: SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
c.collname, col_description(a.attrelid, a.attnum) AS comment
FROM pg_attribute a
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
LEFT JOIN pg_type t ON a.atttypid = t.oid
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
WHERE a.attrelid = '"geo_nodes"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
...
Checking Geo ... Finished
```
When performing a Postgres major version (9 > 10) update this is expected. Follow:
- [initiate-the-replication-process](https://docs.gitlab.com/ee/administration/geo/replication/database.html#step-3-initiate-the-replication-process)
- [Geo database has an outdated FDW remote schema](https://docs.gitlab.com/ee/administration/geo/replication/troubleshooting.html#geo-database-has-an-outdated-fdw-remote-schema-error)
## Fixing replication errors ## Fixing replication errors
The following sections outline troubleshooting steps for fixing replication The following sections outline troubleshooting steps for fixing replication
......
...@@ -577,14 +577,22 @@ the `weight` parameter: ...@@ -577,14 +577,22 @@ the `weight` parameter:
``` ```
Users on GitLab [Ultimate](https://about.gitlab.com/pricing/) will additionally see Users on GitLab [Ultimate](https://about.gitlab.com/pricing/) will additionally see
the `epic_iid` property: the `epic` property:
```json ```javascript
{ {
"project_id" : 4, "project_id" : 4,
"description" : "Omnis vero earum sunt corporis dolor et placeat.", "description" : "Omnis vero earum sunt corporis dolor et placeat.",
"epic_iid" : 42, "epic": {
... "epic_iid" : 5, //deprecated, use `iid` of the `epic` attribute
"epic": {
"id" : 42,
"iid" : 5,
"title": "My epic epic",
"url" : "/groups/h5bp/-/epics/5",
"group_id": 8
},
// ...
} }
``` ```
...@@ -592,6 +600,9 @@ the `epic_iid` property: ...@@ -592,6 +600,9 @@ the `epic_iid` property:
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists. **Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
**Note**: The `epic_iid` attribute is deprecated and [will be removed in 13.0](https://gitlab.com/gitlab-org/gitlab/issues/35157).
Please use `iid` of the `epic` attribute instead.
## New issue ## New issue
Creates a new project issue. Creates a new project issue.
......
...@@ -69,7 +69,7 @@ request is as follows: ...@@ -69,7 +69,7 @@ request is as follows:
the issue(s) once the merge request is merged. the issue(s) once the merge request is merged.
1. If you're allowed to (Core team members, for example), set a relevant milestone 1. If you're allowed to (Core team members, for example), set a relevant milestone
and [labels](issue_workflow.md). and [labels](issue_workflow.md).
1. If the MR changes the UI, it should include *Before* and *After* screenshots. 1. If the MR changes the UI, you'll need approval from a Product Designer (UX), based on the appropriate [product category](https://about.gitlab.com/handbook/product/categories/). UI changes should use available components from the GitLab Design System, [Pajamas](https://design.gitlab.com/). The MR must include *Before* and *After* screenshots.
1. If the MR changes CSS classes, please include the list of affected pages, which 1. If the MR changes CSS classes, please include the list of affected pages, which
can be found by running `grep css-class ./app -R`. can be found by running `grep css-class ./app -R`.
1. Be prepared to answer questions and incorporate feedback into your MR with new 1. Be prepared to answer questions and incorporate feedback into your MR with new
......
...@@ -25,6 +25,10 @@ last commit, pipeline status, and when it was last deployed. ...@@ -25,6 +25,10 @@ last commit, pipeline status, and when it was last deployed.
![Operations Dashboard with projects](img/index_operations_dashboard_with_projects.png) ![Operations Dashboard with projects](img/index_operations_dashboard_with_projects.png)
## Arranging projects on a dashboard
You can drag project cards to change their order. The card order is currently only saved to your browser, so will not change the dashboard for other people.
## Making it the default dashboard when you sign in ## Making it the default dashboard when you sign in
The Operations Dashboard can also be made the default GitLab dashboard shown when The Operations Dashboard can also be made the default GitLab dashboard shown when
......
...@@ -7407,6 +7407,9 @@ msgstr "" ...@@ -7407,6 +7407,9 @@ msgstr ""
msgid "Filter by two-factor authentication" msgid "Filter by two-factor authentication"
msgstr "" msgstr ""
msgid "Filter by user"
msgstr ""
msgid "Filter projects" msgid "Filter projects"
msgstr "" msgstr ""
...@@ -8160,6 +8163,9 @@ msgstr "" ...@@ -8160,6 +8163,9 @@ msgstr ""
msgid "GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}." msgid "GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}."
msgstr "" msgstr ""
msgid "GitLabPages|Access Control is enabled for this Pages website; only authorized users will be able to access it. To make your website publicly available, navigate to your project's %{strong_start}Settings > General > Visibility%{strong_end} and select %{strong_start}Everyone%{strong_end} in pages section. Read the %{link_start}documentation%{link_end} for more information."
msgstr ""
msgid "GitLabPages|Access pages" msgid "GitLabPages|Access pages"
msgstr "" msgstr ""
...@@ -8184,6 +8190,9 @@ msgstr "" ...@@ -8184,6 +8190,9 @@ msgstr ""
msgid "GitLabPages|Force HTTPS (requires valid certificates)" msgid "GitLabPages|Force HTTPS (requires valid certificates)"
msgstr "" msgstr ""
msgid "GitLabPages|GitLab Pages are disabled for this project. You can enable them on your project's %{strong_start}Settings > General > Visibility%{strong_end} page."
msgstr ""
msgid "GitLabPages|It may take up to 30 minutes before the site is available after the first deployment." msgid "GitLabPages|It may take up to 30 minutes before the site is available after the first deployment."
msgstr "" msgstr ""
...@@ -10100,6 +10109,27 @@ msgstr "" ...@@ -10100,6 +10109,27 @@ msgstr ""
msgid "Licenses" msgid "Licenses"
msgstr "" msgstr ""
msgid "License|Buy license"
msgstr ""
msgid "License|License"
msgstr ""
msgid "License|You can restore access to the Gold features at any time by upgrading."
msgstr ""
msgid "License|You can start a free trial of GitLab Ultimate without any obligation or payment details."
msgstr ""
msgid "License|You do not have a license."
msgstr ""
msgid "License|Your License"
msgstr ""
msgid "License|Your free trial of GitLab Ultimate expired on %{trial_ends_on}."
msgstr ""
msgid "Limit display of time tracking units to hours." msgid "Limit display of time tracking units to hours."
msgstr "" msgstr ""
...@@ -12997,6 +13027,9 @@ msgstr "" ...@@ -12997,6 +13027,9 @@ msgstr ""
msgid "Project name" msgid "Project name"
msgstr "" msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
msgid "Project overview" msgid "Project overview"
msgstr "" msgstr ""
......
...@@ -51,5 +51,29 @@ describe "Admin::AbuseReports", :js do ...@@ -51,5 +51,29 @@ describe "Admin::AbuseReports", :js do
end end
end end
end end
describe 'filtering by user' do
let!(:user2) { create(:user) }
let!(:abuse_report) { create(:abuse_report, user: user) }
let!(:abuse_report_2) { create(:abuse_report, user: user2) }
it 'shows only single user report' do
visit admin_abuse_reports_path
page.within '.filter-form' do
click_button 'User'
wait_for_requests
page.within '.dropdown-menu-user' do
click_link user2.name
end
wait_for_requests
end
expect(page).to have_content(user2.name)
expect(page).not_to have_content(user.name)
end
end
end end
end end
...@@ -30,12 +30,52 @@ shared_examples 'pages settings editing' do ...@@ -30,12 +30,52 @@ shared_examples 'pages settings editing' do
expect(page).to have_content('Access pages') expect(page).to have_content('Access pages')
end end
context 'when pages are disabled in the project settings' do
it 'renders disabled warning' do
project.project_feature.update!(pages_access_level: ProjectFeature::DISABLED)
visit project_pages_path(project)
expect(page).to have_content('GitLab Pages are disabled for this project')
end
end
it 'renders first deployment warning' do it 'renders first deployment warning' do
visit project_pages_path(project) visit project_pages_path(project)
expect(page).to have_content('It may take up to 30 minutes before the site is available after the first deployment.') expect(page).to have_content('It may take up to 30 minutes before the site is available after the first deployment.')
end end
shared_examples 'does not render access control warning' do
it 'does not render access control warning' do
visit project_pages_path(project)
expect(page).not_to have_content('Access Control is enabled for this Pages website')
end
end
include_examples 'does not render access control warning'
context 'when access control is enabled in gitlab settings' do
before do
stub_pages_setting(access_control: true)
end
it 'renders access control warning' do
visit project_pages_path(project)
expect(page).to have_content('Access Control is enabled for this Pages website')
end
context 'when pages are public' do
before do
project.project_feature.update!(pages_access_level: ProjectFeature::PUBLIC)
end
include_examples 'does not render access control warning'
end
end
context 'when support for external domains is disabled' do context 'when support for external domains is disabled' do
it 'renders message that support is disabled' do it 'renders message that support is disabled' do
visit project_pages_path(project) visit project_pages_path(project)
......
# frozen_string_literal: true
require 'spec_helper'
describe AbuseReportsFinder, '#execute' do
let(:params) { {} }
let!(:user1) { create(:user) }
let!(:user2) { create(:user) }
let!(:abuse_report_1) { create(:abuse_report, user: user1) }
let!(:abuse_report_2) { create(:abuse_report, user: user2) }
subject { described_class.new(params).execute }
context 'empty params' do
it 'returns all abuse reports' do
expect(subject).to match_array([abuse_report_1, abuse_report_2])
end
end
context 'params[:user_id] is present' do
let(:params) { { user_id: user2 } }
it 'returns abuse reports for the specified user' do
expect(subject).to match_array([abuse_report_2])
end
end
end
...@@ -2260,7 +2260,41 @@ ...@@ -2260,7 +2260,41 @@
] ]
} }
], ],
"snippets": [], "snippets": [
{
"id": 1,
"title": "Test snippet title",
"content": "x = 1",
"author_id": 1,
"project_id": 1,
"created_at": "2019-11-05T15:06:06.579Z",
"updated_at": "2019-11-05T15:06:06.579Z",
"file_name": "",
"visibility_level": 20,
"description": "Test snippet description",
"award_emoji": [
{
"id": 1,
"name": "thumbsup",
"user_id": 1,
"awardable_type": "Snippet",
"awardable_id": 1,
"created_at": "2019-11-05T15:37:21.287Z",
"updated_at": "2019-11-05T15:37:21.287Z"
},
{
"id": 2,
"name": "coffee",
"user_id": 1,
"awardable_type": "Snippet",
"awardable_id": 1,
"created_at": "2019-11-05T15:37:24.645Z",
"updated_at": "2019-11-05T15:37:24.645Z"
}
],
"notes": []
}
],
"releases": [], "releases": [],
"project_members": [ "project_members": [
{ {
......
...@@ -210,6 +210,16 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do ...@@ -210,6 +210,16 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
expect(@project.project_badges.count).to eq(2) expect(@project.project_badges.count).to eq(2)
end end
it 'has snippets' do
expect(@project.snippets.count).to eq(1)
end
it 'has award emoji for a snippet' do
award_emoji = @project.snippets.first.award_emoji
expect(award_emoji.map(&:name)).to contain_exactly('thumbsup', 'coffee')
end
it 'restores the correct service' do it 'restores the correct service' do
expect(CustomIssueTrackerService.first).not_to be_nil expect(CustomIssueTrackerService.first).not_to be_nil
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