Commit 50c50a8f authored by Miguel Rincon's avatar Miguel Rincon

Add time picker to logs page

Add the datepicker component to the logs page and
connect it to the Vuex store.

Fixes a few style issues in the component, so it can adapt to
more layouts.
parent 3c21e5e2
...@@ -149,7 +149,13 @@ export default { ...@@ -149,7 +149,13 @@ export default {
}; };
</script> </script>
<template> <template>
<gl-dropdown :text="timeWindowText" class="date-time-picker" menu-class="date-time-picker-menu"> <gl-dropdown
:text="timeWindowText"
class="date-time-picker"
menu-class="date-time-picker-menu"
v-bind="$attrs"
toggle-class="w-100 text-truncate"
>
<div class="d-flex justify-content-between gl-p-2"> <div class="d-flex justify-content-between gl-p-2">
<gl-form-group <gl-form-group
:label="__('Custom range')" :label="__('Custom range')"
......
<script> <script>
import { mapActions, mapState, mapGetters } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import { GlDropdown, GlDropdownItem, GlFormGroup, GlSearchBoxByClick, GlAlert } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem, GlFormGroup, GlSearchBoxByClick, GlAlert } from '@gitlab/ui';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
import { scrollDown } from '~/lib/utils/scroll_utils'; import { scrollDown } from '~/lib/utils/scroll_utils';
import LogControlButtons from './log_control_buttons.vue'; import LogControlButtons from './log_control_buttons.vue';
import { timeRanges, defaultTimeRange } from '~/monitoring/constants';
export default { export default {
components: { components: {
GlAlert, GlAlert,
...@@ -11,6 +14,7 @@ export default { ...@@ -11,6 +14,7 @@ export default {
GlDropdownItem, GlDropdownItem,
GlFormGroup, GlFormGroup,
GlSearchBoxByClick, GlSearchBoxByClick,
DateTimePicker,
LogControlButtons, LogControlButtons,
}, },
props: { props: {
...@@ -37,12 +41,24 @@ export default { ...@@ -37,12 +41,24 @@ export default {
data() { data() {
return { return {
searchQuery: '', searchQuery: '',
selectedTimeRange: defaultTimeRange,
timeRanges,
isElasticStackCalloutDismissed: false, isElasticStackCalloutDismissed: false,
}; };
}, },
computed: { computed: {
...mapState('environmentLogs', ['environments', 'timeWindow', 'logs', 'pods']), ...mapState('environmentLogs', ['environments', 'timeRange', 'logs', 'pods']),
...mapGetters('environmentLogs', ['trace']), ...mapGetters('environmentLogs', ['trace']),
timeRangeModel: {
get() {
return this.timeRange.current;
},
set(val) {
this.setTimeRange(val);
},
},
showLoader() { showLoader() {
return this.logs.isLoading || !this.logs.isComplete; return this.logs.isLoading || !this.logs.isComplete;
}, },
...@@ -85,7 +101,7 @@ export default { ...@@ -85,7 +101,7 @@ export default {
...mapActions('environmentLogs', [ ...mapActions('environmentLogs', [
'setInitData', 'setInitData',
'setSearch', 'setSearch',
'setTimeWindow', 'setTimeRange',
'showPodLogs', 'showPodLogs',
'showEnvironment', 'showEnvironment',
'fetchEnvironments', 'fetchEnvironments',
...@@ -166,22 +182,13 @@ export default { ...@@ -166,22 +182,13 @@ export default {
label-for="time-window-dropdown" label-for="time-window-dropdown"
class="col-3 px-1" class="col-3 px-1"
> >
<gl-dropdown <date-time-picker
id="time-window-dropdown" ref="dateTimePicker"
ref="time-window-dropdown" v-model="timeRangeModel"
class="w-100 gl-h-32"
:disabled="disableAdvancedControls" :disabled="disableAdvancedControls"
:text="timeWindow.options[timeWindow.current].label" :options="timeRanges"
class="d-flex gl-h-32" />
toggle-class="dropdown-menu-toggle"
>
<gl-dropdown-item
v-for="(option, key) in timeWindow.options"
:key="key"
@click="setTimeWindow(key)"
>
{{ option.label }}
</gl-dropdown-item>
</gl-dropdown>
</gl-form-group> </gl-form-group>
<gl-form-group <gl-form-group
id="search-fg" id="search-fg"
......
import { __ } from '~/locale';
export const defaultTimeWindow = 'oneHour';
export const timeWindows = {
oneHour: {
label: __('1 hour'),
seconds: 60 * 60,
},
fourHours: {
label: __('4 hours'),
seconds: 60 * 60 * 4,
},
oneDay: {
label: __('1 day'),
seconds: 60 * 60 * 24,
},
twoDays: {
label: __('2 days'),
seconds: 60 * 60 * 24 * 3,
},
pastWeek: {
label: __('Past week'),
seconds: 60 * 60 * 24 * 7,
},
twoWeeks: {
label: __('2 weeks'),
seconds: 60 * 60 * 24 * 15,
},
};
...@@ -4,10 +4,17 @@ import httpStatusCodes from '~/lib/utils/http_status'; ...@@ -4,10 +4,17 @@ import httpStatusCodes from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import flash from '~/flash'; import flash from '~/flash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { convertToFixedRange } from '~/lib/utils/datetime_range';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { getTimeRange } from '../utils'; const flashTimeRangeWarning = () => {
import { timeWindows } from '../constants'; flash(s__('Metrics|Invalid time range, please verify.'), 'warning');
};
const flashLogsError = () => {
flash(s__('Metrics|There was an error fetching the logs, please try again'));
};
const requestLogsUntilData = params => const requestLogsUntilData = params =>
backOff((next, stop) => { backOff((next, stop) => {
...@@ -39,8 +46,8 @@ export const setSearch = ({ dispatch, commit }, searchQuery) => { ...@@ -39,8 +46,8 @@ export const setSearch = ({ dispatch, commit }, searchQuery) => {
dispatch('fetchLogs'); dispatch('fetchLogs');
}; };
export const setTimeWindow = ({ dispatch, commit }, timeWindowKey) => { export const setTimeRange = ({ dispatch, commit }, timeRange) => {
commit(types.SET_TIME_WINDOW, timeWindowKey); commit(types.SET_TIME_RANGE, timeRange);
dispatch('fetchLogs'); dispatch('fetchLogs');
}; };
...@@ -72,12 +79,14 @@ export const fetchLogs = ({ commit, state }) => { ...@@ -72,12 +79,14 @@ export const fetchLogs = ({ commit, state }) => {
search: state.search, search: state.search,
}; };
if (state.timeWindow.current) { if (state.timeRange.current) {
const { current } = state.timeWindow; try {
const { start, end } = getTimeRange(timeWindows[current].seconds); const { start, end } = convertToFixedRange(state.timeRange.current);
params.start = start;
params.start = start; params.end = end;
params.end = end; } catch {
flashTimeRangeWarning();
}
} }
commit(types.REQUEST_PODS_DATA); commit(types.REQUEST_PODS_DATA);
...@@ -94,7 +103,7 @@ export const fetchLogs = ({ commit, state }) => { ...@@ -94,7 +103,7 @@ export const fetchLogs = ({ commit, state }) => {
.catch(() => { .catch(() => {
commit(types.RECEIVE_PODS_DATA_ERROR); commit(types.RECEIVE_PODS_DATA_ERROR);
commit(types.RECEIVE_LOGS_DATA_ERROR); commit(types.RECEIVE_LOGS_DATA_ERROR);
flash(s__('Metrics|There was an error fetching the logs, please try again')); flashLogsError();
}); });
}; };
......
export const SET_PROJECT_ENVIRONMENT = 'SET_PROJECT_ENVIRONMENT'; export const SET_PROJECT_ENVIRONMENT = 'SET_PROJECT_ENVIRONMENT';
export const SET_SEARCH = 'SET_SEARCH'; export const SET_SEARCH = 'SET_SEARCH';
export const SET_TIME_WINDOW = 'SET_TIME_WINDOW'; export const SET_TIME_RANGE = 'SET_TIME_RANGE';
export const SET_CURRENT_POD_NAME = 'SET_CURRENT_POD_NAME';
export const REQUEST_ENVIRONMENTS_DATA = 'REQUEST_ENVIRONMENTS_DATA'; export const REQUEST_ENVIRONMENTS_DATA = 'REQUEST_ENVIRONMENTS_DATA';
export const RECEIVE_ENVIRONMENTS_DATA_SUCCESS = 'RECEIVE_ENVIRONMENTS_DATA_SUCCESS'; export const RECEIVE_ENVIRONMENTS_DATA_SUCCESS = 'RECEIVE_ENVIRONMENTS_DATA_SUCCESS';
...@@ -10,7 +11,6 @@ export const REQUEST_LOGS_DATA = 'REQUEST_LOGS_DATA'; ...@@ -10,7 +11,6 @@ export const REQUEST_LOGS_DATA = 'REQUEST_LOGS_DATA';
export const RECEIVE_LOGS_DATA_SUCCESS = 'RECEIVE_LOGS_DATA_SUCCESS'; export const RECEIVE_LOGS_DATA_SUCCESS = 'RECEIVE_LOGS_DATA_SUCCESS';
export const RECEIVE_LOGS_DATA_ERROR = 'RECEIVE_LOGS_DATA_ERROR'; export const RECEIVE_LOGS_DATA_ERROR = 'RECEIVE_LOGS_DATA_ERROR';
export const SET_CURRENT_POD_NAME = 'SET_CURRENT_POD_NAME';
export const REQUEST_PODS_DATA = 'REQUEST_PODS_DATA'; export const REQUEST_PODS_DATA = 'REQUEST_PODS_DATA';
export const RECEIVE_PODS_DATA_SUCCESS = 'RECEIVE_PODS_DATA_SUCCESS'; export const RECEIVE_PODS_DATA_SUCCESS = 'RECEIVE_PODS_DATA_SUCCESS';
export const RECEIVE_PODS_DATA_ERROR = 'RECEIVE_PODS_DATA_ERROR'; export const RECEIVE_PODS_DATA_ERROR = 'RECEIVE_PODS_DATA_ERROR';
...@@ -7,8 +7,8 @@ export default { ...@@ -7,8 +7,8 @@ export default {
}, },
/** Time Range data */ /** Time Range data */
[types.SET_TIME_WINDOW](state, timeWindowKey) { [types.SET_TIME_RANGE](state, timeRange) {
state.timeWindow.current = timeWindowKey; state.timeRange.current = timeRange;
}, },
/** Environments data */ /** Environments data */
......
import { defaultTimeWindow, timeWindows } from '../constants'; import { timeRanges, defaultTimeRange } from '~/monitoring/constants';
export default () => ({ export default () => ({
/** /**
...@@ -9,9 +9,9 @@ export default () => ({ ...@@ -9,9 +9,9 @@ export default () => ({
/** /**
* Time range (Show last) * Time range (Show last)
*/ */
timeWindow: { timeRange: {
options: { ...timeWindows }, options: timeRanges,
current: defaultTimeWindow, current: defaultTimeRange,
}, },
/** /**
......
...@@ -18,10 +18,6 @@ ...@@ -18,10 +18,6 @@
} }
} }
.dropdown-menu {
width: 300px;
}
.controllers { .controllers {
@include build-controllers(16px, flex-end, true, 2); @include build-controllers(16px, flex-end, true, 2);
} }
......
---
title: Add time picker to logs page
merge_request: 23837
author:
type: added
import Vue from 'vue'; import Vue from 'vue';
import { GlDropdown, GlDropdownItem, GlSearchBoxByClick } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem, GlSearchBoxByClick } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
import EnvironmentLogs from 'ee/logs/components/environment_logs.vue'; import EnvironmentLogs from 'ee/logs/components/environment_logs.vue';
import { createStore } from 'ee/logs/stores'; import { createStore } from 'ee/logs/stores';
...@@ -42,7 +43,7 @@ describe('EnvironmentLogs', () => { ...@@ -42,7 +43,7 @@ describe('EnvironmentLogs', () => {
const findEnvironmentsDropdown = () => wrapper.find('.js-environments-dropdown'); const findEnvironmentsDropdown = () => wrapper.find('.js-environments-dropdown');
const findPodsDropdown = () => wrapper.find('.js-pods-dropdown'); const findPodsDropdown = () => wrapper.find('.js-pods-dropdown');
const findSearchBar = () => wrapper.find('.js-logs-search'); const findSearchBar = () => wrapper.find('.js-logs-search');
const findTimeWindowDropdown = () => wrapper.find({ ref: 'time-window-dropdown' }); const findTimeRangePicker = () => wrapper.find({ ref: 'dateTimePicker' });
const findLogControlButtons = () => wrapper.find({ name: 'log-control-buttons-stub' }); const findLogControlButtons = () => wrapper.find({ name: 'log-control-buttons-stub' });
const findLogTrace = () => wrapper.find('.js-log-trace'); const findLogTrace = () => wrapper.find('.js-log-trace');
...@@ -116,8 +117,8 @@ describe('EnvironmentLogs', () => { ...@@ -116,8 +117,8 @@ describe('EnvironmentLogs', () => {
expect(findSearchBar().exists()).toBe(true); expect(findSearchBar().exists()).toBe(true);
expect(findSearchBar().is(GlSearchBoxByClick)).toBe(true); expect(findSearchBar().is(GlSearchBoxByClick)).toBe(true);
expect(findTimeWindowDropdown().exists()).toBe(true); expect(findTimeRangePicker().exists()).toBe(true);
expect(findTimeWindowDropdown().is(GlDropdown)).toBe(true); expect(findTimeRangePicker().is(DateTimePicker)).toBe(true);
// log trace // log trace
expect(findLogTrace().isEmpty()).toBe(false); expect(findLogTrace().isEmpty()).toBe(false);
...@@ -169,7 +170,7 @@ describe('EnvironmentLogs', () => { ...@@ -169,7 +170,7 @@ describe('EnvironmentLogs', () => {
}); });
it('displays a disabled time window dropdown', () => { it('displays a disabled time window dropdown', () => {
expect(findTimeWindowDropdown().attributes('disabled')).toBe('true'); expect(findTimeRangePicker().attributes('disabled')).toBe('true');
}); });
it('does not update buttons state', () => { it('does not update buttons state', () => {
...@@ -207,7 +208,7 @@ describe('EnvironmentLogs', () => { ...@@ -207,7 +208,7 @@ describe('EnvironmentLogs', () => {
it('displays a disabled search bar and time window dropdown', () => { it('displays a disabled search bar and time window dropdown', () => {
expect(findSearchBar().exists()).toBe(true); expect(findSearchBar().exists()).toBe(true);
expect(findSearchBar().attributes('disabled')).toBe('true'); expect(findSearchBar().attributes('disabled')).toBe('true');
expect(findTimeWindowDropdown().attributes('disabled')).toBe('true'); expect(findTimeRangePicker().attributes('disabled')).toBe('true');
}); });
}); });
...@@ -234,7 +235,7 @@ describe('EnvironmentLogs', () => { ...@@ -234,7 +235,7 @@ describe('EnvironmentLogs', () => {
}); });
it('displays an enabled time window dropdown', () => { it('displays an enabled time window dropdown', () => {
expect(findTimeWindowDropdown().attributes('disabled')).toBeFalsy(); expect(findTimeRangePicker().attributes('disabled')).toBeFalsy();
}); });
it('populates environments dropdown', () => { it('populates environments dropdown', () => {
......
...@@ -119,12 +119,19 @@ describe('Logs Store Mutations', () => { ...@@ -119,12 +119,19 @@ describe('Logs Store Mutations', () => {
}); });
}); });
describe('SET_TIME_WINDOW', () => { describe('SET_TIME_RANGE', () => {
it('sets a time window Key', () => { it('sets a default range', () => {
const mockKey = 'fourHours'; expect(state.timeRange.current).toEqual(expect.any(Object));
mutations[types.SET_TIME_WINDOW](state, mockKey); });
it('sets a time range', () => {
const mockRange = {
start: '2020-01-10T18:00:00.000Z',
end: '2020-01-10T10:00:00.000Z',
};
mutations[types.SET_TIME_RANGE](state, mockRange);
expect(state.timeWindow.current).toEqual(mockKey); expect(state.timeRange.current).toEqual(mockRange);
}); });
}); });
......
...@@ -649,9 +649,6 @@ msgstr "" ...@@ -649,9 +649,6 @@ msgstr ""
msgid "1st contribution!" msgid "1st contribution!"
msgstr "" msgstr ""
msgid "2 days"
msgstr ""
msgid "2 weeks" msgid "2 weeks"
msgstr "" msgstr ""
...@@ -682,9 +679,6 @@ msgstr "" ...@@ -682,9 +679,6 @@ msgstr ""
msgid "30+ contributions" msgid "30+ contributions"
msgstr "" msgstr ""
msgid "4 hours"
msgstr ""
msgid "403|Please contact your GitLab administrator to get permission." msgid "403|Please contact your GitLab administrator to get permission."
msgstr "" msgstr ""
...@@ -11991,6 +11985,9 @@ msgstr "" ...@@ -11991,6 +11985,9 @@ msgstr ""
msgid "Metrics|For grouping similar metrics" msgid "Metrics|For grouping similar metrics"
msgstr "" msgstr ""
msgid "Metrics|Invalid time range, please verify."
msgstr ""
msgid "Metrics|Label of the y-axis (usually the unit). The x-axis always represents time." msgid "Metrics|Label of the y-axis (usually the unit). The x-axis always represents time."
msgstr "" msgstr ""
...@@ -13362,9 +13359,6 @@ msgstr "" ...@@ -13362,9 +13359,6 @@ msgstr ""
msgid "Past due" msgid "Past due"
msgstr "" msgstr ""
msgid "Past week"
msgstr ""
msgid "Paste a machine public key here. Read more about how to generate it %{link_start}here%{link_end}" msgid "Paste a machine public key here. Read more about how to generate it %{link_start}here%{link_end}"
msgstr "" msgstr ""
......
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