Read about our upcoming Code of Conduct on this issue

Commit a5ed28de authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent a7cf5267113c
// capture anything starting with http:// or https://
// up until a disallowed character or whitespace
export const blobLinkRegex = /https?:\/\/[^"<>\\^`{|}\s]+/g;
export default { blobLinkRegex };
......@@ -4,10 +4,6 @@ import Flash from '../../flash';
import { handleLocationHash } from '../../lib/utils/common_utils';
import axios from '../../lib/utils/axios_utils';
import { __ } from '~/locale';
import { blobLinkRegex } from '~/blob/blob_utils';
const SIMPLE_VIEWER_NAME = 'simple';
const RICH_VIEWER_NAME = 'rich';
export default class BlobViewer {
constructor() {
......@@ -25,7 +21,7 @@ export default class BlobViewer {
}
static initRichViewer() {
const viewer = document.querySelector(`.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`);
const viewer = document.querySelector('.blob-viewer[data-type="rich"]');
if (!viewer || !viewer.dataset.richType) return;
const initViewer = promise =>
......@@ -65,12 +61,8 @@ export default class BlobViewer {
this.switcherBtns = document.querySelectorAll('.js-blob-viewer-switch-btn');
this.copySourceBtn = document.querySelector('.js-copy-blob-source-btn');
this.simpleViewer = this.$fileHolder[0].querySelector(
`.blob-viewer[data-type="${SIMPLE_VIEWER_NAME}"]`,
);
this.richViewer = this.$fileHolder[0].querySelector(
`.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`,
);
this.simpleViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="simple"]');
this.richViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="rich"]');
this.initBindings();
......@@ -79,10 +71,10 @@ export default class BlobViewer {
switchToInitialViewer() {
const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)');
let initialViewerName = initialViewer.dataset.type;
let initialViewerName = initialViewer.getAttribute('data-type');
if (this.switcher && window.location.hash.indexOf('#L') === 0) {
initialViewerName = SIMPLE_VIEWER_NAME;
initialViewerName = 'simple';
}
this.switchToViewer(initialViewerName);
......@@ -99,41 +91,35 @@ export default class BlobViewer {
this.copySourceBtn.addEventListener('click', () => {
if (this.copySourceBtn.classList.contains('disabled')) return this.copySourceBtn.blur();
return this.switchToViewer(SIMPLE_VIEWER_NAME);
return this.switchToViewer('simple');
});
}
}
static linkifyURLs(viewer) {
if (viewer.dataset.linkified) return;
document.querySelectorAll('.js-blob-content .code .line').forEach(line => {
// eslint-disable-next-line no-param-reassign
line.innerHTML = line.innerHTML.replace(blobLinkRegex, '<a href="$&">$&</a>');
});
// eslint-disable-next-line no-param-reassign
viewer.dataset.linkified = true;
}
switchViewHandler(e) {
const target = e.currentTarget;
e.preventDefault();
this.switchToViewer(target.dataset.viewer);
this.switchToViewer(target.getAttribute('data-viewer'));
}
toggleCopyButtonState() {
if (!this.copySourceBtn) return;
if (this.simpleViewer.dataset.loaded) {
this.copySourceBtn.dataset.title = __('Copy file contents');
if (this.simpleViewer.getAttribute('data-loaded')) {
this.copySourceBtn.setAttribute('title', __('Copy file contents'));
this.copySourceBtn.classList.remove('disabled');
} else if (this.activeViewer === this.simpleViewer) {
this.copySourceBtn.dataset.title = __('Wait for the file to load to copy its contents');
this.copySourceBtn.setAttribute(
'title',
__('Wait for the file to load to copy its contents'),
);
this.copySourceBtn.classList.add('disabled');
} else {
this.copySourceBtn.dataset.title = __('Switch to the source to copy the file contents');
this.copySourceBtn.setAttribute(
'title',
__('Switch to the source to copy the file contents'),
);
this.copySourceBtn.classList.add('disabled');
}
......@@ -173,8 +159,6 @@ export default class BlobViewer {
this.$fileHolder.trigger('highlight:line');
handleLocationHash();
if (name === SIMPLE_VIEWER_NAME) BlobViewer.linkifyURLs(viewer);
this.toggleCopyButtonState();
})
.catch(() => new Flash(__('Error loading viewer')));
......@@ -182,17 +166,17 @@ export default class BlobViewer {
static loadViewer(viewerParam) {
const viewer = viewerParam;
const { url, loaded, loading } = viewer.dataset;
const url = viewer.getAttribute('data-url');
if (!url || loaded || loading) {
if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) {
return Promise.resolve(viewer);
}
viewer.dataset.loading = true;
viewer.setAttribute('data-loading', 'true');
return axios.get(url).then(({ data }) => {
viewer.innerHTML = data.html;
viewer.dataset.loaded = true;
viewer.setAttribute('data-loaded', 'true');
return viewer;
});
......
......@@ -4,8 +4,7 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { __ } from '~/locale';
import { blobLinkRegex } from '~/blob/blob_utils';
import TemplateSelectorMediator from '~/blob/file_template_mediator';
import TemplateSelectorMediator from '../blob/file_template_mediator';
import getModeByFileExtension from '~/lib/utils/ace_utils';
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
......@@ -18,7 +17,6 @@ export default class EditBlob {
this.initModePanesAndLinks();
this.initSoftWrap();
this.initFileSelectors();
this.initBlobContentLinkClickability();
}
configureAceEditor() {
......@@ -91,22 +89,6 @@ export default class EditBlob {
return this.editor.focus();
}
initBlobContentLinkClickability() {
this.editor.renderer.on('afterRender', () => {
document.querySelectorAll('.ace_text-layer .ace_line > *').forEach(token => {
if (token.dataset.linkified || !token.textContent.includes('http')) return;
// eslint-disable-next-line no-param-reassign
token.innerHTML = token.innerHTML.replace(
blobLinkRegex,
'<a target="_blank" href="$&">$&</a>',
);
// eslint-disable-next-line no-param-reassign
token.dataset.linkified = true;
});
});
}
initSoftWrap() {
this.isSoftWrapped = false;
this.$toggleButton = $('.soft-wrap-toggle');
......
......@@ -84,7 +84,8 @@ export default {
this.$nextTick(() => {
if (
this.scrollHeight() <= this.listHeight() &&
this.list.issuesSize > this.list.issues.length
this.list.issuesSize > this.list.issues.length &&
this.list.isExpanded
) {
this.list.page += 1;
this.list.getIssues(false).catch(() => {
......
......@@ -50,8 +50,8 @@ class List {
this.page = 1;
this.loading = true;
this.loadingMore = false;
this.issues = [];
this.issuesSize = 0;
this.issues = obj.issues || [];
this.issuesSize = obj.issuesSize ? obj.issuesSize : 0;
this.defaultAvatar = defaultAvatar;
if (obj.label) {
......
......@@ -258,17 +258,6 @@
}
}
}
.file-editor {
.ace_underline {
text-decoration: none;
}
.ace_line a {
pointer-events: auto;
color: inherit;
}
}
}
span.idiff {
......
......@@ -29,12 +29,3 @@
color: $link;
}
}
// Links to URLs, emails, or dependencies
.code .line a {
color: inherit;
&:hover {
text-decoration: underline;
}
}
......@@ -193,6 +193,11 @@ $dark-il: #de935f;
color: $dark-highlight-color !important;
}
// Links to URLs, emails, or dependencies
.line a {
color: $dark-na;
}
.hll { background-color: $dark-hll-bg; }
.c { color: $dark-c; } /* Comment */
.err { color: $dark-err; } /* Error */
......
......@@ -193,6 +193,11 @@ $monokai-gi: #a6e22e;
color: $black !important;
}
// Links to URLs, emails, or dependencies
.line a {
color: $monokai-k;
}
.hll { background-color: $monokai-hll; }
.c { color: $monokai-c; } /* Comment */
.err { color: $monokai-err-color; background-color: $monokai-err-bg; } /* Error */
......
......@@ -143,6 +143,12 @@
background-color: $white-normal;
}
// Links to URLs, emails, or dependencies
.line a {
color: $gl-text-color;
text-decoration: underline;
}
.hll { background-color: $white-light; }
.gd {
......
......@@ -196,6 +196,11 @@ $solarized-dark-il: #2aa198;
background-color: $solarized-dark-highlight !important;
}
// Links to URLs, emails, or dependencies
.line a {
color: $solarized-dark-kd;
}
/* Solarized Dark
For use with Jekyll and Pygments
......
......@@ -204,6 +204,11 @@ $solarized-light-il: #2aa198;
background-color: $solarized-light-highlight !important;
}
// Links to URLs, emails, or dependencies
.line a {
color: $solarized-light-kd;
}
/* Solarized Light
For use with Jekyll and Pygments
......
......@@ -209,6 +209,11 @@ span.highlight_word {
background-color: $white-highlight !important;
}
// Links to URLs, emails, or dependencies
.line a {
color: $white-nb;
}
.hll { background-color: $white-hll-bg; }
.c { color: $white-c;
......
......@@ -20,11 +20,11 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user!, except: [:route_not_found]
before_action :enforce_terms!, if: :should_enforce_terms?
before_action :validate_user_service_ticket!
before_action :check_password_expiration, if: :html_request?
before_action :check_password_expiration
before_action :ldap_security_check
before_action :sentry_context
before_action :default_headers
before_action :add_gon_variables, if: :html_request?
before_action :add_gon_variables, unless: [:peek_request?, :json_request?]
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :require_email, unless: :devise_controller?
before_action :active_user_check, unless: :devise_controller?
......@@ -455,8 +455,8 @@ def set_page_title_header
response.headers['Page-Title'] = URI.escape(page_title('GitLab'))
end
def html_request?
request.format.html?
def peek_request?
request.path.start_with?('/-/peek')
end
def json_request?
......@@ -466,7 +466,7 @@ def json_request?
def should_enforce_terms?
return false unless Gitlab::CurrentSettings.current_application_settings.enforce_terms
html_request? && !devise_controller?
!(peek_request? || devise_controller?)
end
def set_usage_stats_consent_flag
......
......@@ -4,18 +4,15 @@ module ConfirmEmailWarning
extend ActiveSupport::Concern
included do
before_action :set_confirm_warning, if: :show_confirm_warning?
before_action :set_confirm_warning, if: -> { Feature.enabled?(:soft_email_confirmation) }
end
protected
def show_confirm_warning?
html_request? && request.get? && Feature.enabled?(:soft_email_confirmation)
end
def set_confirm_warning
return unless current_user
return if current_user.confirmed?
return if peek_request? || json_request? || !request.get?
email = current_user.unconfirmed_email || current_user.email
......
# frozen_string_literal: true
module UploadsActions
extend ActiveSupport::Concern
include Gitlab::Utils::StrongMemoize
include SendFileUpload
UPLOAD_MOUNTS = %w(avatar attachment file logo header_logo favicon).freeze
included do
prepend_before_action :set_request_format_from_path_extension
end
def create
uploader = UploadService.new(model, params[:file], uploader_class).execute
......@@ -69,18 +64,6 @@ def authorize
private
# From ActionDispatch::Http::MimeNegotiation. We have an initializer that
# monkey-patches this method out (so that repository paths don't guess a
# format based on extension), but we do want this behaviour when serving
# uploads.
def set_request_format_from_path_extension
path = request.headers['action_dispatch.original_path'] || request.headers['PATH_INFO']
if match = path&.match(/\.(\w+)\z/)
request.format = match.captures.first
end
end
def uploader_class
raise NotImplementedError
end
......
......@@ -20,7 +20,7 @@ class UploadsController < ApplicationController
skip_before_action :authenticate_user!
before_action :upload_mount_satisfied?
before_action :model
before_action :find_model
before_action :authorize_access!, only: [:show]
before_action :authorize_create_access!, only: [:create, :authorize]
before_action :verify_workhorse_api!, only: [:authorize]
......
......@@ -80,7 +80,7 @@ def all_visible_descendant_groups
if current_user
authorized_groups = GroupsFinder.new(current_user,
all_available: false)
.execute.as('authorized')
.execute.arel.as('authorized')
authorized_to_user = groups_table.project(1).from(authorized_groups)
.where(authorized_groups[:id].eq(groups_table[:id]))
.exists
......
# frozen_string_literal: true
module Mutations
module Todos
class Base < ::Mutations::BaseMutation
private
def find_object(id:)
GitlabSchema.object_from_id(id)
end
def to_global_id(id)
::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s
end
end
end
end
# frozen_string_literal: true
module Mutations
module Todos
class MarkDone < ::Mutations::Todos::Base
graphql_name 'TodoMarkDone'
authorize :update_todo
argument :id,
GraphQL::ID_TYPE,
required: true,
description: 'The global id of the todo to mark as done'
field :todo, Types::TodoType,
null: false,
description: 'The requested todo'
# rubocop: disable CodeReuse/ActiveRecord
def resolve(id:)
todo = authorized_find!(id: id)
mark_done(Todo.where(id: todo.id)) unless todo.done?
{
todo: todo.reset,
errors: errors_on_object(todo)
}
end
# rubocop: enable CodeReuse/ActiveRecord
private
def mark_done(todo)
TodoService.new.mark_todos_as_done(todo, current_user)
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