summaryrefslogtreecommitdiff
path: root/app/assets
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/cycle_analytics/components/banner.vue2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/cycle_analitics_app.vue54
-rw-r--r--app/assets/javascripts/cycle_analytics/components/panel_header.vue19
-rw-r--r--app/assets/javascripts/cycle_analytics/components/pipeline_health.vue27
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_component.vue2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/total_time_component.js25
-rw-r--r--app/assets/javascripts/cycle_analytics/components/total_time_component.vue20
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js137
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_service.js4
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_store.js35
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss4
11 files changed, 104 insertions, 225 deletions
diff --git a/app/assets/javascripts/cycle_analytics/components/banner.vue b/app/assets/javascripts/cycle_analytics/components/banner.vue
index 8c5d7a406e9..46daea785b6 100644
--- a/app/assets/javascripts/cycle_analytics/components/banner.vue
+++ b/app/assets/javascripts/cycle_analytics/components/banner.vue
@@ -1,5 +1,5 @@
<script>
- import iconCycleAnalyticsSplash from 'icons/icon_cycle_analytics_splash.svg';
+ import iconCycleAnalyticsSplash from 'icons/_icon_cycle_analytics_splash.svg';
export default {
name: 'cycleAnalyticsBanner',
diff --git a/app/assets/javascripts/cycle_analytics/components/cycle_analitics_app.vue b/app/assets/javascripts/cycle_analytics/components/cycle_analitics_app.vue
index 1329e54fa31..98b144884b3 100644
--- a/app/assets/javascripts/cycle_analytics/components/cycle_analitics_app.vue
+++ b/app/assets/javascripts/cycle_analytics/components/cycle_analitics_app.vue
@@ -4,8 +4,9 @@
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import pipelineHealth from './pipeline_health.vue';
import panelHeader from './panel_header.vue';
- import iconLock from '~/icons/icon_lock.svg';
- import iconNoData from '~/icons/icon_no_data.svg';
+ import banner from './banner.vue'
+ import iconLock from 'icons/_icon_lock.svg';
+ import iconNoData from 'icons/_icon_no_data.svg';
import Store from '../cycle_analytics_store';
import Service from '../cycle_analytics_service';
@@ -26,16 +27,24 @@
type: Boolean,
required: true,
},
+ cssClass: {
+ type: String,
+ required: false,
+ },
},
components: {
loadingIcon,
+ banner,
panelHeader,
pipelineHealth,
stageComponent,
+ 'stage-issue-component': stageComponent,
+ 'stage-code-component': stageComponent,
+ 'stage-test-component': stageComponent,
},
data() {
const store = new Store();
- const service = new Service(this.endpoint);
+ const service = new Service({ endpoint: this.endpoint });
return {
store,
@@ -51,12 +60,16 @@
},
computed: {
currentStage() {
- return this.store.currentActiveStage();
+ console.log(this.store.currentActiveStage())
+ return this.store.currentActiveStage() || {};
},
iconLock() {
return iconLock;
},
},
+ created() {
+ this.fetchCycleAnalyticsData();
+ },
methods: {
handleError() {
this.store.setErrorState(true);
@@ -66,19 +79,6 @@
this.startDate = value;
this.fetchCycleAnalyticsData({ startDate: this.startDate });
},
- // initDropdown() {
- // const $dropdown = $('.js-ca-dropdown');
- // const $label = $dropdown.find('.dropdown-label');
-
- // $dropdown.find('li a').off('click').on('click', (e) => {
- // e.preventDefault();
- // const $target = $(e.currentTarget);
- // this.startDate = $target.data('value');
-
- // $label.text($target.text().trim());
- // this.fetchCycleAnalyticsData({ startDate: this.startDate });
- // });
- // },
fetchCycleAnalyticsData(options) {
const fetchOptions = options || { startDate: this.startDate };
@@ -90,7 +90,6 @@
.then((response) => {
this.store.setCycleAnalyticsData(response);
this.selectDefaultStage();
- this.initDropdown();
this.isLoading = false;
})
.catch(() => {
@@ -139,7 +138,7 @@
};
</script>
<template>
- <div>
+ <div :class="cssClass" id="cycle-analytics">
<banner
v-if="noData && !isOverviewDialogDismissed"
@dimissBanner="dismissOverviewDialog"
@@ -148,20 +147,21 @@
<template v-if="!isLoading && !hasError">
<pipeline-health
:analytics-data="state"
+ :start-date="startDate"
@onClickDropdown="onClickDropdown"
/>
<div class="panel panel-default stage-panel">
- <panel-heading :current-state="currentStage" />
+ <panel-header :current-state="currentStage" />
<div class="stage-panel-body">
<div class="nav stage-nav">
<ul>
<li
class="stage-nav-item"
+ v-for="(stage, i) in state.stages"
:class="{ active: stage.active }"
- @click="selectStage(stage)"
- v-for="(stage, i) in stage.stages">
+ @click="selectStage(stage)">
<div class="stage-nav-item-cell stage-name">
{{ stage.title }}
</div>
@@ -173,22 +173,22 @@
<span
v-else
class="stage-empty">
- {{ __('Not enough data') }}
+ {{__('Not enough data')}}
</span>
</template>
<template v-else>
<span class="not-available">
- {{ __('Not available') }}
+ {{__('Not available')}}
</span>
</template>
</div>
- </li>
+ </li>
</ul>
</div>
<div class="section stage-events">
<loading-icon v-if="isLoadingStage" />
<div
- v-if="currentStage && !currentStage.isUserAlllowed"
+ v-else-if="!isLoadingStage && currentStage && !currentStage.isUserAlllowed"
class="no-access-stage">
<div class="icon-lock" v-html="iconLock">
</div>
@@ -217,7 +217,7 @@
:stage="currentStage"
:items="state.events"
/>
- </div>
+ </template>
</template>
</div>
</div>
diff --git a/app/assets/javascripts/cycle_analytics/components/panel_header.vue b/app/assets/javascripts/cycle_analytics/components/panel_header.vue
index 64620f0e59c..fe253ed2b85 100644
--- a/app/assets/javascripts/cycle_analytics/components/panel_header.vue
+++ b/app/assets/javascripts/cycle_analytics/components/panel_header.vue
@@ -1,11 +1,16 @@
<script>
+ import tooltip from '../../vue_shared/directives/tooltip';
+
export default {
props: {
currentStage: {
type: Object,
- required: true,
+ required: false,
},
},
+ directives: {
+ tooltip
+ },
};
</script>
<template>
@@ -14,24 +19,24 @@
<ul>
<li class="stage-header">
<span class="stage-name">
- {{s__('ProjectLifecycle|Stage')}}
+ {{__('ProjectLifecycle|Stage')}}
</span>
<i
class="fa fa-question-circle"
v-tooltip
- :title="_("The phase of the development lifecycle.")"
+ :title="__('The phase of the development lifecycle.')"
data-placement="top"
aria-hidden="true">
</i>
</li>
<li class="median-header">
<span class="stage-name">
- {{ __('Median') }}
+ {{ __('Median')}}
</span>
<i
class="fa fa-question-circle"
v-tooltip
- :title="_("The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.")"
+ :title="__('The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.')"
data-placement="top"
aria-hidden="true">
</i>
@@ -43,7 +48,7 @@
<i
class="fa fa-question-circle"
v-tooltip
- :title="_("The collection of events added to the data gathered for that stage.")"
+ :title="__('The collection of events added to the data gathered for that stage.')"
data-placement="top"
aria-hidden="true">
</i>
@@ -55,7 +60,7 @@
<i
class="fa fa-question-circle"
v-tooltip
- :title="_("The time taken by each data entry gathered by that stage.")"
+ :title="__('The time taken by each data entry gathered by that stage.')"
data-placement="top"
aria-hidden="true">
</i>
diff --git a/app/assets/javascripts/cycle_analytics/components/pipeline_health.vue b/app/assets/javascripts/cycle_analytics/components/pipeline_health.vue
index e3b9e626f2d..225d4155879 100644
--- a/app/assets/javascripts/cycle_analytics/components/pipeline_health.vue
+++ b/app/assets/javascripts/cycle_analytics/components/pipeline_health.vue
@@ -5,6 +5,10 @@
type: Object,
required: true,
},
+ startDate: {
+ type: Number,
+ required: true,
+ },
},
methods: {
onClickDropdown(value) {
@@ -32,13 +36,13 @@
</p>
</div>
<div class="col-sm-3 col-xs-12 column">
- <div class="dropdown">
+ <div class="dropdown prepend-top-10">
<button
type="button"
data-toggle="dropdown"
class="dropdown-menu-toggle">
<span class="dropdown-label">
- {{ n__('Last %d day', 'Last %d days', 30) }}
+ {{ n__('Last %d day', 'Last %d days', startDate) }}
</span>
<i
class="fa fa-chevron-down"
@@ -46,18 +50,25 @@
</i>
</button>
<ul class="dropdown-menu dropdowm-menu-align-right">
- <li @click="onClickDropdown(7)">
- {{ n__('Last %d day', 'Last %d days', 7) }}
+ <li>
+ <a @click="onClickDropdown(7)">
+ {{ n__('Last %d day', 'Last %d days', 7) }}
+ </a>
</li>
- <li @click="onClickDropdown(30)">
- {{ n__('Last %d day', 'Last %d days', 30) }}
+ <li>
+ <a @click="onClickDropdown(30)">
+ {{ n__('Last %d day', 'Last %d days', 30) }}
+ </a>
</li>
- <li @click="onClickDropdown(90)">
- {{ n__('Last %d day', 'Last %d days', 90) }}
+ <li>
+ <a @click="onClickDropdown(90)">
+ {{ n__('Last %d day', 'Last %d days', 90) }}
+ </a>
</li>
</ul>
</div>
</div>
</div>
</div>
+ </div>
</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
index 032b088f46b..cf5ed934d83 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
@@ -2,7 +2,7 @@
<script>
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
import limitWarning from './limit_warning_component.vue';
- import totalTime from './total_time_component';
+ import totalTime from './total_time_component.vue';
export default {
props: {
diff --git a/app/assets/javascripts/cycle_analytics/components/total_time_component.js b/app/assets/javascripts/cycle_analytics/components/total_time_component.js
deleted file mode 100644
index d5e6167b2a8..00000000000
--- a/app/assets/javascripts/cycle_analytics/components/total_time_component.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* eslint-disable no-param-reassign */
-
-import Vue from 'vue';
-
-const global = window.gl || (window.gl = {});
-global.cycleAnalytics = global.cycleAnalytics || {};
-
-global.cycleAnalytics.TotalTimeComponent = Vue.extend({
- props: {
- time: Object,
- },
- template: `
- <span class="total-time">
- <template v-if="Object.keys(time).length">
- <template v-if="time.days">{{ time.days }} <span>{{ n__('day', 'days', time.days) }}</span></template>
- <template v-if="time.hours">{{ time.hours }} <span>{{ n__('Time|hr', 'Time|hrs', time.hours) }}</span></template>
- <template v-if="time.mins && !time.days">{{ time.mins }} <span>{{ n__('Time|min', 'Time|mins', time.mins) }}</span></template>
- <template v-if="time.seconds && Object.keys(time).length === 1 || time.seconds === 0">{{ time.seconds }} <span>{{ s__('Time|s') }}</span></template>
- </template>
- <template v-else>
- --
- </template>
- </span>
- `,
-});
diff --git a/app/assets/javascripts/cycle_analytics/components/total_time_component.vue b/app/assets/javascripts/cycle_analytics/components/total_time_component.vue
new file mode 100644
index 00000000000..e7985507c0c
--- /dev/null
+++ b/app/assets/javascripts/cycle_analytics/components/total_time_component.vue
@@ -0,0 +1,20 @@
+<script>
+ export default {
+ props: {
+ time: Object,
+ },
+ };
+</script>
+<template>
+ <span class="total-time">
+ <template v-if="Object.keys(time).length">
+ <template v-if="time.days">{{ time.days }} <span>{{ n__('day', 'days', time.days) }}</span></template>
+ <template v-if="time.hours">{{ time.hours }} <span>{{ n__('Time|hr', 'Time|hrs', time.hours) }}</span></template>
+ <template v-if="time.mins && !time.days">{{ time.mins }} <span>{{ n__('Time|min', 'Time|mins', time.mins) }}</span></template>
+ <template v-if="time.seconds && Object.keys(time).length === 1 || time.seconds === 0">{{ time.seconds }} <span>{{ s__('Time|s') }}</span></template>
+ </template>
+ <template v-else>
+ --
+ </template>
+ </span>
+</template>
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
index f3e4432b62d..5c9e0ad9357 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
@@ -1,31 +1,21 @@
/* global Flash */
import Vue from 'vue';
-// import Cookies from 'js-cookie';
import Translate from '../vue_shared/translate';
import cycleAnalytics from './components/cycle_analitics_app.vue';
-// import limitWarningComponent from './components/limit_warning_component.vue';
-// import stateCodeComponent from './components/stage_code_component.vue';
-// import stageIssueComponent from './components/stage_issue_component.vue';
-// import './components/stage_plan_component';
-// import './components/stage_production_component';
-// import './components/stage_review_component';
-// import './components/stage_staging_component';
-// import './components/stage_test_component';
-// import './components/total_time_component';
-// import './cycle_analytics_service';
Vue.use(Translate);
document.addEventListener('DOMContentLoaded', () => new Vue({
- el: '#cycle-analytics',
+ el: '#js-vue-cycle-analytics',
data() {
- const dataset = document.querySelector(this.$options.$el).dataset;
+ const dataset = document.querySelector(this.$options.el).dataset;
return {
endpoint: dataset.requestPath,
noData: dataset.cycleAnalyticsNoData,
helpPath: dataset.helpPath,
+ cssClass: dataset.class,
};
},
components: {
@@ -37,127 +27,8 @@ document.addEventListener('DOMContentLoaded', () => new Vue({
endpoint: this.endpoint,
noData: this.noData,
helpPath: this.helpPath,
+ cssClass: this.cssClass,
},
});
},
}));
-
-// $(() => {
-// const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
-// const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
- // const cycleAnalyticsStore = gl.cycleAnalytics.CycleAnalyticsStore;
- // const cycleAnalyticsService = new gl.cycleAnalytics.CycleAnalyticsService({
- // requestPath: cycleAnalyticsEl.dataset.requestPath,
- // });
-
- // gl.cycleAnalyticsApp = new Vue({
- // el: '#cycle-analytics',
- // name: 'CycleAnalytics',
- // data: {
- // state: cycleAnalyticsStore.state,
- // isLoading: false,
- // isLoadingStage: false,
- // isEmptyStage: false,
- // hasError: false,
- // startDate: 30,
- // isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE),
- // },
- // computed: {
- // currentStage() {
- // return cycleAnalyticsStore.currentActiveStage();
- // },
- // },
- // components: {
- // stageComponent,
- // stageIssueComponent,
- // 'stage-plan-component': gl.cycleAnalytics.StagePlanComponent,
- // stateCodeComponent,
- // 'stage-test-component': gl.cycleAnalytics.StageTestComponent,
- // 'stage-review-component': gl.cycleAnalytics.StageReviewComponent,
- // 'stage-staging-component': gl.cycleAnalytics.StageStagingComponent,
- // 'stage-production-component': gl.cycleAnalytics.StageProductionComponent,
- // },
- // created() {
- // this.fetchCycleAnalyticsData();
- // },
- // methods: {
- // handleError() {
- // cycleAnalyticsStore.setErrorState(true);
- // return new Flash('There was an error while fetching cycle analytics data.');
- // },
- // initDropdown() {
- // const $dropdown = $('.js-ca-dropdown');
- // const $label = $dropdown.find('.dropdown-label');
-
- // $dropdown.find('li a').off('click').on('click', (e) => {
- // e.preventDefault();
- // const $target = $(e.currentTarget);
- // this.startDate = $target.data('value');
-
- // $label.text($target.text().trim());
- // this.fetchCycleAnalyticsData({ startDate: this.startDate });
- // });
- // },
- // fetchCycleAnalyticsData(options) {
- // const fetchOptions = options || { startDate: this.startDate };
-
- // this.isLoading = true;
-
- // cycleAnalyticsService
- // .fetchCycleAnalyticsData(fetchOptions)
- // .done((response) => {
- // cycleAnalyticsStore.setCycleAnalyticsData(response);
- // this.selectDefaultStage();
- // this.initDropdown();
- // })
- // .error(() => {
- // this.handleError();
- // })
- // .always(() => {
- // this.isLoading = false;
- // });
- // },
- // selectDefaultStage() {
- // const stage = this.state.stages[0];
- // this.selectStage(stage);
- // },
- // selectStage(stage) {
- // if (this.isLoadingStage) return;
- // if (this.currentStage === stage) return;
-
- // if (!stage.isUserAllowed) {
- // cycleAnalyticsStore.setActiveStage(stage);
- // return;
- // }
-
- // this.isLoadingStage = true;
- // cycleAnalyticsStore.setStageEvents([], stage);
- // cycleAnalyticsStore.setActiveStage(stage);
-
- // cycleAnalyticsService
- // .fetchStageData({
- // stage,
- // startDate: this.startDate,
- // })
- // .done((response) => {
- // this.isEmptyStage = !response.events.length;
- // cycleAnalyticsStore.setStageEvents(response.events, stage);
- // })
- // .error(() => {
- // this.isEmptyStage = true;
- // })
- // .always(() => {
- // this.isLoadingStage = false;
- // });
- // },
- // dismissOverviewDialog() {
- // this.isOverviewDialogDismissed = true;
- // Cookies.set(OVERVIEW_DIALOG_COOKIE, '1', { expires: 365 });
- // },
- // },
- // });
-
- // // Register global components
- // Vue.component('limit-warning', limitWarningComponent);
- // Vue.component('total-time', gl.cycleAnalytics.TotalTimeComponent);
-// });
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js
index ce5066dc10b..f603fb2fefb 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js
@@ -5,8 +5,8 @@ Vue.use(VueResource);
export default class CycleAnalyticsService {
constructor(options) {
- this.requestPath = options.requestPath;
- this.cycleAnalytics = Vue.resource(options.requestPath);
+ this.requestPath = options.endpoint;
+ this.cycleAnalytics = Vue.resource(options.endpoint);
}
fetchCycleAnalyticsData(options = { startDate: 30 }) {
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js
index fa4be1a2981..40c489737ca 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js
@@ -2,35 +2,36 @@ import { __ } from '../locale';
import '../lib/utils/text_utility';
import DEFAULT_EVENT_OBJECTS from './default_event_objects';
-const EMPTY_STAGE_TEXTS = {
- issue: __('The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.'),
- plan: __('The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.'),
- code: __('The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.'),
- test: __('The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.'),
- review: __('The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.'),
- staging: __('The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.'),
- production: __('The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.'),
-};
-
export default class CycleAnalyticsStore {
constructor() {
this.state = {
- summary: '',
- stats: '',
- analytics: '',
+ summary: [],
+ analytics: {},
events: [],
stages: [],
};
+
+ this.EMPTY_STAGE_TEXTS = {
+ issue: __('The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.'),
+ plan: __('The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.'),
+ code: __('The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.'),
+ test: __('The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.'),
+ review: __('The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.'),
+ staging: __('The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.'),
+ production: __('The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.'),
+ };
}
setCycleAnalyticsData(data) {
+ debugger;
const summary = data.summary.map(item => Object.assign({}, item, { value: item.value || '-' }));
- const stages = data.stages.map((el) => {
+ const stages = data.stats.map((el) => {
const stageSlug = gl.text.dasherize(el.name.toLowerCase());
+
return Object.assign({}, el, {
active: false,
isUserAllowed: data.permissions[stageSlug],
- emptyStageText: EMPTY_STAGE_TEXTS[stageSlug],
+ emptyStageText: this.EMPTY_STAGE_TEXTS[stageSlug],
component: `stage-${stageSlug}-component`,
slug: stageSlug,
});
@@ -52,12 +53,12 @@ export default class CycleAnalyticsStore {
}
deactivateAllStages() {
- this.state.stages = this.state.map(stage => Object.assign({}, stage, { active: false }));
+ this.state.stages = this.state.stages.map(stage => Object.assign({}, stage, { active: false }));
}
setActiveStage(stage) {
this.deactivateAllStages();
- Object.assign(stage, { active: true });
+ this.state.stages.find(state => state.name === stage.name).active = true;
}
setStageEvents(events, stage) {
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
index 2a92673d9fa..4af6f1e529a 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/pages/cycle_analytics.scss
@@ -110,10 +110,6 @@
}
}
- .js-ca-dropdown {
- top: $gl-padding-top;
- }
-
.content-list {
li {
padding: 18px $gl-padding $gl-padding;