Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-30 03:07:52 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-30 03:07:52 +0300
commit4c016ad02422709d3a341215952a9b1cdb4a8451 (patch)
tree599e58df9e1f8987a9f9400b0abf61612e4e125a /app
parentcb3e6b9c1b020378b5f94b4c38319a2dc961de01 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/grafana_integration/components/grafana_integration.vue82
-rw-r--r--app/assets/javascripts/grafana_integration/index.js15
-rw-r--r--app/assets/javascripts/grafana_integration/store/actions.js38
-rw-r--r--app/assets/javascripts/grafana_integration/store/index.js16
-rw-r--r--app/assets/javascripts/grafana_integration/store/mutation_types.js2
-rw-r--r--app/assets/javascripts/grafana_integration/store/mutations.js10
-rw-r--r--app/assets/javascripts/grafana_integration/store/state.js5
-rw-r--r--app/assets/javascripts/pages/projects/settings/operations/show/index.js4
-rw-r--r--app/assets/javascripts/pages/sessions/new/index.js7
-rw-r--r--app/models/analytics/cycle_analytics/project_stage.rb8
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stage.rb6
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml10
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml4
-rw-r--r--app/views/projects/deployments/_confirm_rollback_modal.html.haml2
-rw-r--r--app/views/projects/settings/operations/_grafana_integration.html.haml2
-rw-r--r--app/views/projects/settings/operations/show.html.haml1
16 files changed, 206 insertions, 6 deletions
diff --git a/app/assets/javascripts/grafana_integration/components/grafana_integration.vue b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
new file mode 100644
index 00000000000..2d3212429db
--- /dev/null
+++ b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
@@ -0,0 +1,82 @@
+<script>
+import { GlButton, GlFormGroup, GlFormInput, GlLink } from '@gitlab/ui';
+import Icon from '~/vue_shared/components/icon.vue';
+import { mapState, mapActions } from 'vuex';
+
+export default {
+ components: {
+ GlButton,
+ GlFormGroup,
+ GlFormInput,
+ GlLink,
+ Icon,
+ },
+ data() {
+ return { placeholderUrl: 'https://my-url.grafana.net/my-dashboard' };
+ },
+ computed: {
+ ...mapState(['operationsSettingsEndpoint', 'grafanaToken', 'grafanaUrl']),
+ localGrafanaToken: {
+ get() {
+ return this.grafanaToken;
+ },
+ set(token) {
+ this.setGrafanaToken(token);
+ },
+ },
+ localGrafanaUrl: {
+ get() {
+ return this.grafanaUrl;
+ },
+ set(url) {
+ this.setGrafanaUrl(url);
+ },
+ },
+ },
+ methods: {
+ ...mapActions(['setGrafanaUrl', 'setGrafanaToken', 'updateGrafanaIntegration']),
+ },
+};
+</script>
+
+<template>
+ <section id="grafana" class="settings no-animate js-grafana-integration">
+ <div class="settings-header">
+ <h4 class="js-section-header">
+ {{ s__('GrafanaIntegration|Grafana Authentication') }}
+ </h4>
+ <gl-button class="js-settings-toggle">{{ __('Expand') }}</gl-button>
+ <p class="js-section-sub-header">
+ {{ s__('GrafanaIntegration|Embed Grafana charts in GitLab issues.') }}
+ </p>
+ </div>
+ <div class="settings-content">
+ <form>
+ <gl-form-group
+ :label="s__('GrafanaIntegration|Grafana URL')"
+ label-for="grafana-url"
+ :description="s__('GrafanaIntegration|Enter the base URL of the Grafana instance.')"
+ >
+ <gl-form-input id="grafana-url" v-model="localGrafanaUrl" :placeholder="placeholderUrl" />
+ </gl-form-group>
+ <gl-form-group :label="s__('GrafanaIntegration|API Token')" label-for="grafana-token">
+ <gl-form-input id="grafana-token" v-model="localGrafanaToken" />
+ <p class="form-text text-muted">
+ {{ s__('GrafanaIntegration|Enter the Grafana API Token.') }}
+ <a
+ href="https://grafana.com/docs/http_api/auth/#create-api-token"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ {{ __('More information') }}
+ <icon name="external-link" class="vertical-align-middle" />
+ </a>
+ </p>
+ </gl-form-group>
+ <gl-button variant="success" @click="updateGrafanaIntegration">
+ {{ __('Save Changes') }}
+ </gl-button>
+ </form>
+ </div>
+ </section>
+</template>
diff --git a/app/assets/javascripts/grafana_integration/index.js b/app/assets/javascripts/grafana_integration/index.js
new file mode 100644
index 00000000000..58c28e09f80
--- /dev/null
+++ b/app/assets/javascripts/grafana_integration/index.js
@@ -0,0 +1,15 @@
+import Vue from 'vue';
+import store from './store';
+import GrafanaIntegration from './components/grafana_integration.vue';
+
+export default () => {
+ const el = document.querySelector('.js-grafana-integration');
+
+ return new Vue({
+ el,
+ store: store(el.dataset),
+ render(createElement) {
+ return createElement(GrafanaIntegration);
+ },
+ });
+};
diff --git a/app/assets/javascripts/grafana_integration/store/actions.js b/app/assets/javascripts/grafana_integration/store/actions.js
new file mode 100644
index 00000000000..98085fdcb2d
--- /dev/null
+++ b/app/assets/javascripts/grafana_integration/store/actions.js
@@ -0,0 +1,38 @@
+import axios from '~/lib/utils/axios_utils';
+import { __ } from '~/locale';
+import createFlash from '~/flash';
+import { refreshCurrentPage } from '~/lib/utils/url_utility';
+import * as mutationTypes from './mutation_types';
+
+export const setGrafanaUrl = ({ commit }, url) => commit(mutationTypes.SET_GRAFANA_URL, url);
+
+export const setGrafanaToken = ({ commit }, token) =>
+ commit(mutationTypes.SET_GRAFANA_TOKEN, token);
+
+export const updateGrafanaIntegration = ({ state, dispatch }) =>
+ axios
+ .patch(state.operationsSettingsEndpoint, {
+ project: {
+ grafana_integration_attributes: {
+ grafana_url: state.grafanaUrl,
+ token: state.grafanaToken,
+ },
+ },
+ })
+ .then(() => dispatch('receiveGrafanaIntegrationUpdateSuccess'))
+ .catch(error => dispatch('receiveGrafanaIntegrationUpdateError', error));
+
+export const receiveGrafanaIntegrationUpdateSuccess = () => {
+ /**
+ * The operations_controller currently handles successful requests
+ * by creating a flash banner messsage to notify the user.
+ */
+ refreshCurrentPage();
+};
+
+export const receiveGrafanaIntegrationUpdateError = (_, error) => {
+ const { response } = error;
+ const message = response.data && response.data.message ? response.data.message : '';
+
+ createFlash(`${__('There was an error saving your changes.')} ${message}`, 'alert');
+};
diff --git a/app/assets/javascripts/grafana_integration/store/index.js b/app/assets/javascripts/grafana_integration/store/index.js
new file mode 100644
index 00000000000..e96bb1e8aad
--- /dev/null
+++ b/app/assets/javascripts/grafana_integration/store/index.js
@@ -0,0 +1,16 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import createState from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+Vue.use(Vuex);
+
+export const createStore = initialState =>
+ new Vuex.Store({
+ state: createState(initialState),
+ actions,
+ mutations,
+ });
+
+export default createStore;
diff --git a/app/assets/javascripts/grafana_integration/store/mutation_types.js b/app/assets/javascripts/grafana_integration/store/mutation_types.js
new file mode 100644
index 00000000000..33ce3228823
--- /dev/null
+++ b/app/assets/javascripts/grafana_integration/store/mutation_types.js
@@ -0,0 +1,2 @@
+export const SET_GRAFANA_URL = 'SET_GRAFANA_URL';
+export const SET_GRAFANA_TOKEN = 'SET_GRAFANA_TOKEN';
diff --git a/app/assets/javascripts/grafana_integration/store/mutations.js b/app/assets/javascripts/grafana_integration/store/mutations.js
new file mode 100644
index 00000000000..e8d63a9a732
--- /dev/null
+++ b/app/assets/javascripts/grafana_integration/store/mutations.js
@@ -0,0 +1,10 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.SET_GRAFANA_URL](state, url) {
+ state.grafanaUrl = url;
+ },
+ [types.SET_GRAFANA_TOKEN](state, token) {
+ state.grafanaToken = token;
+ },
+};
diff --git a/app/assets/javascripts/grafana_integration/store/state.js b/app/assets/javascripts/grafana_integration/store/state.js
new file mode 100644
index 00000000000..c25742c82bc
--- /dev/null
+++ b/app/assets/javascripts/grafana_integration/store/state.js
@@ -0,0 +1,5 @@
+export default (initialState = {}) => ({
+ operationsSettingsEndpoint: initialState.operationsSettingsEndpoint,
+ grafanaToken: initialState.grafanaIntegrationToken || '',
+ grafanaUrl: initialState.grafanaIntegrationUrl || '',
+});
diff --git a/app/assets/javascripts/pages/projects/settings/operations/show/index.js b/app/assets/javascripts/pages/projects/settings/operations/show/index.js
index 98e19705976..7037933bc5a 100644
--- a/app/assets/javascripts/pages/projects/settings/operations/show/index.js
+++ b/app/assets/javascripts/pages/projects/settings/operations/show/index.js
@@ -1,9 +1,13 @@
import mountErrorTrackingForm from '~/error_tracking_settings';
import mountOperationSettings from '~/operation_settings';
+import mountGrafanaIntegration from '~/grafana_integration';
import initSettingsPanels from '~/settings_panels';
document.addEventListener('DOMContentLoaded', () => {
mountErrorTrackingForm();
mountOperationSettings();
+ if (gon.features.gfmGrafanaIntegration) {
+ mountGrafanaIntegration();
+ }
initSettingsPanels();
});
diff --git a/app/assets/javascripts/pages/sessions/new/index.js b/app/assets/javascripts/pages/sessions/new/index.js
index c0e798e004f..66ee2d9303f 100644
--- a/app/assets/javascripts/pages/sessions/new/index.js
+++ b/app/assets/javascripts/pages/sessions/new/index.js
@@ -20,12 +20,17 @@ document.addEventListener('DOMContentLoaded', () => {
// Save the URL fragment from the current window location. This will be present if the user was
// redirected to sign-in after attempting to access a protected URL that included a fragment.
preserveUrlFragment(window.location.hash);
+});
+export default function trackData() {
if (gon.tracking_data) {
const tab = document.querySelector(".new-session-tabs a[href='#register-pane']");
const { category, action, ...data } = gon.tracking_data;
+
tab.addEventListener('click', () => {
Tracking.event(category, action, data);
});
}
-});
+}
+
+trackData();
diff --git a/app/models/analytics/cycle_analytics/project_stage.rb b/app/models/analytics/cycle_analytics/project_stage.rb
index 23f0db0829b..0cdf199a146 100644
--- a/app/models/analytics/cycle_analytics/project_stage.rb
+++ b/app/models/analytics/cycle_analytics/project_stage.rb
@@ -10,6 +10,14 @@ module Analytics
alias_attribute :parent, :project
alias_attribute :parent_id, :project_id
+
+ def self.relative_positioning_query_base(stage)
+ where(project_id: stage.project_id)
+ end
+
+ def self.relative_positioning_parent_column
+ :project_id
+ end
end
end
end
diff --git a/app/models/concerns/analytics/cycle_analytics/stage.rb b/app/models/concerns/analytics/cycle_analytics/stage.rb
index 54e9a13d1ea..1376dd97a49 100644
--- a/app/models/concerns/analytics/cycle_analytics/stage.rb
+++ b/app/models/concerns/analytics/cycle_analytics/stage.rb
@@ -4,6 +4,7 @@ module Analytics
module CycleAnalytics
module Stage
extend ActiveSupport::Concern
+ include RelativePositioning
included do
validates :name, presence: true
@@ -17,6 +18,7 @@ module Analytics
alias_attribute :custom_stage?, :custom
scope :default_stages, -> { where(custom: false) }
+ scope :ordered, -> { order(:relative_position, :id) }
end
def parent=(_)
@@ -58,6 +60,10 @@ module Analytics
end_event_identifier.to_s.eql?(stage_params[:end_event_identifier].to_s)
end
+ def find_with_same_parent!(id)
+ parent.cycle_analytics_stages.find(id)
+ end
+
private
def validate_stage_event_pairs
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index 4930c6cf5f7..a6d2c894185 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -16,13 +16,19 @@
.nav-icon-container
= sprite_icon('home')
%span.nav-item-name
- = _('Overview')
+ - if @group.subgroup?
+ = _('Subgroup overview')
+ - else
+ = _('Group overview')
%ul.sidebar-sub-level-items
= nav_link(path: ['groups#show', 'groups#details', 'groups#activity', 'groups#subgroups'], html_options: { class: "fly-out-top-item" } ) do
= link_to group_path(@group) do
%strong.fly-out-top-item-name
- = _('Overview')
+ - if @group.subgroup?
+ = _('Subgroup overview')
+ - else
+ = _('Group overview')
%li.divider.fly-out-top-item
= nav_link(path: ['groups#show', 'groups#details', 'groups#subgroups'], html_options: { class: 'home' }) do
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 247fbfefde9..fdad2a64a80 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -13,13 +13,13 @@
.nav-icon-container
= sprite_icon('home')
%span.nav-item-name
- = _('Project')
+ = _('Project overview')
%ul.sidebar-sub-level-items
= nav_link(path: 'projects#show', html_options: { class: "fly-out-top-item" } ) do
= link_to project_path(@project) do
%strong.fly-out-top-item-name
- = _('Project')
+ = _('Project overview')
%li.divider.fly-out-top-item
= nav_link(path: 'projects#show') do
= link_to project_path(@project), title: _('Project details'), class: 'shortcuts-project' do
diff --git a/app/views/projects/deployments/_confirm_rollback_modal.html.haml b/app/views/projects/deployments/_confirm_rollback_modal.html.haml
index ff40e404e5f..9162827b501 100644
--- a/app/views/projects/deployments/_confirm_rollback_modal.html.haml
+++ b/app/views/projects/deployments/_confirm_rollback_modal.html.haml
@@ -13,7 +13,7 @@
%p= s_('Environments|This action will relaunch the job for commit %{commit_id}, putting the environment in a previous version. Are you sure you want to continue?').html_safe % {commit_id: commit_sha}
- else
%p
- = s_('Environments|This action will run the job defined by staging for commit %{commit_id}, putting the environment in a previous version. You can revert it by re-deploying the latest version of your application. Are you sure you want to continue?').html_safe % {commit_id: commit_sha}
+ = s_('Environments|This action will run the job defined by %{environment_name} for commit %{commit_id}, putting the environment in a previous version. You can revert it by re-deploying the latest version of your application. Are you sure you want to continue?').html_safe % {commit_id: commit_sha, environment_name: @environment.name}
.modal-footer
= button_tag _('Cancel'), type: 'button', class: 'btn btn-cancel', data: { dismiss: 'modal' }
= link_to [:retry, @project.namespace.becomes(Namespace), @project, deployment.deployable], method: :post, class: 'btn btn-danger' do
diff --git a/app/views/projects/settings/operations/_grafana_integration.html.haml b/app/views/projects/settings/operations/_grafana_integration.html.haml
new file mode 100644
index 00000000000..ae90b6dd5aa
--- /dev/null
+++ b/app/views/projects/settings/operations/_grafana_integration.html.haml
@@ -0,0 +1,2 @@
+.js-grafana-integration{ data: { operations_settings_endpoint: project_settings_operations_path(@project),
+ grafana_integration: { url: grafana_integration_url, token: grafana_integration_token } } }
diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml
index 0a7a155bc12..3c955e5f558 100644
--- a/app/views/projects/settings/operations/show.html.haml
+++ b/app/views/projects/settings/operations/show.html.haml
@@ -5,4 +5,5 @@
= render_if_exists 'projects/settings/operations/incidents'
= render 'projects/settings/operations/error_tracking'
= render 'projects/settings/operations/external_dashboard'
+= render 'projects/settings/operations/grafana_integration'
= render_if_exists 'projects/settings/operations/tracing'