Commit 9fde881d authored by Tim Zallmann's avatar Tim Zallmann

Merge branch '32172-improve-responsive-styling-of-pipeline-schedules-form' into 'master'

Polish UI on pipeline schedules form

Closes #32172

See merge request !11332
parents 6a2bcb4b dadd74b5
...@@ -24,9 +24,6 @@ export default { ...@@ -24,9 +24,6 @@ export default {
}; };
}, },
computed: { computed: {
showUnsetWarning() {
return this.cronInterval === '';
},
intervalIsPreset() { intervalIsPreset() {
return _.contains(this.cronIntervalPresets, this.cronInterval); return _.contains(this.cronIntervalPresets, this.cronInterval);
}, },
...@@ -63,67 +60,75 @@ export default { ...@@ -63,67 +60,75 @@ export default {
}, },
template: ` template: `
<div class="interval-pattern-form-group"> <div class="interval-pattern-form-group">
<input <div class="cron-preset-radio-input">
id="custom" <input
class="label-light" id="custom"
type="radio" class="label-light"
:name="inputNameAttribute" type="radio"
:value="cronInterval" :name="inputNameAttribute"
:checked="isEditable" :value="cronInterval"
@click="toggleCustomInput(true)" :checked="isEditable"
/> @click="toggleCustomInput(true)"
/>
<label for="custom"> <label for="custom">
Custom Custom
</label> </label>
<span class="cron-syntax-link-wrap"> <span class="cron-syntax-link-wrap">
(<a :href="cronSyntaxUrl" target="_blank">Cron syntax</a>) (<a :href="cronSyntaxUrl" target="_blank">Cron syntax</a>)
</span> </span>
</div>
<input <div class="cron-preset-radio-input">
id="every-day" <input
class="label-light" id="every-day"
type="radio" class="label-light"
v-model="cronInterval" type="radio"
:name="inputNameAttribute" v-model="cronInterval"
:value="cronIntervalPresets.everyDay" :name="inputNameAttribute"
@click="toggleCustomInput(false)" :value="cronIntervalPresets.everyDay"
/> @click="toggleCustomInput(false)"
/>
<label class="label-light" for="every-day"> <label class="label-light" for="every-day">
Every day (at 4:00am) Every day (at 4:00am)
</label> </label>
</div>
<input <div class="cron-preset-radio-input">
id="every-week" <input
class="label-light" id="every-week"
type="radio" class="label-light"
v-model="cronInterval" type="radio"
:name="inputNameAttribute" v-model="cronInterval"
:value="cronIntervalPresets.everyWeek" :name="inputNameAttribute"
@click="toggleCustomInput(false)" :value="cronIntervalPresets.everyWeek"
/> @click="toggleCustomInput(false)"
/>
<label class="label-light" for="every-week"> <label class="label-light" for="every-week">
Every week (Sundays at 4:00am) Every week (Sundays at 4:00am)
</label> </label>
</div>
<input <div class="cron-preset-radio-input">
id="every-month" <input
class="label-light" id="every-month"
type="radio" class="label-light"
v-model="cronInterval" type="radio"
:name="inputNameAttribute" v-model="cronInterval"
:value="cronIntervalPresets.everyMonth" :name="inputNameAttribute"
@click="toggleCustomInput(false)" :value="cronIntervalPresets.everyMonth"
/> @click="toggleCustomInput(false)"
/>
<label class="label-light" for="every-month"> <label class="label-light" for="every-month">
Every month (on the 1st at 4:00am) Every month (on the 1st at 4:00am)
</label> </label>
</div>
<div class="cron-interval-input-wrapper col-md-6"> <div class="cron-interval-input-wrapper">
<input <input
id="schedule_cron" id="schedule_cron"
class="form-control inline cron-interval-input" class="form-control inline cron-interval-input"
...@@ -135,9 +140,6 @@ export default { ...@@ -135,9 +140,6 @@ export default {
:disabled="!isEditable" :disabled="!isEditable"
/> />
</div> </div>
<span class="cron-unset-status col-md-3" v-if="showUnsetWarning">
Schedule not yet set
</span>
</div> </div>
`, `,
}; };
...@@ -3,7 +3,7 @@ export default class TargetBranchDropdown { ...@@ -3,7 +3,7 @@ export default class TargetBranchDropdown {
this.$dropdown = $('.js-target-branch-dropdown'); this.$dropdown = $('.js-target-branch-dropdown');
this.$dropdownToggle = this.$dropdown.find('.dropdown-toggle-text'); this.$dropdownToggle = this.$dropdown.find('.dropdown-toggle-text');
this.$input = $('#schedule_ref'); this.$input = $('#schedule_ref');
this.initialValue = this.$input.val(); this.initDefaultBranch();
this.initDropdown(); this.initDropdown();
} }
...@@ -29,13 +29,23 @@ export default class TargetBranchDropdown { ...@@ -29,13 +29,23 @@ export default class TargetBranchDropdown {
} }
setDropdownToggle() { setDropdownToggle() {
if (this.initialValue) { const initialValue = this.$input.val();
this.$dropdownToggle.text(this.initialValue);
this.$dropdownToggle.text(initialValue);
}
initDefaultBranch() {
const initialValue = this.$input.val();
const defaultBranch = this.$dropdown.data('defaultBranch');
if (!initialValue) {
this.$input.val(defaultBranch);
} }
} }
updateInputValue({ selectedObj, e }) { updateInputValue({ selectedObj, e }) {
e.preventDefault(); e.preventDefault();
this.$input.val(selectedObj.name); this.$input.val(selectedObj.name);
gl.pipelineScheduleFieldErrors.updateFormValidityState(); gl.pipelineScheduleFieldErrors.updateFormValidityState();
} }
......
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
const defaultTimezone = 'UTC';
export default class TimezoneDropdown { export default class TimezoneDropdown {
constructor() { constructor() {
this.$dropdown = $('.js-timezone-dropdown'); this.$dropdown = $('.js-timezone-dropdown');
this.$dropdownToggle = this.$dropdown.find('.dropdown-toggle-text'); this.$dropdownToggle = this.$dropdown.find('.dropdown-toggle-text');
this.$input = $('#schedule_cron_timezone'); this.$input = $('#schedule_cron_timezone');
this.timezoneData = this.$dropdown.data('data'); this.timezoneData = this.$dropdown.data('data');
this.initialValue = this.$input.val(); this.initDefaultTimezone();
this.initDropdown(); this.initDropdown();
} }
...@@ -42,12 +44,20 @@ export default class TimezoneDropdown { ...@@ -42,12 +44,20 @@ export default class TimezoneDropdown {
return `[UTC ${this.formatUtcOffset(item.offset)}] ${item.name}`; return `[UTC ${this.formatUtcOffset(item.offset)}] ${item.name}`;
} }
setDropdownToggle() { initDefaultTimezone() {
if (this.initialValue) { const initialValue = this.$input.val();
this.$dropdownToggle.text(this.initialValue);
if (!initialValue) {
this.$input.val(defaultTimezone);
} }
} }
setDropdownToggle() {
const initialValue = this.$input.val();
this.$dropdownToggle.text(initialValue);
}
updateInputValue({ selectedObj, e }) { updateInputValue({ selectedObj, e }) {
e.preventDefault(); e.preventDefault();
this.$input.val(selectedObj.identifier); this.$input.val(selectedObj.identifier);
......
...@@ -31,14 +31,6 @@ ...@@ -31,14 +31,6 @@
margin-right: 10px; margin-right: 10px;
font-size: 12px; font-size: 12px;
} }
.cron-unset-status {
padding-top: 16px;
margin-left: -16px;
color: $gl-text-color-secondary;
font-size: 12px;
font-weight: 600;
}
} }
.pipeline-schedule-table-row { .pipeline-schedule-table-row {
...@@ -69,3 +61,16 @@ ...@@ -69,3 +61,16 @@
color: $gl-text-color; color: $gl-text-color;
} }
} }
.cron-preset-radio-input {
display: inline-block;
@media (max-width: $screen-md-max) {
display: block;
margin: 0 0 5px 5px;
}
input {
margin-right: 3px;
}
}
...@@ -5,29 +5,29 @@ ...@@ -5,29 +5,29 @@
= form_for [@project.namespace.becomes(Namespace), @project, @schedule], as: :schedule, html: { id: "new-pipeline-schedule-form", class: "form-horizontal js-pipeline-schedule-form" } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @schedule], as: :schedule, html: { id: "new-pipeline-schedule-form", class: "form-horizontal js-pipeline-schedule-form" } do |f|
= form_errors(@schedule) = form_errors(@schedule)
.form-group .form-group
.col-md-6 .col-md-9
= f.label :description, 'Description', class: 'label-light' = f.label :description, 'Description', class: 'label-light'
= f.text_field :description, class: 'form-control', required: true, autofocus: true, placeholder: 'Provide a short description for this pipeline' = f.text_field :description, class: 'form-control', required: true, autofocus: true, placeholder: 'Provide a short description for this pipeline'
.form-group .form-group
.col-md-12 .col-md-9
= f.label :cron, 'Interval Pattern', class: 'label-light' = f.label :cron, 'Interval Pattern', class: 'label-light'
#interval-pattern-input{ data: { initial_interval: @schedule.cron } } #interval-pattern-input{ data: { initial_interval: @schedule.cron } }
.form-group .form-group
.col-md-6 .col-md-9
= f.label :cron_timezone, 'Cron Timezone', class: 'label-light' = f.label :cron_timezone, 'Cron Timezone', class: 'label-light'
= dropdown_tag("Select a timezone", options: { toggle_class: 'btn js-timezone-dropdown', title: "Select a timezone", filter: true, placeholder: "Filter", data: { data: timezone_data } } ) = dropdown_tag("Select a timezone", options: { toggle_class: 'btn js-timezone-dropdown', title: "Select a timezone", filter: true, placeholder: "Filter", data: { data: timezone_data } } )
= f.text_field :cron_timezone, value: @schedule.cron_timezone, id: 'schedule_cron_timezone', class: 'hidden', name: 'schedule[cron_timezone]', required: true = f.text_field :cron_timezone, value: @schedule.cron_timezone, id: 'schedule_cron_timezone', class: 'hidden', name: 'schedule[cron_timezone]', required: true
.form-group .form-group
.col-md-6 .col-md-9
= f.label :ref, 'Target Branch', class: 'label-light' = f.label :ref, 'Target Branch', class: 'label-light'
= dropdown_tag("Select target branch", options: { toggle_class: 'btn js-target-branch-dropdown git-revision-dropdown-toggle', dropdown_class: 'git-revision-dropdown', title: "Select target branch", filter: true, placeholder: "Filter", data: { data: @project.repository.branch_names } } ) = dropdown_tag("Select target branch", options: { toggle_class: 'btn js-target-branch-dropdown git-revision-dropdown-toggle', dropdown_class: 'git-revision-dropdown', title: "Select target branch", filter: true, placeholder: "Filter", data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } )
= f.text_field :ref, value: @schedule.ref, id: 'schedule_ref', class: 'hidden', name: 'schedule[ref]', required: true = f.text_field :ref, value: @schedule.ref, id: 'schedule_ref', class: 'hidden', name: 'schedule[ref]', required: true
.form-group .form-group
.col-md-6 .col-md-9
= f.label :active, 'Activated', class: 'label-light' = f.label :active, 'Activated', class: 'label-light'
%div %div
= f.check_box :active, required: false, value: @schedule.active? = f.check_box :active, required: false, value: @schedule.active?
active Active
.footer-block.row-content-block .footer-block.row-content-block
= f.submit 'Save pipeline schedule', class: 'btn btn-create', tabindex: 3 = f.submit 'Save pipeline schedule', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', pipeline_schedules_path(@project), class: 'btn btn-cancel' = link_to 'Cancel', pipeline_schedules_path(@project), class: 'btn btn-cancel'
...@@ -70,6 +70,11 @@ feature 'Pipeline Schedules', :feature do ...@@ -70,6 +70,11 @@ feature 'Pipeline Schedules', :feature do
describe 'POST /projects/pipeline_schedules/new', js: true do describe 'POST /projects/pipeline_schedules/new', js: true do
let(:visit_page) { visit_new_pipeline_schedule } let(:visit_page) { visit_new_pipeline_schedule }
it 'sets defaults for timezone and target branch' do
expect(page).to have_button('master')
expect(page).to have_button('UTC')
end
it 'it creates a new scheduled pipeline' do it 'it creates a new scheduled pipeline' do
fill_in_schedule_form fill_in_schedule_form
save_pipeline_schedule save_pipeline_schedule
...@@ -118,12 +123,12 @@ feature 'Pipeline Schedules', :feature do ...@@ -118,12 +123,12 @@ feature 'Pipeline Schedules', :feature do
end end
def select_timezone def select_timezone
click_button 'Select a timezone' find('.js-timezone-dropdown').click
click_link 'American Samoa' click_link 'American Samoa'
end end
def select_target_branch def select_target_branch
click_button 'Select target branch' find('.js-target-branch-dropdown').click
click_link 'master' click_link 'master'
end end
......
...@@ -36,20 +36,6 @@ describe('Interval Pattern Input Component', function () { ...@@ -36,20 +36,6 @@ describe('Interval Pattern Input Component', function () {
expect(this.intervalPatternComponent.initialCronInterval).toBe(this.initialCronInterval); expect(this.intervalPatternComponent.initialCronInterval).toBe(this.initialCronInterval);
}); });
it('sets showUnsetWarning to false', function (done) {
Vue.nextTick(() => {
expect(this.intervalPatternComponent.showUnsetWarning).toBe(false);
done();
});
});
it('does not render showUnsetWarning', function (done) {
Vue.nextTick(() => {
expect(this.intervalPatternComponent.$el.outerHTML).not.toContain('Schedule not yet set');
done();
});
});
it('sets isEditable to true', function (done) { it('sets isEditable to true', function (done) {
Vue.nextTick(() => { Vue.nextTick(() => {
expect(this.intervalPatternComponent.isEditable).toBe(true); expect(this.intervalPatternComponent.isEditable).toBe(true);
...@@ -72,20 +58,6 @@ describe('Interval Pattern Input Component', function () { ...@@ -72,20 +58,6 @@ describe('Interval Pattern Input Component', function () {
expect(this.intervalPatternComponent).toBeDefined(); expect(this.intervalPatternComponent).toBeDefined();
}); });
it('sets showUnsetWarning to false', function (done) {
Vue.nextTick(() => {
expect(this.intervalPatternComponent.showUnsetWarning).toBe(false);
done();
});
});
it('does not render showUnsetWarning', function (done) {
Vue.nextTick(() => {
expect(this.intervalPatternComponent.$el.outerHTML).not.toContain('Schedule not yet set');
done();
});
});
it('sets isEditable to false', function (done) { it('sets isEditable to false', function (done) {
Vue.nextTick(() => { Vue.nextTick(() => {
expect(this.intervalPatternComponent.isEditable).toBe(false); expect(this.intervalPatternComponent.isEditable).toBe(false);
...@@ -113,20 +85,6 @@ describe('Interval Pattern Input Component', function () { ...@@ -113,20 +85,6 @@ describe('Interval Pattern Input Component', function () {
expect(this.intervalPatternComponent.initialCronInterval).toBe(defaultInitialCronInterval); expect(this.intervalPatternComponent.initialCronInterval).toBe(defaultInitialCronInterval);
}); });
it('sets showUnsetWarning to true', function (done) {
Vue.nextTick(() => {
expect(this.intervalPatternComponent.showUnsetWarning).toBe(true);
done();
});
});
it('renders showUnsetWarning to true', function (done) {
Vue.nextTick(() => {
expect(this.intervalPatternComponent.$el.outerHTML).toContain('Schedule not yet set');
done();
});
});
it('sets isEditable to true', function (done) { it('sets isEditable to true', function (done) {
Vue.nextTick(() => { Vue.nextTick(() => {
expect(this.intervalPatternComponent.isEditable).toBe(true); expect(this.intervalPatternComponent.isEditable).toBe(true);
......
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