Commit 6f5a070d authored by Phil Hughes's avatar Phil Hughes

Merge branch 'extend-dashboard-fixture' into 'master'

Expand the dashboard fixture to include metrics data

See merge request gitlab-org/gitlab!35323
parents 56e102a2 e015edfc
...@@ -353,7 +353,10 @@ export default { ...@@ -353,7 +353,10 @@ export default {
</gl-deprecated-button> </gl-deprecated-button>
</div> </div>
<div v-if="externalDashboardUrl.length" class="mb-2 mr-2 d-flex d-sm-block"> <div
v-if="externalDashboardUrl && externalDashboardUrl.length"
class="mb-2 mr-2 d-flex d-sm-block"
>
<gl-deprecated-button <gl-deprecated-button
class="flex-grow-1 js-external-dashboard-link" class="flex-grow-1 js-external-dashboard-link"
variant="primary" variant="primary"
......
import Vue from 'vue'; import Vue from 'vue';
import { GlToast } from '@gitlab/ui'; import { GlToast } from '@gitlab/ui';
import { parseBoolean } from '~/lib/utils/common_utils';
import { getParameterValues } from '~/lib/utils/url_utility'; import { getParameterValues } from '~/lib/utils/url_utility';
import { createStore } from './stores'; import { createStore } from './stores';
import createRouter from './router'; import createRouter from './router';
import { stateAndPropsFromDataset } from './utils';
Vue.use(GlToast); Vue.use(GlToast);
...@@ -12,37 +12,10 @@ export default (props = {}) => { ...@@ -12,37 +12,10 @@ export default (props = {}) => {
if (el && el.dataset) { if (el && el.dataset) {
const [currentDashboard] = getParameterValues('dashboard'); const [currentDashboard] = getParameterValues('dashboard');
const { metricsDashboardBasePath, ...dataset } = el.dataset;
const { const { initState, dataProps } = stateAndPropsFromDataset({ currentDashboard, ...dataset });
deploymentsEndpoint, const store = createStore(initState);
dashboardEndpoint,
dashboardsEndpoint,
projectPath,
logsPath,
currentEnvironmentName,
dashboardTimezone,
metricsDashboardBasePath,
customDashboardBasePath,
...dataProps
} = el.dataset;
const store = createStore({
currentDashboard,
deploymentsEndpoint,
dashboardEndpoint,
dashboardsEndpoint,
dashboardTimezone,
projectPath,
logsPath,
currentEnvironmentName,
customDashboardBasePath,
});
// HTML attributes are always strings, parse other types.
dataProps.hasMetrics = parseBoolean(dataProps.hasMetrics);
dataProps.customMetricsAvailable = parseBoolean(dataProps.customMetricsAvailable);
dataProps.prometheusAlertsAvailable = parseBoolean(dataProps.prometheusAlertsAvailable);
const router = createRouter(metricsDashboardBasePath); const router = createRouter(metricsDashboardBasePath);
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
......
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
removeParams, removeParams,
updateHistory, updateHistory,
} from '~/lib/utils/url_utility'; } from '~/lib/utils/url_utility';
import { parseBoolean } from '~/lib/utils/common_utils';
import { import {
timeRangeParamNames, timeRangeParamNames,
timeRangeFromParams, timeRangeFromParams,
...@@ -12,6 +13,46 @@ import { ...@@ -12,6 +13,46 @@ import {
} from '~/lib/utils/datetime_range'; } from '~/lib/utils/datetime_range';
import { VARIABLE_PREFIX } from './constants'; import { VARIABLE_PREFIX } from './constants';
/**
* Extracts the initial state and props from HTML dataset
* and places them in separate objects to setup bundle.
* @param {*} dataset
*/
export const stateAndPropsFromDataset = (dataset = {}) => {
const {
currentDashboard,
deploymentsEndpoint,
dashboardEndpoint,
dashboardsEndpoint,
dashboardTimezone,
projectPath,
logsPath,
currentEnvironmentName,
customDashboardBasePath,
...dataProps
} = dataset;
// HTML attributes are always strings, parse other types.
dataProps.hasMetrics = parseBoolean(dataProps.hasMetrics);
dataProps.customMetricsAvailable = parseBoolean(dataProps.customMetricsAvailable);
dataProps.prometheusAlertsAvailable = parseBoolean(dataProps.prometheusAlertsAvailable);
return {
initState: {
currentDashboard,
deploymentsEndpoint,
dashboardEndpoint,
dashboardsEndpoint,
dashboardTimezone,
projectPath,
logsPath,
currentEnvironmentName,
customDashboardBasePath,
},
dataProps,
};
};
/** /**
* List of non time range url parameters * List of non time range url parameters
* This will be removed once we add support for free text variables * This will be removed once we add support for free text variables
......
...@@ -6,10 +6,11 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do ...@@ -6,10 +6,11 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers include JavaScriptFixturesHelpers
include MetricsDashboardHelpers include MetricsDashboardHelpers
let(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:project) { project_with_dashboard('.gitlab/dashboards/test.yml') } let_it_be(:namespace) { create(:namespace, name: 'monitoring' )}
let(:environment) { create(:environment, project: project) } let_it_be(:project) { project_with_dashboard_namespace('.gitlab/dashboards/test.yml', namespace: namespace) }
let(:params) { { environment: environment } } let_it_be(:environment) { create(:environment, id: 1, project: project) }
let_it_be(:params) { { environment: environment } }
before(:all) do before(:all) do
clean_frontend_fixtures('metrics_dashboard/') clean_frontend_fixtures('metrics_dashboard/')
...@@ -24,6 +25,7 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do ...@@ -24,6 +25,7 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
project.add_maintainer(user) project.add_maintainer(user)
allow(controller).to receive(:project).and_return(project) allow(controller).to receive(:project).and_return(project)
allow(controller).to receive(:environment).and_return(environment)
allow(controller) allow(controller)
.to receive(:metrics_dashboard_params) .to receive(:metrics_dashboard_params)
.and_return(params) .and_return(params)
...@@ -35,7 +37,9 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do ...@@ -35,7 +37,9 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
it 'metrics_dashboard/environment_metrics_dashboard.json' do it 'metrics_dashboard/environment_metrics_dashboard.json' do
routes.draw { get "metrics_dashboard" => "anonymous#metrics_dashboard" } routes.draw { get "metrics_dashboard" => "anonymous#metrics_dashboard" }
response = get :metrics_dashboard, format: :json response = get :metrics_dashboard, format: :json
expect(response).to be_successful expect(response).to be_successful
end end
end end
...@@ -4,6 +4,10 @@ exports[`Dashboard template matches the default snapshot 1`] = ` ...@@ -4,6 +4,10 @@ exports[`Dashboard template matches the default snapshot 1`] = `
<div <div
class="prometheus-graphs" class="prometheus-graphs"
data-qa-selector="prometheus_graphs" data-qa-selector="prometheus_graphs"
environmentstate="available"
metricsdashboardbasepath="/monitoring/monitor-project/-/environments/1/metrics"
metricsendpoint="/monitoring/monitor-project/-/environments/1/additional_metrics.json"
prometheusstatus=""
> >
<div <div
class="prometheus-graphs-header d-sm-flex flex-sm-wrap pt-2 pr-1 pb-0 pl-2 border-bottom bg-gray-light" class="prometheus-graphs-header d-sm-flex flex-sm-wrap pt-2 pr-1 pb-0 pl-2 border-bottom bg-gray-light"
...@@ -135,15 +139,15 @@ exports[`Dashboard template matches the default snapshot 1`] = ` ...@@ -135,15 +139,15 @@ exports[`Dashboard template matches the default snapshot 1`] = `
<!----> <!---->
<empty-state-stub <empty-state-stub
clusterspath="/path/to/clusters" clusterspath="/monitoring/monitor-project/-/clusters"
documentationpath="/path/to/docs" documentationpath="/help/administration/monitoring/prometheus/index.md"
emptygettingstartedsvgpath="/path/to/getting-started.svg" emptygettingstartedsvgpath="/images/illustrations/monitoring/getting_started.svg"
emptyloadingsvgpath="/path/to/loading.svg" emptyloadingsvgpath="/images/illustrations/monitoring/loading.svg"
emptynodatasmallsvgpath="/path/to/no-data-small.svg" emptynodatasmallsvgpath="/images/illustrations/chart-empty-state-small.svg"
emptynodatasvgpath="/path/to/no-data.svg" emptynodatasvgpath="/images/illustrations/monitoring/no_data.svg"
emptyunabletoconnectsvgpath="/path/to/unable-to-connect.svg" emptyunabletoconnectsvgpath="/images/illustrations/monitoring/unable_to_connect.svg"
selectedstate="gettingStarted" selectedstate="gettingStarted"
settingspath="/path/to/settings" settingspath="/monitoring/monitor-project/-/services/prometheus/edit"
/> />
</div> </div>
`; `;
...@@ -18,8 +18,8 @@ import { ...@@ -18,8 +18,8 @@ import {
singleStatMetricsResult, singleStatMetricsResult,
graphDataPrometheusQueryRangeMultiTrack, graphDataPrometheusQueryRangeMultiTrack,
barMockData, barMockData,
propsData,
} from '../mock_data'; } from '../mock_data';
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
import { panelTypes } from '~/monitoring/constants'; import { panelTypes } from '~/monitoring/constants';
...@@ -32,7 +32,6 @@ import MonitorColumnChart from '~/monitoring/components/charts/column.vue'; ...@@ -32,7 +32,6 @@ import MonitorColumnChart from '~/monitoring/components/charts/column.vue';
import MonitorBarChart from '~/monitoring/components/charts/bar.vue'; import MonitorBarChart from '~/monitoring/components/charts/bar.vue';
import MonitorStackedColumnChart from '~/monitoring/components/charts/stacked_column.vue'; import MonitorStackedColumnChart from '~/monitoring/components/charts/stacked_column.vue';
import { graphData, graphDataEmpty } from '../fixture_data';
import { createStore, monitoringDashboard } from '~/monitoring/stores'; import { createStore, monitoringDashboard } from '~/monitoring/stores';
import { createStore as createEmbedGroupStore } from '~/monitoring/stores/embed_group'; import { createStore as createEmbedGroupStore } from '~/monitoring/stores/embed_group';
...@@ -63,7 +62,7 @@ describe('Dashboard Panel', () => { ...@@ -63,7 +62,7 @@ describe('Dashboard Panel', () => {
wrapper = shallowMount(DashboardPanel, { wrapper = shallowMount(DashboardPanel, {
propsData: { propsData: {
graphData, graphData,
settingsPath: propsData.settingsPath, settingsPath: dashboardProps.settingsPath,
...props, ...props,
}, },
store, store,
...@@ -316,7 +315,7 @@ describe('Dashboard Panel', () => { ...@@ -316,7 +315,7 @@ describe('Dashboard Panel', () => {
return wrapper.vm.$nextTick(() => { return wrapper.vm.$nextTick(() => {
expect(findEditCustomMetricLink().text()).toBe('Edit metrics'); expect(findEditCustomMetricLink().text()).toBe('Edit metrics');
expect(findEditCustomMetricLink().attributes('href')).toBe(propsData.settingsPath); expect(findEditCustomMetricLink().attributes('href')).toBe(dashboardProps.settingsPath);
}); });
}); });
}); });
...@@ -433,7 +432,7 @@ describe('Dashboard Panel', () => { ...@@ -433,7 +432,7 @@ describe('Dashboard Panel', () => {
wrapper = shallowMount(DashboardPanel, { wrapper = shallowMount(DashboardPanel, {
propsData: { propsData: {
clipboardText: exampleText, clipboardText: exampleText,
settingsPath: propsData.settingsPath, settingsPath: dashboardProps.settingsPath,
graphData: { graphData: {
y_label: 'metric', y_label: 'metric',
...graphData, ...graphData,
...@@ -483,7 +482,7 @@ describe('Dashboard Panel', () => { ...@@ -483,7 +482,7 @@ describe('Dashboard Panel', () => {
wrapper = shallowMount(DashboardPanel, { wrapper = shallowMount(DashboardPanel, {
propsData: { propsData: {
graphData, graphData,
settingsPath: propsData.settingsPath, settingsPath: dashboardProps.settingsPath,
namespace: mockNamespace, namespace: mockNamespace,
}, },
store, store,
......
...@@ -29,8 +29,12 @@ import { ...@@ -29,8 +29,12 @@ import {
setupStoreWithVariable, setupStoreWithVariable,
setupStoreWithLinks, setupStoreWithLinks,
} from '../store_utils'; } from '../store_utils';
import { environmentData, dashboardGitResponse, propsData } from '../mock_data'; import { environmentData, dashboardGitResponse } from '../mock_data';
import { metricsDashboardViewModel, metricsDashboardPanelCount } from '../fixture_data'; import {
metricsDashboardViewModel,
metricsDashboardPanelCount,
dashboardProps,
} from '../fixture_data';
import createFlash from '~/flash'; import createFlash from '~/flash';
jest.mock('~/flash'); jest.mock('~/flash');
...@@ -50,7 +54,7 @@ describe('Dashboard', () => { ...@@ -50,7 +54,7 @@ describe('Dashboard', () => {
const createShallowWrapper = (props = {}, options = {}) => { const createShallowWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(Dashboard, { wrapper = shallowMount(Dashboard, {
propsData: { ...propsData, ...props }, propsData: { ...dashboardProps, ...props },
store, store,
stubs: { stubs: {
DashboardHeader, DashboardHeader,
...@@ -61,7 +65,7 @@ describe('Dashboard', () => { ...@@ -61,7 +65,7 @@ describe('Dashboard', () => {
const createMountedWrapper = (props = {}, options = {}) => { const createMountedWrapper = (props = {}, options = {}) => {
wrapper = mount(Dashboard, { wrapper = mount(Dashboard, {
propsData: { ...propsData, ...props }, propsData: { ...dashboardProps, ...props },
store, store,
stubs: { stubs: {
'graph-group': true, 'graph-group': true,
......
...@@ -5,7 +5,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue'; ...@@ -5,7 +5,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue';
import DashboardHeader from '~/monitoring/components/dashboard_header.vue'; import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
import { createStore } from '~/monitoring/stores'; import { createStore } from '~/monitoring/stores';
import { setupAllDashboards } from '../store_utils'; import { setupAllDashboards } from '../store_utils';
import { propsData } from '../mock_data'; import { dashboardProps } from '../fixture_data';
jest.mock('~/lib/utils/url_utility'); jest.mock('~/lib/utils/url_utility');
...@@ -29,7 +29,7 @@ describe('Dashboard template', () => { ...@@ -29,7 +29,7 @@ describe('Dashboard template', () => {
it('matches the default snapshot', () => { it('matches the default snapshot', () => {
wrapper = shallowMount(Dashboard, { wrapper = shallowMount(Dashboard, {
propsData: { ...propsData }, propsData: { ...dashboardProps },
store, store,
stubs: { stubs: {
DashboardHeader, DashboardHeader,
......
...@@ -9,7 +9,8 @@ import { ...@@ -9,7 +9,8 @@ import {
updateHistory, updateHistory,
} from '~/lib/utils/url_utility'; } from '~/lib/utils/url_utility';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { mockProjectDir, propsData } from '../mock_data'; import { mockProjectDir } from '../mock_data';
import { dashboardProps } from '../fixture_data';
import Dashboard from '~/monitoring/components/dashboard.vue'; import Dashboard from '~/monitoring/components/dashboard.vue';
import DashboardHeader from '~/monitoring/components/dashboard_header.vue'; import DashboardHeader from '~/monitoring/components/dashboard_header.vue';
...@@ -26,7 +27,7 @@ describe('dashboard invalid url parameters', () => { ...@@ -26,7 +27,7 @@ describe('dashboard invalid url parameters', () => {
const createMountedWrapper = (props = { hasMetrics: true }, options = {}) => { const createMountedWrapper = (props = { hasMetrics: true }, options = {}) => {
wrapper = mount(Dashboard, { wrapper = mount(Dashboard, {
propsData: { ...propsData, ...props }, propsData: { ...dashboardProps, ...props },
store, store,
stubs: { 'graph-group': true, 'dashboard-panel': true, 'dashboard-header': DashboardHeader }, stubs: { 'graph-group': true, 'dashboard-panel': true, 'dashboard-header': DashboardHeader },
...options, ...options,
......
import { stateAndPropsFromDataset } from '~/monitoring/utils';
import { mapToDashboardViewModel } from '~/monitoring/stores/utils'; import { mapToDashboardViewModel } from '~/monitoring/stores/utils';
import { metricStates } from '~/monitoring/constants'; import { metricStates } from '~/monitoring/constants';
import { convertObjectProps } from '~/lib/utils/common_utils';
import { convertToCamelCase } from '~/lib/utils/text_utility';
import { metricsResult } from './mock_data'; import { metricsResult } from './mock_data';
...@@ -8,6 +11,19 @@ export const metricsDashboardResponse = getJSONFixture( ...@@ -8,6 +11,19 @@ export const metricsDashboardResponse = getJSONFixture(
'metrics_dashboard/environment_metrics_dashboard.json', 'metrics_dashboard/environment_metrics_dashboard.json',
); );
export const metricsDashboardPayload = metricsDashboardResponse.dashboard; export const metricsDashboardPayload = metricsDashboardResponse.dashboard;
const datasetState = stateAndPropsFromDataset(
// It's preferable to have props in snake_case, this will be addressed at:
// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33574
convertObjectProps(
// Some props use kebab-case, convert to snake_case first
key => convertToCamelCase(key.replace(/-/g, '_')),
metricsDashboardResponse.metrics_data,
),
);
export const dashboardProps = datasetState.dataProps;
export const metricsDashboardViewModel = mapToDashboardViewModel(metricsDashboardPayload); export const metricsDashboardViewModel = mapToDashboardViewModel(metricsDashboardPayload);
export const metricsDashboardPanelCount = 22; export const metricsDashboardPanelCount = 22;
......
...@@ -11,8 +11,8 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -11,8 +11,8 @@ import MockAdapter from 'axios-mock-adapter';
import Dashboard from '~/monitoring/components/dashboard.vue'; import Dashboard from '~/monitoring/components/dashboard.vue';
import { createStore } from '~/monitoring/stores'; import { createStore } from '~/monitoring/stores';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { mockApiEndpoint, propsData } from '../mock_data'; import { mockApiEndpoint } from '../mock_data';
import { metricsDashboardPayload } from '../fixture_data'; import { metricsDashboardPayload, dashboardProps } from '../fixture_data';
import { setupStoreWithData } from '../store_utils'; import { setupStoreWithData } from '../store_utils';
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -56,7 +56,7 @@ describe('Dashboard', () => { ...@@ -56,7 +56,7 @@ describe('Dashboard', () => {
component = new DashboardComponent({ component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'), el: document.querySelector('.prometheus-graphs'),
propsData: { propsData: {
...propsData, ...dashboardProps,
hasMetrics: true, hasMetrics: true,
showPanels: true, showPanels: true,
}, },
......
...@@ -7,6 +7,12 @@ module MetricsDashboardHelpers ...@@ -7,6 +7,12 @@ module MetricsDashboardHelpers
create(:project, :custom_repo, files: { dashboard_path => dashboard_yml }) create(:project, :custom_repo, files: { dashboard_path => dashboard_yml })
end end
def project_with_dashboard_namespace(dashboard_path, dashboard_yml = nil)
dashboard_yml ||= fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml')
create(:project, :custom_repo, namespace: namespace, path: 'monitor-project', files: { dashboard_path => dashboard_yml })
end
def delete_project_dashboard(project, user, dashboard_path) def delete_project_dashboard(project, user, dashboard_path)
project.repository.delete_file( project.repository.delete_file(
user, user,
......
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