Commit c9faf2ba authored by Brandon Labuschagne's avatar Brandon Labuschagne

Merge branch 'add-web-ide-preview-success-metrics' into 'master'

Add Web IDE preview success metrics

See merge request gitlab-org/gitlab!78952
parents 0da8c72d e11d4a7c
...@@ -4,7 +4,12 @@ import { listen } from 'codesandbox-api'; ...@@ -4,7 +4,12 @@ import { listen } from 'codesandbox-api';
import { isEmpty, debounce } from 'lodash'; import { isEmpty, debounce } from 'lodash';
import { Manager } from 'smooshpack'; import { Manager } from 'smooshpack';
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { packageJsonPath, LIVE_PREVIEW_DEBOUNCE } from '../../constants'; import {
packageJsonPath,
LIVE_PREVIEW_DEBOUNCE,
PING_USAGE_PREVIEW_KEY,
PING_USAGE_PREVIEW_SUCCESS_KEY,
} from '../../constants';
import eventHub from '../../eventhub'; import eventHub from '../../eventhub';
import { createPathWithExt } from '../../utils'; import { createPathWithExt } from '../../utils';
import Navigator from './navigator.vue'; import Navigator from './navigator.vue';
...@@ -62,6 +67,15 @@ export default { ...@@ -62,6 +67,15 @@ export default {
}; };
}, },
}, },
watch: {
sandpackReady: {
handler(val) {
if (val) {
this.pingUsage(PING_USAGE_PREVIEW_SUCCESS_KEY);
}
},
},
},
mounted() { mounted() {
this.onFilesChangeCallback = debounce(() => this.update(), LIVE_PREVIEW_DEBOUNCE); this.onFilesChangeCallback = debounce(() => this.update(), LIVE_PREVIEW_DEBOUNCE);
eventHub.$on('ide.files.change', this.onFilesChangeCallback); eventHub.$on('ide.files.change', this.onFilesChangeCallback);
...@@ -101,7 +115,7 @@ export default { ...@@ -101,7 +115,7 @@ export default {
initPreview() { initPreview() {
if (!this.mainEntry) return null; if (!this.mainEntry) return null;
this.pingUsage(); this.pingUsage(PING_USAGE_PREVIEW_KEY);
return this.loadFileContent(this.mainEntry) return this.loadFileContent(this.mainEntry)
.then(() => this.$nextTick()) .then(() => this.$nextTick())
......
...@@ -114,3 +114,7 @@ export const LIVE_PREVIEW_DEBOUNCE = 2000; ...@@ -114,3 +114,7 @@ export const LIVE_PREVIEW_DEBOUNCE = 2000;
export const MAX_MR_FILES_AUTO_OPEN = 10; export const MAX_MR_FILES_AUTO_OPEN = 10;
export const DEFAULT_BRANCH = 'main'; export const DEFAULT_BRANCH = 'main';
// Ping Usage Metrics Keys
export const PING_USAGE_PREVIEW_KEY = 'web_ide_clientside_preview';
export const PING_USAGE_PREVIEW_SUCCESS_KEY = 'web_ide_clientside_preview_success';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
export const pingUsage = ({ rootGetters }) => { export const pingUsage = ({ rootGetters }, metricName) => {
const { web_url: projectUrl } = rootGetters.currentProject; const { web_url: projectUrl } = rootGetters.currentProject;
const url = `${projectUrl}/service_ping/web_ide_clientside_preview`; const url = `${projectUrl}/service_ping/${metricName}`;
return axios.post(url); return axios.post(url);
}; };
......
...@@ -13,6 +13,14 @@ class Projects::ServicePingController < Projects::ApplicationController ...@@ -13,6 +13,14 @@ class Projects::ServicePingController < Projects::ApplicationController
head(200) head(200)
end end
def web_ide_clientside_preview_success
return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_success_count
head(200)
end
def web_ide_pipelines_count def web_ide_pipelines_count
Gitlab::UsageDataCounters::WebIdeCounter.increment_pipelines_count Gitlab::UsageDataCounters::WebIdeCounter.increment_pipelines_count
......
---
data_category: optional
key_path: counts.web_ide_previews_success
description: Count of Live Preview tab successful initializations in the Web IDE
product_section: dev
product_stage: create
product_group: group::editor
product_category: web_ide
value_type: number
status: active
time_frame: all
data_source: redis
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
performance_indicator_type: []
milestone: "14.8"
...@@ -581,6 +581,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -581,6 +581,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
scope :service_ping, controller: :service_ping do scope :service_ping, controller: :service_ping do
post :web_ide_clientside_preview # rubocop:todo Cop/PutProjectRoutesUnderScope post :web_ide_clientside_preview # rubocop:todo Cop/PutProjectRoutesUnderScope
post :web_ide_clientside_preview_success # rubocop:todo Cop/PutProjectRoutesUnderScope
post :web_ide_pipelines_count # rubocop:todo Cop/PutProjectRoutesUnderScope post :web_ide_pipelines_count # rubocop:todo Cop/PutProjectRoutesUnderScope
end end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Gitlab module Gitlab
module UsageDataCounters module UsageDataCounters
class WebIdeCounter < BaseCounter class WebIdeCounter < BaseCounter
KNOWN_EVENTS = %w[commits views merge_requests previews terminals pipelines].freeze KNOWN_EVENTS = %w[commits views merge_requests previews previews_success terminals pipelines].freeze
PREFIX = 'web_ide' PREFIX = 'web_ide'
class << self class << self
...@@ -33,6 +33,12 @@ module Gitlab ...@@ -33,6 +33,12 @@ module Gitlab
count('previews') count('previews')
end end
def increment_previews_success_count
return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
count('previews_success')
end
private private
def redis_key(event) def redis_key(event)
......
...@@ -69,6 +69,33 @@ RSpec.describe Projects::ServicePingController do ...@@ -69,6 +69,33 @@ RSpec.describe Projects::ServicePingController do
end end
end end
describe 'POST #web_ide_clientside_preview_success' do
subject { post :web_ide_clientside_preview_success, params: { namespace_id: project.namespace, project_id: project } }
context 'when web ide clientside preview is enabled' do
before do
stub_application_setting(web_ide_clientside_preview_enabled: true)
end
it_behaves_like 'counter is not increased'
it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_SUCCESS_COUNT'
end
context 'when web ide clientside preview is not enabled' do
let(:user) { project.owner }
before do
stub_application_setting(web_ide_clientside_preview_enabled: false)
end
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe 'POST #web_ide_pipelines_count' do describe 'POST #web_ide_pipelines_count' do
subject { post :web_ide_pipelines_count, params: { namespace_id: project.namespace, project_id: project } } subject { post :web_ide_pipelines_count, params: { namespace_id: project.namespace, project_id: project } }
......
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue'; import Vue, { nextTick } from 'vue';
import { dispatch } from 'codesandbox-api';
import smooshpack from 'smooshpack'; import smooshpack from 'smooshpack';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Clientside from '~/ide/components/preview/clientside.vue'; import Clientside from '~/ide/components/preview/clientside.vue';
import { PING_USAGE_PREVIEW_KEY, PING_USAGE_PREVIEW_SUCCESS_KEY } from '~/ide/constants';
import eventHub from '~/ide/eventhub'; import eventHub from '~/ide/eventhub';
jest.mock('smooshpack', () => ({ jest.mock('smooshpack', () => ({
...@@ -39,6 +41,7 @@ describe('IDE clientside preview', () => { ...@@ -39,6 +41,7 @@ describe('IDE clientside preview', () => {
const storeClientsideActions = { const storeClientsideActions = {
pingUsage: jest.fn().mockReturnValue(Promise.resolve({})), pingUsage: jest.fn().mockReturnValue(Promise.resolve({})),
}; };
const dispatchCodesandboxReady = () => dispatch({ type: 'done' });
const waitForCalls = () => new Promise(setImmediate); const waitForCalls = () => new Promise(setImmediate);
...@@ -110,6 +113,20 @@ describe('IDE clientside preview', () => { ...@@ -110,6 +113,20 @@ describe('IDE clientside preview', () => {
it('pings usage', () => { it('pings usage', () => {
expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1); expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1);
expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith(
expect.anything(),
PING_USAGE_PREVIEW_KEY,
);
});
it('pings usage success', async () => {
dispatchCodesandboxReady();
await wrapper.vm.$nextTick();
expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(2);
expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith(
expect.anything(),
PING_USAGE_PREVIEW_SUCCESS_KEY,
);
}); });
}); });
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import { PING_USAGE_PREVIEW_KEY } from '~/ide/constants';
import * as actions from '~/ide/stores/modules/clientside/actions'; import * as actions from '~/ide/stores/modules/clientside/actions';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
const TEST_PROJECT_URL = `${TEST_HOST}/lorem/ipsum`; const TEST_PROJECT_URL = `${TEST_HOST}/lorem/ipsum`;
const TEST_USAGE_URL = `${TEST_PROJECT_URL}/service_ping/web_ide_clientside_preview`; const TEST_USAGE_URL = `${TEST_PROJECT_URL}/service_ping/${PING_USAGE_PREVIEW_KEY}`;
describe('IDE store module clientside actions', () => { describe('IDE store module clientside actions', () => {
let rootGetters; let rootGetters;
...@@ -30,7 +31,7 @@ describe('IDE store module clientside actions', () => { ...@@ -30,7 +31,7 @@ describe('IDE store module clientside actions', () => {
mock.onPost(TEST_USAGE_URL).reply(() => usageSpy()); mock.onPost(TEST_USAGE_URL).reply(() => usageSpy());
testAction(actions.pingUsage, null, rootGetters, [], [], () => { testAction(actions.pingUsage, PING_USAGE_PREVIEW_KEY, rootGetters, [], [], () => {
expect(usageSpy).toHaveBeenCalled(); expect(usageSpy).toHaveBeenCalled();
done(); done();
}); });
......
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