summaryrefslogtreecommitdiff
path: root/app/assets
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/blob/components/blob_header.vue38
-rw-r--r--app/assets/javascripts/blob/components/blob_header_default_actions.vue14
-rw-r--r--app/assets/javascripts/blob/components/blob_header_viewer_switcher.vue15
-rw-r--r--app/assets/javascripts/blob/event_hub.js3
-rw-r--r--app/assets/javascripts/ide/ide_router.js6
-rw-r--r--app/assets/javascripts/ide/ide_router_extension.js21
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js6
-rw-r--r--app/assets/javascripts/pages/projects/graphs/charts/index.js179
-rw-r--r--app/assets/javascripts/pages/projects/graphs/charts/series_data_mixin.js11
9 files changed, 187 insertions, 106 deletions
diff --git a/app/assets/javascripts/blob/components/blob_header.vue b/app/assets/javascripts/blob/components/blob_header.vue
index 61a66513838..b7d9600ec40 100644
--- a/app/assets/javascripts/blob/components/blob_header.vue
+++ b/app/assets/javascripts/blob/components/blob_header.vue
@@ -2,8 +2,7 @@
import ViewerSwitcher from './blob_header_viewer_switcher.vue';
import DefaultActions from './blob_header_default_actions.vue';
import BlobFilepath from './blob_header_filepath.vue';
-import eventHub from '../event_hub';
-import { RICH_BLOB_VIEWER, SIMPLE_BLOB_VIEWER } from './constants';
+import { SIMPLE_BLOB_VIEWER } from './constants';
export default {
components: {
@@ -26,10 +25,15 @@ export default {
required: false,
default: false,
},
+ activeViewerType: {
+ type: String,
+ required: false,
+ default: SIMPLE_BLOB_VIEWER,
+ },
},
data() {
return {
- activeViewer: this.blob.richViewer ? RICH_BLOB_VIEWER : SIMPLE_BLOB_VIEWER,
+ viewer: this.hideViewerSwitcher ? null : this.activeViewerType,
};
},
computed: {
@@ -40,19 +44,16 @@ export default {
return !this.hideDefaultActions;
},
},
- created() {
- if (this.showViewerSwitcher) {
- eventHub.$on('switch-viewer', this.setActiveViewer);
- }
- },
- beforeDestroy() {
- if (this.showViewerSwitcher) {
- eventHub.$off('switch-viewer', this.setActiveViewer);
- }
+ watch: {
+ viewer(newVal, oldVal) {
+ if (!this.hideViewerSwitcher && newVal !== oldVal) {
+ this.$emit('viewer-changed', newVal);
+ }
+ },
},
methods: {
- setActiveViewer(viewer) {
- this.activeViewer = viewer;
+ proxyCopyRequest() {
+ this.$emit('copy');
},
},
};
@@ -66,11 +67,16 @@ export default {
</blob-filepath>
<div class="file-actions d-none d-sm-block">
- <viewer-switcher v-if="showViewerSwitcher" :blob="blob" :active-viewer="activeViewer" />
+ <viewer-switcher v-if="showViewerSwitcher" v-model="viewer" />
<slot name="actions"></slot>
- <default-actions v-if="showDefaultActions" :blob="blob" :active-viewer="activeViewer" />
+ <default-actions
+ v-if="showDefaultActions"
+ :raw-path="blob.rawPath"
+ :active-viewer="viewer"
+ @copy="proxyCopyRequest"
+ />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/blob/components/blob_header_default_actions.vue b/app/assets/javascripts/blob/components/blob_header_default_actions.vue
index e526fae0dba..f5157fba819 100644
--- a/app/assets/javascripts/blob/components/blob_header_default_actions.vue
+++ b/app/assets/javascripts/blob/components/blob_header_default_actions.vue
@@ -7,7 +7,6 @@ import {
RICH_BLOB_VIEWER,
SIMPLE_BLOB_VIEWER,
} from './constants';
-import eventHub from '../event_hub';
export default {
components: {
@@ -19,8 +18,8 @@ export default {
GlTooltip: GlTooltipDirective,
},
props: {
- blob: {
- type: Object,
+ rawPath: {
+ type: String,
required: true,
},
activeViewer: {
@@ -30,11 +29,8 @@ export default {
},
},
computed: {
- rawUrl() {
- return this.blob.rawPath;
- },
downloadUrl() {
- return `${this.blob.rawPath}?inline=false`;
+ return `${this.rawPath}?inline=false`;
},
copyDisabled() {
return this.activeViewer === RICH_BLOB_VIEWER;
@@ -42,7 +38,7 @@ export default {
},
methods: {
requestCopyContents() {
- eventHub.$emit('copy');
+ this.$emit('copy');
},
},
BTN_COPY_CONTENTS_TITLE,
@@ -65,7 +61,7 @@ export default {
v-gl-tooltip.hover
:aria-label="$options.BTN_RAW_TITLE"
:title="$options.BTN_RAW_TITLE"
- :href="rawUrl"
+ :href="rawPath"
target="_blank"
>
<gl-icon name="doc-code" :size="14" />
diff --git a/app/assets/javascripts/blob/components/blob_header_viewer_switcher.vue b/app/assets/javascripts/blob/components/blob_header_viewer_switcher.vue
index 13ea87c99b1..689fa7638f0 100644
--- a/app/assets/javascripts/blob/components/blob_header_viewer_switcher.vue
+++ b/app/assets/javascripts/blob/components/blob_header_viewer_switcher.vue
@@ -6,7 +6,6 @@ import {
SIMPLE_BLOB_VIEWER,
SIMPLE_BLOB_VIEWER_TITLE,
} from './constants';
-import eventHub from '../event_hub';
export default {
components: {
@@ -18,11 +17,7 @@ export default {
GlTooltip: GlTooltipDirective,
},
props: {
- blob: {
- type: Object,
- required: true,
- },
- activeViewer: {
+ value: {
type: String,
default: SIMPLE_BLOB_VIEWER,
required: false,
@@ -30,16 +25,16 @@ export default {
},
computed: {
isSimpleViewer() {
- return this.activeViewer === SIMPLE_BLOB_VIEWER;
+ return this.value === SIMPLE_BLOB_VIEWER;
},
isRichViewer() {
- return this.activeViewer === RICH_BLOB_VIEWER;
+ return this.value === RICH_BLOB_VIEWER;
},
},
methods: {
switchToViewer(viewer) {
- if (viewer !== this.activeViewer) {
- eventHub.$emit('switch-viewer', viewer);
+ if (viewer !== this.value) {
+ this.$emit('input', viewer);
}
},
},
diff --git a/app/assets/javascripts/blob/event_hub.js b/app/assets/javascripts/blob/event_hub.js
deleted file mode 100644
index 0948c2e5352..00000000000
--- a/app/assets/javascripts/blob/event_hub.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import Vue from 'vue';
-
-export default new Vue();
diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js
index 8c84b98a108..0fab3ee0f3b 100644
--- a/app/assets/javascripts/ide/ide_router.js
+++ b/app/assets/javascripts/ide/ide_router.js
@@ -1,11 +1,11 @@
import Vue from 'vue';
-import VueRouter from 'vue-router';
+import IdeRouter from '~/ide/ide_router_extension';
import { joinPaths } from '~/lib/utils/url_utility';
import flash from '~/flash';
import store from './stores';
import { __ } from '~/locale';
-Vue.use(VueRouter);
+Vue.use(IdeRouter);
/**
* Routes below /-/ide/:
@@ -33,7 +33,7 @@ const EmptyRouterComponent = {
},
};
-const router = new VueRouter({
+const router = new IdeRouter({
mode: 'history',
base: joinPaths(gon.relative_url_root || '', '/-/ide/'),
routes: [
diff --git a/app/assets/javascripts/ide/ide_router_extension.js b/app/assets/javascripts/ide/ide_router_extension.js
new file mode 100644
index 00000000000..a146aca7283
--- /dev/null
+++ b/app/assets/javascripts/ide/ide_router_extension.js
@@ -0,0 +1,21 @@
+import VueRouter from 'vue-router';
+import { escapeFileUrl } from '~/lib/utils/url_utility';
+
+// To allow special characters (like "#," for example) in the branch names, we
+// should encode all the locations before those get processed by History API.
+// Otherwise, paths get messed up so that the router receives incorrect
+// branchid. The only way to do it consistently and in a more or less
+// future-proof manner is, unfortunately, to monkey-patch VueRouter or, as
+// suggested here, achieve the same more reliably by subclassing VueRouter and
+// update the methods, used in WebIDE.
+//
+// More context: https://gitlab.com/gitlab-org/gitlab/issues/35473
+
+export default class IDERouter extends VueRouter {
+ push(location, onComplete, onAbort) {
+ super.push(escapeFileUrl(location), onComplete, onAbort);
+ }
+ resolve(to, current, append) {
+ return super.resolve(escapeFileUrl(to), current, append);
+ }
+}
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 267b49e9d98..1ff4f7bab97 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -194,12 +194,14 @@ export function redirectTo(url) {
return window.location.assign(url);
}
+export const escapeFileUrl = fileUrl => encodeURIComponent(fileUrl).replace(/%2F/g, '/');
+
export function webIDEUrl(route = undefined) {
let returnUrl = `${gon.relative_url_root || ''}/-/ide/`;
if (route) {
returnUrl += `project${route.replace(new RegExp(`^${gon.relative_url_root || ''}`), '')}`;
}
- return returnUrl;
+ return escapeFileUrl(returnUrl);
}
/**
@@ -313,8 +315,6 @@ export const setUrlParams = (params, url = window.location.href, clearParams = f
return urlObj.toString();
};
-export const escapeFileUrl = fileUrl => encodeURIComponent(fileUrl).replace(/%2F/g, '/');
-
export function urlIsDifferent(url, compare = String(window.location)) {
return url !== compare;
}
diff --git a/app/assets/javascripts/pages/projects/graphs/charts/index.js b/app/assets/javascripts/pages/projects/graphs/charts/index.js
index 1b94fb06107..803f4e37705 100644
--- a/app/assets/javascripts/pages/projects/graphs/charts/index.js
+++ b/app/assets/javascripts/pages/projects/graphs/charts/index.js
@@ -1,47 +1,15 @@
-import $ from 'jquery';
-import Chart from 'chart.js';
-import { barChartOptions, pieChartOptions } from '~/lib/utils/chart_utils';
+import Vue from 'vue';
+import { __ } from '~/locale';
+import { GlColumnChart } from '@gitlab/ui/dist/charts';
+import SeriesDataMixin from './series_data_mixin';
document.addEventListener('DOMContentLoaded', () => {
- const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML);
+ const languagesContainer = document.getElementById('js-languages-chart');
+ const monthContainer = document.getElementById('js-month-chart');
+ const weekdayContainer = document.getElementById('js-weekday-chart');
+ const hourContainer = document.getElementById('js-hour-chart');
- const barChart = (selector, data) => {
- // get selector by context
- const ctx = selector.get(0).getContext('2d');
- // pointing parent container to make chart.js inherit its width
- const container = $(selector).parent();
- selector.attr('width', $(container).width());
-
- // Scale fonts if window width lower than 768px (iPad portrait)
- const shouldAdjustFontSize = window.innerWidth < 768;
- return new Chart(ctx, {
- type: 'bar',
- data,
- options: barChartOptions(shouldAdjustFontSize),
- });
- };
-
- const pieChart = (context, data) => {
- const options = pieChartOptions();
-
- return new Chart(context, {
- type: 'pie',
- data,
- options,
- });
- };
-
- const chartData = data => ({
- labels: Object.keys(data),
- datasets: [
- {
- backgroundColor: 'rgba(220,220,220,0.5)',
- borderColor: 'rgba(220,220,220,1)',
- borderWidth: 1,
- data: Object.values(data),
- },
- ],
- });
+ const LANGUAGE_CHART_HEIGHT = 300;
const reorderWeekDays = (weekDays, firstDayOfWeek = 0) => {
if (firstDayOfWeek === 0) {
@@ -58,28 +26,115 @@ document.addEventListener('DOMContentLoaded', () => {
}, {});
};
- const hourData = chartData(projectChartData.hour);
- barChart($('#hour-chart'), hourData);
-
- const weekDays = reorderWeekDays(projectChartData.weekDays, gon.first_day_of_week);
- const dayData = chartData(weekDays);
- barChart($('#weekday-chart'), dayData);
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: languagesContainer,
+ components: {
+ GlColumnChart,
+ },
+ data() {
+ return {
+ chartData: JSON.parse(languagesContainer.dataset.chartData),
+ };
+ },
+ computed: {
+ seriesData() {
+ return { full: this.chartData.map(d => [d.label, d.value]) };
+ },
+ },
+ render(h) {
+ return h(GlColumnChart, {
+ props: {
+ data: this.seriesData,
+ xAxisTitle: __('Used programming language'),
+ yAxisTitle: __('Percentage'),
+ xAxisType: 'category',
+ },
+ attrs: {
+ height: LANGUAGE_CHART_HEIGHT,
+ },
+ });
+ },
+ });
- const monthData = chartData(projectChartData.month);
- barChart($('#month-chart'), monthData);
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: monthContainer,
+ components: {
+ GlColumnChart,
+ },
+ mixins: [SeriesDataMixin],
+ data() {
+ return {
+ chartData: JSON.parse(monthContainer.dataset.chartData),
+ };
+ },
+ render(h) {
+ return h(GlColumnChart, {
+ props: {
+ data: this.seriesData,
+ xAxisTitle: __('Day of month'),
+ yAxisTitle: __('No. of commits'),
+ xAxisType: 'category',
+ },
+ });
+ },
+ });
- const data = {
- datasets: [
- {
- data: projectChartData.languages.map(x => x.value),
- backgroundColor: projectChartData.languages.map(x => x.color),
- hoverBackgroundColor: projectChartData.languages.map(x => x.highlight),
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: weekdayContainer,
+ components: {
+ GlColumnChart,
+ },
+ data() {
+ return {
+ chartData: JSON.parse(weekdayContainer.dataset.chartData),
+ };
+ },
+ computed: {
+ seriesData() {
+ const weekDays = reorderWeekDays(this.chartData, gon.first_day_of_week);
+ const data = Object.keys(weekDays).reduce((acc, key) => {
+ acc.push([key, weekDays[key]]);
+ return acc;
+ }, []);
+ return { full: data };
},
- ],
- labels: projectChartData.languages.map(x => x.label),
- };
- const ctx = $('#languages-chart')
- .get(0)
- .getContext('2d');
- pieChart(ctx, data);
+ },
+ render(h) {
+ return h(GlColumnChart, {
+ props: {
+ data: this.seriesData,
+ xAxisTitle: __('Weekday'),
+ yAxisTitle: __('No. of commits'),
+ xAxisType: 'category',
+ },
+ });
+ },
+ });
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: hourContainer,
+ components: {
+ GlColumnChart,
+ },
+ mixins: [SeriesDataMixin],
+ data() {
+ return {
+ chartData: JSON.parse(hourContainer.dataset.chartData),
+ };
+ },
+ render(h) {
+ return h(GlColumnChart, {
+ props: {
+ data: this.seriesData,
+ xAxisTitle: __('Hour (UTC)'),
+ yAxisTitle: __('No. of commits'),
+ xAxisType: 'category',
+ },
+ });
+ },
+ });
});
diff --git a/app/assets/javascripts/pages/projects/graphs/charts/series_data_mixin.js b/app/assets/javascripts/pages/projects/graphs/charts/series_data_mixin.js
new file mode 100644
index 00000000000..941427a1ac3
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/graphs/charts/series_data_mixin.js
@@ -0,0 +1,11 @@
+export default {
+ computed: {
+ seriesData() {
+ const data = Object.keys(this.chartData).reduce((acc, key) => {
+ acc.push([key, this.chartData[key]]);
+ return acc;
+ }, []);
+ return { full: data };
+ },
+ },
+};