Commit 9def3bb8 authored by Francisco Javier López's avatar Francisco Javier López Committed by Heinrich Lee Yu

Add Codesandbox metrics to usage ping

The following actions are tracked:
- The client preview setting is enabled
- Every time the preview feature is used

Move pingUsage call to Vuex clientside module

**Why create a new module?**
This call is a bit unrelated to the other
parts of the IDE. Creating a new module helps
keep this part contained + opens the door for
allowing other clientside specific parts to be
cohesively organized.
parent 71a4f7ab
...@@ -92,6 +92,7 @@ export default { ...@@ -92,6 +92,7 @@ export default {
}, },
methods: { methods: {
...mapActions(['getFileData', 'getRawFileData']), ...mapActions(['getFileData', 'getRawFileData']),
...mapActions('clientside', ['pingUsage']),
loadFileContent(path) { loadFileContent(path) {
return this.getFileData({ path, makeFileActive: false }).then(() => return this.getFileData({ path, makeFileActive: false }).then(() =>
this.getRawFileData({ path }), this.getRawFileData({ path }),
...@@ -100,6 +101,8 @@ export default { ...@@ -100,6 +101,8 @@ export default {
initPreview() { initPreview() {
if (!this.mainEntry) return null; if (!this.mainEntry) return null;
this.pingUsage();
return this.loadFileContent(this.mainEntry) return this.loadFileContent(this.mainEntry)
.then(() => this.$nextTick()) .then(() => this.$nextTick())
.then(() => { .then(() => {
......
...@@ -10,6 +10,7 @@ import mergeRequests from './modules/merge_requests'; ...@@ -10,6 +10,7 @@ import mergeRequests from './modules/merge_requests';
import branches from './modules/branches'; import branches from './modules/branches';
import fileTemplates from './modules/file_templates'; import fileTemplates from './modules/file_templates';
import paneModule from './modules/pane'; import paneModule from './modules/pane';
import clientsideModule from './modules/clientside';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -26,6 +27,7 @@ export const createStore = () => ...@@ -26,6 +27,7 @@ export const createStore = () =>
branches, branches,
fileTemplates: fileTemplates(), fileTemplates: fileTemplates(),
rightPane: paneModule(), rightPane: paneModule(),
clientside: clientsideModule(),
}, },
}); });
......
import axios from '~/lib/utils/axios_utils';
export const pingUsage = ({ rootGetters }) => {
const { web_url: projectUrl } = rootGetters.currentProject;
const url = `${projectUrl}/usage_ping/web_ide_clientside_preview`;
return axios.post(url);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
import * as actions from './actions';
export default () => ({
namespaced: true,
actions,
});
# frozen_string_literal: true
class Projects::UsagePingController < Projects::ApplicationController
before_action :authenticate_user!
def web_ide_clientside_preview
return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_count
head(200)
end
end
---
title: Add Codesandbox metrics to usage ping
merge_request: 19075
author:
type: other
...@@ -617,6 +617,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -617,6 +617,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end end
end end
scope :usage_ping, controller: :usage_ping do
post :web_ide_clientside_preview
end
# Since both wiki and repository routing contains wildcard characters # Since both wiki and repository routing contains wildcard characters
# its preferable to keep it below all other project routes # its preferable to keep it below all other project routes
draw :wiki draw :wiki
......
...@@ -131,7 +131,8 @@ module Gitlab ...@@ -131,7 +131,8 @@ module Gitlab
omniauth_enabled: Gitlab::Auth.omniauth_enabled?, omniauth_enabled: Gitlab::Auth.omniauth_enabled?,
prometheus_metrics_enabled: Gitlab::Metrics.prometheus_metrics_enabled?, prometheus_metrics_enabled: Gitlab::Metrics.prometheus_metrics_enabled?,
reply_by_email_enabled: Gitlab::IncomingEmail.enabled?, reply_by_email_enabled: Gitlab::IncomingEmail.enabled?,
signup_enabled: Gitlab::CurrentSettings.allow_signup? signup_enabled: Gitlab::CurrentSettings.allow_signup?,
web_ide_clientside_preview_enabled: Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
} }
end end
......
...@@ -8,6 +8,7 @@ module Gitlab ...@@ -8,6 +8,7 @@ module Gitlab
COMMITS_COUNT_KEY = 'WEB_IDE_COMMITS_COUNT' COMMITS_COUNT_KEY = 'WEB_IDE_COMMITS_COUNT'
MERGE_REQUEST_COUNT_KEY = 'WEB_IDE_MERGE_REQUESTS_COUNT' MERGE_REQUEST_COUNT_KEY = 'WEB_IDE_MERGE_REQUESTS_COUNT'
VIEWS_COUNT_KEY = 'WEB_IDE_VIEWS_COUNT' VIEWS_COUNT_KEY = 'WEB_IDE_VIEWS_COUNT'
PREVIEW_COUNT_KEY = 'WEB_IDE_PREVIEWS_COUNT'
class << self class << self
def increment_commits_count def increment_commits_count
...@@ -34,11 +35,22 @@ module Gitlab ...@@ -34,11 +35,22 @@ module Gitlab
total_count(VIEWS_COUNT_KEY) total_count(VIEWS_COUNT_KEY)
end end
def increment_previews_count
return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
increment(PREVIEW_COUNT_KEY)
end
def total_previews_count
total_count(PREVIEW_COUNT_KEY)
end
def totals def totals
{ {
web_ide_commits: total_commits_count, web_ide_commits: total_commits_count,
web_ide_views: total_views_count, web_ide_views: total_views_count,
web_ide_merge_requests: total_merge_requests_count web_ide_merge_requests: total_merge_requests_count,
web_ide_previews: total_previews_count
} }
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe Projects::UsagePingController do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
describe 'POST #web_ide_clientside_preview' do
subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } }
before do
sign_in(user) if user
end
context 'when web ide clientside preview is enabled' do
before do
stub_application_setting(web_ide_clientside_preview_enabled: true)
end
context 'when the user is not authenticated' do
let(:user) { nil }
it 'returns 302' do
subject
expect(response).to have_gitlab_http_status(302)
end
end
context 'when the user does not have access to the project' do
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(404)
end
end
context 'when the user has access to the project' do
let(:user) { project.owner }
it 'increments the counter' do
expect do
subject
end.to change { Gitlab::UsageDataCounters::WebIdeCounter.total_previews_count }.by(1)
end
end
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(404)
end
end
end
end
...@@ -24,6 +24,9 @@ describe('IDE clientside preview', () => { ...@@ -24,6 +24,9 @@ describe('IDE clientside preview', () => {
getFileData: jest.fn().mockReturnValue(Promise.resolve({})), getFileData: jest.fn().mockReturnValue(Promise.resolve({})),
getRawFileData: jest.fn().mockReturnValue(Promise.resolve('')), getRawFileData: jest.fn().mockReturnValue(Promise.resolve('')),
}; };
const storeClientsideActions = {
pingUsage: jest.fn().mockReturnValue(Promise.resolve({})),
};
const waitForCalls = () => new Promise(setImmediate); const waitForCalls = () => new Promise(setImmediate);
...@@ -42,6 +45,12 @@ describe('IDE clientside preview', () => { ...@@ -42,6 +45,12 @@ describe('IDE clientside preview', () => {
...getters, ...getters,
}, },
actions: storeActions, actions: storeActions,
modules: {
clientside: {
namespaced: true,
actions: storeClientsideActions,
},
},
}); });
wrapper = shallowMount(Clientside, { wrapper = shallowMount(Clientside, {
...@@ -76,7 +85,8 @@ describe('IDE clientside preview', () => { ...@@ -76,7 +85,8 @@ describe('IDE clientside preview', () => {
describe('with main entry', () => { describe('with main entry', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ getters: { packageJson: dummyPackageJson } }); createComponent({ getters: { packageJson: dummyPackageJson } });
return wrapper.vm.initPreview();
return waitForCalls();
}); });
it('creates sandpack manager', () => { it('creates sandpack manager', () => {
...@@ -95,6 +105,10 @@ describe('IDE clientside preview', () => { ...@@ -95,6 +105,10 @@ describe('IDE clientside preview', () => {
}, },
); );
}); });
it('pings usage', () => {
expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1);
});
}); });
describe('computed', () => { describe('computed', () => {
......
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import { TEST_HOST } from 'helpers/test_constants';
import axios from '~/lib/utils/axios_utils';
import * as actions from '~/ide/stores/modules/clientside/actions';
const TEST_PROJECT_URL = `${TEST_HOST}/lorem/ipsum`;
const TEST_USAGE_URL = `${TEST_PROJECT_URL}/usage_ping/web_ide_clientside_preview`;
describe('IDE store module clientside actions', () => {
let rootGetters;
let mock;
beforeEach(() => {
rootGetters = {
currentProject: {
web_url: TEST_PROJECT_URL,
},
};
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('pingUsage', () => {
it('posts to usage endpoint', done => {
const usageSpy = jest.fn(() => [200]);
mock.onPost(TEST_USAGE_URL).reply(() => usageSpy());
testAction(actions.pingUsage, null, rootGetters, [], [], () => {
expect(usageSpy).toHaveBeenCalled();
done();
});
});
});
});
...@@ -34,22 +34,54 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st ...@@ -34,22 +34,54 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st
it_behaves_like 'counter examples' it_behaves_like 'counter examples'
end end
describe 'previews counter' do
let(:setting_enabled) { true }
before do
stub_application_setting(web_ide_clientside_preview_enabled: setting_enabled)
end
context 'when web ide clientside preview is enabled' do
let(:increment_counter_method) { :increment_previews_count }
let(:total_counter_method) { :total_previews_count }
it_behaves_like 'counter examples'
end
context 'when web ide clientside preview is not enabled' do
let(:setting_enabled) { false }
it 'does not increment the counter' do
expect(described_class.total_previews_count).to eq(0)
2.times { described_class.increment_previews_count }
expect(described_class.total_previews_count).to eq(0)
end
end
end
describe '.totals' do describe '.totals' do
commits = 5 commits = 5
merge_requests = 3 merge_requests = 3
views = 2 views = 2
previews = 4
before do before do
stub_application_setting(web_ide_clientside_preview_enabled: true)
commits.times { described_class.increment_commits_count } commits.times { described_class.increment_commits_count }
merge_requests.times { described_class.increment_merge_requests_count } merge_requests.times { described_class.increment_merge_requests_count }
views.times { described_class.increment_views_count } views.times { described_class.increment_views_count }
previews.times { described_class.increment_previews_count }
end end
it 'can report all totals' do it 'can report all totals' do
expect(described_class.totals).to include( expect(described_class.totals).to include(
web_ide_commits: commits, web_ide_commits: commits,
web_ide_views: views, web_ide_views: views,
web_ide_merge_requests: merge_requests web_ide_merge_requests: merge_requests,
web_ide_previews: previews
) )
end end
end end
......
...@@ -76,6 +76,7 @@ describe Gitlab::UsageData do ...@@ -76,6 +76,7 @@ describe Gitlab::UsageData do
avg_cycle_analytics avg_cycle_analytics
influxdb_metrics_enabled influxdb_metrics_enabled
prometheus_metrics_enabled prometheus_metrics_enabled
web_ide_clientside_preview_enabled
)) ))
end end
...@@ -93,6 +94,7 @@ describe Gitlab::UsageData do ...@@ -93,6 +94,7 @@ describe Gitlab::UsageData do
web_ide_views web_ide_views
web_ide_commits web_ide_commits
web_ide_merge_requests web_ide_merge_requests
web_ide_previews
navbar_searches navbar_searches
cycle_analytics_views cycle_analytics_views
productivity_analytics_views productivity_analytics_views
...@@ -252,6 +254,7 @@ describe Gitlab::UsageData do ...@@ -252,6 +254,7 @@ describe Gitlab::UsageData do
expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled) expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled)
expect(subject[:dependency_proxy_enabled]).to eq(Gitlab.config.dependency_proxy.enabled) expect(subject[:dependency_proxy_enabled]).to eq(Gitlab.config.dependency_proxy.enabled)
expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled) expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled)
expect(subject[:web_ide_clientside_preview_enabled]).to eq(Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?)
end end
end end
......
...@@ -788,4 +788,10 @@ describe 'project routing' do ...@@ -788,4 +788,10 @@ describe 'project routing' do
expect(put("/gitlab/gitlabhq/-/deploy_tokens/1/revoke")).to route_to("projects/deploy_tokens#revoke", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') expect(put("/gitlab/gitlabhq/-/deploy_tokens/1/revoke")).to route_to("projects/deploy_tokens#revoke", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end end
end end
describe Projects::UsagePingController, 'routing' do
it 'routes to usage_ping#web_ide_clientside_preview' do
expect(post('/gitlab/gitlabhq/usage_ping/web_ide_clientside_preview')).to route_to('projects/usage_ping#web_ide_clientside_preview', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
end
end end
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