Commit 6e0afa6c authored by Mark Florian's avatar Mark Florian

Merge branch 'audit-filters-date-range-to-gitlab-ui' into 'master'

Convert audit logs date range field to use GitLab UI

See merge request gitlab-org/gitlab!26911
parents 405d079c 6f6bff4d
<script>
import { GlDaterangePicker } from '@gitlab/ui';
import { parsePikadayDate, pikadayToString } from '~/lib/utils/datetime_utility';
import { queryToObject } from '~/lib/utils/url_utility';
export default {
name: 'DateRangeField',
components: {
GlDaterangePicker,
},
props: {
formElement: {
type: HTMLFormElement,
required: true,
},
},
data() {
const data = {
startDate: null,
endDate: null,
};
const { created_after: initialStartDate, created_before: initialEndDate } = queryToObject(
window.location.search,
);
if (initialStartDate) {
data.startDate = parsePikadayDate(initialStartDate);
}
if (initialEndDate) {
data.endDate = parsePikadayDate(initialEndDate);
}
return data;
},
computed: {
createdAfter() {
return this.startDate ? pikadayToString(this.startDate) : '';
},
createdBefore() {
return this.endDate ? pikadayToString(this.endDate) : '';
},
},
methods: {
handleInput(dates) {
this.startDate = dates.startDate;
this.endDate = dates.endDate;
this.$nextTick(() => this.formElement.submit());
},
},
};
</script>
<template>
<div>
<gl-daterange-picker
class="d-flex flex-wrap flex-sm-nowrap"
:default-start-date="startDate"
:default-end-date="endDate"
start-picker-class="form-group align-items-lg-center mr-0 mr-sm-1 d-flex flex-column flex-lg-row"
end-picker-class="form-group align-items-lg-center mr-0 mr-sm-2 d-flex flex-column flex-lg-row"
@input="handleInput"
/>
<input type="hidden" name="created_after" :value="createdAfter" />
<input type="hidden" name="created_before" :value="createdBefore" />
</div>
</template>
import Vue from 'vue';
import DateRangeField from './components/date_range_field.vue';
import AuditLogs from './audit_logs'; import AuditLogs from './audit_logs';
document.addEventListener('DOMContentLoaded', () => new AuditLogs()); document.addEventListener('DOMContentLoaded', () => new AuditLogs());
document.addEventListener('DOMContentLoaded', () => {
const el = document.querySelector('#js-audit-logs-date-range-app');
const formElement = el.closest('form');
// eslint-disable-next-line no-new
new Vue({
el,
name: 'AuditLogsDateRangeApp',
render: createElement =>
createElement(DateRangeField, {
props: {
...el.dataset,
formElement,
},
}),
});
});
.audit-controls { .audit-controls {
// TODO: Remove this once https://gitlab.com/gitlab-org/gitlab-ui/-/issues/681 is resolved
.gl-datepicker-theme.pika-single {
position: absolute !important;
}
.dropdown-menu-toggle {
// New GitLab UI inputs are 32px high, while the older inputs are 34px
// This can be removed once the audit log fields are converted to use GitLab UI's dropdown instead
padding-bottom: 5px;
padding-top: 5px;
.fa-chevron-down,
.fa-spinner {
top: 10px;
}
}
@include media-breakpoint-down(md) { @include media-breakpoint-down(md) {
.dropdown-menu-toggle, .dropdown-menu-toggle,
.filter-item { .filter-item {
......
...@@ -43,8 +43,11 @@ ...@@ -43,8 +43,11 @@
placeholder: @entity&.full_path || _('Search groups'), idAttribute: 'id', placeholder: @entity&.full_path || _('Search groups'), idAttribute: 'id',
data: { order_by: 'last_activity_at', idattribute: 'id', all_available: true } }) data: { order_by: 'last_activity_at', idattribute: 'id', all_available: true } })
.d-flex.col-lg-auto .d-flex.col-lg-auto.flex-wrap
= render 'shared/audit_events/event_filter' %form.row-content-block.second-block.d-flex.justify-content-lg-end.pb-0
.audit-controls.d-flex.align-items-lg-center.flex-column.flex-lg-row.col-lg-auto.px-0
#js-audit-logs-date-range-app
= render 'shared/audit_events/event_sort'
- if @events.present? - if @events.present?
%table#events-table.table %table#events-table.table
......
...@@ -112,11 +112,27 @@ describe 'Admin::AuditLogs', :js do ...@@ -112,11 +112,27 @@ describe 'Admin::AuditLogs', :js do
let_it_be(:audit_event_2) { create(:user_audit_event, created_at: 3.days.ago) } let_it_be(:audit_event_2) { create(:user_audit_event, created_at: 3.days.ago) }
let_it_be(:audit_event_3) { create(:user_audit_event, created_at: 1.day.ago) } let_it_be(:audit_event_3) { create(:user_audit_event, created_at: 1.day.ago) }
before do it 'shows only 2 days old events' do
visit admin_audit_logs_path visit admin_audit_logs_path(created_after: 4.days.ago.to_date, created_before: 2.days.ago.to_date)
expect(page).to have_content(audit_event_2.present.date)
expect(page).not_to have_content(audit_event_1.present.date)
expect(page).not_to have_content(audit_event_3.present.date)
end
it 'shows only yesterday events' do
visit admin_audit_logs_path(created_after: 2.days.ago.to_date)
expect(page).to have_content(audit_event_3.present.date)
expect(page).not_to have_content(audit_event_1.present.date)
expect(page).not_to have_content(audit_event_2.present.date)
end end
it_behaves_like 'audit events filter' it 'shows a message if provided date is invalid' do
visit admin_audit_logs_path(created_after: '12-345-6789')
expect(page).to have_content('Invalid date format. Please use UTC format as YYYY-MM-DD')
end
end end
end end
......
import { shallowMount } from '@vue/test-utils';
import { GlDaterangePicker } from '@gitlab/ui';
import DateRangeField from 'ee/pages/admin/audit_logs/components/date_range_field.vue';
import { parsePikadayDate } from '~/lib/utils/datetime_utility';
describe('DateRangeField component', () => {
const DATE = '1970-01-01';
let wrapper;
const createComponent = (props = {}) => {
const formElement = document.createElement('form');
document.body.appendChild(formElement);
return shallowMount(DateRangeField, {
propsData: { formElement, ...props },
});
};
beforeEach(() => {
delete window.location;
window.location = { search: '' };
});
afterEach(() => {
document.querySelector('form').remove();
wrapper.destroy();
});
it('should populate the initial start date if passed in the query string', () => {
window.location.search = `?created_after=${DATE}`;
wrapper = createComponent();
expect(wrapper.find(GlDaterangePicker).props()).toMatchObject({
defaultStartDate: parsePikadayDate(DATE),
defaultEndDate: null,
});
});
it('should populate the initial end date if passed in the query string', () => {
window.location.search = `?created_before=${DATE}`;
wrapper = createComponent();
expect(wrapper.find(GlDaterangePicker).props()).toMatchObject({
defaultStartDate: null,
defaultEndDate: parsePikadayDate(DATE),
});
});
it('should populate both the initial start and end dates if passed in the query string', () => {
window.location.search = `?created_after=${DATE}&created_before=${DATE}`;
wrapper = createComponent();
expect(wrapper.find(GlDaterangePicker).props()).toMatchObject({
defaultStartDate: parsePikadayDate(DATE),
defaultEndDate: parsePikadayDate(DATE),
});
});
it('should populate the date hidden fields on input', () => {
wrapper = createComponent();
wrapper
.find(GlDaterangePicker)
.vm.$emit('input', { startDate: parsePikadayDate(DATE), endDate: parsePikadayDate(DATE) });
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find('input[name="created_after"]').attributes().value).toEqual(DATE);
expect(wrapper.find('input[name="created_before"]').attributes().value).toEqual(DATE);
});
});
it('should submit the form on input change', () => {
wrapper = createComponent();
const spy = jest.spyOn(wrapper.props().formElement, 'submit');
wrapper
.find(GlDaterangePicker)
.vm.$emit('input', { startDate: parsePikadayDate(DATE), endDate: parsePikadayDate(DATE) });
return wrapper.vm.$nextTick().then(() => {
expect(spy).toHaveBeenCalledTimes(1);
});
});
});
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