New upstream version 10.6.5+dfsg
This commit is contained in:
parent
427f406db4
commit
b52b15043b
56 changed files with 51909 additions and 71 deletions
|
@ -75,7 +75,7 @@ stages:
|
|||
|
||||
.use-mysql: &use-mysql
|
||||
services:
|
||||
- mysql:latest
|
||||
- mysql:5.7
|
||||
- redis:alpine
|
||||
|
||||
# Skip all jobs except the ones that begin with 'docs/'.
|
||||
|
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -2,6 +2,31 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 10.6.5 (2018-04-24)
|
||||
|
||||
### Security (1 change)
|
||||
|
||||
- Sanitizes user name to avoid XSS attacks.
|
||||
|
||||
|
||||
## 10.6.4 (2018-04-09)
|
||||
|
||||
### Fixed (8 changes, 1 of them is from the community)
|
||||
|
||||
- Correct copy text for the promote milestone and label modals. !17726
|
||||
- Avoid validation errors when running the Pages domain verification service. !17992
|
||||
- Fix autolinking URLs containing ampersands. !18045
|
||||
- Fix exceptions raised when migrating pipeline stages in the background. !18076
|
||||
- Work around Prometheus Helm chart name changes to fix integration. !18206 (joshlambert)
|
||||
- Don't show Jump to Discussion button on Issues.
|
||||
- Fix listing commit branch/tags that contain special characters.
|
||||
- Fix 404 in group boards when moving issue between lists.
|
||||
|
||||
### Performance (1 change)
|
||||
|
||||
- Free open file descriptors and libgit2 buffers in UpdatePagesService.
|
||||
|
||||
|
||||
## 10.6.3 (2018-04-03)
|
||||
|
||||
### Security (2 changes)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
10.6.3
|
||||
10.6.5
|
||||
|
|
|
@ -19,7 +19,7 @@ export default class BoardService {
|
|||
}
|
||||
|
||||
static generateIssuePath(boardId, id) {
|
||||
return `${gon.relative_url_root}/-/boards/${boardId ? `/${boardId}` : ''}/issues${id ? `/${id}` : ''}`;
|
||||
return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues${id ? `/${id}` : ''}`;
|
||||
}
|
||||
|
||||
all() {
|
||||
|
|
|
@ -292,10 +292,12 @@ Please check your network connection and try again.`;
|
|||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-if="note.resolvable"
|
||||
class="btn-group discussion-actions"
|
||||
role="group">
|
||||
role="group"
|
||||
>
|
||||
<div
|
||||
v-if="note.resolvable && !discussionResolved"
|
||||
v-if="!discussionResolved"
|
||||
class="btn-group"
|
||||
role="group">
|
||||
<a
|
||||
|
|
|
@ -19,15 +19,19 @@
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
groupName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return sprintf(s__('Milestones|Promote %{milestoneTitle} to group milestone?'), { milestoneTitle: this.milestoneTitle });
|
||||
},
|
||||
text() {
|
||||
return s__(`Milestones|Promoting this milestone will make it available for all projects inside the group.
|
||||
return sprintf(s__(`Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}.
|
||||
Existing project milestones with the same title will be merged.
|
||||
This action cannot be reversed.`);
|
||||
This action cannot be reversed.`), { milestoneTitle: this.milestoneTitle, groupName: this.groupName });
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -25,6 +25,7 @@ export default () => {
|
|||
const modalProps = {
|
||||
milestoneTitle: button.dataset.milestoneTitle,
|
||||
url: button.dataset.url,
|
||||
groupName: button.dataset.groupName,
|
||||
};
|
||||
eventHub.$once('promoteMilestoneModal.requestStarted', onRequestStarted);
|
||||
eventHub.$emit('promoteMilestoneModal.props', modalProps);
|
||||
|
@ -54,6 +55,7 @@ export default () => {
|
|||
return {
|
||||
modalProps: {
|
||||
milestoneTitle: '',
|
||||
groupName: '',
|
||||
url: '',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import _ from 'underscore';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createFlash from '~/flash';
|
||||
import GlModal from '~/vue_shared/components/gl_modal.vue';
|
||||
|
@ -27,19 +28,26 @@
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
groupName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
text() {
|
||||
return s__(`Milestones|Promoting this label will make it available for all projects inside the group.
|
||||
Existing project labels with the same title will be merged. This action cannot be reversed.`);
|
||||
return sprintf(s__(`Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}.
|
||||
Existing project labels with the same title will be merged. This action cannot be reversed.`), {
|
||||
labelTitle: this.labelTitle,
|
||||
groupName: this.groupName,
|
||||
});
|
||||
},
|
||||
title() {
|
||||
const label = `<span
|
||||
class="label color-label"
|
||||
style="background-color: ${this.labelColor}; color: ${this.labelTextColor};"
|
||||
>${this.labelTitle}</span>`;
|
||||
>${_.escape(this.labelTitle)}</span>`;
|
||||
|
||||
return sprintf(s__('Labels|Promote label %{labelTitle} to Group Label?'), {
|
||||
return sprintf(s__('Labels|<span>Promote label</span> %{labelTitle} <span>to Group Label?</span>'), {
|
||||
labelTitle: label,
|
||||
}, false);
|
||||
},
|
||||
|
@ -69,6 +77,7 @@
|
|||
>
|
||||
<div
|
||||
slot="title"
|
||||
class="modal-title-with-label"
|
||||
v-html="title"
|
||||
>
|
||||
{{ title }}
|
||||
|
|
|
@ -30,6 +30,7 @@ const initLabelIndex = () => {
|
|||
labelColor: button.dataset.labelColor,
|
||||
labelTextColor: button.dataset.labelTextColor,
|
||||
url: button.dataset.url,
|
||||
groupName: button.dataset.groupName,
|
||||
};
|
||||
eventHub.$once('promoteLabelModal.requestStarted', onRequestStarted);
|
||||
eventHub.$emit('promoteLabelModal.props', modalProps);
|
||||
|
@ -62,6 +63,7 @@ const initLabelIndex = () => {
|
|||
labelColor: '',
|
||||
labelTextColor: '',
|
||||
url: '',
|
||||
groupName: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import _ from 'underscore';
|
||||
|
||||
function isValidProjectId(id) {
|
||||
return id > 0;
|
||||
}
|
||||
|
@ -41,7 +43,7 @@ class SidebarMoveIssue {
|
|||
renderRow: project => `
|
||||
<li>
|
||||
<a href="#" class="js-move-issue-dropdown-item">
|
||||
${project.name_with_namespace}
|
||||
${_.escape(project.name_with_namespace)}
|
||||
</a>
|
||||
</li>
|
||||
`,
|
||||
|
|
|
@ -4,9 +4,15 @@
|
|||
|
||||
.page-title,
|
||||
.modal-title {
|
||||
.modal-title-with-label span {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.color-label {
|
||||
font-size: $gl-font-size;
|
||||
padding: $gl-vert-padding $label-padding-modal;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ class Projects::LabelsController < Projects::ApplicationController
|
|||
begin
|
||||
return render_404 unless promote_service.execute(@label)
|
||||
|
||||
flash[:notice] = "#{@label.title} promoted to group label."
|
||||
flash[:notice] = "#{@label.title} promoted to <a href=\"#{group_labels_path(@project.group)}\">group label</a>.".html_safe
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to(project_labels_path(@project), status: 303)
|
||||
|
|
|
@ -70,9 +70,9 @@ class Projects::MilestonesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def promote
|
||||
Milestones::PromoteService.new(project, current_user).execute(milestone)
|
||||
promoted_milestone = Milestones::PromoteService.new(project, current_user).execute(milestone)
|
||||
|
||||
flash[:notice] = "#{milestone.title} promoted to group milestone"
|
||||
flash[:notice] = "#{milestone.title} promoted to <a href=\"#{group_milestone_path(project.group, promoted_milestone.iid)}\">group milestone</a>.".html_safe
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to project_milestones_path(project)
|
||||
|
|
|
@ -10,6 +10,7 @@ module Clusters
|
|||
Applications::Prometheus.application_name => Applications::Prometheus,
|
||||
Applications::Runner.application_name => Applications::Runner
|
||||
}.freeze
|
||||
DEFAULT_ENVIRONMENT = '*'.freeze
|
||||
|
||||
belongs_to :user
|
||||
|
||||
|
@ -50,6 +51,7 @@ module Clusters
|
|||
|
||||
scope :enabled, -> { where(enabled: true) }
|
||||
scope :disabled, -> { where(enabled: false) }
|
||||
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
|
||||
|
||||
def status_name
|
||||
if provider
|
||||
|
|
|
@ -1,16 +1,24 @@
|
|||
module DeploymentPlatform
|
||||
# EE would override this and utilize the extra argument
|
||||
# EE would override this and utilize environment argument
|
||||
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
def deployment_platform(environment: nil)
|
||||
@deployment_platform ||=
|
||||
find_cluster_platform_kubernetes ||
|
||||
find_kubernetes_service_integration ||
|
||||
build_cluster_and_deployment_platform
|
||||
@deployment_platform ||= {}
|
||||
|
||||
@deployment_platform[environment] ||= find_deployment_platform(environment)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_cluster_platform_kubernetes
|
||||
clusters.find_by(enabled: true)&.platform_kubernetes
|
||||
def find_deployment_platform(environment)
|
||||
find_cluster_platform_kubernetes(environment: environment) ||
|
||||
find_kubernetes_service_integration ||
|
||||
build_cluster_and_deployment_platform
|
||||
end
|
||||
|
||||
# EE would override this and utilize environment argument
|
||||
def find_cluster_platform_kubernetes(environment: nil)
|
||||
clusters.enabled.default_environment
|
||||
.last&.platform_kubernetes
|
||||
end
|
||||
|
||||
def find_kubernetes_service_integration
|
||||
|
|
|
@ -42,7 +42,10 @@ module Boards
|
|||
)
|
||||
end
|
||||
|
||||
attrs[:move_between_ids] = move_between_ids if move_between_ids
|
||||
if move_between_ids
|
||||
attrs[:move_between_ids] = move_between_ids
|
||||
attrs[:board_group_id] = board.group&.id
|
||||
end
|
||||
|
||||
attrs
|
||||
end
|
||||
|
|
|
@ -55,9 +55,10 @@ module Issues
|
|||
return unless params[:move_between_ids]
|
||||
|
||||
after_id, before_id = params.delete(:move_between_ids)
|
||||
board_group_id = params.delete(:board_group_id)
|
||||
|
||||
issue_before = get_issue_if_allowed(issue.project, before_id) if before_id
|
||||
issue_after = get_issue_if_allowed(issue.project, after_id) if after_id
|
||||
issue_before = get_issue_if_allowed(before_id, board_group_id)
|
||||
issue_after = get_issue_if_allowed(after_id, board_group_id)
|
||||
|
||||
issue.move_between(issue_before, issue_after)
|
||||
end
|
||||
|
@ -84,8 +85,16 @@ module Issues
|
|||
|
||||
private
|
||||
|
||||
def get_issue_if_allowed(project, id)
|
||||
issue = project.issues.find(id)
|
||||
def get_issue_if_allowed(id, board_group_id = nil)
|
||||
return unless id
|
||||
|
||||
issue =
|
||||
if board_group_id
|
||||
IssuesFinder.new(current_user, group_id: board_group_id).find_by(id: id)
|
||||
else
|
||||
project.issues.find(id)
|
||||
end
|
||||
|
||||
issue if can?(current_user, :update_issue, issue)
|
||||
end
|
||||
|
||||
|
|
|
@ -31,15 +31,17 @@ module Projects
|
|||
|
||||
# Check if we did extract public directory
|
||||
archive_public_path = File.join(archive_path, 'public')
|
||||
raise FailedToExtractError, 'pages miss the public folder' unless Dir.exist?(archive_public_path)
|
||||
raise InvaildStateError, 'pages miss the public folder' unless Dir.exist?(archive_public_path)
|
||||
raise InvaildStateError, 'pages are outdated' unless latest?
|
||||
|
||||
deploy_page!(archive_public_path)
|
||||
success
|
||||
end
|
||||
rescue InvaildStateError, FailedToExtractError => e
|
||||
register_failure
|
||||
rescue InvaildStateError => e
|
||||
error(e.message)
|
||||
rescue => e
|
||||
error(e.message, false)
|
||||
raise e
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -50,12 +52,13 @@ module Projects
|
|||
super
|
||||
end
|
||||
|
||||
def error(message, http_status = nil)
|
||||
def error(message, allow_delete_artifact = true)
|
||||
register_failure
|
||||
log_error("Projects::UpdatePagesService: #{message}")
|
||||
@status.allow_failure = !latest?
|
||||
@status.description = message
|
||||
@status.drop(:script_failure)
|
||||
delete_artifact!
|
||||
delete_artifact! if allow_delete_artifact
|
||||
super
|
||||
end
|
||||
|
||||
|
@ -76,7 +79,7 @@ module Projects
|
|||
elsif artifacts.ends_with?('.zip')
|
||||
extract_zip_archive!(temp_path)
|
||||
else
|
||||
raise FailedToExtractError, 'unsupported artifacts format'
|
||||
raise InvaildStateError, 'unsupported artifacts format'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -89,13 +92,13 @@ module Projects
|
|||
end
|
||||
|
||||
def extract_zip_archive!(temp_path)
|
||||
raise FailedToExtractError, 'missing artifacts metadata' unless build.artifacts_metadata?
|
||||
raise InvaildStateError, 'missing artifacts metadata' unless build.artifacts_metadata?
|
||||
|
||||
# Calculate page size after extract
|
||||
public_entry = build.artifacts_metadata_entry(SITE_PATH, recursive: true)
|
||||
|
||||
if public_entry.total_size > max_size
|
||||
raise FailedToExtractError, "artifacts for pages are too large: #{public_entry.total_size}"
|
||||
raise InvaildStateError, "artifacts for pages are too large: #{public_entry.total_size}"
|
||||
end
|
||||
|
||||
# Requires UnZip at least 6.00 Info-ZIP.
|
||||
|
@ -174,6 +177,9 @@ module Projects
|
|||
|
||||
def latest_sha
|
||||
project.commit(build.ref).try(:sha).to_s
|
||||
ensure
|
||||
# Close any file descriptors that were opened and free libgit2 buffers
|
||||
project.cleanup
|
||||
end
|
||||
|
||||
def sha
|
||||
|
|
|
@ -34,7 +34,8 @@ class VerifyPagesDomainService < BaseService
|
|||
# Prevent any pre-existing grace period from being truncated
|
||||
reverify = [domain.enabled_until, VERIFICATION_PERIOD.from_now].compact.max
|
||||
|
||||
domain.update!(verified_at: Time.now, enabled_until: reverify)
|
||||
domain.assign_attributes(verified_at: Time.now, enabled_until: reverify)
|
||||
domain.save!(validate: false)
|
||||
|
||||
if was_disabled
|
||||
notify(:enabled)
|
||||
|
@ -47,7 +48,9 @@ class VerifyPagesDomainService < BaseService
|
|||
|
||||
def unverify_domain!
|
||||
if domain.verified?
|
||||
domain.update!(verified_at: nil)
|
||||
domain.assign_attributes(verified_at: nil)
|
||||
domain.save!(validate: false)
|
||||
|
||||
notify(:verification_failed)
|
||||
end
|
||||
|
||||
|
@ -55,7 +58,8 @@ class VerifyPagesDomainService < BaseService
|
|||
end
|
||||
|
||||
def disable_domain!
|
||||
domain.update!(verified_at: nil, enabled_until: nil)
|
||||
domain.assign_attributes(verified_at: nil, enabled_until: nil)
|
||||
domain.save!(validate: false)
|
||||
|
||||
notify(:disabled)
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
%button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
|
||||
target: '#promote-milestone-modal',
|
||||
milestone_title: @milestone.title,
|
||||
group_name: @project.group.name,
|
||||
url: promote_project_milestone_path(@milestone.project, @milestone),
|
||||
container: 'body' },
|
||||
disabled: true,
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
label_title: label.title,
|
||||
label_color: label.color,
|
||||
label_text_color: label.text_color,
|
||||
group_name: label.project.group.name,
|
||||
target: '#promote-label-modal',
|
||||
container: 'body',
|
||||
toggle: 'modal' } }
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
= hidden_field(resource_name, field, value: value)
|
||||
= hidden_field_tag(:spam_log_id, spammable.spam_log.id)
|
||||
= hidden_field_tag(:recaptcha_verification, true)
|
||||
= recaptcha_tags script: script, callback: 'recaptchaDialogCallback'
|
||||
= recaptcha_tags script: script, callback: 'recaptchaDialogCallback' unless Rails.env.test?
|
||||
|
||||
-# Yields a block with given extra params.
|
||||
= yield
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
type: 'button',
|
||||
data: { url: promote_project_milestone_path(milestone.project, milestone),
|
||||
milestone_title: milestone.title,
|
||||
group_name: @project.group.name,
|
||||
target: '#promote-milestone-modal',
|
||||
container: 'body',
|
||||
toggle: 'modal' } }
|
||||
|
|
|
@ -15,13 +15,8 @@ codequality:
|
|||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- docker pull codeclimate/codeclimate
|
||||
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
|
||||
- docker run
|
||||
--env SOURCE_CODE="$PWD" \
|
||||
--volume "$PWD":/code \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
|
||||
- docker run --env SOURCE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
|
||||
artifacts:
|
||||
paths: [codeclimate.json]
|
||||
```
|
||||
|
|
|
@ -105,8 +105,12 @@ module Banzai
|
|||
end
|
||||
end
|
||||
|
||||
options = link_options.merge(href: match)
|
||||
content_tag(:a, match.html_safe, options) + dropped
|
||||
# match has come from node.to_html above, so we know it's encoded
|
||||
# correctly.
|
||||
html_safe_match = match.html_safe
|
||||
options = link_options.merge(href: html_safe_match)
|
||||
|
||||
content_tag(:a, html_safe_match, options) + dropped
|
||||
end
|
||||
|
||||
def autolink_filter(text)
|
||||
|
|
|
@ -12,6 +12,7 @@ module Gitlab
|
|||
|
||||
class Build < ActiveRecord::Base
|
||||
self.table_name = 'ci_builds'
|
||||
self.inheritance_column = :_type_disabled
|
||||
|
||||
def ensure_stage!(attempts: 2)
|
||||
find_stage || create_stage!
|
||||
|
|
|
@ -8,6 +8,7 @@ module Gitlab
|
|||
class Repository
|
||||
include Gitlab::Git::RepositoryMirroring
|
||||
include Gitlab::Git::Popen
|
||||
include Gitlab::EncodingHelper
|
||||
|
||||
ALLOWED_OBJECT_DIRECTORIES_VARIABLES = %w[
|
||||
GIT_OBJECT_DIRECTORY
|
||||
|
@ -1498,7 +1499,7 @@ module Gitlab
|
|||
names.lines.each do |line|
|
||||
next unless line.start_with?(refs_prefix)
|
||||
|
||||
refs << line.rstrip[left_slice_count..-1]
|
||||
refs << encode_utf8(line.rstrip[left_slice_count..-1])
|
||||
end
|
||||
|
||||
refs
|
||||
|
|
|
@ -18,7 +18,7 @@ describe Projects::ClustersController do
|
|||
context 'when project has one or more clusters' do
|
||||
let(:project) { create(:project) }
|
||||
let!(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
|
||||
let!(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, projects: [project]) }
|
||||
let!(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, :production_environment, projects: [project]) }
|
||||
it 'lists available clusters' do
|
||||
go
|
||||
|
||||
|
@ -32,7 +32,7 @@ describe Projects::ClustersController do
|
|||
|
||||
before do
|
||||
allow(Clusters::Cluster).to receive(:paginates_per).and_return(1)
|
||||
create_list(:cluster, 2, :provided_by_gcp, projects: [project])
|
||||
create_list(:cluster, 2, :provided_by_gcp, :production_environment, projects: [project])
|
||||
get :index, namespace_id: project.namespace, project_id: project, page: last_page
|
||||
end
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ describe Projects::MilestonesController do
|
|||
it 'shows group milestone' do
|
||||
post :promote, namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid
|
||||
|
||||
expect(flash[:notice]).to eq("#{milestone.title} promoted to group milestone")
|
||||
expect(flash[:notice]).to eq("#{milestone.title} promoted to <a href=\"#{group_milestone_path(project.group, milestone.iid)}\">group milestone</a>.")
|
||||
expect(response).to redirect_to(project_milestones_path(project))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,5 +32,9 @@ FactoryBot.define do
|
|||
trait :disabled do
|
||||
enabled false
|
||||
end
|
||||
|
||||
trait :production_environment do
|
||||
sequence(:environment_scope) { |n| "production#{n}/*" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,9 +34,6 @@ describe 'New issue', :js do
|
|||
|
||||
click_button 'Submit issue'
|
||||
|
||||
# reCAPTCHA alerts when it can't contact the server, so just accept it and move on
|
||||
page.driver.browser.switch_to.alert.accept
|
||||
|
||||
# it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha
|
||||
# recaptcha verification is skipped in test environment and it always returns true
|
||||
expect(page).not_to have_content('issue title')
|
||||
|
|
|
@ -6,7 +6,7 @@ describe ClustersFinder do
|
|||
|
||||
describe '#execute' do
|
||||
let(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
|
||||
let(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, projects: [project]) }
|
||||
let(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, :production_environment, projects: [project]) }
|
||||
|
||||
subject { described_class.new(project, user, scope).execute }
|
||||
|
||||
|
|
|
@ -25,26 +25,34 @@ describe('issue_discussion component', () => {
|
|||
});
|
||||
|
||||
it('should render user avatar', () => {
|
||||
expect(vm.$el.querySelector('.user-avatar-link')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.user-avatar-link')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should render discussion header', () => {
|
||||
expect(vm.$el.querySelector('.discussion-header')).toBeDefined();
|
||||
expect(vm.$el.querySelector('.discussion-header')).not.toBeNull();
|
||||
expect(vm.$el.querySelector('.notes').children.length).toEqual(discussionMock.notes.length);
|
||||
});
|
||||
|
||||
describe('actions', () => {
|
||||
it('should render reply button', () => {
|
||||
expect(vm.$el.querySelector('.js-vue-discussion-reply').textContent.trim()).toEqual('Reply...');
|
||||
expect(vm.$el.querySelector('.js-vue-discussion-reply').textContent.trim()).toEqual(
|
||||
'Reply...',
|
||||
);
|
||||
});
|
||||
|
||||
it('should toggle reply form', (done) => {
|
||||
vm.$el.querySelector('.js-vue-discussion-reply').click();
|
||||
Vue.nextTick(() => {
|
||||
expect(vm.$refs.noteForm).toBeDefined();
|
||||
expect(vm.$refs.noteForm).not.toBeNull();
|
||||
expect(vm.isReplying).toEqual(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render jump to discussion button', () => {
|
||||
expect(
|
||||
vm.$el.querySelector('*[data-original-title="Jump to next unresolved discussion"]'),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ describe('Promote label modal', () => {
|
|||
labelColor: '#5cb85c',
|
||||
labelTextColor: '#ffffff',
|
||||
url: `${gl.TEST_HOST}/dummy/promote/labels`,
|
||||
groupName: 'group',
|
||||
};
|
||||
|
||||
describe('Modal title and description', () => {
|
||||
|
@ -24,7 +25,7 @@ describe('Promote label modal', () => {
|
|||
});
|
||||
|
||||
it('contains the proper description', () => {
|
||||
expect(vm.text).toContain('Promoting this label will make it available for all projects inside the group');
|
||||
expect(vm.text).toContain(`Promoting ${labelMockData.labelTitle} will make it available for all projects inside ${labelMockData.groupName}`);
|
||||
});
|
||||
|
||||
it('contains a label span with the color', () => {
|
||||
|
|
|
@ -10,6 +10,7 @@ describe('Promote milestone modal', () => {
|
|||
const milestoneMockData = {
|
||||
milestoneTitle: 'v1.0',
|
||||
url: `${gl.TEST_HOST}/dummy/promote/milestones`,
|
||||
groupName: 'group',
|
||||
};
|
||||
|
||||
describe('Modal title and description', () => {
|
||||
|
@ -22,7 +23,7 @@ describe('Promote milestone modal', () => {
|
|||
});
|
||||
|
||||
it('contains the proper description', () => {
|
||||
expect(vm.text).toContain('Promoting this milestone will make it available for all projects inside the group.');
|
||||
expect(vm.text).toContain(`Promoting ${milestoneMockData.milestoneTitle} will make it available for all projects inside ${milestoneMockData.groupName}.`);
|
||||
});
|
||||
|
||||
it('contains the correct title', () => {
|
||||
|
|
|
@ -130,7 +130,7 @@ const RESPONSE_MAP = {
|
|||
'name_with_namespace': 'No project',
|
||||
}, {
|
||||
'id': 20,
|
||||
'name_with_namespace': 'foo / bar',
|
||||
'name_with_namespace': '<img src=x onerror=alert(document.domain)> foo / bar',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -68,6 +68,15 @@ describe('SidebarMoveIssue', () => {
|
|||
|
||||
expect($.fn.glDropdown).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('escapes html from project name', (done) => {
|
||||
this.$toggleButton.dropdown('toggle');
|
||||
|
||||
setTimeout(() => {
|
||||
expect(this.$content.find('.js-move-issue-dropdown-item')[1].innerHTML.trim()).toEqual('<img src=x onerror=alert(document.domain)> foo / bar');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onConfirmClicked', () => {
|
||||
|
|
|
@ -167,6 +167,15 @@ describe Banzai::Filter::AutolinkFilter do
|
|||
expect(actual).to eq(expected_complicated_link)
|
||||
end
|
||||
|
||||
it 'does not double-encode HTML entities' do
|
||||
encoded_link = "#{link}?foo=bar&baz=quux"
|
||||
expected_encoded_link = %Q{<a href="#{encoded_link}">#{encoded_link}</a>}
|
||||
actual = unescape(filter(encoded_link).to_html)
|
||||
|
||||
expect(actual).to eq(Rinku.auto_link(encoded_link))
|
||||
expect(actual).to eq(expected_encoded_link)
|
||||
end
|
||||
|
||||
it 'does not include trailing HTML entities' do
|
||||
doc = filter("See <<<#{link}>>>")
|
||||
|
||||
|
|
|
@ -51,4 +51,20 @@ describe Gitlab::BackgroundMigration::MigrateBuildStage, :migration, schema: 201
|
|||
expect { described_class.new.perform(1, 6) }
|
||||
.to raise_error ActiveRecord::RecordNotUnique
|
||||
end
|
||||
|
||||
context 'when invalid class can be loaded due to single table inheritance' do
|
||||
let(:commit_status) do
|
||||
jobs.create!(id: 7, commit_id: 1, project_id: 123, stage_idx: 4,
|
||||
stage: 'post-deploy', status: :failed)
|
||||
end
|
||||
|
||||
before do
|
||||
commit_status.update_column(:type, 'SomeClass')
|
||||
end
|
||||
|
||||
it 'does ignore single table inheritance type' do
|
||||
expect { described_class.new.perform(1, 7) }.not_to raise_error
|
||||
expect(jobs.find(7)).to have_attributes(stage_id: (a_value > 0))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -604,17 +604,20 @@ describe Gitlab::Git::Repository, seed_helper: true do
|
|||
shared_examples 'returning the right branches' do
|
||||
let(:head_id) { repository.rugged.head.target.oid }
|
||||
let(:new_branch) { head_id }
|
||||
let(:utf8_branch) { 'branch-é' }
|
||||
|
||||
before do
|
||||
repository.create_branch(new_branch, 'master')
|
||||
repository.create_branch(utf8_branch, 'master')
|
||||
end
|
||||
|
||||
after do
|
||||
repository.delete_branch(new_branch)
|
||||
repository.delete_branch(utf8_branch)
|
||||
end
|
||||
|
||||
it 'displays that branch' do
|
||||
expect(repository.branch_names_contains_sha(head_id)).to include('master', new_branch)
|
||||
expect(repository.branch_names_contains_sha(head_id)).to include('master', new_branch, utf8_branch)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -339,7 +339,7 @@ describe ProjectPresenter do
|
|||
|
||||
it 'returns link to clusters page if more than one exists' do
|
||||
project.add_master(user)
|
||||
create(:cluster, projects: [project])
|
||||
create(:cluster, :production_environment, projects: [project])
|
||||
create(:cluster, projects: [project])
|
||||
|
||||
expect(presenter.kubernetes_cluster_anchor_data).to eq(OpenStruct.new(enabled: true,
|
||||
|
|
|
@ -48,7 +48,7 @@ describe Boards::Issues::MoveService do
|
|||
parent.add_developer(user)
|
||||
end
|
||||
|
||||
it_behaves_like 'issues move service'
|
||||
it_behaves_like 'issues move service', true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -82,7 +82,7 @@ describe Clusters::CreateService do
|
|||
|
||||
context 'when project has a cluster' do
|
||||
include_context 'valid params'
|
||||
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
|
||||
let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) }
|
||||
|
||||
it 'does not create a cluster' do
|
||||
expect(ClusterProvisionWorker).not_to receive(:perform_async)
|
||||
|
|
|
@ -97,6 +97,37 @@ describe Issues::UpdateService, :mailer do
|
|||
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
|
||||
end
|
||||
|
||||
context 'when moving issue between issues from different projects' do
|
||||
let(:group) { create(:group) }
|
||||
let(:project_1) { create(:project, namespace: group) }
|
||||
let(:project_2) { create(:project, namespace: group) }
|
||||
let(:project_3) { create(:project, namespace: group) }
|
||||
|
||||
let(:issue_1) { create(:issue, project: project_1) }
|
||||
let(:issue_2) { create(:issue, project: project_2) }
|
||||
let(:issue_3) { create(:issue, project: project_3) }
|
||||
|
||||
before do
|
||||
group.add_developer(user)
|
||||
end
|
||||
|
||||
it 'sorts issues as specified by parameters' do
|
||||
# Moving all issues to end here like the last example won't work since
|
||||
# all projects only have the same issue count
|
||||
# so their relative_position will be the same.
|
||||
issue_1.move_to_end
|
||||
issue_2.move_after(issue_1)
|
||||
issue_3.move_after(issue_2)
|
||||
[issue_1, issue_2, issue_3].map(&:save)
|
||||
|
||||
opts[:move_between_ids] = [issue_1.id, issue_2.id]
|
||||
opts[:board_group_id] = group.id
|
||||
|
||||
described_class.new(issue_3.project, user, opts).execute(issue_3)
|
||||
expect(issue_2.relative_position).to be_between(issue_1.relative_position, issue_2.relative_position)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user cannot admin issues in the project' do
|
||||
let(:guest) { create(:user) }
|
||||
before do
|
||||
|
|
|
@ -87,7 +87,8 @@ describe Projects::UpdatePagesService do
|
|||
it 'fails for empty file fails' do
|
||||
build.update_attributes(legacy_artifacts_file: empty_file)
|
||||
|
||||
expect(execute).not_to eq(:success)
|
||||
expect { execute }
|
||||
.to raise_error(Projects::UpdatePagesService::FailedToExtractError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -159,7 +160,8 @@ describe Projects::UpdatePagesService do
|
|||
it 'fails for empty file fails' do
|
||||
build.job_artifacts_archive.update_attributes(file: empty_file)
|
||||
|
||||
expect(execute).not_to eq(:success)
|
||||
expect { execute }
|
||||
.to raise_error(Projects::UpdatePagesService::FailedToExtractError)
|
||||
end
|
||||
|
||||
context 'when timeout happens by DNS error' do
|
||||
|
@ -172,7 +174,39 @@ describe Projects::UpdatePagesService do
|
|||
expect { execute }.to raise_error(SocketError)
|
||||
|
||||
build.reload
|
||||
expect(build.artifacts?).to eq(true)
|
||||
expect(deploy_status).to be_failed
|
||||
expect(build.artifacts?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when failed to extract zip artifacts' do
|
||||
before do
|
||||
allow_any_instance_of(described_class)
|
||||
.to receive(:extract_zip_archive!)
|
||||
.and_raise(Projects::UpdatePagesService::FailedToExtractError)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { execute }
|
||||
.to raise_error(Projects::UpdatePagesService::FailedToExtractError)
|
||||
|
||||
build.reload
|
||||
expect(deploy_status).to be_failed
|
||||
expect(build.artifacts?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when missing artifacts metadata' do
|
||||
before do
|
||||
allow(build).to receive(:artifacts_metadata?).and_return(false)
|
||||
end
|
||||
|
||||
it 'does not raise an error and remove artifacts as failed job' do
|
||||
execute
|
||||
|
||||
build.reload
|
||||
expect(deploy_status).to be_failed
|
||||
expect(build.artifacts?).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -93,6 +93,25 @@ describe VerifyPagesDomainService do
|
|||
expect(domain).not_to be_enabled
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid domain' do
|
||||
let(:domain) { build(:pages_domain, :expired, :with_missing_chain) }
|
||||
|
||||
before do
|
||||
domain.save(validate: false)
|
||||
end
|
||||
|
||||
it 'can be disabled' do
|
||||
error_status[:message] += '. It is now disabled.'
|
||||
|
||||
stub_resolver
|
||||
|
||||
expect(service.execute).to eq(error_status)
|
||||
|
||||
expect(domain).not_to be_verified
|
||||
expect(domain).not_to be_enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'timeout behaviour' do
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
module MigrationsHelpers
|
||||
def table(name)
|
||||
Class.new(ActiveRecord::Base) { self.table_name = name }
|
||||
Class.new(ActiveRecord::Base) do
|
||||
self.table_name = name
|
||||
self.inheritance_column = :_type_disabled
|
||||
end
|
||||
end
|
||||
|
||||
def migrations_paths
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
shared_examples 'issues move service' do
|
||||
shared_examples 'issues move service' do |group|
|
||||
context 'when moving an issue between lists' do
|
||||
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
|
||||
let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list2.id } }
|
||||
|
@ -83,5 +83,18 @@ shared_examples 'issues move service' do
|
|||
|
||||
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
|
||||
end
|
||||
|
||||
if group
|
||||
context 'when on a group board' do
|
||||
it 'sends the board_group_id parameter' do
|
||||
params.merge!(move_after_id: issue1.id, move_before_id: issue2.id)
|
||||
|
||||
match_params = { move_between_ids: [issue1.id, issue2.id], board_group_id: parent.id }
|
||||
expect(Issues::UpdateService).to receive(:new).with(issue.project, user, match_params).and_return(double(execute: build(:issue)))
|
||||
|
||||
described_class.new(parent, user, params).execute(issue)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
1202
vendor/assets/javascripts/jquery.atwho.js
vendored
Normal file
1202
vendor/assets/javascripts/jquery.atwho.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
436
vendor/assets/javascripts/jquery.caret.js
vendored
Normal file
436
vendor/assets/javascripts/jquery.caret.js
vendored
Normal file
|
@ -0,0 +1,436 @@
|
|||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(["jquery"], function ($) {
|
||||
return (root.returnExportsGlobal = factory($));
|
||||
});
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node. Does not work with strict CommonJS, but
|
||||
// only CommonJS-like enviroments that support module.exports,
|
||||
// like Node.
|
||||
module.exports = factory(require("jquery"));
|
||||
} else {
|
||||
factory(jQuery);
|
||||
}
|
||||
}(this, function ($) {
|
||||
|
||||
/*
|
||||
Implement Github like autocomplete mentions
|
||||
http://ichord.github.com/At.js
|
||||
|
||||
Copyright (c) 2013 chord.luo@gmail.com
|
||||
Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
/*
|
||||
本插件操作 textarea 或者 input 内的插入符
|
||||
只实现了获得插入符在文本框中的位置,我设置
|
||||
插入符的位置.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
var EditableCaret, InputCaret, Mirror, Utils, discoveryIframeOf, methods, oDocument, oFrame, oWindow, pluginName, setContextBy;
|
||||
|
||||
pluginName = 'caret';
|
||||
|
||||
EditableCaret = (function() {
|
||||
function EditableCaret($inputor) {
|
||||
this.$inputor = $inputor;
|
||||
this.domInputor = this.$inputor[0];
|
||||
}
|
||||
|
||||
EditableCaret.prototype.setPos = function(pos) {
|
||||
var fn, found, offset, sel;
|
||||
if (sel = oWindow.getSelection()) {
|
||||
offset = 0;
|
||||
found = false;
|
||||
(fn = function(pos, parent) {
|
||||
var node, range, _i, _len, _ref, _results;
|
||||
_ref = parent.childNodes;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
node = _ref[_i];
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
if (node.nodeType === 3) {
|
||||
if (offset + node.length >= pos) {
|
||||
found = true;
|
||||
range = oDocument.createRange();
|
||||
range.setStart(node, pos - offset);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
break;
|
||||
} else {
|
||||
_results.push(offset += node.length);
|
||||
}
|
||||
} else {
|
||||
_results.push(fn(pos, node));
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})(pos, this.domInputor);
|
||||
}
|
||||
return this.domInputor;
|
||||
};
|
||||
|
||||
EditableCaret.prototype.getIEPosition = function() {
|
||||
return this.getPosition();
|
||||
};
|
||||
|
||||
EditableCaret.prototype.getPosition = function() {
|
||||
var inputor_offset, offset;
|
||||
offset = this.getOffset();
|
||||
inputor_offset = this.$inputor.offset();
|
||||
offset.left -= inputor_offset.left;
|
||||
offset.top -= inputor_offset.top;
|
||||
return offset;
|
||||
};
|
||||
|
||||
EditableCaret.prototype.getOldIEPos = function() {
|
||||
var preCaretTextRange, textRange;
|
||||
textRange = oDocument.selection.createRange();
|
||||
preCaretTextRange = oDocument.body.createTextRange();
|
||||
preCaretTextRange.moveToElementText(this.domInputor);
|
||||
preCaretTextRange.setEndPoint("EndToEnd", textRange);
|
||||
return preCaretTextRange.text.length;
|
||||
};
|
||||
|
||||
EditableCaret.prototype.getPos = function() {
|
||||
var clonedRange, pos, range;
|
||||
if (range = this.range()) {
|
||||
clonedRange = range.cloneRange();
|
||||
clonedRange.selectNodeContents(this.domInputor);
|
||||
clonedRange.setEnd(range.endContainer, range.endOffset);
|
||||
pos = clonedRange.toString().length;
|
||||
clonedRange.detach();
|
||||
return pos;
|
||||
} else if (oDocument.selection) {
|
||||
return this.getOldIEPos();
|
||||
}
|
||||
};
|
||||
|
||||
EditableCaret.prototype.getOldIEOffset = function() {
|
||||
var range, rect;
|
||||
range = oDocument.selection.createRange().duplicate();
|
||||
range.moveStart("character", -1);
|
||||
rect = range.getBoundingClientRect();
|
||||
return {
|
||||
height: rect.bottom - rect.top,
|
||||
left: rect.left,
|
||||
top: rect.top
|
||||
};
|
||||
};
|
||||
|
||||
EditableCaret.prototype.getOffset = function(pos) {
|
||||
var clonedRange, offset, range, rect, shadowCaret;
|
||||
if (oWindow.getSelection && (range = this.range())) {
|
||||
if (range.endOffset - 1 > 0 && range.endContainer !== this.domInputor) {
|
||||
clonedRange = range.cloneRange();
|
||||
clonedRange.setStart(range.endContainer, range.endOffset - 1);
|
||||
clonedRange.setEnd(range.endContainer, range.endOffset);
|
||||
rect = clonedRange.getBoundingClientRect();
|
||||
offset = {
|
||||
height: rect.height,
|
||||
left: rect.left + rect.width,
|
||||
top: rect.top
|
||||
};
|
||||
clonedRange.detach();
|
||||
}
|
||||
if (!offset || (offset != null ? offset.height : void 0) === 0) {
|
||||
clonedRange = range.cloneRange();
|
||||
shadowCaret = $(oDocument.createTextNode("|"));
|
||||
clonedRange.insertNode(shadowCaret[0]);
|
||||
clonedRange.selectNode(shadowCaret[0]);
|
||||
rect = clonedRange.getBoundingClientRect();
|
||||
offset = {
|
||||
height: rect.height,
|
||||
left: rect.left,
|
||||
top: rect.top
|
||||
};
|
||||
shadowCaret.remove();
|
||||
clonedRange.detach();
|
||||
}
|
||||
} else if (oDocument.selection) {
|
||||
offset = this.getOldIEOffset();
|
||||
}
|
||||
if (offset) {
|
||||
offset.top += $(oWindow).scrollTop();
|
||||
offset.left += $(oWindow).scrollLeft();
|
||||
}
|
||||
return offset;
|
||||
};
|
||||
|
||||
EditableCaret.prototype.range = function() {
|
||||
var sel;
|
||||
if (!oWindow.getSelection) {
|
||||
return;
|
||||
}
|
||||
sel = oWindow.getSelection();
|
||||
if (sel.rangeCount > 0) {
|
||||
return sel.getRangeAt(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return EditableCaret;
|
||||
|
||||
})();
|
||||
|
||||
InputCaret = (function() {
|
||||
function InputCaret($inputor) {
|
||||
this.$inputor = $inputor;
|
||||
this.domInputor = this.$inputor[0];
|
||||
}
|
||||
|
||||
InputCaret.prototype.getIEPos = function() {
|
||||
var endRange, inputor, len, normalizedValue, pos, range, textInputRange;
|
||||
inputor = this.domInputor;
|
||||
range = oDocument.selection.createRange();
|
||||
pos = 0;
|
||||
if (range && range.parentElement() === inputor) {
|
||||
normalizedValue = inputor.value.replace(/\r\n/g, "\n");
|
||||
len = normalizedValue.length;
|
||||
textInputRange = inputor.createTextRange();
|
||||
textInputRange.moveToBookmark(range.getBookmark());
|
||||
endRange = inputor.createTextRange();
|
||||
endRange.collapse(false);
|
||||
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
|
||||
pos = len;
|
||||
} else {
|
||||
pos = -textInputRange.moveStart("character", -len);
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
InputCaret.prototype.getPos = function() {
|
||||
if (oDocument.selection) {
|
||||
return this.getIEPos();
|
||||
} else {
|
||||
return this.domInputor.selectionStart;
|
||||
}
|
||||
};
|
||||
|
||||
InputCaret.prototype.setPos = function(pos) {
|
||||
var inputor, range;
|
||||
inputor = this.domInputor;
|
||||
if (oDocument.selection) {
|
||||
range = inputor.createTextRange();
|
||||
range.move("character", pos);
|
||||
range.select();
|
||||
} else if (inputor.setSelectionRange) {
|
||||
inputor.setSelectionRange(pos, pos);
|
||||
}
|
||||
return inputor;
|
||||
};
|
||||
|
||||
InputCaret.prototype.getIEOffset = function(pos) {
|
||||
var h, textRange, x, y;
|
||||
textRange = this.domInputor.createTextRange();
|
||||
pos || (pos = this.getPos());
|
||||
textRange.move('character', pos);
|
||||
x = textRange.boundingLeft;
|
||||
y = textRange.boundingTop;
|
||||
h = textRange.boundingHeight;
|
||||
return {
|
||||
left: x,
|
||||
top: y,
|
||||
height: h
|
||||
};
|
||||
};
|
||||
|
||||
InputCaret.prototype.getOffset = function(pos) {
|
||||
var $inputor, offset, position;
|
||||
$inputor = this.$inputor;
|
||||
if (oDocument.selection) {
|
||||
offset = this.getIEOffset(pos);
|
||||
offset.top += $(oWindow).scrollTop() + $inputor.scrollTop();
|
||||
offset.left += $(oWindow).scrollLeft() + $inputor.scrollLeft();
|
||||
return offset;
|
||||
} else {
|
||||
offset = $inputor.offset();
|
||||
position = this.getPosition(pos);
|
||||
return offset = {
|
||||
left: offset.left + position.left - $inputor.scrollLeft(),
|
||||
top: offset.top + position.top - $inputor.scrollTop(),
|
||||
height: position.height
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
InputCaret.prototype.getPosition = function(pos) {
|
||||
var $inputor, at_rect, end_range, format, html, mirror, start_range;
|
||||
$inputor = this.$inputor;
|
||||
format = function(value) {
|
||||
value = value.replace(/<|>|`|"|&/g, '?').replace(/\r\n|\r|\n/g, "<br/>");
|
||||
if (/firefox/i.test(navigator.userAgent)) {
|
||||
value = value.replace(/\s/g, ' ');
|
||||
}
|
||||
return value;
|
||||
};
|
||||
if (pos === void 0) {
|
||||
pos = this.getPos();
|
||||
}
|
||||
start_range = $inputor.val().slice(0, pos);
|
||||
end_range = $inputor.val().slice(pos);
|
||||
html = "<span style='position: relative; display: inline;'>" + format(start_range) + "</span>";
|
||||
html += "<span id='caret' style='position: relative; display: inline;'>|</span>";
|
||||
html += "<span style='position: relative; display: inline;'>" + format(end_range) + "</span>";
|
||||
mirror = new Mirror($inputor);
|
||||
return at_rect = mirror.create(html).rect();
|
||||
};
|
||||
|
||||
InputCaret.prototype.getIEPosition = function(pos) {
|
||||
var h, inputorOffset, offset, x, y;
|
||||
offset = this.getIEOffset(pos);
|
||||
inputorOffset = this.$inputor.offset();
|
||||
x = offset.left - inputorOffset.left;
|
||||
y = offset.top - inputorOffset.top;
|
||||
h = offset.height;
|
||||
return {
|
||||
left: x,
|
||||
top: y,
|
||||
height: h
|
||||
};
|
||||
};
|
||||
|
||||
return InputCaret;
|
||||
|
||||
})();
|
||||
|
||||
Mirror = (function() {
|
||||
Mirror.prototype.css_attr = ["borderBottomWidth", "borderLeftWidth", "borderRightWidth", "borderTopStyle", "borderRightStyle", "borderBottomStyle", "borderLeftStyle", "borderTopWidth", "boxSizing", "fontFamily", "fontSize", "fontWeight", "height", "letterSpacing", "lineHeight", "marginBottom", "marginLeft", "marginRight", "marginTop", "outlineWidth", "overflow", "overflowX", "overflowY", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "textAlign", "textOverflow", "textTransform", "whiteSpace", "wordBreak", "wordWrap"];
|
||||
|
||||
function Mirror($inputor) {
|
||||
this.$inputor = $inputor;
|
||||
}
|
||||
|
||||
Mirror.prototype.mirrorCss = function() {
|
||||
var css,
|
||||
_this = this;
|
||||
css = {
|
||||
position: 'absolute',
|
||||
left: -9999,
|
||||
top: 0,
|
||||
zIndex: -20000
|
||||
};
|
||||
if (this.$inputor.prop('tagName') === 'TEXTAREA') {
|
||||
this.css_attr.push('width');
|
||||
}
|
||||
$.each(this.css_attr, function(i, p) {
|
||||
return css[p] = _this.$inputor.css(p);
|
||||
});
|
||||
return css;
|
||||
};
|
||||
|
||||
Mirror.prototype.create = function(html) {
|
||||
this.$mirror = $('<div></div>');
|
||||
this.$mirror.css(this.mirrorCss());
|
||||
this.$mirror.html(html);
|
||||
this.$inputor.after(this.$mirror);
|
||||
return this;
|
||||
};
|
||||
|
||||
Mirror.prototype.rect = function() {
|
||||
var $flag, pos, rect;
|
||||
$flag = this.$mirror.find("#caret");
|
||||
pos = $flag.position();
|
||||
rect = {
|
||||
left: pos.left,
|
||||
top: pos.top,
|
||||
height: $flag.height()
|
||||
};
|
||||
this.$mirror.remove();
|
||||
return rect;
|
||||
};
|
||||
|
||||
return Mirror;
|
||||
|
||||
})();
|
||||
|
||||
Utils = {
|
||||
contentEditable: function($inputor) {
|
||||
return !!($inputor[0].contentEditable && $inputor[0].contentEditable === 'true');
|
||||
}
|
||||
};
|
||||
|
||||
methods = {
|
||||
pos: function(pos) {
|
||||
if (pos || pos === 0) {
|
||||
return this.setPos(pos);
|
||||
} else {
|
||||
return this.getPos();
|
||||
}
|
||||
},
|
||||
position: function(pos) {
|
||||
if (oDocument.selection) {
|
||||
return this.getIEPosition(pos);
|
||||
} else {
|
||||
return this.getPosition(pos);
|
||||
}
|
||||
},
|
||||
offset: function(pos) {
|
||||
var offset;
|
||||
offset = this.getOffset(pos);
|
||||
return offset;
|
||||
}
|
||||
};
|
||||
|
||||
oDocument = null;
|
||||
|
||||
oWindow = null;
|
||||
|
||||
oFrame = null;
|
||||
|
||||
setContextBy = function(settings) {
|
||||
var iframe;
|
||||
if (iframe = settings != null ? settings.iframe : void 0) {
|
||||
oFrame = iframe;
|
||||
oWindow = iframe.contentWindow;
|
||||
return oDocument = iframe.contentDocument || oWindow.document;
|
||||
} else {
|
||||
oFrame = void 0;
|
||||
oWindow = window;
|
||||
return oDocument = document;
|
||||
}
|
||||
};
|
||||
|
||||
discoveryIframeOf = function($dom) {
|
||||
var error;
|
||||
oDocument = $dom[0].ownerDocument;
|
||||
oWindow = oDocument.defaultView || oDocument.parentWindow;
|
||||
try {
|
||||
return oFrame = oWindow.frameElement;
|
||||
} catch (_error) {
|
||||
error = _error;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.caret = function(method, value, settings) {
|
||||
var caret;
|
||||
if (methods[method]) {
|
||||
if ($.isPlainObject(value)) {
|
||||
setContextBy(value);
|
||||
value = void 0;
|
||||
} else {
|
||||
setContextBy(settings);
|
||||
}
|
||||
caret = Utils.contentEditable(this) ? new EditableCaret(this) : new InputCaret(this);
|
||||
return methods[method].apply(caret, [value]);
|
||||
} else {
|
||||
return $.error("Method " + method + " does not exist on jQuery.caret");
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.caret.EditableCaret = EditableCaret;
|
||||
|
||||
$.fn.caret.InputCaret = InputCaret;
|
||||
|
||||
$.fn.caret.Utils = Utils;
|
||||
|
||||
$.fn.caret.apis = methods;
|
||||
|
||||
|
||||
}));
|
9365
vendor/assets/javascripts/pdf.js
vendored
Executable file
9365
vendor/assets/javascripts/pdf.js
vendored
Executable file
File diff suppressed because it is too large
Load diff
6
vendor/assets/javascripts/pdf.min.js
vendored
Executable file
6
vendor/assets/javascripts/pdf.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
38338
vendor/assets/javascripts/pdf.worker.js
vendored
Executable file
38338
vendor/assets/javascripts/pdf.worker.js
vendored
Executable file
File diff suppressed because it is too large
Load diff
19
vendor/assets/javascripts/pdf.worker.min.js
vendored
Executable file
19
vendor/assets/javascripts/pdf.worker.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
2235
vendor/assets/javascripts/xterm/xterm.js
vendored
Normal file
2235
vendor/assets/javascripts/xterm/xterm.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
vendor/prometheus/values.yaml
vendored
1
vendor/prometheus/values.yaml
vendored
|
@ -14,6 +14,7 @@ rbac:
|
|||
create: false
|
||||
|
||||
server:
|
||||
fullnameOverride: "prometheus-prometheus-server"
|
||||
image:
|
||||
tag: v2.1.0
|
||||
|
||||
|
|
Loading…
Reference in a new issue