Commit a1f25133 authored by Miguel Rincon's avatar Miguel Rincon Committed by Ezekiel Kigbo

Add "New Panel" link to dashboards

Add a new link to allow users to navigate to the panel preview page.
The new link is added directly in the actions menu.
parent 89cc8d2d
...@@ -11,6 +11,8 @@ import { ...@@ -11,6 +11,8 @@ import {
GlTooltipDirective, GlTooltipDirective,
} from '@gitlab/ui'; } from '@gitlab/ui';
import CustomMetricsFormFields from '~/custom_metrics/components/custom_metrics_form_fields.vue'; import CustomMetricsFormFields from '~/custom_metrics/components/custom_metrics_form_fields.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { PANEL_NEW_PAGE } from '../router/constants';
import DuplicateDashboardModal from './duplicate_dashboard_modal.vue'; import DuplicateDashboardModal from './duplicate_dashboard_modal.vue';
import CreateDashboardModal from './create_dashboard_modal.vue'; import CreateDashboardModal from './create_dashboard_modal.vue';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
...@@ -36,6 +38,7 @@ export default { ...@@ -36,6 +38,7 @@ export default {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
TrackEvent: TrackEventDirective, TrackEvent: TrackEventDirective,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
addingMetricsAvailable: { addingMetricsAvailable: {
type: Boolean, type: Boolean,
...@@ -56,6 +59,10 @@ export default { ...@@ -56,6 +59,10 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
isOotbDashboard: {
type: Boolean,
required: true,
},
}, },
data() { data() {
return { customMetricsFormIsValid: null }; return { customMetricsFormIsValid: null };
...@@ -72,15 +79,22 @@ export default { ...@@ -72,15 +79,22 @@ export default {
}, },
isMenuItemEnabled() { isMenuItemEnabled() {
return { return {
addPanel: !this.isOotbDashboard,
createDashboard: Boolean(this.projectPath), createDashboard: Boolean(this.projectPath),
editDashboard: this.selectedDashboard?.can_edit, editDashboard: this.selectedDashboard?.can_edit,
}; };
}, },
isMenuItemShown() { isMenuItemShown() {
return { return {
addPanel: this.glFeatures.metricsDashboardNewPanelPage,
duplicateDashboard: this.isOutOfTheBoxDashboard, duplicateDashboard: this.isOutOfTheBoxDashboard,
}; };
}, },
newPanelPageLocation() {
// Retains params/query if any
const { params, query } = this.$route ?? {};
return { name: PANEL_NEW_PAGE, params, query };
},
}, },
methods: { methods: {
...mapActions('monitoringDashboard', ['toggleStarredValue']), ...mapActions('monitoringDashboard', ['toggleStarredValue']),
...@@ -117,7 +131,9 @@ export default { ...@@ -117,7 +131,9 @@ export default {
starDashboard: s__('Metrics|Star dashboard'), starDashboard: s__('Metrics|Star dashboard'),
unstarDashboard: s__('Metrics|Unstar dashboard'), unstarDashboard: s__('Metrics|Unstar dashboard'),
addMetric: s__('Metrics|Add metric'), addMetric: s__('Metrics|Add metric'),
editDashboardInfo: s__('Metrics|Duplicate this dashboard to edit dashboard YAML'), addPanel: s__('Metrics|Add panel'),
addPanelInfo: s__('Metrics|Duplicate this dashboard to add panel or edit dashboard YAML.'),
editDashboardInfo: s__('Metrics|Duplicate this dashboard to add panel or edit dashboard YAML.'),
editDashboard: s__('Metrics|Edit dashboard YAML'), editDashboard: s__('Metrics|Edit dashboard YAML'),
createDashboard: s__('Metrics|Create new dashboard'), createDashboard: s__('Metrics|Create new dashboard'),
}, },
...@@ -176,6 +192,32 @@ export default { ...@@ -176,6 +192,32 @@ export default {
</gl-modal> </gl-modal>
</template> </template>
<template v-if="isMenuItemShown.addPanel">
<gl-new-dropdown-item
v-if="isMenuItemEnabled.addPanel"
data-testid="add-panel-item-enabled"
:to="newPanelPageLocation"
>
{{ $options.i18n.addPanel }}
</gl-new-dropdown-item>
<!--
wrapper for tooltip as button can be `disabled`
https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
-->
<div v-else v-gl-tooltip :title="$options.i18n.addPanelInfo">
<gl-new-dropdown-item
:alt="$options.i18n.addPanelInfo"
:to="newPanelPageLocation"
data-testid="add-panel-item-disabled"
disabled
class="gl-cursor-not-allowed"
>
<span class="gl-text-gray-400">{{ $options.i18n.addPanel }}</span>
</gl-new-dropdown-item>
</div>
</template>
<gl-new-dropdown-item <gl-new-dropdown-item
v-if="isMenuItemEnabled.editDashboard" v-if="isMenuItemEnabled.editDashboard"
:href="selectedDashboard ? selectedDashboard.project_blob_path : null" :href="selectedDashboard ? selectedDashboard.project_blob_path : null"
......
...@@ -118,6 +118,9 @@ export default { ...@@ -118,6 +118,9 @@ export default {
shouldShowSettingsButton() { shouldShowSettingsButton() {
return this.canAccessOperationsSettings && this.operationsSettingsPath; return this.canAccessOperationsSettings && this.operationsSettingsPath;
}, },
isOOTBDashboard() {
return this.selectedDashboard?.out_of_the_box_dashboard ?? false;
},
}, },
methods: { methods: {
...mapActions('monitoringDashboard', ['filterEnvironments']), ...mapActions('monitoringDashboard', ['filterEnvironments']),
...@@ -266,6 +269,7 @@ export default { ...@@ -266,6 +269,7 @@ export default {
:custom-metrics-path="customMetricsPath" :custom-metrics-path="customMetricsPath"
:validate-query-path="validateQueryPath" :validate-query-path="validateQueryPath"
:default-branch="defaultBranch" :default-branch="defaultBranch"
:is-ootb-dashboard="isOOTBDashboard"
/> />
</div> </div>
......
...@@ -5,6 +5,7 @@ query getAnnotations( ...@@ -5,6 +5,7 @@ query getAnnotations(
$startingFrom: Time! $startingFrom: Time!
) { ) {
project(fullPath: $projectPath) { project(fullPath: $projectPath) {
id
environments(name: $environmentName) { environments(name: $environmentName) {
nodes { nodes {
id id
......
query getEnvironments($projectPath: ID!, $search: String, $states: [String!]) { query getEnvironments($projectPath: ID!, $search: String, $states: [String!]) {
project(fullPath: $projectPath) { project(fullPath: $projectPath) {
id
data: environments(search: $search, states: $states) { data: environments(search: $search, states: $states) {
environments: nodes { environments: nodes {
name name
......
...@@ -13,12 +13,12 @@ import { DASHBOARD_PAGE, PANEL_NEW_PAGE } from './constants'; ...@@ -13,12 +13,12 @@ import { DASHBOARD_PAGE, PANEL_NEW_PAGE } from './constants';
export default [ export default [
{ {
name: PANEL_NEW_PAGE, name: PANEL_NEW_PAGE,
path: '/:dashboard(.*)?/panel/new', path: '/:dashboard(.+)?/panel/new',
component: PanelNewPage, component: PanelNewPage,
}, },
{ {
name: DASHBOARD_PAGE, name: DASHBOARD_PAGE,
path: '/:dashboard(.*)?', path: '/:dashboard(.+)?',
component: DashboardPage, component: DashboardPage,
}, },
]; ];
...@@ -15,6 +15,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -15,6 +15,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
push_frontend_feature_flag(:prometheus_computed_alerts) push_frontend_feature_flag(:prometheus_computed_alerts)
push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate) push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate)
push_frontend_feature_flag(:alert_runbooks) push_frontend_feature_flag(:alert_runbooks)
push_frontend_feature_flag(:metrics_dashboard_new_panel_page)
end end
before_action :authorize_read_environment!, except: [:metrics, :additional_metrics, :metrics_dashboard, :metrics_redirect] before_action :authorize_read_environment!, except: [:metrics, :additional_metrics, :metrics_dashboard, :metrics_redirect]
before_action :authorize_create_environment!, only: [:new, :create] before_action :authorize_create_environment!, only: [:new, :create]
......
...@@ -11,6 +11,7 @@ module Projects ...@@ -11,6 +11,7 @@ module Projects
push_frontend_feature_flag(:prometheus_computed_alerts) push_frontend_feature_flag(:prometheus_computed_alerts)
push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate) push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate)
push_frontend_feature_flag(:alert_runbooks) push_frontend_feature_flag(:alert_runbooks)
push_frontend_feature_flag(:metrics_dashboard_new_panel_page)
end end
def show def show
......
...@@ -15284,7 +15284,7 @@ msgstr "" ...@@ -15284,7 +15284,7 @@ msgstr ""
msgid "Metrics|Duplicate dashboard" msgid "Metrics|Duplicate dashboard"
msgstr "" msgstr ""
msgid "Metrics|Duplicate this dashboard to edit dashboard YAML" msgid "Metrics|Duplicate this dashboard to add panel or edit dashboard YAML."
msgstr "" msgstr ""
msgid "Metrics|Duplicating..." msgid "Metrics|Duplicating..."
......
...@@ -109,6 +109,7 @@ exports[`Dashboard template matches the default snapshot 1`] = ` ...@@ -109,6 +109,7 @@ exports[`Dashboard template matches the default snapshot 1`] = `
<actions-menu-stub <actions-menu-stub
custommetricspath="/monitoring/monitor-project/prometheus/metrics" custommetricspath="/monitoring/monitor-project/prometheus/metrics"
defaultbranch="master" defaultbranch="master"
isootbdashboard="true"
validatequerypath="/monitoring/monitor-project/prometheus/metrics/validate_query" validatequerypath="/monitoring/monitor-project/prometheus/metrics/validate_query"
/> />
</div> </div>
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlNewDropdownItem } from '@gitlab/ui';
import { createStore } from '~/monitoring/stores'; import { createStore } from '~/monitoring/stores';
import { DASHBOARD_PAGE, PANEL_NEW_PAGE } from '~/monitoring/router/constants';
import { setupAllDashboards, setupStoreWithData } from '../store_utils'; import { setupAllDashboards, setupStoreWithData } from '../store_utils';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
...@@ -21,6 +23,8 @@ describe('Actions menu', () => { ...@@ -21,6 +23,8 @@ describe('Actions menu', () => {
let wrapper; let wrapper;
const findAddMetricItem = () => wrapper.find('[data-testid="add-metric-item"]'); const findAddMetricItem = () => wrapper.find('[data-testid="add-metric-item"]');
const findAddPanelItemEnabled = () => wrapper.find('[data-testid="add-panel-item-enabled"]');
const findAddPanelItemDisabled = () => wrapper.find('[data-testid="add-panel-item-disabled"]');
const findAddMetricModal = () => wrapper.find('[data-testid="add-metric-modal"]'); const findAddMetricModal = () => wrapper.find('[data-testid="add-metric-modal"]');
const findAddMetricModalSubmitButton = () => const findAddMetricModalSubmitButton = () =>
wrapper.find('[data-testid="add-metric-modal-submit-button"]'); wrapper.find('[data-testid="add-metric-modal-submit-button"]');
...@@ -38,6 +42,9 @@ describe('Actions menu', () => { ...@@ -38,6 +42,9 @@ describe('Actions menu', () => {
const createShallowWrapper = (props = {}, options = {}) => { const createShallowWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(ActionsMenu, { wrapper = shallowMount(ActionsMenu, {
propsData: { ...dashboardActionsMenuProps, ...props }, propsData: { ...dashboardActionsMenuProps, ...props },
provide: {
glFeatures: { metricsDashboardNewPanelPage: true },
},
store, store,
...options, ...options,
}); });
...@@ -141,6 +148,54 @@ describe('Actions menu', () => { ...@@ -141,6 +148,54 @@ describe('Actions menu', () => {
}); });
}); });
describe('add panel item', () => {
const GlNewDropdownItemStub = {
extends: GlNewDropdownItem,
props: {
to: [String, Object],
},
};
let $route;
beforeEach(() => {
$route = { name: DASHBOARD_PAGE, params: { dashboard: 'my_dashboard.yml' } };
createShallowWrapper(
{
isOotbDashboard: false,
},
{
mocks: { $route },
stubs: { GlNewDropdownItem: GlNewDropdownItemStub },
},
);
});
it('is disabled for ootb dashboards', () => {
createShallowWrapper({
isOotbDashboard: true,
});
return wrapper.vm.$nextTick(() => {
expect(findAddPanelItemDisabled().exists()).toBe(true);
});
});
it('is visible for custom dashboards', () => {
expect(findAddPanelItemEnabled().exists()).toBe(true);
});
it('renders a link to the new panel page for custom dashboards', () => {
expect(findAddPanelItemEnabled().props('to')).toEqual({
name: PANEL_NEW_PAGE,
params: {
dashboard: 'my_dashboard.yml',
},
});
});
});
describe('edit dashboard yml item', () => { describe('edit dashboard yml item', () => {
beforeEach(() => { beforeEach(() => {
createShallowWrapper(); createShallowWrapper();
......
...@@ -628,4 +628,5 @@ export const dashboardActionsMenuProps = { ...@@ -628,4 +628,5 @@ export const dashboardActionsMenuProps = {
addingMetricsAvailable: true, addingMetricsAvailable: true,
customMetricsPath: 'https://path/to/customMetrics', customMetricsPath: 'https://path/to/customMetrics',
validateQueryPath: 'https://path/to/validateQuery', validateQueryPath: 'https://path/to/validateQuery',
isOotbDashboard: true,
}; };
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