Commit 3cab2087 authored by Mike Greiling's avatar Mike Greiling

Run all ee-specific files through prettier

parent b09b82f1
<script> <script>
import Flash from '~/flash'; import Flash from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import GitlabSlackService from '../services/gitlab_slack_service'; import GitlabSlackService from '../services/gitlab_slack_service';
export default { export default {
props: { props: {
projects: { projects: {
type: Array, type: Array,
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
.catch(() => Flash('Unable to build Slack link.')); .catch(() => Flash('Unable to build Slack link.'));
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -2,7 +2,10 @@ import $ from 'jquery'; ...@@ -2,7 +2,10 @@ import $ from 'jquery';
import _ from 'underscore'; import _ from 'underscore';
export default () => { export default () => {
$('.approver-list').on('click', '.unsaved-approvers.approver .btn-remove', function approverListClickCallback(ev) { $('.approver-list').on(
'click',
'.unsaved-approvers.approver .btn-remove',
function approverListClickCallback(ev) {
const removeElement = $(this).closest('li'); const removeElement = $(this).closest('li');
const approverId = parseInt(removeElement.attr('id').replace('user_', ''), 10); const approverId = parseInt(removeElement.attr('id').replace('user_', ''), 10);
const approverIds = $('input#merge_request_approver_ids'); const approverIds = $('input#merge_request_approver_ids');
...@@ -16,9 +19,13 @@ export default () => { ...@@ -16,9 +19,13 @@ export default () => {
} }
ev.preventDefault(); ev.preventDefault();
}); },
);
$('.approver-list').on('click', '.unsaved-approvers.approver-group .btn-remove', function approverListRemoveClickCallback(ev) { $('.approver-list').on(
'click',
'.unsaved-approvers.approver-group .btn-remove',
function approverListRemoveClickCallback(ev) {
const removeElement = $(this).closest('li'); const removeElement = $(this).closest('li');
const approverGroupId = parseInt(removeElement.attr('id').replace('group_', ''), 10); const approverGroupId = parseInt(removeElement.attr('id').replace('group_', ''), 10);
const approverGroupIds = $('input#merge_request_approver_group_ids'); const approverGroupIds = $('input#merge_request_approver_group_ids');
...@@ -32,18 +39,23 @@ export default () => { ...@@ -32,18 +39,23 @@ export default () => {
} }
ev.preventDefault(); ev.preventDefault();
}); },
);
$('form.merge-request-form').on('submit', function mergeRequestFormSubmitCallback() { $('form.merge-request-form').on('submit', function mergeRequestFormSubmitCallback() {
if ($('input#merge_request_approver_ids').length) { if ($('input#merge_request_approver_ids').length) {
let approverIds = $.map($('li.unsaved-approvers.approver').not('.approver-template'), li => li.id.replace('user_', '')); let approverIds = $.map($('li.unsaved-approvers.approver').not('.approver-template'), li =>
li.id.replace('user_', ''),
);
const approversInput = $(this).find('input#merge_request_approver_ids'); const approversInput = $(this).find('input#merge_request_approver_ids');
approverIds = approverIds.concat(approversInput.val().split(',')); approverIds = approverIds.concat(approversInput.val().split(','));
approversInput.val(_.compact(approverIds).join(',')); approversInput.val(_.compact(approverIds).join(','));
} }
if ($('input#merge_request_approver_group_ids').length) { if ($('input#merge_request_approver_group_ids').length) {
let approverGroupIds = $.map($('li.unsaved-approvers.approver-group'), li => li.id.replace('group_', '')); let approverGroupIds = $.map($('li.unsaved-approvers.approver-group'), li =>
li.id.replace('group_', ''),
);
const approverGroupsInput = $(this).find('input#merge_request_approver_group_ids'); const approverGroupsInput = $(this).find('input#merge_request_approver_group_ids');
approverGroupIds = approverGroupIds.concat(approverGroupsInput.val().split(',')); approverGroupIds = approverGroupIds.concat(approverGroupsInput.val().split(','));
approverGroupsInput.val(_.compact(approverGroupIds).join(',')); approverGroupsInput.val(_.compact(approverGroupIds).join(','));
...@@ -58,9 +70,11 @@ export default () => { ...@@ -58,9 +70,11 @@ export default () => {
return false; return false;
} }
const approverItemHTML = $('.unsaved-approvers.approver-template').clone() const approverItemHTML = $('.unsaved-approvers.approver-template')
.clone()
.removeClass('hide approver-template')[0] .removeClass('hide approver-template')[0]
.outerHTML.replace(/\{approver_name\}/g, username).replace(/\{user_id\}/g, userId); .outerHTML.replace(/\{approver_name\}/g, username)
.replace(/\{user_id\}/g, userId);
$('.no-approvers').remove(); $('.no-approvers').remove();
$('.approver-list').append(approverItemHTML); $('.approver-list').append(approverItemHTML);
......
import BoardsListSelector from './boards_list_selector/index'; import BoardsListSelector from './boards_list_selector/index';
export default function () { export default function() {
const $addListEl = document.querySelector('#js-add-list'); const $addListEl = document.querySelector('#js-add-list');
return new BoardsListSelector({ return new BoardsListSelector({
propsData: { propsData: {
......
...@@ -20,8 +20,8 @@ export default Board.extend({ ...@@ -20,8 +20,8 @@ export default Board.extend({
} }
const { issuesSize, totalWeight } = this.list; const { issuesSize, totalWeight } = this.list;
return sprintf(__( return sprintf(
`${n__('%d issue', '%d issues', issuesSize)} with %{totalWeight} total weight`), __(`${n__('%d issue', '%d issues', issuesSize)} with %{totalWeight} total weight`),
{ {
totalWeight, totalWeight,
}, },
......
...@@ -43,15 +43,17 @@ export default Vue.extend({ ...@@ -43,15 +43,17 @@ export default Vue.extend({
}) })
.catch(() => { .catch(() => {
this.loading = false; this.loading = false;
Flash(sprintf(__('Something went wrong while fetching %{listType} list'), { Flash(
sprintf(__('Something went wrong while fetching %{listType} list'), {
listType: this.listType, listType: this.listType,
})); }),
);
}); });
}, },
filterItems(term, items) { filterItems(term, items) {
const query = term.toLowerCase(); const query = term.toLowerCase();
return items.filter((item) => { return items.filter(item => {
const name = item.name ? item.name.toLowerCase() : item.title.toLowerCase(); const name = item.name ? item.name.toLowerCase() : item.title.toLowerCase();
const foundName = name.indexOf(query) > -1; const foundName = name.indexOf(query) > -1;
......
...@@ -31,7 +31,7 @@ export default { ...@@ -31,7 +31,7 @@ export default {
if (!this.query) return this.items; if (!this.query) return this.items;
const query = this.query.toLowerCase(); const query = this.query.toLowerCase();
return this.items.filter((item) => { return this.items.filter(item => {
const name = item.name ? item.name.toLowerCase() : item.title.toLowerCase(); const name = item.name ? item.name.toLowerCase() : item.title.toLowerCase();
if (this.listType === 'milestones') { if (this.listType === 'milestones') {
......
...@@ -140,8 +140,7 @@ export default Vue.extend({ ...@@ -140,8 +140,7 @@ export default Vue.extend({
handleDropdownTabClick(e) { handleDropdownTabClick(e) {
const $addListEl = $('#js-add-list'); const $addListEl = $('#js-add-list');
$addListEl.data('preventClose', true); $addListEl.data('preventClose', true);
if (e.target.dataset.action === 'tab-assignees' && if (e.target.dataset.action === 'tab-assignees' && !this.hasAssigneesListMounted) {
!this.hasAssigneesListMounted) {
this.assigneeList = AssigneeList(); this.assigneeList = AssigneeList();
this.hasAssigneesListMounted = true; this.hasAssigneesListMounted = true;
} }
......
import BoardsListSelector from './boards_list_selector'; import BoardsListSelector from './boards_list_selector';
export default function () { export default function() {
const $addListEl = document.querySelector('#js-add-list'); const $addListEl = document.querySelector('#js-add-list');
return new BoardsListSelector({ return new BoardsListSelector({
propsData: { propsData: {
......
<script> <script>
import MilestoneSelect from '~/milestone_select'; import MilestoneSelect from '~/milestone_select';
const ANY_MILESTONE = 'Any Milestone'; const ANY_MILESTONE = 'Any Milestone';
const NO_MILESTONE = 'No Milestone'; const NO_MILESTONE = 'No Milestone';
export default { export default {
props: { props: {
board: { board: {
type: Object, type: Object,
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
}; };
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
import WeightSelect from 'ee/weight_select'; import WeightSelect from 'ee/weight_select';
const ANY_WEIGHT = 'Any Weight'; const ANY_WEIGHT = 'Any Weight';
const NO_WEIGHT = 'No Weight'; const NO_WEIGHT = 'No Weight';
export default { export default {
props: { props: {
board: { board: {
type: Object, type: Object,
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
return -1; return -1;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -19,7 +19,8 @@ const d3 = { ...@@ -19,7 +19,8 @@ const d3 = {
axisLeft, axisLeft,
line, line,
transition, transition,
easeLinear }; easeLinear,
};
const margin = { top: 5, right: 65, bottom: 30, left: 50 }; const margin = { top: 5, right: 65, bottom: 30, left: 50 };
// const parseDate = d3.timeFormat('%Y-%m-%d'); // const parseDate = d3.timeFormat('%Y-%m-%d');
const bisectDate = d3.bisector(d => d.date).left; const bisectDate = d3.bisector(d => d.date).left;
...@@ -28,7 +29,9 @@ const tooltipDistance = 15; ...@@ -28,7 +29,9 @@ const tooltipDistance = 15;
export default class BurndownChart { export default class BurndownChart {
constructor({ container, startDate, dueDate }) { constructor({ container, startDate, dueDate }) {
this.canvas = d3.select(container).append('svg') this.canvas = d3
.select(container)
.append('svg')
.attr('height', '100%') .attr('height', '100%')
.attr('width', '100%'); .attr('width', '100%');
...@@ -56,21 +59,35 @@ export default class BurndownChart { ...@@ -56,21 +59,35 @@ export default class BurndownChart {
this.chartLegendIdealKey = this.chartLegendGroup.append('g'); this.chartLegendIdealKey = this.chartLegendGroup.append('g');
this.chartLegendIdealKey.append('line').attr('class', 'ideal line'); this.chartLegendIdealKey.append('line').attr('class', 'ideal line');
this.chartLegendIdealKey.append('text').text('Guideline'); this.chartLegendIdealKey.append('text').text('Guideline');
this.chartLegendIdealKeyBBox = this.chartLegendIdealKey.select('text').node().getBBox(); this.chartLegendIdealKeyBBox = this.chartLegendIdealKey
.select('text')
.node()
.getBBox();
this.chartLegendActualKey = this.chartLegendGroup.append('g'); this.chartLegendActualKey = this.chartLegendGroup.append('g');
this.chartLegendActualKey.append('line').attr('class', 'actual line'); this.chartLegendActualKey.append('line').attr('class', 'actual line');
this.chartLegendActualKey.append('text').text('Progress'); this.chartLegendActualKey.append('text').text('Progress');
this.chartLegendActualKeyBBox = this.chartLegendActualKey.select('text').node().getBBox(); this.chartLegendActualKeyBBox = this.chartLegendActualKey
.select('text')
.node()
.getBBox();
// create tooltips // create tooltips
this.chartFocus = this.chartGroup.append('g').attr('class', 'focus').style('display', 'none'); this.chartFocus = this.chartGroup
.append('g')
.attr('class', 'focus')
.style('display', 'none');
this.chartFocus.append('circle').attr('r', 4); this.chartFocus.append('circle').attr('r', 4);
this.tooltipGroup = this.chartFocus.append('g').attr('class', 'chart-tooltip'); this.tooltipGroup = this.chartFocus.append('g').attr('class', 'chart-tooltip');
this.tooltipGroup.append('rect').attr('rx', 3).attr('ry', 3); this.tooltipGroup
.append('rect')
.attr('rx', 3)
.attr('ry', 3);
this.tooltipGroup.append('text'); this.tooltipGroup.append('text');
this.chartOverlay = this.chartGroup.append('rect').attr('class', 'overlay') this.chartOverlay = this.chartGroup
.append('rect')
.attr('class', 'overlay')
.on('mouseover', () => this.chartFocus.style('display', null)) .on('mouseover', () => this.chartFocus.style('display', null))
.on('mouseout', () => this.chartFocus.style('display', 'none')) .on('mouseout', () => this.chartFocus.style('display', 'none'))
.on('mousemove', () => this.handleMousemove()); .on('mousemove', () => this.handleMousemove());
...@@ -91,28 +108,33 @@ export default class BurndownChart { ...@@ -91,28 +108,33 @@ export default class BurndownChart {
this.yMax = 1; this.yMax = 1;
// create scales // create scales
this.xScale = d3.scaleTime() this.xScale = d3
.scaleTime()
.range([0, this.chartWidth]) .range([0, this.chartWidth])
.domain([this.startDate, this.xMax]); .domain([this.startDate, this.xMax]);
this.yScale = d3.scaleLinear() this.yScale = d3
.scaleLinear()
.range([this.chartHeight, 0]) .range([this.chartHeight, 0])
.domain([0, this.yMax]); .domain([0, this.yMax]);
// create axes // create axes
this.xAxis = d3.axisBottom() this.xAxis = d3
.axisBottom()
.scale(this.xScale) .scale(this.xScale)
.tickFormat(d3.timeFormat('%b %-d')) .tickFormat(d3.timeFormat('%b %-d'))
.tickPadding(6) .tickPadding(6)
.tickSize(4, 0); .tickSize(4, 0);
this.yAxis = d3.axisLeft() this.yAxis = d3
.axisLeft()
.scale(this.yScale) .scale(this.yScale)
.tickPadding(6) .tickPadding(6)
.tickSize(4, 0); .tickSize(4, 0);
// create lines // create lines
this.line = d3.line() this.line = d3
.line()
.x(d => this.xScale(new Date(d.date))) .x(d => this.xScale(new Date(d.date)))
.y(d => this.yScale(d.value)); .y(d => this.yScale(d.value));
...@@ -122,10 +144,12 @@ export default class BurndownChart { ...@@ -122,10 +144,12 @@ export default class BurndownChart {
// set data and force re-render // set data and force re-render
setData(data, { label = 'Remaining', animate } = {}) { setData(data, { label = 'Remaining', animate } = {}) {
this.data = data.map(datum => ({ this.data = data
.map(datum => ({
date: new Date(datum[0]), date: new Date(datum[0]),
value: parseInt(datum[1], 10), value: parseInt(datum[1], 10),
})).sort((a, b) => (a.date - b.date)); }))
.sort((a, b) => a.date - b.date);
// adjust axis domain to correspond with data // adjust axis domain to correspond with data
this.xMax = Math.max(d3.max(this.data, d => d.date) || 0, this.dueDate); this.xMax = Math.max(d3.max(this.data, d => d.date) || 0, this.dueDate);
...@@ -138,7 +162,10 @@ export default class BurndownChart { ...@@ -138,7 +162,10 @@ export default class BurndownChart {
// (this must be done here to prevent layout thrashing) // (this must be done here to prevent layout thrashing)
if (this.label !== label) { if (this.label !== label) {
this.label = label; this.label = label;
this.yAxisLabelBBox = this.yAxisLabelText.text(label).node().getBBox(); this.yAxisLabelBBox = this.yAxisLabelText
.text(label)
.node()
.getBBox();
} }
// set ideal line data // set ideal line data
...@@ -206,15 +233,18 @@ export default class BurndownChart { ...@@ -206,15 +233,18 @@ export default class BurndownChart {
// replace x-axis line with one which continues into the right margin // replace x-axis line with one which continues into the right margin
this.xAxisGroup.select('.domain').remove(); this.xAxisGroup.select('.domain').remove();
this.xAxisGroup.select('.domain-line').attr('x1', 0).attr('x2', this.chartWidth + margin.right); this.xAxisGroup
.select('.domain-line')
.attr('x1', 0)
.attr('x2', this.chartWidth + margin.right);
// update y-axis label // update y-axis label
const axisLabelOffset = (this.yAxisLabelBBox.height / 2) - margin.left; const axisLabelOffset = this.yAxisLabelBBox.height / 2 - margin.left;
const axisLabelPadding = (this.chartHeight - this.yAxisLabelBBox.width - 10) / 2; const axisLabelPadding = (this.chartHeight - this.yAxisLabelBBox.width - 10) / 2;
this.yAxisLabelText this.yAxisLabelText
.attr('y', 0 - margin.left) .attr('y', 0 - margin.left)
.attr('x', 0 - (this.chartHeight / 2)) .attr('x', 0 - this.chartHeight / 2)
.attr('dy', '1em') .attr('dy', '1em')
.style('text-anchor', 'middle') .style('text-anchor', 'middle')
.attr('transform', 'rotate(-90)'); .attr('transform', 'rotate(-90)');
...@@ -240,18 +270,21 @@ export default class BurndownChart { ...@@ -240,18 +270,21 @@ export default class BurndownChart {
const idealKeyOffset = legendPadding; const idealKeyOffset = legendPadding;
const actualKeyOffset = legendPadding + keyHeight + legendSpacing; const actualKeyOffset = legendPadding + keyHeight + legendSpacing;
const legendWidth = (legendPadding * 2) + 24 + keyWidth; const legendWidth = legendPadding * 2 + 24 + keyWidth;
const legendHeight = (legendPadding * 2) + (keyHeight * 2) + legendSpacing; const legendHeight = legendPadding * 2 + keyHeight * 2 + legendSpacing;
const legendOffset = (this.chartWidth + margin.right) - legendWidth - 1; const legendOffset = this.chartWidth + margin.right - legendWidth - 1;
this.chartLegendGroup.select('rect') this.chartLegendGroup
.select('rect')
.attr('width', legendWidth) .attr('width', legendWidth)
.attr('height', legendHeight); .attr('height', legendHeight);
this.chartLegendGroup.selectAll('text') this.chartLegendGroup
.selectAll('text')
.attr('x', 24) .attr('x', 24)
.attr('dy', '1em'); .attr('dy', '1em');
this.chartLegendGroup.selectAll('line') this.chartLegendGroup
.selectAll('line')
.attr('y1', keyHeight / 2) .attr('y1', keyHeight / 2)
.attr('y2', keyHeight / 2) .attr('y2', keyHeight / 2)
.attr('x1', 0) .attr('x1', 0)
...@@ -298,15 +331,19 @@ export default class BurndownChart { ...@@ -298,15 +331,19 @@ export default class BurndownChart {
const x = this.xScale(datum.date); const x = this.xScale(datum.date);
const y = this.yScale(datum.value); const y = this.yScale(datum.value);
const textSize = this.tooltipGroup.select('text').text(tooltip).node().getBBox(); const textSize = this.tooltipGroup
const width = textSize.width + (tooltipPadding.x * 2); .select('text')
const height = textSize.height + (tooltipPadding.y * 2); .text(tooltip)
.node()
.getBBox();
const width = textSize.width + tooltipPadding.x * 2;
const height = textSize.height + tooltipPadding.y * 2;
// calculate bounraries // calculate bounraries
const xMin = 0 - x - margin.left; const xMin = 0 - x - margin.left;
const yMin = 0 - y - margin.top; const yMin = 0 - y - margin.top;
const xMax = (this.chartWidth + margin.right) - x - width; const xMax = this.chartWidth + margin.right - x - width;
const yMax = (this.chartHeight + margin.bottom) - y - height; const yMax = this.chartHeight + margin.bottom - y - height;
// try to fit tooltip above point // try to fit tooltip above point
let xOffset = 0 - Math.floor(width / 2); let xOffset = 0 - Math.floor(width / 2);
...@@ -331,12 +368,14 @@ export default class BurndownChart { ...@@ -331,12 +368,14 @@ export default class BurndownChart {
this.chartFocus.attr('transform', `translate(${x}, ${y})`); this.chartFocus.attr('transform', `translate(${x}, ${y})`);
this.tooltipGroup.attr('transform', `translate(${xOffset}, ${yOffset})`); this.tooltipGroup.attr('transform', `translate(${xOffset}, ${yOffset})`);
this.tooltipGroup.select('text') this.tooltipGroup
.select('text')
.attr('dy', '1em') .attr('dy', '1em')
.attr('x', tooltipPadding.x) .attr('x', tooltipPadding.x)
.attr('y', tooltipPadding.y); .attr('y', tooltipPadding.y);
this.tooltipGroup.select('rect') this.tooltipGroup
.select('rect')
.attr('width', width) .attr('width', width)
.attr('height', height); .attr('height', height);
} }
...@@ -357,7 +396,10 @@ export default class BurndownChart { ...@@ -357,7 +396,10 @@ export default class BurndownChart {
static animateLinePath(path, duration = 1000, cb) { static animateLinePath(path, duration = 1000, cb) {
const lineLength = path.node().getTotalLength(); const lineLength = path.node().getTotalLength();
const linearTransition = d3.transition().duration(duration).ease(d3.easeLinear); const linearTransition = d3
.transition()
.duration(duration)
.ease(d3.easeLinear);
path path
.attr('stroke-dasharray', `${lineLength} ${lineLength}`) .attr('stroke-dasharray', `${lineLength} ${lineLength}`)
.attr('stroke-dashoffset', lineLength) .attr('stroke-dashoffset', lineLength)
......
...@@ -31,7 +31,10 @@ export default () => { ...@@ -31,7 +31,10 @@ export default () => {
const show = $this.data('show'); const show = $this.data('show');
if (currentView !== show) { if (currentView !== show) {
currentView = show; currentView = show;
$this.addClass('active').siblings().removeClass('active'); $this
.addClass('active')
.siblings()
.removeClass('active');
switch (show) { switch (show) {
case 'count': case 'count':
chart.setData(openIssuesCount, { label: 'Open issues', animate: true }); chart.setData(openIssuesCount, { label: 'Open issues', animate: true });
......
<script> <script>
/** /**
* Renders a deploy board. * Renders a deploy board.
* *
* A deploy board is composed by: * A deploy board is composed by:
...@@ -8,13 +8,13 @@ ...@@ -8,13 +8,13 @@
* - Button Actions. * - Button Actions.
* [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png) * [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png)
*/ */
import _ from 'underscore'; import _ from 'underscore';
import { n__ } from '~/locale'; import { n__ } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import deployBoardSvg from 'ee_empty_states/icons/_deploy_board.svg'; import deployBoardSvg from 'ee_empty_states/icons/_deploy_board.svg';
import instanceComponent from './deploy_board_instance_component.vue'; import instanceComponent from './deploy_board_instance_component.vue';
export default { export default {
components: { components: {
instanceComponent, instanceComponent,
}, },
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
return deployBoardSvg; return deployBoardSvg;
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="js-deploy-board deploy-board"> <div class="js-deploy-board deploy-board">
......
<script> <script>
/** /**
* An instance in deploy board is represented by a square in this mockup: * An instance in deploy board is represented by a square in this mockup:
* https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png * https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png
* *
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
* this information in the tooltip and the colors. * this information in the tooltip and the colors.
* Mockup is https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1551#note_26595150 * Mockup is https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1551#note_26595150
*/ */
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
tooltip, tooltip,
}, },
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
return `${this.logsPath}?pod_name=${this.podName}`; return `${this.logsPath}?pod_name=${this.podName}`;
}, },
}, },
}; };
</script> </script>
<template> <template>
<a <a
......
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import timeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import timeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import { stateEvent } from '../../constants'; import { stateEvent } from '../../constants';
export default { export default {
name: 'EpicHeader', name: 'EpicHeader',
directives: { directives: {
tooltip, tooltip,
...@@ -54,7 +54,9 @@ ...@@ -54,7 +54,9 @@
return this.isEpicOpen ? __('Open') : __('Closed'); return this.isEpicOpen ? __('Open') : __('Closed');
}, },
actionButtonClass() { actionButtonClass() {
return `btn btn-grouped js-btn-epic-action qa-close-reopen-epic-button ${this.isEpicOpen ? 'btn-close' : 'btn-open'}`; return `btn btn-grouped js-btn-epic-action qa-close-reopen-epic-button ${
this.isEpicOpen ? 'btn-close' : 'btn-open'
}`;
}, },
actionButtonText() { actionButtonText() {
return this.isEpicOpen ? __('Close epic') : __('Reopen epic'); return this.isEpicOpen ? __('Close epic') : __('Reopen epic');
...@@ -68,7 +70,8 @@ ...@@ -68,7 +70,8 @@
}, },
methods: { methods: {
deleteEpic() { deleteEpic() {
if (window.confirm(s__('Epic will be removed! Are you sure?'))) { // eslint-disable-line no-alert if (window.confirm(s__('Epic will be removed! Are you sure?'))) {
// eslint-disable-line no-alert
this.deleteLoading = true; this.deleteLoading = true;
this.$emit('deleteEpic'); this.$emit('deleteEpic');
} }
...@@ -81,7 +84,7 @@ ...@@ -81,7 +84,7 @@
this.$emit('toggleEpicStatus', this.isEpicOpen ? stateEvent.close : stateEvent.reopen); this.$emit('toggleEpicStatus', this.isEpicOpen ? stateEvent.close : stateEvent.reopen);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -7,7 +7,9 @@ export default class SidebarContext { ...@@ -7,7 +7,9 @@ export default class SidebarContext {
constructor() { constructor() {
const $issuableSidebar = $('.js-issuable-update'); const $issuableSidebar = $('.js-issuable-update');
Mousetrap.bind('l', () => SidebarContext.openSidebarDropdown($issuableSidebar.find('.js-labels-block'))); Mousetrap.bind('l', () =>
SidebarContext.openSidebarDropdown($issuableSidebar.find('.js-labels-block')),
);
$issuableSidebar $issuableSidebar
.off('click', '.js-sidebar-dropdown-toggle') .off('click', '.js-sidebar-dropdown-toggle')
......
<script> <script>
import Flash from '~/flash'; import Flash from '~/flash';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import loadingButton from '~/vue_shared/components/loading_button.vue'; import loadingButton from '~/vue_shared/components/loading_button.vue';
import NewEpicService from '../services/new_epic_service'; import NewEpicService from '../services/new_epic_service';
export default { export default {
name: 'NewEpic', name: 'NewEpic',
components: { components: {
loadingButton, loadingButton,
...@@ -39,7 +39,8 @@ ...@@ -39,7 +39,8 @@
methods: { methods: {
createEpic() { createEpic() {
this.creating = true; this.creating = true;
this.service.createEpic(this.title) this.service
.createEpic(this.title)
.then(({ data }) => { .then(({ data }) => {
visitUrl(data.web_url); visitUrl(data.web_url);
}) })
...@@ -55,7 +56,7 @@ ...@@ -55,7 +56,7 @@
}, 25); }, 25);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -7,12 +7,14 @@ export default () => { ...@@ -7,12 +7,14 @@ export default () => {
if (el) { if (el) {
const props = el.dataset; const props = el.dataset;
new Vue({ // eslint-disable-line no-new new Vue({
// eslint-disable-line no-new
el, el,
components: { components: {
'new-epic-app': NewEpicApp, 'new-epic-app': NewEpicApp,
}, },
render: createElement => createElement('new-epic-app', { render: createElement =>
createElement('new-epic-app', {
props, props,
}), }),
}); });
......
...@@ -119,7 +119,9 @@ export default { ...@@ -119,7 +119,9 @@ export default {
}, },
popoverOptions() { popoverOptions() {
return this.getPopoverConfig({ return this.getPopoverConfig({
title: s__('Epics|These dates affect how your epics appear in the roadmap. Dates from milestones come from the milestones assigned to issues in the epic. You can also set fixed dates or remove them entirely.'), title: s__(
'Epics|These dates affect how your epics appear in the roadmap. Dates from milestones come from the milestones assigned to issues in the epic. You can also set fixed dates or remove them entirely.',
),
content: ` content: `
<a <a
href="${gon.gitlab_url}/help/user/group/epics/index.md#start-date-and-due-date" href="${gon.gitlab_url}/help/user/group/epics/index.md#start-date-and-due-date"
...@@ -304,4 +306,3 @@ export default { ...@@ -304,4 +306,3 @@ export default {
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import Participants from '~/sidebar/components/participants/participants.vue'; import Participants from '~/sidebar/components/participants/participants.vue';
export default { export default {
components: { components: {
Participants, Participants,
}, },
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
this.$emit('toggleCollapse'); this.$emit('toggleCollapse');
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import Subscriptions from '~/sidebar/components/subscriptions/subscriptions.vue'; import Subscriptions from '~/sidebar/components/subscriptions/subscriptions.vue';
export default { export default {
components: { components: {
Subscriptions, Subscriptions,
}, },
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
this.$emit('toggleCollapse'); this.$emit('toggleCollapse');
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { NODE_ACTIONS } from '../constants'; import { NODE_ACTIONS } from '../constants';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
export default { export default {
components: { components: {
Icon, Icon,
}, },
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
eventHub.$emit('repairNode', this.node); eventHub.$emit('repairNode', this.node);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import popover from '~/vue_shared/directives/popover'; import popover from '~/vue_shared/directives/popover';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import StackedProgressBar from '~/vue_shared/components/stacked_progress_bar.vue'; import StackedProgressBar from '~/vue_shared/components/stacked_progress_bar.vue';
import { VALUE_TYPE, CUSTOM_TYPE } from '../constants'; import { VALUE_TYPE, CUSTOM_TYPE } from '../constants';
import GeoNodeSyncSettings from './geo_node_sync_settings.vue'; import GeoNodeSyncSettings from './geo_node_sync_settings.vue';
import GeoNodeEventStatus from './geo_node_event_status.vue'; import GeoNodeEventStatus from './geo_node_event_status.vue';
export default { export default {
components: { components: {
Icon, Icon,
StackedProgressBar, StackedProgressBar,
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
}; };
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
/* eslint-disable vue/no-side-effects-in-computed-properties */ /* eslint-disable vue/no-side-effects-in-computed-properties */
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import NodeDetailsSectionMain from './node_detail_sections/node_details_section_main.vue'; import NodeDetailsSectionMain from './node_detail_sections/node_details_section_main.vue';
import NodeDetailsSectionSync from './node_detail_sections/node_details_section_sync.vue'; import NodeDetailsSectionSync from './node_detail_sections/node_details_section_sync.vue';
import NodeDetailsSectionVerification from './node_detail_sections/node_details_section_verification.vue'; import NodeDetailsSectionVerification from './node_detail_sections/node_details_section_verification.vue';
import NodeDetailsSectionOther from './node_detail_sections/node_details_section_other.vue'; import NodeDetailsSectionOther from './node_detail_sections/node_details_section_other.vue';
export default { export default {
components: { components: {
NodeDetailsSectionMain, NodeDetailsSectionMain,
NodeDetailsSectionSync, NodeDetailsSectionSync,
...@@ -46,15 +46,17 @@ ...@@ -46,15 +46,17 @@
return !this.nodeDetails.healthy; return !this.nodeDetails.healthy;
}, },
hasVersionMismatch() { hasVersionMismatch() {
if (this.nodeDetails.version !== this.nodeDetails.primaryVersion || if (
this.nodeDetails.revision !== this.nodeDetails.primaryRevision) { this.nodeDetails.version !== this.nodeDetails.primaryVersion ||
this.nodeDetails.revision !== this.nodeDetails.primaryRevision
) {
this.errorMessage = s__('GeoNodes|GitLab version does not match the primary node version'); this.errorMessage = s__('GeoNodes|GitLab version does not match the primary node version');
return true; return true;
} }
return false; return false;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { formatDate } from '~/lib/utils/datetime_utility'; import { formatDate } from '~/lib/utils/datetime_utility';
import timeAgoMixin from '~/vue_shared/mixins/timeago'; import timeAgoMixin from '~/vue_shared/mixins/timeago';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
tooltip, tooltip,
}, },
mixins: [ mixins: [timeAgoMixin],
timeAgoMixin,
],
props: { props: {
eventId: { eventId: {
type: Number, type: Number,
...@@ -37,7 +35,7 @@ ...@@ -37,7 +35,7 @@
return this.eventId; return this.eventId;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
components: { components: {
icon, icon,
}, },
...@@ -56,10 +56,12 @@ ...@@ -56,10 +56,12 @@
if (this.nodeDetailsFailed) { if (this.nodeDetailsFailed) {
return ''; return '';
} }
return s__('GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS.'); return s__(
'GeoNodes|You have configured Geo nodes using an insecure HTTP connection. We recommend the use of HTTPS.',
);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import { HEALTH_STATUS_ICON } from '../constants'; import { HEALTH_STATUS_ICON } from '../constants';
export default { export default {
components: { components: {
icon, icon,
}, },
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
return HEALTH_STATUS_ICON[this.status.toLowerCase()]; return HEALTH_STATUS_ICON[this.status.toLowerCase()];
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import { TIME_DIFF } from '../constants'; import { TIME_DIFF } from '../constants';
export default { export default {
directives: { directives: {
tooltip, tooltip,
}, },
...@@ -80,8 +80,7 @@ ...@@ -80,8 +80,7 @@
statusIcon(syncLag) { statusIcon(syncLag) {
if (syncLag <= TIME_DIFF.FIVE_MINS) { if (syncLag <= TIME_DIFF.FIVE_MINS) {
return 'retry'; return 'retry';
} else if (syncLag > TIME_DIFF.FIVE_MINS && } else if (syncLag > TIME_DIFF.FIVE_MINS && syncLag <= TIME_DIFF.HOUR) {
syncLag <= TIME_DIFF.HOUR) {
return 'warning'; return 'warning';
} }
return 'status_failed'; return 'status_failed';
...@@ -92,17 +91,17 @@ ...@@ -92,17 +91,17 @@
return `${timeAgoStr} (${pendingEvents} events)`; return `${timeAgoStr} (${pendingEvents} events)`;
}, },
statusTooltip(lagInSeconds) { statusTooltip(lagInSeconds) {
if (this.eventTimestampEmpty || if (this.eventTimestampEmpty || lagInSeconds <= TIME_DIFF.FIVE_MINS) {
lagInSeconds <= TIME_DIFF.FIVE_MINS) {
return ''; return '';
} else if (lagInSeconds > TIME_DIFF.FIVE_MINS && } else if (lagInSeconds > TIME_DIFF.FIVE_MINS && lagInSeconds <= TIME_DIFF.HOUR) {
lagInSeconds <= TIME_DIFF.HOUR) { return s__(
return s__('GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage.'); 'GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage.',
);
} }
return s__('GeoNodeSyncStatus|Node is failing or broken.'); return s__('GeoNodeSyncStatus|Node is failing or broken.');
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { __ } from '~/locale'; import { __ } from '~/locale';
import GeoNodeHealthStatus from '../geo_node_health_status.vue'; import GeoNodeHealthStatus from '../geo_node_health_status.vue';
import GeoNodeActions from '../geo_node_actions.vue'; import GeoNodeActions from '../geo_node_actions.vue';
export default { export default {
components: { components: {
GeoNodeHealthStatus, GeoNodeHealthStatus,
GeoNodeActions, GeoNodeActions,
...@@ -33,8 +33,7 @@ ...@@ -33,8 +33,7 @@
}, },
computed: { computed: {
nodeVersion() { nodeVersion() {
if (this.nodeDetails.version == null && if (this.nodeDetails.version == null && this.nodeDetails.revision == null) {
this.nodeDetails.revision == null) {
return __('Unknown'); return __('Unknown');
} }
return `${this.nodeDetails.version} (${this.nodeDetails.revision})`; return `${this.nodeDetails.version} (${this.nodeDetails.revision})`;
...@@ -43,7 +42,7 @@ ...@@ -43,7 +42,7 @@
return this.nodeDetails.healthy ? this.nodeDetails.health : this.nodeDetails.healthStatus; return this.nodeDetails.healthy ? this.nodeDetails.health : this.nodeDetails.healthStatus;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import { numberToHumanSize } from '~/lib/utils/number_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils';
import { VALUE_TYPE } from '../../constants'; import { VALUE_TYPE } from '../../constants';
import DetailsSectionMixin from '../../mixins/details_section_mixin'; import DetailsSectionMixin from '../../mixins/details_section_mixin';
import GeoNodeDetailItem from '../geo_node_detail_item.vue'; import GeoNodeDetailItem from '../geo_node_detail_item.vue';
import SectionRevealButton from './section_reveal_button.vue'; import SectionRevealButton from './section_reveal_button.vue';
export default { export default {
valueType: VALUE_TYPE, valueType: VALUE_TYPE,
components: { components: {
SectionRevealButton, SectionRevealButton,
GeoNodeDetailItem, GeoNodeDetailItem,
}, },
mixins: [ mixins: [DetailsSectionMixin],
DetailsSectionMixin,
],
props: { props: {
nodeDetails: { nodeDetails: {
type: Object, type: Object,
...@@ -48,14 +46,12 @@ ...@@ -48,14 +46,12 @@
]; ];
if (this.nodeDetails.replicationSlots.totalCount) { if (this.nodeDetails.replicationSlots.totalCount) {
primaryNodeDetailItems.push( primaryNodeDetailItems.push({
{
itemTitle: s__('GeoNodes|Replication slot WAL'), itemTitle: s__('GeoNodes|Replication slot WAL'),
itemValue: numberToHumanSize(this.nodeDetails.replicationSlotWAL), itemValue: numberToHumanSize(this.nodeDetails.replicationSlotWAL),
itemValueType: VALUE_TYPE.PLAIN, itemValueType: VALUE_TYPE.PLAIN,
cssClass: 'node-detail-value-bold', cssClass: 'node-detail-value-bold',
}, });
);
} }
return primaryNodeDetailItems; return primaryNodeDetailItems;
...@@ -75,11 +71,15 @@ ...@@ -75,11 +71,15 @@
if (this.nodeDetails.storageShardsMatch == null) { if (this.nodeDetails.storageShardsMatch == null) {
return __('Unknown'); return __('Unknown');
} }
return this.nodeDetails.storageShardsMatch ? __('OK') : s__('GeoNodes|Does not match the primary storage configuration'); return this.nodeDetails.storageShardsMatch
? __('OK')
: s__('GeoNodes|Does not match the primary storage configuration');
}, },
storageShardsCssClass() { storageShardsCssClass() {
const cssClass = 'node-detail-value-bold'; const cssClass = 'node-detail-value-bold';
return !this.nodeDetails.storageShardsMatch ? `${cssClass} node-detail-value-error` : cssClass; return !this.nodeDetails.storageShardsMatch
? `${cssClass} node-detail-value-error`
: cssClass;
}, },
}, },
methods: { methods: {
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
this.showSectionItems = toggleState; this.showSectionItems = toggleState;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { VALUE_TYPE, HELP_INFO_URL } from '../../constants'; import { VALUE_TYPE, HELP_INFO_URL } from '../../constants';
import DetailsSectionMixin from '../../mixins/details_section_mixin'; import DetailsSectionMixin from '../../mixins/details_section_mixin';
import GeoNodeDetailItem from '../geo_node_detail_item.vue'; import GeoNodeDetailItem from '../geo_node_detail_item.vue';
import SectionRevealButton from './section_reveal_button.vue'; import SectionRevealButton from './section_reveal_button.vue';
export default { export default {
components: { components: {
GeoNodeDetailItem, GeoNodeDetailItem,
SectionRevealButton, SectionRevealButton,
}, },
mixins: [ mixins: [DetailsSectionMixin],
DetailsSectionMixin,
],
props: { props: {
nodeDetails: { nodeDetails: {
type: Object, type: Object,
...@@ -35,9 +33,9 @@ ...@@ -35,9 +33,9 @@
}, },
computed: { computed: {
nodeDetailItems() { nodeDetailItems() {
return this.nodeTypePrimary ? return this.nodeTypePrimary
this.getPrimaryNodeDetailItems() : ? this.getPrimaryNodeDetailItems()
this.getSecondaryNodeDetailItems(); : this.getSecondaryNodeDetailItems();
}, },
}, },
methods: { methods: {
...@@ -51,7 +49,9 @@ ...@@ -51,7 +49,9 @@
neutraLabel: s__('GeoNodes|Not checksummed'), neutraLabel: s__('GeoNodes|Not checksummed'),
failureLabel: s__('GeoNodes|Failed'), failureLabel: s__('GeoNodes|Failed'),
helpInfo: { helpInfo: {
title: s__('GeoNodes|Repositories checksummed for verification with their counterparts on Secondary nodes'), title: s__(
'GeoNodes|Repositories checksummed for verification with their counterparts on Secondary nodes',
),
url: HELP_INFO_URL, url: HELP_INFO_URL,
urlText: s__('GeoNodes|Learn more about Repository checksum progress'), urlText: s__('GeoNodes|Learn more about Repository checksum progress'),
}, },
...@@ -64,7 +64,9 @@ ...@@ -64,7 +64,9 @@
neutraLabel: s__('GeoNodes|Not checksummed'), neutraLabel: s__('GeoNodes|Not checksummed'),
failureLabel: s__('GeoNodes|Failed'), failureLabel: s__('GeoNodes|Failed'),
helpInfo: { helpInfo: {
title: s__('GeoNodes|Wikis checksummed for verification with their counterparts on Secondary nodes'), title: s__(
'GeoNodes|Wikis checksummed for verification with their counterparts on Secondary nodes',
),
url: HELP_INFO_URL, url: HELP_INFO_URL,
urlText: s__('GeoNodes|Learn more about Wiki checksum progress'), urlText: s__('GeoNodes|Learn more about Wiki checksum progress'),
}, },
...@@ -81,7 +83,9 @@ ...@@ -81,7 +83,9 @@
neutraLabel: s__('GeoNodes|Unverified'), neutraLabel: s__('GeoNodes|Unverified'),
failureLabel: s__('GeoNodes|Failed'), failureLabel: s__('GeoNodes|Failed'),
helpInfo: { helpInfo: {
title: s__('GeoNodes|Repositories verified with their counterparts on the Primary node'), title: s__(
'GeoNodes|Repositories verified with their counterparts on the Primary node',
),
url: HELP_INFO_URL, url: HELP_INFO_URL,
urlText: s__('GeoNodes|Learn more about Repository verification'), urlText: s__('GeoNodes|Learn more about Repository verification'),
}, },
...@@ -105,7 +109,7 @@ ...@@ -105,7 +109,7 @@
this.showSectionItems = toggleState; this.showSectionItems = toggleState;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
export default { export default {
components: { components: {
icon, icon,
}, },
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
this.$emit('toggleButton', this.toggleState); this.$emit('toggleButton', this.toggleState);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -30,4 +30,5 @@ export const TIME_DIFF = { ...@@ -30,4 +30,5 @@ export const TIME_DIFF = {
export const STATUS_DELAY_THRESHOLD_MS = 60000; export const STATUS_DELAY_THRESHOLD_MS = 60000;
export const HELP_INFO_URL = 'https://docs.gitlab.com/ee/administration/geo/disaster_recovery/background_verification.html#repository-verification'; export const HELP_INFO_URL =
'https://docs.gitlab.com/ee/administration/geo/disaster_recovery/background_verification.html#repository-verification';
...@@ -13,9 +13,7 @@ export default { ...@@ -13,9 +13,7 @@ export default {
}, },
statusInfoStaleMessage() { statusInfoStaleMessage() {
return sprintf(s__('GeoNodes|Data is out of date from %{timeago}'), { return sprintf(s__('GeoNodes|Data is out of date from %{timeago}'), {
timeago: this.timeFormated( timeago: this.timeFormated(this.nodeDetails.statusCheckTimestamp),
this.nodeDetails.statusCheckTimestamp,
),
}); });
}, },
}, },
......
...@@ -8,9 +8,7 @@ export default class GeoNodesStore { ...@@ -8,9 +8,7 @@ export default class GeoNodesStore {
} }
setNodes(nodes) { setNodes(nodes) {
this.state.nodes = nodes.map( this.state.nodes = nodes.map(node => GeoNodesStore.formatNode(node));
node => GeoNodesStore.formatNode(node),
);
} }
getNodes() { getNodes() {
......
...@@ -19,7 +19,7 @@ const setupAutoCompleteEpics = ($input, defaultCallbacks) => { ...@@ -19,7 +19,7 @@ const setupAutoCompleteEpics = ($input, defaultCallbacks) => {
callbacks: { callbacks: {
...defaultCallbacks, ...defaultCallbacks,
beforeSave(merges) { beforeSave(merges) {
return $.map(merges, (m) => { return $.map(merges, m => {
if (m.title == null) { if (m.title == null) {
return m; return m;
} }
......
...@@ -11,18 +11,16 @@ export default () => { ...@@ -11,18 +11,16 @@ export default () => {
modal: true, modal: true,
show: false, show: false,
}) })
.on('show.bs.modal', (e) => { .on('show.bs.modal', e => {
const { const { cloneUrlPrimary, cloneUrlSecondary } = $(e.currentTarget).data();
cloneUrlPrimary,
cloneUrlSecondary,
} = $(e.currentTarget).data();
$('#geo-info-1').val( $('#geo-info-1').val(
`git clone ${(cloneUrlSecondary || '<clone url for secondary repository>')}`, `git clone ${cloneUrlSecondary || '<clone url for secondary repository>'}`,
); );
$('#geo-info-2').val( $('#geo-info-2').val(
`git remote set-url --push origin ${(cloneUrlPrimary || '<clone url for primary repository>')}`, `git remote set-url --push origin ${cloneUrlPrimary ||
'<clone url for primary repository>'}`,
); );
}); });
}; };
...@@ -78,11 +78,15 @@ export default class KubernetesPodLogs extends LogOutputBehaviours { ...@@ -78,11 +78,15 @@ export default class KubernetesPodLogs extends LogOutputBehaviours {
this.$podDropdown this.$podDropdown
.find('.dropdown-menu-toggle') .find('.dropdown-menu-toggle')
.html(`<span class="dropdown-toggle-text">${this.podName}</span><i class="fa fa-chevron-down"></i>`); .html(
`<span class="dropdown-toggle-text">${
this.podName
}</span><i class="fa fa-chevron-down"></i>`,
);
$podDropdownMenu.off('click'); $podDropdownMenu.off('click');
$podDropdownMenu.empty(); $podDropdownMenu.empty();
pods.forEach((pod) => { pods.forEach(pod => {
$podDropdownMenu.append(` $podDropdownMenu.append(`
<button class='dropdown-item'> <button class='dropdown-item'>
${_.escape(pod)} ${_.escape(pod)}
......
...@@ -16,7 +16,7 @@ export default function initLDAPGroupsSelect() { ...@@ -16,7 +16,7 @@ export default function initLDAPGroupsSelect() {
id: function(group) { id: function(group) {
return group.cn; return group.cn;
}, },
placeholder: "Search for a LDAP group", placeholder: 'Search for a LDAP group',
minimumInputLength: 1, minimumInputLength: 1,
query: function(query) { query: function(query) {
var provider; var provider;
...@@ -24,7 +24,7 @@ export default function initLDAPGroupsSelect() { ...@@ -24,7 +24,7 @@ export default function initLDAPGroupsSelect() {
return Api.ldap_groups(query.term, provider, function(groups) { return Api.ldap_groups(query.term, provider, function(groups) {
var data; var data;
data = { data = {
results: groups results: groups,
}; };
return query.callback(data); return query.callback(data);
}); });
...@@ -32,18 +32,18 @@ export default function initLDAPGroupsSelect() { ...@@ -32,18 +32,18 @@ export default function initLDAPGroupsSelect() {
initSelection: function(element, callback) { initSelection: function(element, callback) {
var id; var id;
id = $(element).val(); id = $(element).val();
if (id !== "") { if (id !== '') {
return callback({ return callback({
cn: id cn: id,
}); });
} }
}, },
formatResult: ldapGroupResult, formatResult: ldapGroupResult,
formatSelection: groupFormatSelection, formatSelection: groupFormatSelection,
dropdownCssClass: "ajax-groups-dropdown", dropdownCssClass: 'ajax-groups-dropdown',
formatNoMatches: function(nomatch) { formatNoMatches: function(nomatch) {
return "Match not found; try refining your search query."; return 'Match not found; try refining your search query.';
} },
}); });
}); });
return $('#ldap_group_link_provider').on('change', function() { return $('#ldap_group_link_provider').on('change', function() {
......
...@@ -96,7 +96,11 @@ export default class MirrorPull { ...@@ -96,7 +96,11 @@ export default class MirrorPull {
// Make backOff polling to get data // Make backOff polling to get data
backOff((next, stop) => { backOff((next, stop) => {
axios axios
.get(`${projectMirrorSSHEndpoint}?ssh_url=${repositoryUrl}&compare_host_keys=${encodeURIComponent(currentKnownHosts)}`) .get(
`${projectMirrorSSHEndpoint}?ssh_url=${repositoryUrl}&compare_host_keys=${encodeURIComponent(
currentKnownHosts,
)}`,
)
.then(({ data, status }) => { .then(({ data, status }) => {
if (status === 204) { if (status === 204) {
this.backOffRequestCounter += 1; this.backOffRequestCounter += 1;
......
...@@ -97,9 +97,7 @@ export default { ...@@ -97,9 +97,7 @@ export default {
this.isLoading = true; this.isLoading = true;
return Promise.all( return Promise.all(
this.alerts.map(alertPath => this.alerts.map(alertPath =>
this.service this.service.readAlert(alertPath).then(alertData => {
.readAlert(alertPath)
.then(alertData => {
this.$emit('setAlerts', this.customMetricId, { this.$emit('setAlerts', this.customMetricId, {
...this.alertData, ...this.alertData,
[alertPath]: alertData, [alertPath]: alertData,
......
...@@ -26,17 +26,15 @@ export default { ...@@ -26,17 +26,15 @@ export default {
const [xMin, xMax] = this.graphDrawData.xDom; const [xMin, xMax] = this.graphDrawData.xDom;
const [yMin, yMax] = this.graphDrawData.yDom; const [yMin, yMax] = this.graphDrawData.yDom;
const outOfRange = (this.operator === '>' && this.threshold > yMax) || const outOfRange =
(this.operator === '>' && this.threshold > yMax) ||
(this.operator === '<' && this.threshold < yMin); (this.operator === '<' && this.threshold < yMin);
if (outOfRange) { if (outOfRange) {
return []; return [];
} }
return [ return [{ time: xMin, value: this.threshold }, { time: xMax, value: this.threshold }];
{ time: xMin, value: this.threshold },
{ time: xMax, value: this.threshold },
];
}, },
linePath() { linePath() {
if (!this.graphDrawData.lineFunction) { if (!this.graphDrawData.lineFunction) {
......
...@@ -4,38 +4,39 @@ import $ from 'jquery'; ...@@ -4,38 +4,39 @@ import $ from 'jquery';
import Api from '~/api'; import Api from '~/api';
function AdminEmailSelect() { function AdminEmailSelect() {
$('.ajax-admin-email-select').each((function(_this) { $('.ajax-admin-email-select').each(
(function(_this) {
return function(i, select) { return function(i, select) {
var skip_ldap; var skip_ldap;
skip_ldap = $(select).hasClass('skip_ldap'); skip_ldap = $(select).hasClass('skip_ldap');
return $(select).select2({ return $(select).select2({
placeholder: "Select group or project", placeholder: 'Select group or project',
multiple: $(select).hasClass('multiselect'), multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0, minimumInputLength: 0,
query: function(query) { query: function(query) {
const groupsFetch = Api.groups(query.term, {}); const groupsFetch = Api.groups(query.term, {});
const projectsFetch = Api.projects(query.term, { const projectsFetch = Api.projects(query.term, {
order_by: 'id', order_by: 'id',
membership: false membership: false,
}); });
return Promise.all([projectsFetch, groupsFetch]).then(function([projects, groups]) { return Promise.all([projectsFetch, groupsFetch]).then(function([projects, groups]) {
var all, data; var all, data;
all = { all = {
id: "all" id: 'all',
}; };
data = [all].concat(groups, projects); data = [all].concat(groups, projects);
return query.callback({ return query.callback({
results: data results: data,
}); });
}); });
}, },
id: function(object) { id: function(object) {
if (object.path_with_namespace) { if (object.path_with_namespace) {
return "project-" + object.id; return 'project-' + object.id;
} else if (object.path) { } else if (object.path) {
return "group-" + object.id; return 'group-' + object.id;
} else { } else {
return "all"; return 'all';
} }
}, },
formatResult(...args) { formatResult(...args) {
...@@ -44,20 +45,33 @@ function AdminEmailSelect() { ...@@ -44,20 +45,33 @@ function AdminEmailSelect() {
formatSelection(...args) { formatSelection(...args) {
return _this.formatSelection(...args); return _this.formatSelection(...args);
}, },
dropdownCssClass: "ajax-admin-email-dropdown", dropdownCssClass: 'ajax-admin-email-dropdown',
escapeMarkup: function(m) { escapeMarkup: function(m) {
return m; return m;
} },
}); });
}; };
})(this)); })(this),
);
} }
AdminEmailSelect.prototype.formatResult = function(object) { AdminEmailSelect.prototype.formatResult = function(object) {
if (object.path_with_namespace) { if (object.path_with_namespace) {
return "<div class='project-result'> <div class='project-name'>" + object.name + "</div> <div class='project-path'>" + object.path_with_namespace + "</div> </div>"; return (
"<div class='project-result'> <div class='project-name'>" +
object.name +
"</div> <div class='project-path'>" +
object.path_with_namespace +
'</div> </div>'
);
} else if (object.path) { } else if (object.path) {
return "<div class='group-result'> <div class='group-name'>" + object.name + "</div> <div class='group-path'>" + object.path + "</div> </div>"; return (
"<div class='group-result'> <div class='group-name'>" +
object.name +
"</div> <div class='group-path'>" +
object.path +
'</div> </div>'
);
} else { } else {
return "<div class='group-result'> <div class='group-name'>All</div> <div class='group-path'>All groups and projects</div> </div>"; return "<div class='group-result'> <div class='group-name'>All</div> <div class='group-path'>All groups and projects</div> </div>";
} }
...@@ -65,11 +79,11 @@ AdminEmailSelect.prototype.formatResult = function(object) { ...@@ -65,11 +79,11 @@ AdminEmailSelect.prototype.formatResult = function(object) {
AdminEmailSelect.prototype.formatSelection = function(object) { AdminEmailSelect.prototype.formatSelection = function(object) {
if (object.path_with_namespace) { if (object.path_with_namespace) {
return "Project: " + object.name; return 'Project: ' + object.name;
} else if (object.path) { } else if (object.path) {
return "Group: " + object.name; return 'Group: ' + object.name;
} else { } else {
return "All groups and projects"; return 'All groups and projects';
} }
}; };
......
...@@ -24,11 +24,11 @@ export default function geoNodeForm() { ...@@ -24,11 +24,11 @@ export default function geoNodeForm() {
const $syncByNamespaces = $('.js-sync-by-namespace', $container); const $syncByNamespaces = $('.js-sync-by-namespace', $container);
const $syncByShards = $('.js-sync-by-shard', $container); const $syncByShards = $('.js-sync-by-shard', $container);
$primaryCheckbox.on('change', e => $primaryCheckbox.on('change', e => onPrimaryCheckboxChange(e, $namespaces));
onPrimaryCheckboxChange(e, $namespaces));
$selectiveSyncTypeSelect.on('change', e => $selectiveSyncTypeSelect.on('change', e =>
onSelectiveSyncTypeChange(e, $syncByNamespaces, $syncByShards)); onSelectiveSyncTypeChange(e, $syncByNamespaces, $syncByShards),
);
$select2Dropdown.select2({ $select2Dropdown.select2({
placeholder: s__('Geo|Select groups to replicate.'), placeholder: s__('Geo|Select groups to replicate.'),
......
...@@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', () => {
merge_requests_created: [], merge_requests_created: [],
}; };
outputElIds.forEach((id) => { outputElIds.forEach(id => {
data[id].data.forEach((d, index) => { data[id].data.forEach((d, index) => {
formattedData[id].push({ formattedData[id].push({
name: data.labels[index], name: data.labels[index],
......
...@@ -107,8 +107,7 @@ export default class EEMirrorRepos extends MirrorRepos { ...@@ -107,8 +107,7 @@ export default class EEMirrorRepos extends MirrorRepos {
}; };
} }
return super.deleteMirror(event, payload) return super.deleteMirror(event, payload).then(() => {
.then(() => {
if (isPullMirror) this.$mirrorDirectionSelect.removeAttr('disabled'); if (isPullMirror) this.$mirrorDirectionSelect.removeAttr('disabled');
}); });
} }
......
...@@ -4,10 +4,7 @@ export default () => { ...@@ -4,10 +4,7 @@ export default () => {
const dataEl = document.getElementById('js-file-lock'); const dataEl = document.getElementById('js-file-lock');
if (dataEl) { if (dataEl) {
const { const { toggle_path, path } = JSON.parse(dataEl.innerHTML);
toggle_path,
path,
} = JSON.parse(dataEl.innerHTML);
initPathLocks(toggle_path, path); initPathLocks(toggle_path, path);
} }
......
...@@ -4,13 +4,16 @@ import { __ } from '~/locale'; ...@@ -4,13 +4,16 @@ import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
export default function initPathLocks(url, path) { export default function initPathLocks(url, path) {
$('a.path-lock').on('click', (e) => { $('a.path-lock').on('click', e => {
e.preventDefault(); e.preventDefault();
axios.post(url, { axios
.post(url, {
path, path,
}).then(() => { })
.then(() => {
window.location.reload(); window.location.reload();
}).catch(() => flash(__('An error occurred while initializing path locks'))); })
.catch(() => flash(__('An error occurred while initializing path locks')));
}); });
} }
<script> <script>
import ciStatus from '~/vue_shared/components/ci_icon.vue'; import ciStatus from '~/vue_shared/components/ci_icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
tooltip, tooltip,
}, },
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
return `${this.projectName} - ${this.pipelineStatus.label}`; return `${this.projectName} - ${this.pipelineStatus.label}`;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import linkedPipeline from './linked_pipeline.vue'; import linkedPipeline from './linked_pipeline.vue';
export default { export default {
components: { components: {
linkedPipeline, linkedPipeline,
}, },
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
return `graph-position-${this.graphPosition}`; return `graph-position-${this.graphPosition}`;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -46,8 +46,9 @@ const bindEvents = () => { ...@@ -46,8 +46,9 @@ const bindEvents = () => {
const $activeTabProjectName = $('.tab-pane.active #project_name'); const $activeTabProjectName = $('.tab-pane.active #project_name');
const $activeTabProjectPath = $('.tab-pane.active #project_path'); const $activeTabProjectPath = $('.tab-pane.active #project_path');
$activeTabProjectName.focus(); $activeTabProjectName.focus();
$activeTabProjectName $activeTabProjectName.keyup(() =>
.keyup(() => projectNew.onProjectNameChange($activeTabProjectName, $activeTabProjectPath)); projectNew.onProjectNameChange($activeTabProjectName, $activeTabProjectPath),
);
} }
$useCustomTemplateBtn.on('change', chooseTemplate); $useCustomTemplateBtn.on('change', chooseTemplate);
...@@ -60,7 +61,6 @@ const bindEvents = () => { ...@@ -60,7 +61,6 @@ const bindEvents = () => {
}; };
export default () => { export default () => {
const $navElement = $('.nav-link[href="#custom-templates"]'); const $navElement = $('.nav-link[href="#custom-templates"]');
const $tabContent = $('.project-templates-buttons#custom-templates'); const $tabContent = $('.project-templates-buttons#custom-templates');
......
<script> <script>
import Flash from '~/flash'; import Flash from '~/flash';
import serviceDeskSetting from './service_desk_setting.vue'; import serviceDeskSetting from './service_desk_setting.vue';
import ServiceDeskStore from '../stores/service_desk_store'; import ServiceDeskStore from '../stores/service_desk_store';
import ServiceDeskService from '../services/service_desk_service'; import ServiceDeskService from '../services/service_desk_service';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
export default { export default {
name: 'ServiceDeskRoot', name: 'ServiceDeskRoot',
components: { components: {
...@@ -59,18 +59,23 @@ ...@@ -59,18 +59,23 @@
this.flash.innerHTML = ''; this.flash.innerHTML = '';
} }
this.service.fetchIncomingEmail() this.service
.fetchIncomingEmail()
.then(res => res.json()) .then(res => res.json())
.then((data) => { .then(data => {
const email = data.service_desk_address; const email = data.service_desk_address;
if (!email) { if (!email) {
throw new Error('Response didn\'t include `service_desk_address`'); throw new Error("Response didn't include `service_desk_address`");
} }
this.store.setIncomingEmail(email); this.store.setIncomingEmail(email);
}) })
.catch(() => { .catch(() => {
this.flash = new Flash('An error occurred while fetching the Service Desk address.', 'alert', this.$el); this.flash = new Flash(
'An error occurred while fetching the Service Desk address.',
'alert',
this.$el,
);
}); });
}, },
...@@ -81,23 +86,28 @@ ...@@ -81,23 +86,28 @@
this.flash.destroy(); this.flash.destroy();
} }
this.service.toggleServiceDesk(isChecked) this.service
.toggleServiceDesk(isChecked)
.then(res => res.json()) .then(res => res.json())
.then((data) => { .then(data => {
const email = data.service_desk_address; const email = data.service_desk_address;
if (isChecked && !email) { if (isChecked && !email) {
throw new Error('Response didn\'t include `service_desk_address`'); throw new Error("Response didn't include `service_desk_address`");
} }
this.store.setIncomingEmail(email); this.store.setIncomingEmail(email);
}) })
.catch(() => { .catch(() => {
const verb = isChecked ? 'enabling' : 'disabling'; const verb = isChecked ? 'enabling' : 'disabling';
this.flash = new Flash(`An error occurred while ${verb} Service Desk.`, 'alert', this.$el); this.flash = new Flash(
`An error occurred while ${verb} Service Desk.`,
'alert',
this.$el,
);
}); });
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
export default { export default {
name: 'ServiceDeskSetting', name: 'ServiceDeskSetting',
directives: { directives: {
tooltip, tooltip,
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
eventHub.$emit('serviceDeskEnabledCheckboxToggled', isChecked); eventHub.$emit('serviceDeskEnabledCheckboxToggled', isChecked);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -14,9 +14,7 @@ export default () => { ...@@ -14,9 +14,7 @@ export default () => {
data() { data() {
const { dataset } = serviceDeskRootElement; const { dataset } = serviceDeskRootElement;
return { return {
initialIsEnabled: convertPermissionToBoolean( initialIsEnabled: convertPermissionToBoolean(dataset.enabled),
dataset.enabled,
),
endpoint: dataset.endpoint, endpoint: dataset.endpoint,
incomingEmail: dataset.incomingEmail, incomingEmail: dataset.incomingEmail,
}; };
......
class ServiceDeskStore { class ServiceDeskStore {
constructor(initialState = {}) { constructor(initialState = {}) {
this.state = Object.assign({ this.state = Object.assign(
{
incomingEmail: '', incomingEmail: '',
}, initialState); },
initialState,
);
} }
setIncomingEmail(value) { setIncomingEmail(value) {
......
import Stats from 'ee/stats'; import Stats from 'ee/stats';
const bindTrackEvents = (container) => { const bindTrackEvents = container => {
Stats.bindTrackableContainer(container); Stats.bindTrackableContainer(container);
}; };
......
...@@ -11,18 +11,32 @@ export default class EEPrometheusMetrics extends PrometheusMetrics { ...@@ -11,18 +11,32 @@ export default class EEPrometheusMetrics extends PrometheusMetrics {
super(wrapperSelector); super(wrapperSelector);
this.$wrapperCustomMetrics = $(wrapperSelector); this.$wrapperCustomMetrics = $(wrapperSelector);
this.$monitoredCustomMetricsPanel = this.$wrapperCustomMetrics.find('.js-panel-custom-monitored-metrics'); this.$monitoredCustomMetricsPanel = this.$wrapperCustomMetrics.find(
this.$monitoredCustomMetricsCount = this.$monitoredCustomMetricsPanel.find('.js-custom-monitored-count'); '.js-panel-custom-monitored-metrics',
this.$monitoredCustomMetricsLoading = this.$monitoredCustomMetricsPanel.find('.js-loading-custom-metrics'); );
this.$monitoredCustomMetricsEmpty = this.$monitoredCustomMetricsPanel.find('.js-empty-custom-metrics'); this.$monitoredCustomMetricsCount = this.$monitoredCustomMetricsPanel.find(
this.$monitoredCustomMetricsList = this.$monitoredCustomMetricsPanel.find('.js-custom-metrics-list'); '.js-custom-monitored-count',
);
this.$monitoredCustomMetricsLoading = this.$monitoredCustomMetricsPanel.find(
'.js-loading-custom-metrics',
);
this.$monitoredCustomMetricsEmpty = this.$monitoredCustomMetricsPanel.find(
'.js-empty-custom-metrics',
);
this.$monitoredCustomMetricsList = this.$monitoredCustomMetricsPanel.find(
'.js-custom-metrics-list',
);
this.$newCustomMetricButton = this.$monitoredCustomMetricsPanel.find('.js-new-metric-button'); this.$newCustomMetricButton = this.$monitoredCustomMetricsPanel.find('.js-new-metric-button');
this.$flashCustomMetricsContainer = this.$wrapperCustomMetrics.find('.flash-container'); this.$flashCustomMetricsContainer = this.$wrapperCustomMetrics.find('.flash-container');
this.customMetrics = []; this.customMetrics = [];
this.environmentsData = []; this.environmentsData = [];
this.activeCustomMetricsEndpoint = this.$monitoredCustomMetricsPanel.data('active-custom-metrics'); this.activeCustomMetricsEndpoint = this.$monitoredCustomMetricsPanel.data(
this.environmentsDataEndpoint = this.$monitoredCustomMetricsPanel.data('environments-data-endpoint'); 'active-custom-metrics',
);
this.environmentsDataEndpoint = this.$monitoredCustomMetricsPanel.data(
'environments-data-endpoint',
);
} }
showMonitoringCustomMetricsPanelState(stateName) { showMonitoringCustomMetricsPanelState(stateName) {
...@@ -49,20 +63,25 @@ export default class EEPrometheusMetrics extends PrometheusMetrics { ...@@ -49,20 +63,25 @@ export default class EEPrometheusMetrics extends PrometheusMetrics {
} }
populateCustomMetrics() { populateCustomMetrics() {
const sortedMetrics = _(this.customMetrics).chain() const sortedMetrics = _(this.customMetrics)
.chain()
.map(metric => ({ ...metric, group: capitalizeFirstCharacter(metric.group) })) .map(metric => ({ ...metric, group: capitalizeFirstCharacter(metric.group) }))
.sortBy('title') .sortBy('title')
.sortBy('group') .sortBy('group')
.value(); .value();
sortedMetrics.forEach((metric) => { sortedMetrics.forEach(metric => {
this.$monitoredCustomMetricsList.append(EEPrometheusMetrics.customMetricTemplate(metric)); this.$monitoredCustomMetricsList.append(EEPrometheusMetrics.customMetricTemplate(metric));
}); });
this.$monitoredCustomMetricsCount.text(this.customMetrics.length); this.$monitoredCustomMetricsCount.text(this.customMetrics.length);
this.showMonitoringCustomMetricsPanelState(PANEL_STATE.LIST); this.showMonitoringCustomMetricsPanelState(PANEL_STATE.LIST);
if (!this.environmentsData) { if (!this.environmentsData) {
this.showFlashMessage(s__('PrometheusService|These metrics will only be monitored after your first deployment to an environment')); this.showFlashMessage(
s__(
'PrometheusService|These metrics will only be monitored after your first deployment to an environment',
),
);
} }
} }
...@@ -86,7 +105,7 @@ export default class EEPrometheusMetrics extends PrometheusMetrics { ...@@ -86,7 +105,7 @@ export default class EEPrometheusMetrics extends PrometheusMetrics {
this.populateCustomMetrics(customMetrics.data.metrics); this.populateCustomMetrics(customMetrics.data.metrics);
} }
}) })
.catch((customMetricError) => { .catch(customMetricError => {
this.showFlashMessage(customMetricError); this.showFlashMessage(customMetricError);
this.showMonitoringCustomMetricsPanelState(PANEL_STATE.EMPTY); this.showMonitoringCustomMetricsPanelState(PANEL_STATE.EMPTY);
}); });
......
...@@ -17,4 +17,3 @@ export default class ProtectedEnvironmentEditList { ...@@ -17,4 +17,3 @@ export default class ProtectedEnvironmentEditList {
}); });
} }
} }
...@@ -43,8 +43,9 @@ export default { ...@@ -43,8 +43,9 @@ export default {
return `Paste issue link${this.allowAutoComplete ? ' or <#issue id>' : ''}`; return `Paste issue link${this.allowAutoComplete ? ' or <#issue id>' : ''}`;
}, },
isSubmitButtonDisabled() { isSubmitButtonDisabled() {
return (this.inputValue.length === 0 && this.pendingReferences.length === 0) return (
|| this.isSubmitting; (this.inputValue.length === 0 && this.pendingReferences.length === 0) || this.isSubmitting
);
}, },
allowAutoComplete() { allowAutoComplete() {
return Object.keys(this.autoCompleteSources).length > 0; return Object.keys(this.autoCompleteSources).length > 0;
......
...@@ -113,10 +113,10 @@ export default { ...@@ -113,10 +113,10 @@ export default {
if (issueToRemove) { if (issueToRemove) {
RelatedIssuesService.remove(issueToRemove.relation_path) RelatedIssuesService.remove(issueToRemove.relation_path)
.then(res => res.json()) .then(res => res.json())
.then((data) => { .then(data => {
this.store.setRelatedIssues(data.issues); this.store.setRelatedIssues(data.issues);
}) })
.catch((res) => { .catch(res => {
if (res && res.status !== 404) { if (res && res.status !== 404) {
Flash('An error occurred while removing issues.'); Flash('An error occurred while removing issues.');
} }
...@@ -136,9 +136,10 @@ export default { ...@@ -136,9 +136,10 @@ export default {
if (this.state.pendingReferences.length > 0) { if (this.state.pendingReferences.length > 0) {
this.isSubmitting = true; this.isSubmitting = true;
this.service.addRelatedIssues(this.state.pendingReferences) this.service
.addRelatedIssues(this.state.pendingReferences)
.then(res => res.json()) .then(res => res.json())
.then((data) => { .then(data => {
// We could potentially lose some pending issues in the interim here // We could potentially lose some pending issues in the interim here
this.store.setPendingReferences([]); this.store.setPendingReferences([]);
this.store.setRelatedIssues(data.issues); this.store.setRelatedIssues(data.issues);
...@@ -147,9 +148,9 @@ export default { ...@@ -147,9 +148,9 @@ export default {
// Close the form on submission // Close the form on submission
this.isFormVisible = false; this.isFormVisible = false;
}) })
.catch((res) => { .catch(res => {
this.isSubmitting = false; this.isSubmitting = false;
let errorMessage = 'We can\'t find an issue that matches what you are looking for.'; let errorMessage = "We can't find an issue that matches what you are looking for.";
if (res.data && res.data.message) { if (res.data && res.data.message) {
errorMessage = res.data.message; errorMessage = res.data.message;
} }
...@@ -164,9 +165,10 @@ export default { ...@@ -164,9 +165,10 @@ export default {
}, },
fetchRelatedIssues() { fetchRelatedIssues() {
this.isFetching = true; this.isFetching = true;
this.service.fetchRelatedIssues() this.service
.fetchRelatedIssues()
.then(res => res.json()) .then(res => res.json())
.then((issues) => { .then(issues => {
this.store.setRelatedIssues(issues); this.store.setRelatedIssues(issues);
this.isFetching = false; this.isFetching = false;
}) })
...@@ -186,7 +188,7 @@ export default { ...@@ -186,7 +188,7 @@ export default {
move_after_id: afterId, move_after_id: afterId,
}) })
.then(res => res.json()) .then(res => res.json())
.then((res) => { .then(res => {
if (!res.message) { if (!res.message) {
this.store.updateIssueOrder(oldIndex, newIndex); this.store.updateIssueOrder(oldIndex, newIndex);
} }
...@@ -197,15 +199,14 @@ export default { ...@@ -197,15 +199,14 @@ export default {
} }
}, },
onInput(newValue, caretPos) { onInput(newValue, caretPos) {
const rawReferences = newValue const rawReferences = newValue.split(/\s/);
.split(/\s/);
let touchedReference; let touchedReference;
let iteratingPos = 0; let iteratingPos = 0;
const untouchedRawReferences = rawReferences const untouchedRawReferences = rawReferences
.filter((reference) => { .filter(reference => {
let isTouched = false; let isTouched = false;
if (caretPos >= iteratingPos && caretPos <= (iteratingPos + reference.length)) { if (caretPos >= iteratingPos && caretPos <= iteratingPos + reference.length) {
touchedReference = reference; touchedReference = reference;
isTouched = true; isTouched = true;
} }
...@@ -216,22 +217,16 @@ export default { ...@@ -216,22 +217,16 @@ export default {
}) })
.filter(reference => reference.trim().length > 0); .filter(reference => reference.trim().length > 0);
this.store.setPendingReferences( this.store.setPendingReferences(this.state.pendingReferences.concat(untouchedRawReferences));
this.state.pendingReferences.concat(untouchedRawReferences),
);
this.inputValue = `${touchedReference}`; this.inputValue = `${touchedReference}`;
}, },
onBlur(newValue) { onBlur(newValue) {
this.processAllReferences(newValue); this.processAllReferences(newValue);
}, },
processAllReferences(value = '') { processAllReferences(value = '') {
const rawReferences = value const rawReferences = value.split(/\s+/).filter(reference => reference.trim().length > 0);
.split(/\s+/)
.filter(reference => reference.trim().length > 0);
this.store.setPendingReferences( this.store.setPendingReferences(this.state.pendingReferences.concat(rawReferences));
this.state.pendingReferences.concat(rawReferences),
);
this.inputValue = ''; this.inputValue = '';
}, },
}, },
......
...@@ -11,7 +11,8 @@ export default function initRelatedIssues() { ...@@ -11,7 +11,8 @@ export default function initRelatedIssues() {
components: { components: {
relatedIssuesRoot: RelatedIssuesRoot, relatedIssuesRoot: RelatedIssuesRoot,
}, },
render: createElement => createElement('related-issues-root', { render: createElement =>
createElement('related-issues-root', {
props: { props: {
endpoint: relatedIssuesRootElement.dataset.endpoint, endpoint: relatedIssuesRootElement.dataset.endpoint,
canAdmin: convertPermissionToBoolean( canAdmin: convertPermissionToBoolean(
......
...@@ -13,9 +13,12 @@ class RelatedIssuesService { ...@@ -13,9 +13,12 @@ class RelatedIssuesService {
} }
addRelatedIssues(newIssueReferences) { addRelatedIssues(newIssueReferences) {
return this.relatedIssuesResource.save({}, { return this.relatedIssuesResource.save(
{},
{
issue_references: newIssueReferences, issue_references: newIssueReferences,
}); },
);
} }
static saveOrder({ endpoint, move_before_id, move_after_id }) { static saveOrder({ endpoint, move_before_id, move_after_id }) {
......
...@@ -28,10 +28,10 @@ class RelatedIssuesStore { ...@@ -28,10 +28,10 @@ class RelatedIssuesStore {
} }
removePendingRelatedIssue(indexToRemove) { removePendingRelatedIssue(indexToRemove) {
this.state.pendingReferences = this.state.pendingReferences = this.state.pendingReferences.filter(
this.state.pendingReferences.filter((reference, index) => index !== indexToRemove); (reference, index) => index !== indexToRemove,
);
} }
} }
export default RelatedIssuesStore; export default RelatedIssuesStore;
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import Flash from '~/flash'; import Flash from '~/flash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import epicsListEmpty from './epics_list_empty.vue'; import epicsListEmpty from './epics_list_empty.vue';
import roadmapShell from './roadmap_shell.vue'; import roadmapShell from './roadmap_shell.vue';
export default { export default {
components: { components: {
epicsListEmpty, epicsListEmpty,
roadmapShell, roadmapShell,
...@@ -77,9 +77,10 @@ ...@@ -77,9 +77,10 @@
methods: { methods: {
fetchEpics() { fetchEpics() {
this.hasError = false; this.hasError = false;
this.service.getEpics() this.service
.getEpics()
.then(res => res.data) .then(res => res.data)
.then((epics) => { .then(epics => {
this.isLoading = false; this.isLoading = false;
if (epics.length) { if (epics.length) {
this.store.setEpics(epics); this.store.setEpics(epics);
...@@ -115,7 +116,7 @@ ...@@ -115,7 +116,7 @@
}, 200)(); }, 200)();
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import epicItemDetails from './epic_item_details.vue'; import epicItemDetails from './epic_item_details.vue';
import epicItemTimeline from './epic_item_timeline.vue'; import epicItemTimeline from './epic_item_timeline.vue';
export default { export default {
components: { components: {
epicItemDetails, epicItemDetails,
epicItemTimeline, epicItemTimeline,
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
required: true, required: true,
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import { dateInWords } from '~/lib/utils/datetime_utility'; import { dateInWords } from '~/lib/utils/datetime_utility';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
tooltip, tooltip,
}, },
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
return `${startDateInWords} &ndash; ${dateInWords(this.endDate, true)}`; return `${startDateInWords} &ndash; ${dateInWords(this.endDate, true)}`;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -17,11 +17,7 @@ export default { ...@@ -17,11 +17,7 @@ export default {
directives: { directives: {
tooltip, tooltip,
}, },
mixins: [ mixins: [QuartersPresetMixin, MonthsPresetMixin, WeeksPresetMixin],
QuartersPresetMixin,
MonthsPresetMixin,
WeeksPresetMixin,
],
props: { props: {
presetType: { presetType: {
type: String, type: String,
......
<script> <script>
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import SectionMixin from '../mixins/section_mixin'; import SectionMixin from '../mixins/section_mixin';
import epicItem from './epic_item.vue'; import epicItem from './epic_item.vue';
export default { export default {
components: { components: {
epicItem, epicItem,
}, },
mixins: [ mixins: [SectionMixin],
SectionMixin,
],
props: { props: {
presetType: { presetType: {
type: String, type: String,
...@@ -114,14 +112,14 @@ ...@@ -114,14 +112,14 @@
if (approxChildrenHeight < this.shellHeight) { if (approxChildrenHeight < this.shellHeight) {
// reset approximate height and recalculate actual height // reset approximate height and recalculate actual height
approxChildrenHeight = 0; approxChildrenHeight = 0;
children.forEach((child) => { children.forEach(child => {
// accumulate children height // accumulate children height
// compensate for bottom border // compensate for bottom border
approxChildrenHeight += child.$el.clientHeight; approxChildrenHeight += child.$el.clientHeight;
}); });
// set height and show empty row reducing horizontal scrollbar size // set height and show empty row reducing horizontal scrollbar size
this.emptyRowHeight = (this.shellHeight - approxChildrenHeight); this.emptyRowHeight = this.shellHeight - approxChildrenHeight;
this.showEmptyRow = true; this.showEmptyRow = true;
} else { } else {
this.showBottomShadow = true; this.showBottomShadow = true;
...@@ -138,10 +136,10 @@ ...@@ -138,10 +136,10 @@
this.$el.scrollTo(uptoTodayIndicator, 0); this.$el.scrollTo(uptoTodayIndicator, 0);
}, },
handleEpicsListScroll({ scrollTop, clientHeight, scrollHeight }) { handleEpicsListScroll({ scrollTop, clientHeight, scrollHeight }) {
this.showBottomShadow = (Math.ceil(scrollTop) + clientHeight) < scrollHeight; this.showBottomShadow = Math.ceil(scrollTop) + clientHeight < scrollHeight;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { monthInWords } from '~/lib/utils/datetime_utility'; import { monthInWords } from '~/lib/utils/datetime_utility';
import MonthsHeaderSubItem from './months_header_sub_item.vue'; import MonthsHeaderSubItem from './months_header_sub_item.vue';
export default { export default {
components: { components: {
MonthsHeaderSubItem, MonthsHeaderSubItem,
}, },
...@@ -51,8 +51,10 @@ ...@@ -51,8 +51,10 @@
// //
// End result of doing this is; // End result of doing this is;
// 2017 Nov, Dec, 2018 Jan, Feb, Mar // 2017 Nov, Dec, 2018 Jan, Feb, Mar
if (this.timeframeIndex !== 0 && if (
this.timeframe[this.timeframeIndex - 1].getFullYear() === year) { this.timeframeIndex !== 0 &&
this.timeframe[this.timeframeIndex - 1].getFullYear() === year
) {
return month; return month;
} }
...@@ -66,22 +68,20 @@ ...@@ -66,22 +68,20 @@
// Show dark color text only if timeframe item year & month // Show dark color text only if timeframe item year & month
// are greater than current year. // are greater than current year.
if (timeframeYear >= this.currentYear && if (timeframeYear >= this.currentYear && timeframeMonth >= this.currentMonth) {
timeframeMonth >= this.currentMonth) {
itemLabelClass += 'label-dark'; itemLabelClass += 'label-dark';
} }
// Show bold text only if timeframe item year & month // Show bold text only if timeframe item year & month
// is current year & month // is current year & month
if (timeframeYear === this.currentYear && if (timeframeYear === this.currentYear && timeframeMonth === this.currentMonth) {
timeframeMonth === this.currentMonth) {
itemLabelClass += ' label-bold'; itemLabelClass += ' label-bold';
} }
return itemLabelClass; return itemLabelClass;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { getSundays } from '~/lib/utils/datetime_utility'; import { getSundays } from '~/lib/utils/datetime_utility';
import { PRESET_TYPES } from '../../constants'; import { PRESET_TYPES } from '../../constants';
import timelineTodayIndicator from '../timeline_today_indicator.vue'; import timelineTodayIndicator from '../timeline_today_indicator.vue';
export default { export default {
presetType: PRESET_TYPES.MONTHS, presetType: PRESET_TYPES.MONTHS,
components: { components: {
timelineTodayIndicator, timelineTodayIndicator,
...@@ -37,8 +37,10 @@ ...@@ -37,8 +37,10 @@
const timeframeYear = this.timeframeItem.getFullYear(); const timeframeYear = this.timeframeItem.getFullYear();
const timeframeMonth = this.timeframeItem.getMonth(); const timeframeMonth = this.timeframeItem.getMonth();
return this.currentDate.getMonth() === timeframeMonth && return (
this.currentDate.getFullYear() === timeframeYear; this.currentDate.getMonth() === timeframeMonth &&
this.currentDate.getFullYear() === timeframeYear
);
}, },
}, },
methods: { methods: {
...@@ -46,10 +48,12 @@ ...@@ -46,10 +48,12 @@
const daysToClosestWeek = this.currentDate.getDate() - subItem.getDate(); const daysToClosestWeek = this.currentDate.getDate() - subItem.getDate();
// Show dark color text only for upcoming dates // Show dark color text only for upcoming dates
// and current week date // and current week date
if (daysToClosestWeek <= 6 && if (
daysToClosestWeek <= 6 &&
this.currentDate.getDate() >= subItem.getDate() && this.currentDate.getDate() >= subItem.getDate() &&
this.currentDate.getFullYear() === subItem.getFullYear() && this.currentDate.getFullYear() === subItem.getFullYear() &&
this.currentDate.getMonth() === subItem.getMonth()) { this.currentDate.getMonth() === subItem.getMonth()
) {
return 'label-dark label-bold'; return 'label-dark label-bold';
} else if (subItem >= this.currentDate) { } else if (subItem >= this.currentDate) {
return 'label-dark'; return 'label-dark';
...@@ -57,7 +61,7 @@ ...@@ -57,7 +61,7 @@
return ''; return '';
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import QuartersHeaderSubItem from './quarters_header_sub_item.vue'; import QuartersHeaderSubItem from './quarters_header_sub_item.vue';
export default { export default {
components: { components: {
QuartersHeaderSubItem, QuartersHeaderSubItem,
}, },
...@@ -41,8 +41,7 @@ ...@@ -41,8 +41,7 @@
}, },
timelineHeaderLabel() { timelineHeaderLabel() {
const { quarterSequence } = this.timeframeItem; const { quarterSequence } = this.timeframeItem;
if (quarterSequence === 1 || if (quarterSequence === 1 || (this.timeframeIndex === 0 && quarterSequence !== 1)) {
this.timeframeIndex === 0 && quarterSequence !== 1) {
return `${this.timeframeItem.year} Q${quarterSequence}`; return `${this.timeframeItem.year} Q${quarterSequence}`;
} }
...@@ -50,8 +49,7 @@ ...@@ -50,8 +49,7 @@
}, },
timelineHeaderClass() { timelineHeaderClass() {
let headerClass = ''; let headerClass = '';
if (this.currentDate >= this.quarterBeginDate && if (this.currentDate >= this.quarterBeginDate && this.currentDate <= this.quarterEndDate) {
this.currentDate <= this.quarterEndDate) {
headerClass = 'label-dark label-bold'; headerClass = 'label-dark label-bold';
} else if (this.currentDate < this.quarterBeginDate) { } else if (this.currentDate < this.quarterBeginDate) {
headerClass = 'label-dark'; headerClass = 'label-dark';
...@@ -60,7 +58,7 @@ ...@@ -60,7 +58,7 @@
return headerClass; return headerClass;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { monthInWords } from '~/lib/utils/datetime_utility'; import { monthInWords } from '~/lib/utils/datetime_utility';
import { PRESET_TYPES } from '../../constants'; import { PRESET_TYPES } from '../../constants';
import timelineTodayIndicator from '../timeline_today_indicator.vue'; import timelineTodayIndicator from '../timeline_today_indicator.vue';
export default { export default {
presetType: PRESET_TYPES.QUARTERS, presetType: PRESET_TYPES.QUARTERS,
components: { components: {
timelineTodayIndicator, timelineTodayIndicator,
...@@ -31,16 +31,17 @@ ...@@ -31,16 +31,17 @@
return this.timeframeItem.range; return this.timeframeItem.range;
}, },
hasToday() { hasToday() {
return this.currentDate >= this.quarterBeginDate && return this.currentDate >= this.quarterBeginDate && this.currentDate <= this.quarterEndDate;
this.currentDate <= this.quarterEndDate;
}, },
}, },
methods: { methods: {
getSubItemValueClass(subItem) { getSubItemValueClass(subItem) {
let itemValueClass = ''; let itemValueClass = '';
if (this.currentDate.getFullYear() === subItem.getFullYear() && if (
this.currentDate.getMonth() === subItem.getMonth()) { this.currentDate.getFullYear() === subItem.getFullYear() &&
this.currentDate.getMonth() === subItem.getMonth()
) {
itemValueClass = 'label-dark label-bold'; itemValueClass = 'label-dark label-bold';
} else if (this.currentDate < subItem) { } else if (this.currentDate < subItem) {
itemValueClass = 'label-dark'; itemValueClass = 'label-dark';
...@@ -51,7 +52,7 @@ ...@@ -51,7 +52,7 @@
return monthInWords(subItem, true); return monthInWords(subItem, true);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { monthInWords } from '~/lib/utils/datetime_utility'; import { monthInWords } from '~/lib/utils/datetime_utility';
import WeeksHeaderSubItem from './weeks_header_sub_item.vue'; import WeeksHeaderSubItem from './weeks_header_sub_item.vue';
export default { export default {
components: { components: {
WeeksHeaderSubItem, WeeksHeaderSubItem,
}, },
...@@ -45,13 +45,15 @@ ...@@ -45,13 +45,15 @@
}, },
timelineHeaderLabel() { timelineHeaderLabel() {
if (this.timeframeIndex === 0) { if (this.timeframeIndex === 0) {
return `${this.timeframeItem.getFullYear()} ${monthInWords(this.timeframeItem, true)} ${this.timeframeItem.getDate()}`; return `${this.timeframeItem.getFullYear()} ${monthInWords(
this.timeframeItem,
true,
)} ${this.timeframeItem.getDate()}`;
} }
return `${monthInWords(this.timeframeItem, true)} ${this.timeframeItem.getDate()}`; return `${monthInWords(this.timeframeItem, true)} ${this.timeframeItem.getDate()}`;
}, },
timelineHeaderClass() { timelineHeaderClass() {
if (this.currentDate >= this.timeframeItem && if (this.currentDate >= this.timeframeItem && this.currentDate <= this.lastDayOfCurrentWeek) {
this.currentDate <= this.lastDayOfCurrentWeek) {
return 'label-dark label-bold'; return 'label-dark label-bold';
} else if (this.currentDate < this.lastDayOfCurrentWeek) { } else if (this.currentDate < this.lastDayOfCurrentWeek) {
return 'label-dark'; return 'label-dark';
...@@ -59,7 +61,7 @@ ...@@ -59,7 +61,7 @@
return ''; return '';
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -23,7 +23,8 @@ export default { ...@@ -23,7 +23,8 @@ export default {
const headerSubItems = new Array(7) const headerSubItems = new Array(7)
.fill() .fill()
.map( .map(
(val, i) => new Date( (val, i) =>
new Date(
timeframeItem.getFullYear(), timeframeItem.getFullYear(),
timeframeItem.getMonth(), timeframeItem.getMonth(),
timeframeItem.getDate() + i, timeframeItem.getDate() + i,
......
<script> <script>
import bp from '~/breakpoints'; import bp from '~/breakpoints';
import { SCROLL_BAR_SIZE, EPIC_ITEM_HEIGHT, SHELL_MIN_WIDTH } from '../constants'; import { SCROLL_BAR_SIZE, EPIC_ITEM_HEIGHT, SHELL_MIN_WIDTH } from '../constants';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import epicsListSection from './epics_list_section.vue'; import epicsListSection from './epics_list_section.vue';
import roadmapTimelineSection from './roadmap_timeline_section.vue'; import roadmapTimelineSection from './roadmap_timeline_section.vue';
export default { export default {
components: { components: {
epicsListSection, epicsListSection,
roadmapTimelineSection, roadmapTimelineSection,
...@@ -38,9 +38,10 @@ ...@@ -38,9 +38,10 @@
}, },
computed: { computed: {
containerStyles() { containerStyles() {
const width = bp.windowWidth() > SHELL_MIN_WIDTH ? const width =
this.shellWidth + this.getWidthOffset() : bp.windowWidth() > SHELL_MIN_WIDTH
this.shellWidth; ? this.shellWidth + this.getWidthOffset()
: this.shellWidth;
return { return {
width: `${width}px`, width: `${width}px`,
...@@ -58,7 +59,7 @@ ...@@ -58,7 +59,7 @@
// see https://vuejs.org/v2/api/#Vue-nextTick // see https://vuejs.org/v2/api/#Vue-nextTick
if (this.$el.parentElement) { if (this.$el.parentElement) {
this.shellHeight = window.innerHeight - this.$el.offsetTop; this.shellHeight = window.innerHeight - this.$el.offsetTop;
this.noScroll = this.shellHeight > (EPIC_ITEM_HEIGHT * (this.epics.length + 1)); this.noScroll = this.shellHeight > EPIC_ITEM_HEIGHT * (this.epics.length + 1);
this.shellWidth = this.$el.parentElement.clientWidth + this.getWidthOffset(); this.shellWidth = this.$el.parentElement.clientWidth + this.getWidthOffset();
} }
}); });
...@@ -72,7 +73,7 @@ ...@@ -72,7 +73,7 @@
eventHub.$emit('epicsListScrolled', { scrollTop, scrollLeft, clientHeight, scrollHeight }); eventHub.$emit('epicsListScrolled', { scrollTop, scrollLeft, clientHeight, scrollHeight });
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { PRESET_TYPES } from '../constants'; import { PRESET_TYPES } from '../constants';
import SectionMixin from '../mixins/section_mixin'; import SectionMixin from '../mixins/section_mixin';
import QuartersHeaderItem from './preset_quarters/quarters_header_item.vue'; import QuartersHeaderItem from './preset_quarters/quarters_header_item.vue';
import MonthsHeaderItem from './preset_months/months_header_item.vue'; import MonthsHeaderItem from './preset_months/months_header_item.vue';
import WeeksHeaderItem from './preset_weeks/weeks_header_item.vue'; import WeeksHeaderItem from './preset_weeks/weeks_header_item.vue';
export default { export default {
components: { components: {
QuartersHeaderItem, QuartersHeaderItem,
MonthsHeaderItem, MonthsHeaderItem,
WeeksHeaderItem, WeeksHeaderItem,
}, },
mixins: [ mixins: [SectionMixin],
SectionMixin,
],
props: { props: {
presetType: { presetType: {
type: String, type: String,
...@@ -66,10 +64,10 @@ ...@@ -66,10 +64,10 @@
methods: { methods: {
handleEpicsListScroll({ scrollTop }) { handleEpicsListScroll({ scrollTop }) {
// Add class only when epics list is scrolled at 1% the height of header // Add class only when epics list is scrolled at 1% the height of header
this.scrolledHeaderClass = (scrollTop > this.$el.clientHeight / 100) ? 'scroll-top-shadow' : ''; this.scrolledHeaderClass = scrollTop > this.$el.clientHeight / 100 ? 'scroll-top-shadow' : '';
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -48,14 +48,16 @@ export default { ...@@ -48,14 +48,16 @@ export default {
// based on the current presetType // based on the current presetType
if (this.presetType === PRESET_TYPES.QUARTERS) { if (this.presetType === PRESET_TYPES.QUARTERS) {
left = Math.floor( left = Math.floor(
dayInQuarter(this.currentDate, this.timeframeItem.range) / (dayInQuarter(this.currentDate, this.timeframeItem.range) /
totalDaysInQuarter(this.timeframeItem.range) * totalDaysInQuarter(this.timeframeItem.range)) *
100, 100,
); );
} else if (this.presetType === PRESET_TYPES.MONTHS) { } else if (this.presetType === PRESET_TYPES.MONTHS) {
left = Math.floor(this.currentDate.getDate() / totalDaysInMonth(this.timeframeItem) * 100); left = Math.floor(
(this.currentDate.getDate() / totalDaysInMonth(this.timeframeItem)) * 100,
);
} else if (this.presetType === PRESET_TYPES.WEEKS) { } else if (this.presetType === PRESET_TYPES.WEEKS) {
left = Math.floor(((this.currentDate.getDay() + 1) / 7 * 100) - 7); left = Math.floor(((this.currentDate.getDay() + 1) / 7) * 100 - 7);
} }
// We add 20 to height to ensure that // We add 20 to height to ensure that
...@@ -73,7 +75,7 @@ export default { ...@@ -73,7 +75,7 @@ export default {
const rootOffsetLeft = this.$root.$el.offsetLeft; const rootOffsetLeft = this.$root.$el.offsetLeft;
// 3px to compensate size of bubble on top of Indicator // 3px to compensate size of bubble on top of Indicator
this.todayBarReady = (indicatorX - rootOffsetLeft) >= (EPIC_DETAILS_CELL_WIDTH + 3); this.todayBarReady = indicatorX - rootOffsetLeft >= EPIC_DETAILS_CELL_WIDTH + 3;
}, },
}, },
}; };
......
...@@ -25,17 +25,29 @@ export const PRESET_TYPES = { ...@@ -25,17 +25,29 @@ export const PRESET_TYPES = {
export const PRESET_DEFAULTS = { export const PRESET_DEFAULTS = {
QUARTERS: { QUARTERS: {
TIMEFRAME_LENGTH: 18, TIMEFRAME_LENGTH: 18,
emptyStateDefault: s__('GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the quarters view, only epics in the past quarter, current quarter, and next 4 quarters are shown &ndash; from %{startDate} to %{endDate}.'), emptyStateDefault: s__(
emptyStateWithFilters: s__('GroupRoadmap|To widen your search, change or remove filters. In the quarters view, only epics in the past quarter, current quarter, and next 4 quarters are shown &ndash; from %{startDate} to %{endDate}.'), 'GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the quarters view, only epics in the past quarter, current quarter, and next 4 quarters are shown &ndash; from %{startDate} to %{endDate}.',
),
emptyStateWithFilters: s__(
'GroupRoadmap|To widen your search, change or remove filters. In the quarters view, only epics in the past quarter, current quarter, and next 4 quarters are shown &ndash; from %{startDate} to %{endDate}.',
),
}, },
MONTHS: { MONTHS: {
TIMEFRAME_LENGTH: 7, TIMEFRAME_LENGTH: 7,
emptyStateDefault: s__('GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the months view, only epics in the past month, current month, and next 5 months are shown &ndash; from %{startDate} to %{endDate}.'), emptyStateDefault: s__(
emptyStateWithFilters: s__('GroupRoadmap|To widen your search, change or remove filters. In the months view, only epics in the past month, current month, and next 5 months are shown &ndash; from %{startDate} to %{endDate}.'), 'GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the months view, only epics in the past month, current month, and next 5 months are shown &ndash; from %{startDate} to %{endDate}.',
),
emptyStateWithFilters: s__(
'GroupRoadmap|To widen your search, change or remove filters. In the months view, only epics in the past month, current month, and next 5 months are shown &ndash; from %{startDate} to %{endDate}.',
),
}, },
WEEKS: { WEEKS: {
TIMEFRAME_LENGTH: 42, TIMEFRAME_LENGTH: 42,
emptyStateDefault: s__('GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the weeks view, only epics in the past week, current week, and next 4 weeks are shown &ndash; from %{startDate} to %{endDate}.'), emptyStateDefault: s__(
emptyStateWithFilters: s__('GroupRoadmap|To widen your search, change or remove filters. In the weeks view, only epics in the past week, current week, and next 4 weeks are shown &ndash; from %{startDate} to %{endDate}.'), 'GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the weeks view, only epics in the past week, current week, and next 4 weeks are shown &ndash; from %{startDate} to %{endDate}.',
),
emptyStateWithFilters: s__(
'GroupRoadmap|To widen your search, change or remove filters. In the weeks view, only epics in the past week, current week, and next 4 weeks are shown &ndash; from %{startDate} to %{endDate}.',
),
}, },
}; };
...@@ -73,7 +73,7 @@ export default { ...@@ -73,7 +73,7 @@ export default {
} }
// Calculate proportional offset based on startDate and total days in // Calculate proportional offset based on startDate and total days in
// current month. // current month.
return `left: ${startDate / daysInMonth * 100}%;`; return `left: ${(startDate / daysInMonth) * 100}%;`;
}, },
/** /**
* This method is externally only called when current timeframe cell has timeline * This method is externally only called when current timeframe cell has timeline
......
...@@ -65,7 +65,7 @@ export default { ...@@ -65,7 +65,7 @@ export default {
return `right: ${TIMELINE_END_OFFSET_HALF}px;`; return `right: ${TIMELINE_END_OFFSET_HALF}px;`;
} }
return `left: ${startDay / daysInQuarter * 100}%;`; return `left: ${(startDay / daysInQuarter) * 100}%;`;
}, },
/** /**
* This method is externally only called when current timeframe cell has timeline * This method is externally only called when current timeframe cell has timeline
......
...@@ -23,7 +23,7 @@ export default { ...@@ -23,7 +23,7 @@ export default {
return Math.max(width, TIMELINE_CELL_MIN_WIDTH); return Math.max(width, TIMELINE_CELL_MIN_WIDTH);
}, },
sectionContainerStyles() { sectionContainerStyles() {
const width = EPIC_DETAILS_CELL_WIDTH + (this.sectionItemWidth * this.timeframe.length); const width = EPIC_DETAILS_CELL_WIDTH + this.sectionItemWidth * this.timeframe.length;
return { return {
width: `${width}px`, width: `${width}px`,
}; };
......
...@@ -43,7 +43,7 @@ export default { ...@@ -43,7 +43,7 @@ export default {
*/ */
getTimelineBarEndOffsetHalfForWeek() { getTimelineBarEndOffsetHalfForWeek() {
const dayWidth = this.getCellWidth() / 7; const dayWidth = this.getCellWidth() / 7;
return TIMELINE_END_OFFSET_HALF + (dayWidth * 0.5); return TIMELINE_END_OFFSET_HALF + dayWidth * 0.5;
}, },
/** /**
* In case startDate for any epic is undefined or is out of range * In case startDate for any epic is undefined or is out of range
...@@ -82,7 +82,7 @@ export default { ...@@ -82,7 +82,7 @@ export default {
return `right: ${TIMELINE_END_OFFSET_HALF}px;`; return `right: ${TIMELINE_END_OFFSET_HALF}px;`;
} }
return `left: ${(startDate * dayWidth) - (dayWidth / 2)}px;`; return `left: ${startDate * dayWidth - dayWidth / 2}px;`;
}, },
/** /**
* This method is externally only called when current timeframe cell has timeline * This method is externally only called when current timeframe cell has timeline
......
...@@ -4,8 +4,9 @@ import vulnerabilities from './modules/vulnerabilities/index'; ...@@ -4,8 +4,9 @@ import vulnerabilities from './modules/vulnerabilities/index';
Vue.use(Vuex); Vue.use(Vuex);
export default () => new Vuex.Store({ export default () =>
new Vuex.Store({
modules: { modules: {
vulnerabilities, vulnerabilities,
}, },
}); });
<script> <script>
import { __ } from '~/locale'; import { __ } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import { spriteIcon } from '~/lib/utils/common_utils'; import { spriteIcon } from '~/lib/utils/common_utils';
import Store from '../stores/sidebar_store'; import Store from '../stores/sidebar_store';
export default { export default {
name: 'SidebarItemEpic', name: 'SidebarItemEpic',
directives: { directives: {
tooltip, tooltip,
...@@ -41,14 +41,18 @@ ...@@ -41,14 +41,18 @@
if (this.store.epic.human_readable_end_date || this.store.epic.human_readable_timestamp) { if (this.store.epic.human_readable_end_date || this.store.epic.human_readable_timestamp) {
tooltipTitle += '<br />'; tooltipTitle += '<br />';
tooltipTitle += this.store.epic.human_readable_end_date ? `${this.store.epic.human_readable_end_date} ` : ''; tooltipTitle += this.store.epic.human_readable_end_date
tooltipTitle += this.store.epic.human_readable_timestamp ? `(${this.store.epic.human_readable_timestamp})` : ''; ? `${this.store.epic.human_readable_end_date} `
: '';
tooltipTitle += this.store.epic.human_readable_timestamp
? `(${this.store.epic.human_readable_timestamp})`
: '';
} }
return tooltipTitle; return tooltipTitle;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -14,7 +14,8 @@ function mountWeightComponent(mediator) { ...@@ -14,7 +14,8 @@ function mountWeightComponent(mediator) {
components: { components: {
sidebarWeight, sidebarWeight,
}, },
render: createElement => createElement('sidebar-weight', { render: createElement =>
createElement('sidebar-weight', {
props: { props: {
mediator, mediator,
}, },
......
...@@ -15,13 +15,14 @@ export default class SidebarMediator extends CESidebarMediator { ...@@ -15,13 +15,14 @@ export default class SidebarMediator extends CESidebarMediator {
updateWeight(newWeight) { updateWeight(newWeight) {
this.store.setLoadingState('weight', true); this.store.setLoadingState('weight', true);
return this.service.update('issue[weight]', newWeight) return this.service
.update('issue[weight]', newWeight)
.then(res => res.json()) .then(res => res.json())
.then((data) => { .then(data => {
this.store.setWeight(data.weight); this.store.setWeight(data.weight);
this.store.setLoadingState('weight', false); this.store.setLoadingState('weight', false);
}) })
.catch((err) => { .catch(err => {
this.store.setLoadingState('weight', false); this.store.setLoadingState('weight', false);
throw err; throw err;
}); });
......
...@@ -2,7 +2,11 @@ import $ from 'jquery'; ...@@ -2,7 +2,11 @@ import $ from 'jquery';
const snowPlowEnabled = () => typeof window.snowplow === 'function'; const snowPlowEnabled = () => typeof window.snowplow === 'function';
const trackEvent = (category, eventName, additionalData = { label: '', property: '', value: '' }) => { const trackEvent = (
category,
eventName,
additionalData = { label: '', property: '', value: '' },
) => {
if (!snowPlowEnabled()) { if (!snowPlowEnabled()) {
return; return;
} }
...@@ -14,14 +18,7 @@ const trackEvent = (category, eventName, additionalData = { label: '', property: ...@@ -14,14 +18,7 @@ const trackEvent = (category, eventName, additionalData = { label: '', property:
const { label, property, value } = additionalData; const { label, property, value } = additionalData;
try { try {
window.snowplow( window.snowplow('trackStructEvent', category, eventName, label, property, value);
'trackStructEvent',
category,
eventName,
label,
property,
value,
);
} catch (e) { } catch (e) {
// do nothing // do nothing
} }
...@@ -32,7 +29,7 @@ const bindTrackableContainer = (container = '', category = document.body.dataset ...@@ -32,7 +29,7 @@ const bindTrackableContainer = (container = '', category = document.body.dataset
return; return;
} }
const clickHandler = (e) => { const clickHandler = e => {
const target = e.currentTarget; const target = e.currentTarget;
const label = target.getAttribute('data-track-label'); const label = target.getAttribute('data-track-label');
const property = target.getAttribute('data-track-property') || ''; const property = target.getAttribute('data-track-property') || '';
...@@ -45,7 +42,10 @@ const bindTrackableContainer = (container = '', category = document.body.dataset ...@@ -45,7 +42,10 @@ const bindTrackableContainer = (container = '', category = document.body.dataset
} }
// overrides value if data-track_value is set // overrides value if data-track_value is set
if (typeof target.getAttribute('data-track-value') !== 'undefined' && target.getAttribute('data-track-value') !== null) { if (
typeof target.getAttribute('data-track-value') !== 'undefined' &&
target.getAttribute('data-track-value') !== null
) {
value = target.getAttribute('data-track-value'); value = target.getAttribute('data-track-value');
} }
...@@ -54,12 +54,12 @@ const bindTrackableContainer = (container = '', category = document.body.dataset ...@@ -54,12 +54,12 @@ const bindTrackableContainer = (container = '', category = document.body.dataset
const trackableElements = document.querySelectorAll(`${container} [data-track-label]`); const trackableElements = document.querySelectorAll(`${container} [data-track-label]`);
trackableElements.forEach(element => { trackableElements.forEach(element => {
element.addEventListener('click', (e) => clickHandler(e)); element.addEventListener('click', e => clickHandler(e));
}); });
// jquery required for select2 events // jquery required for select2 events
// see: https://github.com/select2/select2/issues/4686#issuecomment-264747428 // see: https://github.com/select2/select2/issues/4686#issuecomment-264747428
$(`${container} .select2[data-track-label]`).on('click', (e) => clickHandler(e)); $(`${container} .select2[data-track-label]`).on('click', e => clickHandler(e));
}; };
export default { export default {
......
...@@ -71,9 +71,9 @@ export default { ...@@ -71,9 +71,9 @@ export default {
} }
if (this.approvalsLeft === 0) { if (this.approvalsLeft === 0) {
return this.userCanApprove ? return this.userCanApprove
s__('mrWidget|Merge request approved; you can approve additionally') : ? s__('mrWidget|Merge request approved; you can approve additionally')
s__('mrWidget|Merge request approved'); : s__('mrWidget|Merge request approved');
} }
if (this.suggestedApprovers.length >= 1) { if (this.suggestedApprovers.length >= 1) {
......
<script> <script>
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import ciStatus from '~/vue_shared/components/ci_icon.vue'; import ciStatus from '~/vue_shared/components/ci_icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
tooltip, tooltip,
}, },
...@@ -48,9 +48,9 @@ ...@@ -48,9 +48,9 @@
return this.linkedPipelines.length; return this.linkedPipelines.length;
}, },
linkedPipelinesTrimmed() { linkedPipelinesTrimmed() {
return (this.totalPipelineCount > this.maxRenderedPipelines) ? return this.totalPipelineCount > this.maxRenderedPipelines
this.linkedPipelines.slice(0, this.maxRenderedPipelines) : ? this.linkedPipelines.slice(0, this.maxRenderedPipelines)
this.linkedPipelines; : this.linkedPipelines;
}, },
shouldRenderCounter() { shouldRenderCounter() {
return this.isDownstream && this.linkedPipelines.length > this.maxRenderedPipelines; return this.isDownstream && this.linkedPipelines.length > this.maxRenderedPipelines;
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
return `ci-status-icon-${group}`; return `ci-status-icon-${group}`;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -9,9 +9,7 @@ export const licenseReport = state => ...@@ -9,9 +9,7 @@ export const licenseReport = state =>
export const licenseSummaryText = (state, getters) => { export const licenseSummaryText = (state, getters) => {
const hasReportItems = getters.licenseReport && getters.licenseReport.length; const hasReportItems = getters.licenseReport && getters.licenseReport.length;
const baseReportHasLicenses = const baseReportHasLicenses =
state.baseReport state.baseReport && state.baseReport.licenses && state.baseReport.licenses.length;
&& state.baseReport.licenses
&& state.baseReport.licenses.length;
if (getters.isLoading) { if (getters.isLoading) {
return sprintf(s__('ciReport|Loading %{reportName} report'), { return sprintf(s__('ciReport|Loading %{reportName} report'), {
......
import { n__, sprintf } from '~/locale'; import { n__, sprintf } from '~/locale';
import { import { STATUS_FAILED, STATUS_NEUTRAL, STATUS_SUCCESS } from '~/reports/constants';
STATUS_FAILED,
STATUS_NEUTRAL,
STATUS_SUCCESS,
} from '~/reports/constants';
import { LICENSE_APPROVAL_STATUS } from 'ee/vue_shared/license_management/constants'; import { LICENSE_APPROVAL_STATUS } from 'ee/vue_shared/license_management/constants';
/** /**
......
import { import { LOADING, ERROR, SUCCESS } from '../store/constants';
LOADING,
ERROR,
SUCCESS,
} from '../store/constants';
export default { export default {
methods: { methods: {
......
...@@ -4,7 +4,9 @@ export default { ...@@ -4,7 +4,9 @@ export default {
computed: { computed: {
sastPopover() { sastPopover() {
return { return {
title: s__('ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code.'), title: s__(
'ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code.',
),
content: sprintf( content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}'), s__('ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}'),
{ {
...@@ -17,7 +19,9 @@ export default { ...@@ -17,7 +19,9 @@ export default {
}, },
sastContainerPopover() { sastContainerPopover() {
return { return {
title: s__('ciReport|Container scanning detects known vulnerabilities in your docker images.'), title: s__(
'ciReport|Container scanning detects known vulnerabilities in your docker images.',
),
content: sprintf( content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about Container Scanning %{linkEndTag}'), s__('ciReport|%{linkStartTag}Learn more about Container Scanning %{linkEndTag}'),
{ {
...@@ -30,7 +34,9 @@ export default { ...@@ -30,7 +34,9 @@ export default {
}, },
dastPopover() { dastPopover() {
return { return {
title: s__('ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application.'), title: s__(
'ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application.',
),
content: sprintf( content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about DAST %{linkEndTag}'), s__('ciReport|%{linkStartTag}Learn more about DAST %{linkEndTag}'),
{ {
...@@ -43,7 +49,9 @@ export default { ...@@ -43,7 +49,9 @@ export default {
}, },
dependencyScanningPopover() { dependencyScanningPopover() {
return { return {
title: s__('ciReport|Dependency Scanning detects known vulnerabilities in your source code\'s dependencies.'), title: s__(
"ciReport|Dependency Scanning detects known vulnerabilities in your source code's dependencies.",
),
content: sprintf( content: sprintf(
s__('ciReport|%{linkStartTag}Learn more about Dependency Scanning %{linkEndTag}'), s__('ciReport|%{linkStartTag}Learn more about Dependency Scanning %{linkEndTag}'),
{ {
......
...@@ -7,9 +7,10 @@ import state from './state'; ...@@ -7,9 +7,10 @@ import state from './state';
Vue.use(Vuex); Vue.use(Vuex);
export default () => new Vuex.Store({ export default () =>
new Vuex.Store({
actions, actions,
getters, getters,
mutations, mutations,
state: state(), state: state(),
}); });
...@@ -230,10 +230,16 @@ export default { ...@@ -230,10 +230,16 @@ export default {
[types.RECEIVE_DEPENDENCY_SCANNING_REPORTS](state, reports) { [types.RECEIVE_DEPENDENCY_SCANNING_REPORTS](state, reports) {
if (reports.base && reports.head) { if (reports.base && reports.head) {
const filterKey = 'cve'; const filterKey = 'cve';
const parsedHead = parseDependencyScanningIssues(reports.head, reports.enrichData, const parsedHead = parseDependencyScanningIssues(
state.blobPath.head); reports.head,
const parsedBase = parseDependencyScanningIssues(reports.base, reports.enrichData, reports.enrichData,
state.blobPath.base); state.blobPath.head,
);
const parsedBase = parseDependencyScanningIssues(
reports.base,
reports.enrichData,
state.blobPath.base,
);
const newIssues = filterByKey(parsedHead, parsedBase, filterKey); const newIssues = filterByKey(parsedHead, parsedBase, filterKey);
const resolvedIssues = filterByKey(parsedBase, parsedHead, filterKey); const resolvedIssues = filterByKey(parsedBase, parsedHead, filterKey);
...@@ -250,8 +256,11 @@ export default { ...@@ -250,8 +256,11 @@ export default {
} }
if (reports.head && !reports.base) { if (reports.head && !reports.base) {
const newIssues = parseDependencyScanningIssues(reports.head, reports.enrichData, const newIssues = parseDependencyScanningIssues(
state.blobPath.head); reports.head,
reports.enrichData,
state.blobPath.head,
);
Vue.set(state.dependencyScanning, 'newIssues', newIssues); Vue.set(state.dependencyScanning, 'newIssues', newIssues);
Vue.set(state.dependencyScanning, 'isLoading', false); Vue.set(state.dependencyScanning, 'isLoading', false);
......
...@@ -18,9 +18,9 @@ export const findIssueIndex = (issues, issue) => ...@@ -18,9 +18,9 @@ export const findIssueIndex = (issues, issue) =>
* @param {Array} feedback * @param {Array} feedback
*/ */
function enrichVulnerabilityWithfeedback(vulnerability, feedback = []) { function enrichVulnerabilityWithfeedback(vulnerability, feedback = []) {
return feedback.filter( return feedback
fb => fb.project_fingerprint === vulnerability.project_fingerprint, .filter(fb => fb.project_fingerprint === vulnerability.project_fingerprint)
).reduce((vuln, fb) => { .reduce((vuln, fb) => {
if (fb.feedback_type === 'dismissal') { if (fb.feedback_type === 'dismissal') {
return { return {
...vuln, ...vuln,
...@@ -155,24 +155,30 @@ export const parseSastContainer = (issues = [], feedback = []) => ...@@ -155,24 +155,30 @@ export const parseSastContainer = (issues = [], feedback = []) =>
const parsed = { const parsed = {
...issue, ...issue,
category: 'container_scanning', category: 'container_scanning',
project_fingerprint: sha1(`${issue.namespace}:${issue.vulnerability}:${issue.featurename}:${issue.featureversion}`), project_fingerprint: sha1(
`${issue.namespace}:${issue.vulnerability}:${issue.featurename}:${issue.featureversion}`,
),
title: issue.vulnerability, title: issue.vulnerability,
description: !_.isEmpty(issue.description) ? issue.description : description: !_.isEmpty(issue.description)
sprintf(s__('ciReport|%{namespace} is affected by %{vulnerability}.'), { ? issue.description
: sprintf(s__('ciReport|%{namespace} is affected by %{vulnerability}.'), {
namespace: issue.namespace, namespace: issue.namespace,
vulnerability: issue.vulnerability, vulnerability: issue.vulnerability,
}), }),
path: issue.namespace, path: issue.namespace,
identifiers: [{ identifiers: [
{
type: 'CVE', type: 'CVE',
name: issue.vulnerability, name: issue.vulnerability,
value: issue.vulnerability, value: issue.vulnerability,
url: `https://cve.mitre.org/cgi-bin/cvename.cgi?name=${issue.vulnerability}`, url: `https://cve.mitre.org/cgi-bin/cvename.cgi?name=${issue.vulnerability}`,
}], },
],
}; };
// Generate solution // Generate solution
if (!_.isEmpty(issue.fixedby) && if (
!_.isEmpty(issue.fixedby) &&
!_.isEmpty(issue.featurename) && !_.isEmpty(issue.featurename) &&
!_.isEmpty(issue.featureversion) !_.isEmpty(issue.featureversion)
) { ) {
...@@ -213,12 +219,14 @@ export const parseDastIssues = (issues = [], feedback = []) => ...@@ -213,12 +219,14 @@ export const parseDastIssues = (issues = [], feedback = []) =>
if (!_.isEmpty(issue.cweid)) { if (!_.isEmpty(issue.cweid)) {
Object.assign(parsed, { Object.assign(parsed, {
identifiers: [{ identifiers: [
{
type: 'CWE', type: 'CWE',
name: `CWE-${issue.cweid}`, name: `CWE-${issue.cweid}`,
value: issue.cweid, value: issue.cweid,
url: `https://cwe.mitre.org/data/definitions/${issue.cweid}.html`, url: `https://cwe.mitre.org/data/definitions/${issue.cweid}.html`,
}], },
],
}); });
} }
......
...@@ -6,7 +6,15 @@ function WeightSelect(els, options = {}) { ...@@ -6,7 +6,15 @@ function WeightSelect(els, options = {}) {
const $els = $(els || '.js-weight-select'); const $els = $(els || '.js-weight-select');
$els.each(function(i, dropdown) { $els.each(function(i, dropdown) {
var $block, $dropdown, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, updateUrl, updateWeight; var $block,
$dropdown,
$loading,
$selectbox,
$sidebarCollapsedValue,
$value,
abilityName,
updateUrl,
updateWeight;
$dropdown = $(dropdown); $dropdown = $(dropdown);
updateUrl = $dropdown.data('issueUpdate'); updateUrl = $dropdown.data('issueUpdate');
$selectbox = $dropdown.closest('.selectbox'); $selectbox = $dropdown.closest('.selectbox');
...@@ -15,7 +23,7 @@ function WeightSelect(els, options = {}) { ...@@ -15,7 +23,7 @@ function WeightSelect(els, options = {}) {
$value = $block.find('.value'); $value = $block.find('.value');
abilityName = $dropdown.data('abilityName'); abilityName = $dropdown.data('abilityName');
$loading = $block.find('.block-loading').fadeOut(); $loading = $block.find('.block-loading').fadeOut();
const fieldName = options.fieldName || $dropdown.data("fieldName"); const fieldName = options.fieldName || $dropdown.data('fieldName');
const inputField = $dropdown.closest('.selectbox').find(`input[name='${fieldName}']`); const inputField = $dropdown.closest('.selectbox').find(`input[name='${fieldName}']`);
if (Object.keys(options).includes('selected')) { if (Object.keys(options).includes('selected')) {
...@@ -25,16 +33,16 @@ function WeightSelect(els, options = {}) { ...@@ -25,16 +33,16 @@ function WeightSelect(els, options = {}) {
return $dropdown.glDropdown({ return $dropdown.glDropdown({
selectable: true, selectable: true,
fieldName, fieldName,
toggleLabel: function (selected, el) { toggleLabel: function(selected, el) {
return $(el).data("id"); return $(el).data('id');
}, },
hidden: function(e) { hidden: function(e) {
$selectbox.hide(); $selectbox.hide();
return $value.css('display', ''); return $value.css('display', '');
}, },
id: function(obj, el) { id: function(obj, el) {
if ($(el).data("none") == null) { if ($(el).data('none') == null) {
return $(el).data("id"); return $(el).data('id');
} else { } else {
return ''; return '';
} }
...@@ -51,7 +59,7 @@ function WeightSelect(els, options = {}) { ...@@ -51,7 +59,7 @@ function WeightSelect(els, options = {}) {
} else if ($dropdown.is('.js-issuable-form-weight')) { } else if ($dropdown.is('.js-issuable-form-weight')) {
e.preventDefault(); e.preventDefault();
} }
} },
}); });
}); });
} }
......
...@@ -11,13 +11,16 @@ describe('AddGitlabSlackApplication', () => { ...@@ -11,13 +11,16 @@ describe('AddGitlabSlackApplication', () => {
const docsPath = '//docsPath'; const docsPath = '//docsPath';
const gitlabLogoPath = '//gitlabLogoPath'; const gitlabLogoPath = '//gitlabLogoPath';
const slackLogoPath = '//slackLogoPath'; const slackLogoPath = '//slackLogoPath';
const projects = [{ const projects = [
{
id: 4, id: 4,
name: 'test', name: 'test',
}, { },
{
id: 6, id: 6,
name: 'nope', name: 'nope',
}]; },
];
const DEFAULT_PROPS = { const DEFAULT_PROPS = {
projects, projects,
gitlabForSlackGifPath, gitlabForSlackGifPath,
...@@ -31,20 +34,20 @@ describe('AddGitlabSlackApplication', () => { ...@@ -31,20 +34,20 @@ describe('AddGitlabSlackApplication', () => {
const AddGitlabSlackApplication = Vue.extend(addGitlabSlackApplication); const AddGitlabSlackApplication = Vue.extend(addGitlabSlackApplication);
it('opens popup when button is clicked', (done) => { it('opens popup when button is clicked', done => {
const vm = mountComponent(AddGitlabSlackApplication, DEFAULT_PROPS); const vm = mountComponent(AddGitlabSlackApplication, DEFAULT_PROPS);
vm.$el.querySelector('.js-popup-button').click(); vm.$el.querySelector('.js-popup-button').click();
vm.$nextTick() vm.$nextTick()
.then(() => { .then(() => {
expect(vm.$el.querySelector('.js-popup')).toBeDefined() expect(vm.$el.querySelector('.js-popup')).toBeDefined();
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('hides popup when button is clicked', (done) => { it('hides popup when button is clicked', done => {
const vm = mountComponent(AddGitlabSlackApplication, DEFAULT_PROPS); const vm = mountComponent(AddGitlabSlackApplication, DEFAULT_PROPS);
vm.popupOpen = true; vm.popupOpen = true;
...@@ -53,13 +56,13 @@ describe('AddGitlabSlackApplication', () => { ...@@ -53,13 +56,13 @@ describe('AddGitlabSlackApplication', () => {
.then(() => vm.$el.querySelector('.js-popup-button').click()) .then(() => vm.$el.querySelector('.js-popup-button').click())
.then(vm.$nextTick) .then(vm.$nextTick)
.then(() => { .then(() => {
expect(vm.$el.querySelector('.js-popup')).toBeNull() expect(vm.$el.querySelector('.js-popup')).toBeNull();
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('popup has a project select when signed in', (done) => { it('popup has a project select when signed in', done => {
const vm = mountComponent(AddGitlabSlackApplication, { const vm = mountComponent(AddGitlabSlackApplication, {
...DEFAULT_PROPS, ...DEFAULT_PROPS,
isSignedIn: true, isSignedIn: true,
...@@ -69,13 +72,13 @@ describe('AddGitlabSlackApplication', () => { ...@@ -69,13 +72,13 @@ describe('AddGitlabSlackApplication', () => {
vm.$nextTick() vm.$nextTick()
.then(() => { .then(() => {
expect(vm.$el.querySelector('.js-project-select')).toBeDefined() expect(vm.$el.querySelector('.js-project-select')).toBeDefined();
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('popup has a message when there is no projects', (done) => { it('popup has a message when there is no projects', done => {
const vm = mountComponent(AddGitlabSlackApplication, { const vm = mountComponent(AddGitlabSlackApplication, {
...DEFAULT_PROPS, ...DEFAULT_PROPS,
projects: [], projects: [],
...@@ -86,14 +89,15 @@ describe('AddGitlabSlackApplication', () => { ...@@ -86,14 +89,15 @@ describe('AddGitlabSlackApplication', () => {
vm.$nextTick() vm.$nextTick()
.then(() => { .then(() => {
expect(vm.$el.querySelector('.js-no-projects').textContent) expect(vm.$el.querySelector('.js-no-projects').textContent).toMatch(
.toMatch("You don't have any projects available."); "You don't have any projects available.",
);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('popup has a sign in link when logged out', (done) => { it('popup has a sign in link when logged out', done => {
const vm = mountComponent(AddGitlabSlackApplication, { const vm = mountComponent(AddGitlabSlackApplication, {
...DEFAULT_PROPS, ...DEFAULT_PROPS,
}); });
...@@ -103,14 +107,15 @@ describe('AddGitlabSlackApplication', () => { ...@@ -103,14 +107,15 @@ describe('AddGitlabSlackApplication', () => {
vm.$nextTick() vm.$nextTick()
.then(() => { .then(() => {
expect(vm.$el.querySelector('.js-gitlab-slack-sign-in-link').href) expect(vm.$el.querySelector('.js-gitlab-slack-sign-in-link').href).toMatch(
.toMatch(new RegExp(signInPath, 'i')); new RegExp(signInPath, 'i'),
);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
it('redirects user to external link when submitted', (done) => { it('redirects user to external link when submitted', done => {
const vm = mountComponent(AddGitlabSlackApplication, { const vm = mountComponent(AddGitlabSlackApplication, {
...DEFAULT_PROPS, ...DEFAULT_PROPS,
isSignedIn: true, isSignedIn: true,
...@@ -127,7 +132,7 @@ describe('AddGitlabSlackApplication', () => { ...@@ -127,7 +132,7 @@ describe('AddGitlabSlackApplication', () => {
.then(vm.$nextTick) .then(vm.$nextTick)
.then(addToSlackPromise) .then(addToSlackPromise)
.then(() => { .then(() => {
expect(redirectTo).toHaveBeenCalledWith(redirectLink) expect(redirectTo).toHaveBeenCalledWith(redirectLink);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
......
...@@ -98,8 +98,9 @@ describe('Approvals Body Component', () => { ...@@ -98,8 +98,9 @@ describe('Approvals Body Component', () => {
vm.userCanApprove = true; vm.userCanApprove = true;
Vue.nextTick(() => { Vue.nextTick(() => {
expect(vm.approvalsRequiredStringified) expect(vm.approvalsRequiredStringified).toBe(
.toBe('Merge request approved; you can approve additionally'); 'Merge request approved; you can approve additionally',
);
done(); done();
}); });
}); });
......
...@@ -114,8 +114,7 @@ describe('Batch comments draft note component', () => { ...@@ -114,8 +114,7 @@ describe('Batch comments draft note component', () => {
it('dispatches updateDraft', done => { it('dispatches updateDraft', done => {
vm.$el.querySelector('.js-note-edit').click(); vm.$el.querySelector('.js-note-edit').click();
vm vm.$nextTick()
.$nextTick()
.then(() => { .then(() => {
vm.$el.querySelector('.js-vue-issue-save').click(); vm.$el.querySelector('.js-vue-issue-save').click();
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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