Skip to content
Snippets Groups Projects
Commit c833a09d authored by Jose Ivan Vargas Lopez's avatar Jose Ivan Vargas Lopez
Browse files

Merge branch 'master' into jivl-update-katex

parents 46ae0362 0a22ff26
No related branches found
No related tags found
No related merge requests found
Showing
with 354 additions and 125 deletions
Loading
Loading
@@ -2,6 +2,16 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
 
## 10.4.3 (2018-02-05)
### Security (4 changes)
- Fix namespace access issue for GitHub, BitBucket, and GitLab.com project importers.
- Fix stored XSS in code blocks that ignore highlighting.
- Fix wilcard protected tags protecting all branches.
- Restrict Todo API mark_as_done endpoint to the user's todos only.
## 10.4.2 (2018-01-30)
 
### Fixed (6 changes)
Loading
Loading
@@ -197,6 +207,16 @@ entry.
- Use a background migration for issues.closed_at.
 
 
## 10.3.7 (2018-02-05)
### Security (4 changes)
- Fix namespace access issue for GitHub, BitBucket, and GitLab.com project importers.
- Fix stored XSS in code blocks that ignore highlighting.
- Fix wilcard protected tags protecting all branches.
- Restrict Todo API mark_as_done endpoint to the user's todos only.
## 10.3.6 (2018-01-22)
 
### Fixed (17 changes, 2 of them are from the community)
Loading
Loading
@@ -415,6 +435,16 @@ entry.
- Clean up schema of the "merge_requests" table.
 
 
## 10.2.8 (2018-02-07)
### Security (4 changes)
- Fix namespace access issue for GitHub, BitBucket, and GitLab.com project importers.
- Fix stored XSS in code blocks that ignore highlighting.
- Fix wilcard protected tags protecting all branches.
- Restrict Todo API mark_as_done endpoint to the user's todos only.
## 10.2.7 (2018-01-18)
 
- No changes.
Loading
Loading
0.78.0
0.81.0
6.0.2
6.0.3
3.5.1
3.6.0
Loading
Loading
@@ -294,7 +294,7 @@ group :metrics do
gem 'influxdb', '~> 0.2', require: false
 
# Prometheus
gem 'prometheus-client-mmap', '~> 0.7.0.beta44'
gem 'prometheus-client-mmap', '~> 0.9.1'
gem 'raindrops', '~> 0.18'
end
 
Loading
Loading
@@ -410,7 +410,9 @@ group :ed25519 do
end
 
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.83.0', require: 'gitaly'
gem 'gitaly-proto', '~> 0.84.0', require: 'gitaly'
# Locked until https://github.com/google/protobuf/issues/4210 is closed
gem 'google-protobuf', '= 3.5.1'
 
gem 'toml-rb', '~> 0.3.15', require: false
 
Loading
Loading
Loading
Loading
@@ -285,7 +285,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.83.0)
gitaly-proto (0.84.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
Loading
Loading
@@ -340,7 +340,7 @@ GEM
mime-types (~> 3.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
google-protobuf (3.5.1.1)
google-protobuf (3.5.1)
googleapis-common-protos-types (1.0.1)
google-protobuf (~> 3.0)
googleauth (0.5.3)
Loading
Loading
@@ -636,7 +636,7 @@ GEM
parser
unparser
procto (0.0.3)
prometheus-client-mmap (0.7.0.beta44)
prometheus-client-mmap (0.9.1)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
Loading
Loading
@@ -1056,7 +1056,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.83.0)
gitaly-proto (~> 0.84.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)
Loading
Loading
@@ -1066,6 +1066,7 @@ DEPENDENCIES
gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0)
google-api-client (~> 0.13.6)
google-protobuf (= 3.5.1)
gpgme
grape (~> 1.0)
grape-entity (~> 0.6.0)
Loading
Loading
@@ -1131,7 +1132,7 @@ DEPENDENCIES
peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2)
premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.7.0.beta44)
prometheus-client-mmap (~> 0.9.1)
pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1)
Loading
Loading
{"iconCount":189,"spriteSize":85900,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_notfound","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]}
\ No newline at end of file
{"iconCount":191,"spriteSize":86607,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","soft-unwrap","soft-wrap","spam","spinner","staged","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_notfound","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","unstaged","user","users","volume-up","warning","work"]}
\ No newline at end of file
This diff is collapsed.
<svg xmlns="http://www.w3.org/2000/svg" width="142" height="104" viewBox="0 0 142 104"><g fill="none" fill-rule="evenodd"><g transform="translate(112 4)"><path fill="#FFF" d="M8 4a4 4 0 0 0-4 4v14a4 4 0 0 0 4 4h14a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4H8z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M8 4a4 4 0 0 0-4 4v14a4 4 0 0 0 4 4h14a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4H8zm0-4h14a8 8 0 0 1 8 8v14a8 8 0 0 1-8 8H8a8 8 0 0 1-8-8V8a8 8 0 0 1 8-8z"/><rect width="10" height="10" x="10" y="10" fill="#FC6D26" rx="5"/></g><g transform="translate(5 74)"><rect width="30" height="30" fill="#FFF" rx="8"/><path fill="#E1DBF1" fill-rule="nonzero" d="M8 4a4 4 0 0 0-4 4v14a4 4 0 0 0 4 4h14a4 4 0 0 0 4-4V8a4 4 0 0 0-4-4H8zm0-4h14a8 8 0 0 1 8 8v14a8 8 0 0 1-8 8H8a8 8 0 0 1-8-8V8a8 8 0 0 1 8-8z"/><rect width="10" height="10" x="10" y="10" fill="#6B4FBB" rx="5"/></g><path fill="#FFF" d="M6 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6z"/><path fill="#FDC4A8" fill-rule="nonzero" d="M6 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6zm0-4h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6a6 6 0 0 1 6-6z"/><rect width="8" height="8" x="8" y="8" fill="#FC6D26" rx="4"/><g transform="translate(112 77)"><rect width="24" height="24" fill="#FFF" rx="6"/><path fill="#E1DBF1" fill-rule="nonzero" d="M6 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6zm0-4h12a6 6 0 0 1 6 6v12a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6V6a6 6 0 0 1 6-6z"/><rect width="8" height="8" x="8" y="8" fill="#6B4FBB" rx="4"/></g><g transform="translate(46 29)"><rect width="46" height="46" y="2" fill="#E1DBF1" rx="10"/><rect width="46" height="46" fill="#E1DBF1" rx="10"/><path fill="#C3B8E3" fill-rule="nonzero" d="M10 4a6 6 0 0 0-6 6v26a6 6 0 0 0 6 6h26a6 6 0 0 0 6-6V10a6 6 0 0 0-6-6H10zm0-4h26c5.523 0 10 4.477 10 10v26c0 5.523-4.477 10-10 10H10C4.477 46 0 41.523 0 36V10C0 4.477 4.477 0 10 0z"/><rect width="14" height="14" x="16" y="16" fill="#6B4FBB" rx="2"/></g><path fill="#E1DBF1" fill-rule="nonzero" d="M98.413 35.682a2 2 0 1 1-2.826-2.83l2.122-2.12a2 2 0 1 1 2.827 2.83l-2.123 2.12z"/><path fill="#C3B8E3" d="M104.78 29.32a2 2 0 0 1-2.826-2.829l2.122-2.12a2 2 0 0 1 2.827 2.83l-2.122 2.12z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M42.413 89.682a2 2 0 1 1-2.826-2.83l2.122-2.12a2 2 0 1 1 2.827 2.83l-2.123 2.12z"/><path fill="#E1DBF1" d="M48.78 83.32a2 2 0 1 1-2.826-2.829l2.122-2.12a2 2 0 1 1 2.827 2.83l-2.122 2.12z"/><path fill="#E1DBF1" fill-rule="nonzero" d="M27.713 26.531a2 2 0 1 1 2.574-3.062l2.296 1.93a2 2 0 1 1-2.573 3.062l-2.297-1.93z"/><path fill="#C3B8E3" d="M34.604 32.321a2 2 0 1 1 2.573-3.062l2.297 1.93A2 2 0 0 1 36.9 34.25l-2.297-1.93z"/><path fill="#C3B8E3" fill-rule="nonzero" d="M93.74 74.553a2 2 0 0 1 2.52-3.106l2.33 1.891a2 2 0 1 1-2.521 3.106l-2.33-1.891z"/><path fill="#E1DBF1" d="M100.727 80.225a2 2 0 1 1 2.521-3.105l2.33 1.89a2 2 0 1 1-2.522 3.106l-2.33-1.89z"/></g></svg>
\ No newline at end of file
Loading
Loading
@@ -2,7 +2,7 @@
import Sortable from 'vendor/Sortable';
import Vue from 'vue';
import AccessorUtilities from '../../lib/utils/accessor';
import boardList from './board_list';
import boardList from './board_list.vue';
import boardBlankState from './board_blank_state';
import './board_delete';
 
Loading
Loading
<script>
import Sortable from 'vendor/Sortable';
import boardNewIssue from './board_new_issue';
import boardCard from './board_card.vue';
Loading
Loading
@@ -8,6 +9,11 @@ const Store = gl.issueBoards.BoardsStore;
 
export default {
name: 'BoardList',
components: {
boardCard,
boardNewIssue,
loadingIcon,
},
props: {
disabled: {
type: Boolean,
Loading
Loading
@@ -42,46 +48,6 @@ export default {
showIssueForm: false,
};
},
components: {
boardCard,
boardNewIssue,
loadingIcon,
},
methods: {
listHeight() {
return this.$refs.list.getBoundingClientRect().height;
},
scrollHeight() {
return this.$refs.list.scrollHeight;
},
scrollTop() {
return this.$refs.list.scrollTop + this.listHeight();
},
scrollToTop() {
this.$refs.list.scrollTop = 0;
},
loadNextPage() {
const getIssues = this.list.nextPage();
const loadingDone = () => {
this.list.loadingMore = false;
};
if (getIssues) {
this.list.loadingMore = true;
getIssues
.then(loadingDone)
.catch(loadingDone);
}
},
toggleForm() {
this.showIssueForm = !this.showIssueForm;
},
onScroll() {
if (!this.loadingMore && (this.scrollTop() > this.scrollHeight() - this.scrollOffset)) {
this.loadNextPage();
}
},
},
watch: {
filters: {
handler() {
Loading
Loading
@@ -157,51 +123,90 @@ export default {
eventHub.$off(`scroll-board-list-${this.list.id}`, this.scrollToTop);
this.$refs.list.removeEventListener('scroll', this.onScroll);
},
template: `
<div class="board-list-component">
<div
class="board-list-loading text-center"
aria-label="Loading issues"
v-if="loading">
<loading-icon />
</div>
<board-new-issue
:list="list"
v-if="list.type !== 'closed' && showIssueForm"/>
<ul
class="board-list"
v-show="!loading"
ref="list"
:data-board="list.id"
:class="{ 'is-smaller': showIssueForm }">
<board-card
v-for="(issue, index) in issues"
ref="issue"
:index="index"
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:disabled="disabled"
:key="issue.id" />
<li
class="board-list-count text-center"
v-if="showCount"
data-issue-id="-1">
methods: {
listHeight() {
return this.$refs.list.getBoundingClientRect().height;
},
scrollHeight() {
return this.$refs.list.scrollHeight;
},
scrollTop() {
return this.$refs.list.scrollTop + this.listHeight();
},
scrollToTop() {
this.$refs.list.scrollTop = 0;
},
loadNextPage() {
const getIssues = this.list.nextPage();
const loadingDone = () => {
this.list.loadingMore = false;
};
 
<loading-icon
v-show="list.loadingMore"
label="Loading more issues"
/>
if (getIssues) {
this.list.loadingMore = true;
getIssues
.then(loadingDone)
.catch(loadingDone);
}
},
toggleForm() {
this.showIssueForm = !this.showIssueForm;
},
onScroll() {
if (!this.loadingMore && (this.scrollTop() > this.scrollHeight() - this.scrollOffset)) {
this.loadNextPage();
}
},
},
};
</script>
 
<span v-if="list.issues.length === list.issuesSize">
Showing all issues
</span>
<span v-else>
Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
</span>
</li>
</ul>
<template>
<div class="board-list-component">
<div
class="board-list-loading text-center"
aria-label="Loading issues"
v-if="loading">
<loading-icon />
</div>
`,
};
<board-new-issue
:list="list"
v-if="list.type !== 'closed' && showIssueForm"/>
<ul
class="board-list"
v-show="!loading"
ref="list"
:data-board="list.id"
:class="{ 'is-smaller': showIssueForm }">
<board-card
v-for="(issue, index) in issues"
ref="issue"
:index="index"
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:disabled="disabled"
:key="issue.id" />
<li
class="board-list-count text-center"
v-if="showCount"
data-issue-id="-1">
<loading-icon
v-show="list.loadingMore"
label="Loading more issues"
/>
<span
v-if="list.issues.length === list.issuesSize"
>
Showing all issues
</span>
<span
v-else
>
Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
</span>
</li>
</ul>
</div>
</template>
/* eslint-disable func-names, no-new, space-before-function-paren, one-var,
promise/catch-or-return */
import axios from '~/lib/utils/axios_utils';
import _ from 'underscore';
import CreateLabelDropdown from '../../create_label';
 
Loading
Loading
@@ -28,9 +29,9 @@ gl.issueBoards.newListDropdownInit = () => {
 
$this.glDropdown({
data(term, callback) {
$.get($this.attr('data-list-labels-path'))
.then((resp) => {
callback(resp);
axios.get($this.attr('data-list-labels-path'))
.then(({ data }) => {
callback(data);
});
},
renderRow (label) {
Loading
Loading
import _ from 'underscore';
import axios from '../lib/utils/axios_utils';
import { s__ } from '../locale';
import Flash from '../flash';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
import statusCodes from '../lib/utils/http_status';
import VariableList from './ci_variable_list';
function generateErrorBoxContent(errors) {
const errorList = [].concat(errors).map(errorString => `
<li>
${_.escape(errorString)}
</li>
`);
return `
<p>
${s__('CiVariable|Validation failed')}
</p>
<ul>
${errorList.join('')}
</ul>
`;
}
// Used for the variable list on CI/CD projects/groups settings page
export default class AjaxVariableList {
constructor({
container,
saveButton,
errorBox,
formField = 'variables',
saveEndpoint,
}) {
this.container = container;
this.saveButton = saveButton;
this.errorBox = errorBox;
this.saveEndpoint = saveEndpoint;
this.variableList = new VariableList({
container: this.container,
formField,
});
this.bindEvents();
this.variableList.init();
}
bindEvents() {
this.saveButton.addEventListener('click', this.onSaveClicked.bind(this));
}
onSaveClicked() {
const loadingIcon = this.saveButton.querySelector('.js-secret-variables-save-loading-icon');
loadingIcon.classList.toggle('hide', false);
this.errorBox.classList.toggle('hide', true);
// We use this to prevent a user from changing a key before we have a chance
// to match it up in `updateRowsWithPersistedVariables`
this.variableList.toggleEnableRow(false);
return axios.patch(this.saveEndpoint, {
variables_attributes: this.variableList.getAllData(),
}, {
// We want to be able to process the `res.data` from a 400 error response
// and print the validation messages such as duplicate variable keys
validateStatus: status => (
status >= statusCodes.OK &&
status < statusCodes.MULTIPLE_CHOICES
) ||
status === statusCodes.BAD_REQUEST,
})
.then((res) => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
if (res.status === statusCodes.OK && res.data) {
this.updateRowsWithPersistedVariables(res.data.variables);
} else if (res.status === statusCodes.BAD_REQUEST) {
// Validation failed
this.errorBox.innerHTML = generateErrorBoxContent(res.data);
this.errorBox.classList.toggle('hide', false);
}
})
.catch(() => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
Flash(s__('CiVariable|Error occured while saving variables'));
});
}
updateRowsWithPersistedVariables(persistedVariables = []) {
const persistedVariableMap = [].concat(persistedVariables).reduce((variableMap, variable) => ({
...variableMap,
[variable.key]: variable,
}), {});
this.container.querySelectorAll('.js-row').forEach((row) => {
// If we submitted a row that was destroyed, remove it so we don't try
// to destroy it again which would cause a BE error
const destroyInput = row.querySelector('.js-ci-variable-input-destroy');
if (convertPermissionToBoolean(destroyInput.value)) {
row.remove();
// Update the ID input so any future edits and `_destroy` will apply on the BE
} else {
const key = row.querySelector('.js-ci-variable-input-key').value;
const persistedVariable = persistedVariableMap[key];
if (persistedVariable) {
// eslint-disable-next-line no-param-reassign
row.querySelector('.js-ci-variable-input-id').value = persistedVariable.id;
row.setAttribute('data-is-persisted', 'true');
}
}
});
}
}
Loading
Loading
@@ -11,7 +11,7 @@ function createEnvironmentItem(value) {
return {
title: value === '*' ? ALL_ENVIRONMENTS_STRING : value,
id: value,
text: value,
text: value === '*' ? s__('CiVariable|* (All environments)') : value,
};
}
 
Loading
Loading
@@ -39,13 +39,13 @@ export default class VariableList {
},
protected: {
selector: '.js-ci-variable-input-protected',
default: 'true',
default: 'false',
},
environment: {
environment_scope: {
// We can't use a `.js-` class here because
// gl_dropdown replaces the <input> and doesn't copy over the class
// See https://gitlab.com/gitlab-org/gitlab-ce/issues/42458
selector: `input[name="${this.formField}[variables_attributes][][environment]"]`,
selector: `input[name="${this.formField}[variables_attributes][][environment_scope]"]`,
default: '*',
},
_destroy: {
Loading
Loading
@@ -104,12 +104,15 @@ export default class VariableList {
 
setupToggleButtons($row[0]);
 
// Reset the resizable textarea
$row.find(this.inputMap.value.selector).css('height', '');
const $environmentSelect = $row.find('.js-variable-environment-toggle');
if ($environmentSelect.length) {
const createItemDropdown = new CreateItemDropdown({
$dropdown: $environmentSelect,
defaultToggleLabel: ALL_ENVIRONMENTS_STRING,
fieldName: `${this.formField}[variables_attributes][][environment]`,
fieldName: `${this.formField}[variables_attributes][][environment_scope]`,
getData: (term, callback) => callback(this.getEnvironmentValues()),
createNewItemFromValue: createEnvironmentItem,
onSelect: () => {
Loading
Loading
@@ -117,7 +120,7 @@ export default class VariableList {
// so they have the new value we just picked
this.refreshDropdownData();
 
$row.find(this.inputMap.environment.selector).trigger('trigger-change');
$row.find(this.inputMap.environment_scope.selector).trigger('trigger-change');
},
});
 
Loading
Loading
@@ -143,7 +146,8 @@ export default class VariableList {
$row.after($rowClone);
}
 
removeRow($row) {
removeRow(row) {
const $row = $(row);
const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
 
if (isPersisted) {
Loading
Loading
@@ -155,6 +159,10 @@ export default class VariableList {
} else {
$row.remove();
}
// Refresh the other dropdowns in the variable list
// so any value with the variable deleted is gone
this.refreshDropdownData();
}
 
checkIfRowTouched($row) {
Loading
Loading
@@ -165,6 +173,11 @@ export default class VariableList {
});
}
 
toggleEnableRow(isEnabled = true) {
this.$container.find(this.inputMap.key.selector).attr('disabled', !isEnabled);
this.$container.find('.js-row-remove-button').attr('disabled', !isEnabled);
}
getAllData() {
// Ignore the last empty row because we don't want to try persist
// a blank variable and run into validation problems.
Loading
Loading
@@ -185,7 +198,7 @@ export default class VariableList {
}
 
getEnvironmentValues() {
const valueMap = this.$container.find(this.inputMap.environment.selector).toArray()
const valueMap = this.$container.find(this.inputMap.environment_scope.selector).toArray()
.reduce((prevValueMap, envInput) => ({
...prevValueMap,
[envInput.value]: envInput.value,
Loading
Loading
Loading
Loading
@@ -32,13 +32,16 @@ export default class Clusters {
installIngressPath,
installRunnerPath,
installPrometheusPath,
managePrometheusPath,
clusterStatus,
clusterStatusReason,
helpPath,
ingressHelpPath,
} = document.querySelector('.js-edit-cluster-form').dataset;
 
this.store = new ClustersStore();
this.store.setHelpPath(helpPath);
this.store.setHelpPaths(helpPath, ingressHelpPath);
this.store.setManagePrometheusPath(managePrometheusPath);
this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason);
this.service = new ClustersService({
Loading
Loading
@@ -93,6 +96,8 @@ export default class Clusters {
props: {
applications: this.state.applications,
helpPath: this.state.helpPath,
ingressHelpPath: this.state.ingressHelpPath,
managePrometheusPath: this.state.managePrometheusPath,
},
});
},
Loading
Loading
@@ -172,7 +177,7 @@ export default class Clusters {
.map(appId => newApplicationMap[appId].title);
 
if (appTitles.length > 0) {
const text = sprintf(s__('ClusterIntegration|%{appList} was successfully installed on your cluster'), {
const text = sprintf(s__('ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster'), {
appList: appTitles.join(', '),
});
Flash(text, 'notice', this.successApplicationContainer);
Loading
Loading
Loading
Loading
@@ -32,6 +32,10 @@
type: String,
required: false,
},
manageLink: {
type: String,
required: false,
},
description: {
type: String,
required: true,
Loading
Loading
@@ -89,6 +93,12 @@
 
return label;
},
showManageButton() {
return this.manageLink && this.status === APPLICATION_INSTALLED;
},
manageButtonLabel() {
return s__('ClusterIntegration|Manage');
},
hasError() {
return this.status === APPLICATION_ERROR ||
this.requestStatus === REQUEST_FAILURE;
Loading
Loading
@@ -141,9 +151,21 @@
<div v-html="description"></div>
</div>
<div
class="table-section table-button-footer section-15 section-align-top"
class="table-section table-button-footer section-align-top"
:class="{ 'section-20': showManageButton, 'section-15': !showManageButton }"
role="gridcell"
>
<div
v-if="showManageButton"
class="btn-group table-action-buttons"
>
<a
class="btn"
:href="manageLink"
>
{{ manageButtonLabel }}
</a>
</div>
<div class="btn-group table-action-buttons">
<loading-button
class="js-cluster-application-install-button"
Loading
Loading
Loading
Loading
@@ -18,13 +18,24 @@
required: false,
default: '',
},
ingressHelpPath: {
type: String,
required: false,
default: '',
},
managePrometheusPath: {
type: String,
required: false,
default: '',
},
},
computed: {
generalApplicationDescription() {
return sprintf(
_.escape(s__(`ClusterIntegration|Install applications on your cluster.
Read more about %{helpLink}`)),
{
_.escape(s__(
`ClusterIntegration|Install applications on your Kubernetes cluster.
Read more about %{helpLink}`,
)), {
helpLink: `<a href="${this.helpPath}">
${_.escape(s__('ClusterIntegration|installing applications'))}
</a>`,
Loading
Loading
@@ -34,7 +45,7 @@
},
helmTillerDescription() {
return _.escape(s__(
`ClusterIntegration|Helm streamlines installing and managing Kubernets applications.
`ClusterIntegration|Helm streamlines installing and managing Kubernetes applications.
Tiller runs inside of your Kubernetes Cluster, and manages
releases of your charts.`,
));
Loading
Loading
@@ -49,7 +60,7 @@
_.escape(s__(
`ClusterIntegration|%{boldNotice} This will add some extra resources
like a load balancer, which may incur additional costs depending on
the hosting provider Kubernetes is installed on. If you are using GKE,
the hosting provider your Kubernetes cluster is installed on. If you are using GKE,
you can %{pricingLink}.`,
)), {
boldNotice: `<strong>${_.escape(s__('ClusterIntegration|Note:'))}</strong>`,
Loading
Loading
@@ -59,13 +70,28 @@
false,
);
 
const externalIpParagraph = sprintf(
_.escape(s__(
`ClusterIntegration|After installing Ingress, you will need to point your wildcard DNS
at the generated external IP address in order to view your app after it is deployed. %{ingressHelpLink}`,
)), {
ingressHelpLink: `<a href="${this.ingressHelpPath}">
${_.escape(s__('ClusterIntegration|More information'))}
</a>`,
},
false,
);
return `
<p>
${descriptionParagraph}
</p>
<p class="append-bottom-0">
<p>
${extraCostParagraph}
</p>
<p class="settings-message append-bottom-0">
${externalIpParagraph}
</p>
`;
},
gitlabRunnerDescription() {
Loading
Loading
@@ -76,11 +102,12 @@
},
prometheusDescription() {
return sprintf(
_.escape(s__(`ClusterIntegration|Prometheus is an open-source monitoring system
with %{gitlabIntegrationLink} to monitor deployed applications.`)),
{
_.escape(s__(
`ClusterIntegration|Prometheus is an open-source monitoring system
with %{gitlabIntegrationLink} to monitor deployed applications.`,
)), {
gitlabIntegrationLink: `<a href="https://docs.gitlab.com/ce/user/project/integrations/prometheus.html"
target="_blank" rel="noopener noreferrer">
target="_blank" rel="noopener noreferrer">
${_.escape(s__('ClusterIntegration|GitLab Integration'))}</a>`,
},
false,
Loading
Loading
@@ -129,6 +156,7 @@ target="_blank" rel="noopener noreferrer">
id="prometheus"
:title="applications.prometheus.title"
title-link="https://prometheus.io/docs/introduction/overview/"
:manage-link="managePrometheusPath"
:description="prometheusDescription"
:status="applications.prometheus.status"
:status-reason="applications.prometheus.statusReason"
Loading
Loading
Loading
Loading
@@ -4,6 +4,7 @@ export default class ClusterStore {
constructor() {
this.state = {
helpPath: null,
ingressHelpPath: null,
status: null,
statusReason: null,
applications: {
Loading
Loading
@@ -39,8 +40,13 @@ export default class ClusterStore {
};
}
 
setHelpPath(helpPath) {
setHelpPaths(helpPath, ingressHelpPath) {
this.state.helpPath = helpPath;
this.state.ingressHelpPath = ingressHelpPath;
}
setManagePrometheusPath(managePrometheusPath) {
this.state.managePrometheusPath = managePrometheusPath;
}
 
updateStatus(status) {
Loading
Loading
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, object-shorthand, max-len */
import 'vendor/jquery.waitforimages';
 
// Width where images must fits in, for 2-up this gets divided by 2
const availWidth = 900;
Loading
Loading
Loading
Loading
@@ -6,5 +6,5 @@ import 'vendor/jquery.endless-scroll';
import 'vendor/jquery.caret';
import 'vendor/jquery.atwho';
import 'vendor/jquery.scrollTo';
import 'vendor/jquery.waitforimages';
import 'jquery.waitforimages';
import 'select2/select2';
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment