diff options
author | Simon Knox <psimyn@gmail.com> | 2017-11-07 18:29:14 +1100 |
---|---|---|
committer | Simon Knox <psimyn@gmail.com> | 2017-11-07 18:29:14 +1100 |
commit | 8b78c1e5726f21147ba05377f241f03b3810d41f (patch) | |
tree | 6d38e8e427e7de58f51d55e8c64804050fef1b63 /app/assets/javascripts | |
parent | e9fb244ad3fdbb42585c1455302eec91af5e11d2 (diff) | |
parent | e99ddb6f374c9f79c1c78e808c5e9bd983bed227 (diff) | |
download | gitlab-ce-8b78c1e5726f21147ba05377f241f03b3810d41f.tar.gz |
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into 38394-smarter-interval
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r-- | app/assets/javascripts/behaviors/copy_as_gfm.js (renamed from app/assets/javascripts/copy_as_gfm.js) | 18 | ||||
-rw-r--r-- | app/assets/javascripts/behaviors/index.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/main.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/monitoring/components/graph.vue | 8 | ||||
-rw-r--r-- | app/assets/javascripts/monitoring/components/graph/legend.vue | 25 | ||||
-rw-r--r-- | app/assets/javascripts/monitoring/components/graph/path.vue | 12 | ||||
-rw-r--r-- | app/assets/javascripts/monitoring/utils/measurements.js | 8 | ||||
-rw-r--r-- | app/assets/javascripts/monitoring/utils/multiple_time_series.js | 49 | ||||
-rw-r--r-- | app/assets/javascripts/notes.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/search_autocomplete.js | 16 | ||||
-rw-r--r-- | app/assets/javascripts/shortcuts_issuable.js | 5 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/markdown/field.vue | 33 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/markdown/header.vue | 53 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue | 17 |
14 files changed, 162 insertions, 88 deletions
diff --git a/app/assets/javascripts/copy_as_gfm.js b/app/assets/javascripts/behaviors/copy_as_gfm.js index 93b0cbf4209..e7dc4ef8304 100644 --- a/app/assets/javascripts/copy_as_gfm.js +++ b/app/assets/javascripts/behaviors/copy_as_gfm.js @@ -1,7 +1,8 @@ /* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */ + import _ from 'underscore'; -import { insertText, getSelectedFragment, nodeMatchesSelector } from './lib/utils/common_utils'; -import { placeholderImage } from './lazy_loader'; +import { insertText, getSelectedFragment, nodeMatchesSelector } from '../lib/utils/common_utils'; +import { placeholderImage } from '../lazy_loader'; const gfmRules = { // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert @@ -284,7 +285,7 @@ const gfmRules = { }, }; -class CopyAsGFM { +export class CopyAsGFM { constructor() { $(document).on('copy', '.md, .wiki', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection); }); $(document).on('copy', 'pre.code.highlight, .diff-content .line_content', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformCodeSelection); }); @@ -469,7 +470,12 @@ class CopyAsGFM { } } -window.gl = window.gl || {}; -window.gl.CopyAsGFM = CopyAsGFM; +// Export CopyAsGFM as a global for rspec to access +// see /spec/features/copy_as_gfm_spec.rb +if (process.env.NODE_ENV !== 'production') { + window.CopyAsGFM = CopyAsGFM; +} -new CopyAsGFM(); +export default function initCopyAsGFM() { + return new CopyAsGFM(); +} diff --git a/app/assets/javascripts/behaviors/index.js b/app/assets/javascripts/behaviors/index.js index 44b2c974b9e..671532394a9 100644 --- a/app/assets/javascripts/behaviors/index.js +++ b/app/assets/javascripts/behaviors/index.js @@ -1,5 +1,6 @@ import './autosize'; import './bind_in_out'; +import initCopyAsGFM from './copy_as_gfm'; import './details_behavior'; import installGlEmojiElement from './gl_emoji'; import './quick_submit'; @@ -7,3 +8,4 @@ import './requires_input'; import './toggler_behavior'; installGlEmojiElement(); +initCopyAsGFM(); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 9117f033c9f..31c5cfc5e55 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -46,7 +46,6 @@ import './commits'; import './compare'; import './compare_autocomplete'; import './confirm_danger_modal'; -import './copy_as_gfm'; import './copy_to_clipboard'; import Flash, { removeFlashClickListener } from './flash'; import './gl_dropdown'; diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue index 5aa3865f96a..f8782fde927 100644 --- a/app/assets/javascripts/monitoring/components/graph.vue +++ b/app/assets/javascripts/monitoring/components/graph.vue @@ -138,7 +138,7 @@ renderAxesPaths() { this.timeSeries = createTimeSeries( - this.graphData.queries[0], + this.graphData.queries, this.graphWidth, this.graphHeight, this.graphHeightOffset, @@ -153,8 +153,9 @@ const axisYScale = d3.scale.linear() .range([this.graphHeight - this.graphHeightOffset, 0]); - axisXScale.domain(d3.extent(this.timeSeries[0].values, d => d.time)); - axisYScale.domain([0, d3.max(this.timeSeries[0].values.map(d => d.value))]); + const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []); + axisXScale.domain(d3.extent(allValues, d => d.time)); + axisYScale.domain([0, d3.max(allValues.map(d => d.value))]); const xAxis = d3.svg.axis() .scale(axisXScale) @@ -246,6 +247,7 @@ :key="index" :generated-line-path="path.linePath" :generated-area-path="path.areaPath" + :line-style="path.lineStyle" :line-color="path.lineColor" :area-color="path.areaColor" /> diff --git a/app/assets/javascripts/monitoring/components/graph/legend.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue index 85b6d7f4cbe..440b1b12631 100644 --- a/app/assets/javascripts/monitoring/components/graph/legend.vue +++ b/app/assets/javascripts/monitoring/components/graph/legend.vue @@ -79,7 +79,8 @@ }, formatMetricUsage(series) { - const value = series.values[this.currentDataIndex].value; + const value = series.values[this.currentDataIndex] && + series.values[this.currentDataIndex].value; if (isNaN(value)) { return '-'; } @@ -92,6 +93,12 @@ } return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`; }, + + strokeDashArray(type) { + if (type === 'dashed') return '6, 3'; + if (type === 'dotted') return '3, 3'; + return null; + }, }, mounted() { this.$nextTick(() => { @@ -162,13 +169,15 @@ v-for="(series, index) in timeSeries" :key="index" :transform="translateLegendGroup(index)"> - <rect - :fill="series.areaColor" - :width="measurements.legends.width" - :height="measurements.legends.height" - x="20" - :y="graphHeight - measurements.legendOffset"> - </rect> + <line + :stroke="series.lineColor" + :stroke-width="measurements.legends.height" + :stroke-dasharray="strokeDashArray(series.lineStyle)" + :x1="measurements.legends.offsetX" + :x2="measurements.legends.offsetX + measurements.legends.width" + :y1="graphHeight - measurements.legends.offsetY" + :y2="graphHeight - measurements.legends.offsetY"> + </line> <text v-if="timeSeries.length > 1" class="legend-metric-title" diff --git a/app/assets/javascripts/monitoring/components/graph/path.vue b/app/assets/javascripts/monitoring/components/graph/path.vue index 043f1bf66bb..5e6d409033a 100644 --- a/app/assets/javascripts/monitoring/components/graph/path.vue +++ b/app/assets/javascripts/monitoring/components/graph/path.vue @@ -9,6 +9,10 @@ type: String, required: true, }, + lineStyle: { + type: String, + required: false, + }, lineColor: { type: String, required: true, @@ -18,6 +22,13 @@ required: true, }, }, + computed: { + strokeDashArray() { + if (this.lineStyle === 'dashed') return '3, 1'; + if (this.lineStyle === 'dotted') return '1, 1'; + return null; + }, + }, }; </script> <template> @@ -34,6 +45,7 @@ :stroke="lineColor" fill="none" stroke-width="1" + :stroke-dasharray="strokeDashArray" transform="translate(-5, 20)"> </path> </g> diff --git a/app/assets/javascripts/monitoring/utils/measurements.js b/app/assets/javascripts/monitoring/utils/measurements.js index ee3c45efacc..ee866850e13 100644 --- a/app/assets/javascripts/monitoring/utils/measurements.js +++ b/app/assets/javascripts/monitoring/utils/measurements.js @@ -7,15 +7,16 @@ export default { left: 40, }, legends: { - width: 10, + width: 15, height: 3, + offsetX: 20, + offsetY: 32, }, backgroundLegend: { width: 30, height: 50, }, axisLabelLineOffset: -20, - legendOffset: 33, }, large: { // This covers both md and lg screen sizes margin: { @@ -27,13 +28,14 @@ export default { legends: { width: 15, height: 3, + offsetX: 20, + offsetY: 34, }, backgroundLegend: { width: 30, height: 150, }, axisLabelLineOffset: 20, - legendOffset: 36, }, xTicks: 8, yTicks: 3, diff --git a/app/assets/javascripts/monitoring/utils/multiple_time_series.js b/app/assets/javascripts/monitoring/utils/multiple_time_series.js index 65eec0d8d02..d21a265bd43 100644 --- a/app/assets/javascripts/monitoring/utils/multiple_time_series.js +++ b/app/assets/javascripts/monitoring/utils/multiple_time_series.js @@ -11,7 +11,9 @@ const defaultColorPalette = { const defaultColorOrder = ['blue', 'orange', 'red', 'green', 'purple']; -export default function createTimeSeries(queryData, graphWidth, graphHeight, graphHeightOffset) { +const defaultStyleOrder = ['solid', 'dashed', 'dotted']; + +function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom, yDom, lineStyle) { let usedColors = []; function pickColor(name) { @@ -31,17 +33,7 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra return defaultColorPalette[pick]; } - const maxValues = queryData.result.map((timeSeries, index) => { - const maxValue = d3.max(timeSeries.values.map(d => d.value)); - return { - maxValue, - index, - }; - }); - - const maxValueFromSeries = _.max(maxValues, val => val.maxValue); - - return queryData.result.map((timeSeries, timeSeriesNumber) => { + return query.result.map((timeSeries, timeSeriesNumber) => { let metricTag = ''; let lineColor = ''; let areaColor = ''; @@ -52,9 +44,9 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra const timeSeriesScaleY = d3.scale.linear() .range([graphHeight - graphHeightOffset, 0]); - timeSeriesScaleX.domain(d3.extent(timeSeries.values, d => d.time)); + timeSeriesScaleX.domain(xDom); timeSeriesScaleX.ticks(d3.time.minute, 60); - timeSeriesScaleY.domain([0, maxValueFromSeries.maxValue]); + timeSeriesScaleY.domain(yDom); const defined = d => !isNaN(d.value) && d.value != null; @@ -72,10 +64,10 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra .y1(d => timeSeriesScaleY(d.value)); const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]]; - const seriesCustomizationData = queryData.series != null && - _.findWhere(queryData.series[0].when, - { value: timeSeriesMetricLabel }); - if (seriesCustomizationData != null) { + const seriesCustomizationData = query.series != null && + _.findWhere(query.series[0].when, { value: timeSeriesMetricLabel }); + + if (seriesCustomizationData) { metricTag = seriesCustomizationData.value || timeSeriesMetricLabel; [lineColor, areaColor] = pickColor(seriesCustomizationData.color); } else { @@ -83,14 +75,35 @@ export default function createTimeSeries(queryData, graphWidth, graphHeight, gra [lineColor, areaColor] = pickColor(); } + if (query.track) { + metricTag += ` - ${query.track}`; + } + return { linePath: lineFunction(timeSeries.values), areaPath: areaFunction(timeSeries.values), timeSeriesScaleX, values: timeSeries.values, + lineStyle, lineColor, areaColor, metricTag, }; }); } + +export default function createTimeSeries(queries, graphWidth, graphHeight, graphHeightOffset) { + const allValues = queries.reduce((allQueryResults, query) => allQueryResults.concat( + query.result.reduce((allResults, result) => allResults.concat(result.values), []), + ), []); + + const xDom = d3.extent(allValues, d => d.time); + const yDom = [0, d3.max(allValues.map(d => d.value))]; + + return queries.reduce((series, query, index) => { + const lineStyle = defaultStyleOrder[index % defaultStyleOrder.length]; + return series.concat( + queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom, yDom, lineStyle), + ); + }, []); +} diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 705bec23b53..e1ab28978e8 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -413,8 +413,9 @@ export default class Notes { return; } this.note_ids.push(noteEntity.id); + form = $form || $(`.js-discussion-note-form[data-discussion-id="${noteEntity.discussion_id}"]`); - row = form.closest('tr'); + row = (form.length || !noteEntity.discussion_line_code) ? form.closest('tr') : $(`#${noteEntity.discussion_line_code}`); if (noteEntity.on_image) { row = form; diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index f15452ec683..9dec5d7645a 100644 --- a/app/assets/javascripts/search_autocomplete.js +++ b/app/assets/javascripts/search_autocomplete.js @@ -162,13 +162,19 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. items = [ { header: "" + name - }, { + } + ]; + const issueItems = [ + { text: 'Issues assigned to me', url: issuesPath + "/?assignee_username=" + userName }, { text: "Issues I've created", url: issuesPath + "/?author_username=" + userName - }, 'separator', { + } + ]; + const mergeRequestItems = [ + { text: 'Merge requests assigned to me', url: mrPath + "/?assignee_username=" + userName }, { @@ -176,6 +182,11 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. url: mrPath + "/?author_username=" + userName } ]; + if (options.issuesDisabled) { + items = items.concat(mergeRequestItems); + } else { + items = items.concat(...issueItems, 'separator', ...mergeRequestItems); + } if (!name) { items.splice(0, 1); } @@ -408,6 +419,7 @@ import { isInGroupsPage, isInProjectPage, getGroupSlug, getProjectSlug } from '. gl.projectOptions[projectPath] = { name: $projectOptionsDataEl.data('name'), issuesPath: $projectOptionsDataEl.data('issues-path'), + issuesDisabled: $projectOptionsDataEl.data('issues-disabled'), mrPath: $projectOptionsDataEl.data('mr-path') }; } diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js index fc97938e3d1..4f4f606d293 100644 --- a/app/assets/javascripts/shortcuts_issuable.js +++ b/app/assets/javascripts/shortcuts_issuable.js @@ -4,6 +4,7 @@ import _ from 'underscore'; import 'mousetrap'; import ShortcutsNavigation from './shortcuts_navigation'; +import { CopyAsGFM } from './behaviors/copy_as_gfm'; export default class ShortcutsIssuable extends ShortcutsNavigation { constructor(isMergeRequest) { @@ -33,8 +34,8 @@ export default class ShortcutsIssuable extends ShortcutsNavigation { return false; } - const el = window.gl.CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true)); - const selected = window.gl.CopyAsGFM.nodeToGFM(el); + const el = CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true)); + const selected = CopyAsGFM.nodeToGFM(el); if (selected.trim() === '') { return false; diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index 8c0d9b9cda8..a873e00d0f3 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -3,6 +3,7 @@ import GLForm from '../../../gl_form'; import markdownHeader from './header.vue'; import markdownToolbar from './toolbar.vue'; + import icon from '../icon.vue'; export default { props: { @@ -37,6 +38,7 @@ components: { markdownHeader, markdownToolbar, + icon, }, computed: { shouldShowReferencedUsers() { @@ -45,8 +47,10 @@ }, }, methods: { - toggleMarkdownPreview() { - this.previewMarkdown = !this.previewMarkdown; + showPreviewTab() { + if (this.previewMarkdown) return; + + this.previewMarkdown = true; /* Can't use `$refs` as the component is technically in the parent component @@ -54,20 +58,22 @@ */ const text = this.$slots.textarea[0].elm.value; - if (!this.previewMarkdown) { - this.markdownPreview = ''; - } else if (text) { + if (text) { this.markdownPreviewLoading = true; this.$http.post(this.markdownPreviewPath, { text }) .then(resp => resp.json()) - .then((data) => { - this.renderMarkdown(data); - }) + .then(data => this.renderMarkdown(data)) .catch(() => new Flash('Error loading markdown preview')); } else { this.renderMarkdown(); } }, + + showWriteTab() { + this.markdownPreview = ''; + this.previewMarkdown = false; + }, + renderMarkdown(data = {}) { this.markdownPreviewLoading = false; this.markdownPreview = data.body || 'Nothing to preview.'; @@ -104,7 +110,8 @@ ref="gl-form"> <markdown-header :preview-markdown="previewMarkdown" - @toggle-markdown="toggleMarkdownPreview" /> + @preview-markdown="showPreviewTab" + @write-markdown="showWriteTab" /> <div class="md-write-holder" v-show="!previewMarkdown"> @@ -114,10 +121,10 @@ class="zen-control zen-control-leave js-zen-leave" href="#" aria-label="Enter zen mode"> - <i - class="fa fa-compress" - aria-hidden="true"> - </i> + <icon + name="screen-normal" + :size="32"> + </icon> </a> <markdown-toolbar :markdown-docs-path="markdownDocsPath" diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 5bf2a90cc3b..70f5fc1d664 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -1,6 +1,7 @@ <script> import tooltip from '../../directives/tooltip'; import toolbarButton from './toolbar_button.vue'; + import icon from '../icon.vue'; export default { props: { @@ -14,25 +15,34 @@ }, components: { toolbarButton, + icon, }, methods: { - toggleMarkdownPreview(e, form) { - if (form && !form.find('.js-vue-markdown-field').length) { - return; - } else if (e.target.blur) { - e.target.blur(); - } + isMarkdownForm(form) { + return form && !form.find('.js-vue-markdown-field').length; + }, + + previewMarkdownTab(event, form) { + if (event.target.blur) event.target.blur(); + if (this.isMarkdownForm(form)) return; + + this.$emit('preview-markdown'); + }, + + writeMarkdownTab(event, form) { + if (event.target.blur) event.target.blur(); + if (this.isMarkdownForm(form)) return; - this.$emit('toggle-markdown'); + this.$emit('write-markdown'); }, }, mounted() { - $(document).on('markdown-preview:show.vue', this.toggleMarkdownPreview); - $(document).on('markdown-preview:hide.vue', this.toggleMarkdownPreview); + $(document).on('markdown-preview:show.vue', this.previewMarkdownTab); + $(document).on('markdown-preview:hide.vue', this.writeMarkdownTab); }, beforeDestroy() { - $(document).on('markdown-preview:show.vue', this.toggleMarkdownPreview); - $(document).off('markdown-preview:hide.vue', this.toggleMarkdownPreview); + $(document).off('markdown-preview:show.vue', this.previewMarkdownTab); + $(document).off('markdown-preview:hide.vue', this.writeMarkdownTab); }, }; </script> @@ -42,17 +52,19 @@ <ul class="nav-links clearfix"> <li :class="{ active: !previewMarkdown }"> <a + class="js-write-link" href="#md-write-holder" tabindex="-1" - @click.prevent="toggleMarkdownPreview($event)"> + @click.prevent="writeMarkdownTab($event)"> Write </a> </li> <li :class="{ active: previewMarkdown }"> <a + class="js-preview-link" href="#md-preview-holder" tabindex="-1" - @click.prevent="toggleMarkdownPreview($event)"> + @click.prevent="previewMarkdownTab($event)"> Preview </a> </li> @@ -70,7 +82,7 @@ tag="> " :prepend="true" button-title="Insert a quote" - icon="quote-right" /> + icon="quote" /> <toolbar-button tag="`" tag-block="```" @@ -80,17 +92,17 @@ tag="* " :prepend="true" button-title="Add a bullet list" - icon="list-ul" /> + icon="list-bulleted" /> <toolbar-button tag="1. " :prepend="true" button-title="Add a numbered list" - icon="list-ol" /> + icon="list-numbered" /> <toolbar-button tag="* [ ] " :prepend="true" button-title="Add a task list" - icon="check-square-o" /> + icon="task-done" /> </div> <div class="toolbar-group"> <button @@ -101,10 +113,9 @@ tabindex="-1" title="Go full screen" type="button"> - <i - aria-hidden="true" - class="fa fa-arrows-alt fa-fw"> - </i> + <icon + name="screen-full"> + </icon> </button> </div> </li> diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue index f7da7ebfcfe..b930fb116a3 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue @@ -1,5 +1,6 @@ <script> import tooltip from '../../directives/tooltip'; + import icon from '../icon.vue'; export default { props: { @@ -26,14 +27,12 @@ default: false, }, }, + components: { + icon, + }, directives: { tooltip, }, - computed: { - iconClass() { - return `fa-${this.icon}`; - }, - }, }; </script> @@ -49,10 +48,8 @@ :data-md-prepend="prepend" :title="buttonTitle" :aria-label="buttonTitle"> - <i - aria-hidden="true" - class="fa fa-fw" - :class="iconClass"> - </i> + <icon + :name="icon"> + </icon> </button> </template> |