diff options
author | Shinya Maeda <shinya@gitlab.com> | 2018-06-01 14:32:40 +0900 |
---|---|---|
committer | Shinya Maeda <shinya@gitlab.com> | 2018-06-01 14:32:40 +0900 |
commit | 272b8dca80eddfcf40933ad5295e9d11f8b1fa93 (patch) | |
tree | 9cafcf1ce1643fbfa1d3237e1af3a569f48d8459 /app | |
parent | 0e22b50df8b269ccae32ab68b9ba26e7eea861b0 (diff) | |
parent | 50fda506e3bc93af47c8ebcbfc7d38c7ae55467d (diff) | |
download | gitlab-ce-272b8dca80eddfcf40933ad5295e9d11f8b1fa93.tar.gz |
Merge branch 'master' into per-project-pipeline-iid
Diffstat (limited to 'app')
145 files changed, 1054 insertions, 840 deletions
diff --git a/app/assets/javascripts/boards/components/modal/empty_state.js b/app/assets/javascripts/boards/components/modal/empty_state.js index eb8a66975ee..1e5f2383223 100644 --- a/app/assets/javascripts/boards/components/modal/empty_state.js +++ b/app/assets/javascripts/boards/components/modal/empty_state.js @@ -41,10 +41,10 @@ gl.issueBoards.ModalEmptyState = Vue.extend({ template: ` <section class="empty-state"> <div class="row"> - <div class="col-xs-12 col-sm-6 order-sm-last"> + <div class="col-12 col-md-6 order-md-last"> <aside class="svg-content"><img :src="emptyStateSvg"/></aside> </div> - <div class="col-xs-12 col-sm-6 order-sm-first"> + <div class="col-12 col-md-6 order-md-first"> <div class="text-content"> <h4>{{ contents.title }}</h4> <p v-html="contents.content"></p> diff --git a/app/assets/javascripts/boards/components/modal/list.js b/app/assets/javascripts/boards/components/modal/list.js index 6c662432037..f86896d2178 100644 --- a/app/assets/javascripts/boards/components/modal/list.js +++ b/app/assets/javascripts/boards/components/modal/list.js @@ -1,5 +1,3 @@ -/* global ListIssue */ - import Vue from 'vue'; import bp from '../../../breakpoints'; import ModalStore from '../../stores/modal_store'; @@ -56,8 +54,11 @@ gl.issueBoards.ModalList = Vue.extend({ scrollHandler() { const currentPage = Math.floor(this.issues.length / this.perPage); - if ((this.scrollTop() > this.scrollHeight() - 100) && !this.loadingNewPage - && currentPage === this.page) { + if ( + this.scrollTop() > this.scrollHeight() - 100 && + !this.loadingNewPage && + currentPage === this.page + ) { this.loadingNewPage = true; this.page += 1; } diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index 371774098b9..eb335f352d3 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -1,71 +1,69 @@ <script> - /* global ListIssue */ +import $ from 'jquery'; +import _ from 'underscore'; +import eventHub from '../eventhub'; +import loadingIcon from '../../vue_shared/components/loading_icon.vue'; +import Api from '../../api'; - import $ from 'jquery'; - import _ from 'underscore'; - import eventHub from '../eventhub'; - import loadingIcon from '../../vue_shared/components/loading_icon.vue'; - import Api from '../../api'; - - export default { - name: 'BoardProjectSelect', - components: { - loadingIcon, - }, - props: { - groupId: { - type: Number, - required: true, - default: 0, - }, +export default { + name: 'BoardProjectSelect', + components: { + loadingIcon, + }, + props: { + groupId: { + type: Number, + required: true, + default: 0, }, - data() { - return { - loading: true, - selectedProject: {}, - }; + }, + data() { + return { + loading: true, + selectedProject: {}, + }; + }, + computed: { + selectedProjectName() { + return this.selectedProject.name || 'Select a project'; }, - computed: { - selectedProjectName() { - return this.selectedProject.name || 'Select a project'; + }, + mounted() { + $(this.$refs.projectsDropdown).glDropdown({ + filterable: true, + filterRemote: true, + search: { + fields: ['name_with_namespace'], }, - }, - mounted() { - $(this.$refs.projectsDropdown).glDropdown({ - filterable: true, - filterRemote: true, - search: { - fields: ['name_with_namespace'], - }, - clicked: ({ $el, e }) => { - e.preventDefault(); - this.selectedProject = { - id: $el.data('project-id'), - name: $el.data('project-name'), - }; - eventHub.$emit('setSelectedProject', this.selectedProject); - }, - selectable: true, - data: (term, callback) => { - this.loading = true; - return Api.groupProjects(this.groupId, term, (projects) => { - this.loading = false; - callback(projects); - }); - }, - renderRow(project) { - return ` + clicked: ({ $el, e }) => { + e.preventDefault(); + this.selectedProject = { + id: $el.data('project-id'), + name: $el.data('project-name'), + }; + eventHub.$emit('setSelectedProject', this.selectedProject); + }, + selectable: true, + data: (term, callback) => { + this.loading = true; + return Api.groupProjects(this.groupId, term, projects => { + this.loading = false; + callback(projects); + }); + }, + renderRow(project) { + return ` <li> <a href='#' class='dropdown-menu-link' data-project-id="${project.id}" data-project-name="${project.name}"> ${_.escape(project.name)} </a> </li> `; - }, - text: project => project.name, - }); - }, - }; + }, + text: project => project.name, + }); + }, +}; </script> <template> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index 705953c86e3..e2b42ab2642 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -126,7 +126,6 @@ export default { </div> <form v-if="!isCompact" - class="form-horizontal" @submit.prevent.stop="commitChanges" ref="formEl" > diff --git a/app/assets/javascripts/ide/components/external_link.vue b/app/assets/javascripts/ide/components/external_link.vue new file mode 100644 index 00000000000..cf3316a8179 --- /dev/null +++ b/app/assets/javascripts/ide/components/external_link.vue @@ -0,0 +1,41 @@ +<script> +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + components: { + Icon, + }, + props: { + file: { + type: Object, + required: true, + }, + }, + computed: { + showButtons() { + return this.file.permalink; + }, + }, +}; +</script> + +<template> + <div + v-if="showButtons" + class="pull-right ide-btn-group" + > + <a + :href="file.permalink" + target="_blank" + :title="s__('IDE|Open in file view')" + rel="noopener noreferrer" + > + <span class="vertical-align-middle">Open in file view</span> + <icon + name="external-link" + css-classes="vertical-align-middle space-right" + :size="16" + /> + </a> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/ide_file_buttons.vue b/app/assets/javascripts/ide/components/ide_file_buttons.vue deleted file mode 100644 index 30b00abf6ed..00000000000 --- a/app/assets/javascripts/ide/components/ide_file_buttons.vue +++ /dev/null @@ -1,84 +0,0 @@ -<script> -import { __ } from '~/locale'; -import tooltip from '~/vue_shared/directives/tooltip'; -import Icon from '~/vue_shared/components/icon.vue'; - -export default { - components: { - Icon, - }, - directives: { - tooltip, - }, - props: { - file: { - type: Object, - required: true, - }, - }, - computed: { - showButtons() { - return ( - this.file.rawPath || this.file.blamePath || this.file.commitsPath || this.file.permalink - ); - }, - rawDownloadButtonLabel() { - return this.file.binary ? __('Download') : __('Raw'); - }, - }, -}; -</script> - -<template> - <div - v-if="showButtons" - class="float-right ide-btn-group" - > - <a - v-tooltip - v-if="!file.binary" - :href="file.blamePath" - :title="__('Blame')" - class="btn btn-sm btn-transparent blame" - > - <icon - name="blame" - :size="16" - /> - </a> - <a - v-tooltip - :href="file.commitsPath" - :title="__('History')" - class="btn btn-sm btn-transparent history" - > - <icon - name="history" - :size="16" - /> - </a> - <a - v-tooltip - :href="file.permalink" - :title="__('Permalink')" - class="btn btn-sm btn-transparent permalink" - > - <icon - name="link" - :size="16" - /> - </a> - <a - v-tooltip - :href="file.rawPath" - target="_blank" - class="btn btn-sm btn-transparent prepend-left-10 raw" - rel="noopener noreferrer" - :title="rawDownloadButtonLabel"> - <icon - name="download" - :size="16" - /> - </a> - </div> -</template> diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index a281ecb95c8..93453989c08 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -6,12 +6,12 @@ import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer import { activityBarViews, viewerTypes } from '../constants'; import monacoLoader from '../monaco_loader'; import Editor from '../lib/editor'; -import IdeFileButtons from './ide_file_buttons.vue'; +import ExternalLink from './external_link.vue'; export default { components: { ContentViewer, - IdeFileButtons, + ExternalLink, }, props: { file: { @@ -224,7 +224,7 @@ export default { </a> </li> </ul> - <ide-file-buttons + <external-link :file="file" /> </div> diff --git a/app/assets/javascripts/ide/lib/common/model.js b/app/assets/javascripts/ide/lib/common/model.js index b1e43a1e38c..e5149b1f3ad 100644 --- a/app/assets/javascripts/ide/lib/common/model.js +++ b/app/assets/javascripts/ide/lib/common/model.js @@ -1,4 +1,3 @@ -/* global monaco */ import Disposable from './disposable'; import eventHub from '../../eventhub'; diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 13aea91d8ba..74f9c112f5a 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -84,11 +84,11 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive }); }; -export const setFileMrChange = ({ state, commit }, { file, mrChange }) => { +export const setFileMrChange = ({ commit }, { file, mrChange }) => { commit(types.SET_FILE_MERGE_REQUEST_CHANGE, { file, mrChange }); }; -export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) => { +export const getRawFileData = ({ state, commit }, { path, baseSha }) => { const file = state.entries[path]; return new Promise((resolve, reject) => { service @@ -156,7 +156,7 @@ export const setEditorPosition = ({ getters, commit }, { editorRow, editorColumn } }; -export const setFileViewMode = ({ state, commit }, { file, viewMode }) => { +export const setFileViewMode = ({ commit }, { file, viewMode }) => { commit(types.SET_FILE_VIEWMODE, { file, viewMode }); }; diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js index da73034fd7d..5ec9bd661bb 100644 --- a/app/assets/javascripts/ide/stores/actions/merge_request.js +++ b/app/assets/javascripts/ide/stores/actions/merge_request.js @@ -3,7 +3,7 @@ import service from '../../services'; import * as types from '../mutation_types'; export const getMergeRequestData = ( - { commit, state, dispatch }, + { commit, state }, { projectId, mergeRequestId, force = false } = {}, ) => new Promise((resolve, reject) => { @@ -32,7 +32,7 @@ export const getMergeRequestData = ( }); export const getMergeRequestChanges = ( - { commit, state, dispatch }, + { commit, state }, { projectId, mergeRequestId, force = false } = {}, ) => new Promise((resolve, reject) => { @@ -58,7 +58,7 @@ export const getMergeRequestChanges = ( }); export const getMergeRequestVersions = ( - { commit, state, dispatch }, + { commit, state }, { projectId, mergeRequestId, force = false } = {}, ) => new Promise((resolve, reject) => { diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js index cece9154c82..75cfd9946d7 100644 --- a/app/assets/javascripts/ide/stores/actions/project.js +++ b/app/assets/javascripts/ide/stores/actions/project.js @@ -7,10 +7,7 @@ import Poll from '../../../lib/utils/poll'; let eTagPoll; -export const getProjectData = ( - { commit, state, dispatch }, - { namespace, projectId, force = false } = {}, -) => +export const getProjectData = ({ commit, state }, { namespace, projectId, force = false } = {}) => new Promise((resolve, reject) => { if (!state.projects[`${namespace}/${projectId}`] || force) { commit(types.TOGGLE_LOADING, { entry: state }); @@ -40,10 +37,7 @@ export const getProjectData = ( } }); -export const getBranchData = ( - { commit, state, dispatch }, - { projectId, branchId, force = false } = {}, -) => +export const getBranchData = ({ commit, state }, { projectId, branchId, force = false } = {}) => new Promise((resolve, reject) => { if ( typeof state.projects[`${projectId}`] === 'undefined' || @@ -78,7 +72,7 @@ export const getBranchData = ( } }); -export const refreshLastCommitData = ({ commit, state, dispatch }, { projectId, branchId } = {}) => +export const refreshLastCommitData = ({ commit }, { projectId, branchId } = {}) => service .getBranchData(projectId, branchId) .then(({ data }) => { @@ -92,7 +86,7 @@ export const refreshLastCommitData = ({ commit, state, dispatch }, { projectId, flash(__('Error loading last commit.'), 'alert', document, null, false, true); }); -export const pollSuccessCallBack = ({ commit, state, dispatch }, { data }) => { +export const pollSuccessCallBack = ({ commit, state }, { data }) => { if (data.pipelines && data.pipelines.length) { const lastCommitHash = state.projects[state.currentProjectId].branches[state.currentBranchId].commit.id; diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js index 6536be04f0a..cc5116413f7 100644 --- a/app/assets/javascripts/ide/stores/actions/tree.js +++ b/app/assets/javascripts/ide/stores/actions/tree.js @@ -5,7 +5,7 @@ import * as types from '../mutation_types'; import { findEntry } from '../utils'; import FilesDecoratorWorker from '../workers/files_decorator_worker'; -export const toggleTreeOpen = ({ commit, dispatch }, path) => { +export const toggleTreeOpen = ({ commit }, path) => { commit(types.TOGGLE_TREE_OPEN, path); }; @@ -23,7 +23,7 @@ export const handleTreeEntryAction = ({ commit, dispatch }, row) => { } }; -export const getLastCommitData = ({ state, commit, dispatch, getters }, tree = state) => { +export const getLastCommitData = ({ state, commit, dispatch }, tree = state) => { if (!tree || tree.lastCommitPath === null || !tree.lastCommitPath) return; service @@ -49,7 +49,7 @@ export const getLastCommitData = ({ state, commit, dispatch, getters }, tree = s .catch(() => flash('Error fetching log data.', 'alert', document, null, false, true)); }; -export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } = {}) => +export const getFiles = ({ state, commit }, { projectId, branchId } = {}) => new Promise((resolve, reject) => { if (!state.trees[`${projectId}/${branchId}`]) { const selectedProject = state.projects[projectId]; diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index cd25c3060f2..0a0db4033c8 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -31,9 +31,9 @@ export const setLastCommitMessage = ({ rootState, commit }, data) => { const currentProject = rootState.projects[rootState.currentProjectId]; const commitStats = data.stats ? sprintf(__('with %{additions} additions, %{deletions} deletions.'), { - additions: data.stats.additions, // eslint-disable-line indent - deletions: data.stats.deletions, // eslint-disable-line indent - }) // eslint-disable-line indent + additions: data.stats.additions, // eslint-disable-line indent-legacy + deletions: data.stats.deletions, // eslint-disable-line indent-legacy + }) // eslint-disable-line indent-legacy : ''; const commitMsg = sprintf( __('Your changes have been committed. Commit %{commitId} %{commitStats}'), @@ -74,10 +74,7 @@ export const checkCommitStatus = ({ rootState }) => ), ); -export const updateFilesAfterCommit = ( - { commit, dispatch, state, rootState, rootGetters }, - { data }, -) => { +export const updateFilesAfterCommit = ({ commit, dispatch, rootState }, { data }) => { const selectedProject = rootState.projects[rootState.currentProjectId]; const lastCommit = { commit_path: `${selectedProject.web_url}/commit/${data.id}`, diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index 90d4e19e90b..bb8b3d91e40 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -30,7 +30,7 @@ export default class IssuableForm { } this.initAutosave(); - this.form.on('submit:success', this.handleSubmit); + this.form.on('submit', this.handleSubmit); this.form.on('click', '.btn-cancel', this.resetAutosave); this.initWip(); diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index c67bd7fb0c6..611e8200b4d 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -84,7 +84,7 @@ export default class Job { If the browser does not support position sticky, it returns the position as static. If the browser does support sticky, then we allow the browser to handle it, if not then we use a polyfill - **/ + */ if (this.$topBar.css('position') !== 'static') return; StickyFill.add(this.$topBar); diff --git a/app/assets/javascripts/jobs/job_details_mediator.js b/app/assets/javascripts/jobs/job_details_mediator.js index 5a216f8fae2..89019da9d1e 100644 --- a/app/assets/javascripts/jobs/job_details_mediator.js +++ b/app/assets/javascripts/jobs/job_details_mediator.js @@ -1,5 +1,3 @@ -/* global Build */ - import Visibility from 'visibilityjs'; import Flash from '../flash'; import Poll from '../lib/utils/poll'; @@ -50,7 +48,8 @@ export default class JobMediator { } getJob() { - return this.service.getJob() + return this.service + .getJob() .then(response => this.successCallback(response)) .catch(() => this.errorCallback()); } diff --git a/app/assets/javascripts/locale/index.js b/app/assets/javascripts/locale/index.js index 2f4328b56e1..2cc5fb10027 100644 --- a/app/assets/javascripts/locale/index.js +++ b/app/assets/javascripts/locale/index.js @@ -9,7 +9,7 @@ delete window.translations; Translates `text` @param text The text to be translated @returns {String} The translated text -**/ +*/ const gettext = locale.gettext.bind(locale); /** @@ -21,7 +21,7 @@ const gettext = locale.gettext.bind(locale); @param pluralText Plural text to translate (eg. '%d days') @param count Number to decide which translation to use (eg. 2) @returns {String} Translated text with the number replaced (eg. '2 days') -**/ +*/ const ngettext = (text, pluralText, count) => { const translated = locale.ngettext(text, pluralText, count).replace(/%d/g, count).split('|'); @@ -38,7 +38,7 @@ const ngettext = (text, pluralText, count) => { (eg. 'Context') @param key Is the dynamic variable you want to be translated @returns {String} Translated context based text -**/ +*/ const pgettext = (keyOrContext, key) => { const normalizedKey = key ? `${keyOrContext}|${key}` : keyOrContext; const translated = gettext(normalizedKey).split('|'); diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js index 5f4a053f98e..599104dcfa0 100644 --- a/app/assets/javascripts/locale/sprintf.js +++ b/app/assets/javascripts/locale/sprintf.js @@ -10,7 +10,7 @@ import _ from 'underscore'; @see https://ruby-doc.org/core-2.3.3/Kernel.html#method-i-sprintf @see https://gitlab.com/gitlab-org/gitlab-ce/issues/37992 -**/ +*/ export default (input, parameters, escapeParameters = true) => { let output = input; diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index bac7d966ecc..493c119dc6f 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -427,7 +427,7 @@ export default class MergeRequestTabs { If the browser does not support position sticky, it returns the position as static. If the browser does support sticky, then we allow the browser to handle it, if not then we default back to Bootstraps affix - **/ + */ if ($tabs.css('position') !== 'static') return; const $diffTabs = $('#diff-notes-app'); diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 98ce070288e..b2222476924 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -12,20 +12,13 @@ import { isInViewport, scrollToElement } from '../../lib/utils/common_utils'; let eTagPoll; -export const setNotesData = ({ commit }, data) => - commit(types.SET_NOTES_DATA, data); -export const setNoteableData = ({ commit }, data) => - commit(types.SET_NOTEABLE_DATA, data); -export const setUserData = ({ commit }, data) => - commit(types.SET_USER_DATA, data); -export const setLastFetchedAt = ({ commit }, data) => - commit(types.SET_LAST_FETCHED_AT, data); -export const setInitialNotes = ({ commit }, data) => - commit(types.SET_INITIAL_NOTES, data); -export const setTargetNoteHash = ({ commit }, data) => - commit(types.SET_TARGET_NOTE_HASH, data); -export const toggleDiscussion = ({ commit }, data) => - commit(types.TOGGLE_DISCUSSION, data); +export const setNotesData = ({ commit }, data) => commit(types.SET_NOTES_DATA, data); +export const setNoteableData = ({ commit }, data) => commit(types.SET_NOTEABLE_DATA, data); +export const setUserData = ({ commit }, data) => commit(types.SET_USER_DATA, data); +export const setLastFetchedAt = ({ commit }, data) => commit(types.SET_LAST_FETCHED_AT, data); +export const setInitialNotes = ({ commit }, data) => commit(types.SET_INITIAL_NOTES, data); +export const setTargetNoteHash = ({ commit }, data) => commit(types.SET_TARGET_NOTE_HASH, data); +export const toggleDiscussion = ({ commit }, data) => commit(types.TOGGLE_DISCUSSION, data); export const fetchNotes = ({ commit }, path) => service @@ -69,20 +62,14 @@ export const createNewNote = ({ commit }, { endpoint, data }) => return res; }); -export const removePlaceholderNotes = ({ commit }) => - commit(types.REMOVE_PLACEHOLDER_NOTES); +export const removePlaceholderNotes = ({ commit }) => commit(types.REMOVE_PLACEHOLDER_NOTES); -export const toggleResolveNote = ( - { commit }, - { endpoint, isResolved, discussion }, -) => +export const toggleResolveNote = ({ commit }, { endpoint, isResolved, discussion }) => service .toggleResolveNote(endpoint, isResolved) .then(res => res.json()) .then(res => { - const mutationType = discussion - ? types.UPDATE_DISCUSSION - : types.UPDATE_NOTE; + const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE; commit(mutationType, res); }); @@ -114,7 +101,7 @@ export const reopenIssue = ({ commit, dispatch, state }) => { export const toggleStateButtonLoading = ({ commit }, value) => commit(types.TOGGLE_STATE_BUTTON_LOADING, value); -export const emitStateChangedEvent = ({ commit, getters }, data) => { +export const emitStateChangedEvent = ({ getters }, data) => { const event = new CustomEvent('issuable_vue_app:change', { detail: { data, @@ -179,10 +166,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => { loadAwardsHandler() .then(awardsHandler => { - awardsHandler.addAwardToEmojiBar( - votesBlock, - commandsChanges.emoji_award, - ); + awardsHandler.addAwardToEmojiBar(votesBlock, commandsChanges.emoji_award); awardsHandler.scrollToAwards(); }) .catch(() => { @@ -194,10 +178,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => { }); } - if ( - commandsChanges.spend_time != null || - commandsChanges.time_estimate != null - ) { + if (commandsChanges.spend_time != null || commandsChanges.time_estimate != null) { sidebarTimeTrackingEventHub.$emit('timeTrackingUpdated', res); } } @@ -218,14 +199,8 @@ const pollSuccessCallBack = (resp, commit, state, getters) => { resp.notes.forEach(note => { if (notesById[note.id]) { commit(types.UPDATE_NOTE, note); - } else if ( - note.type === constants.DISCUSSION_NOTE || - note.type === constants.DIFF_NOTE - ) { - const discussion = utils.findNoteObjectById( - state.notes, - note.discussion_id, - ); + } else if (note.type === constants.DISCUSSION_NOTE || note.type === constants.DIFF_NOTE) { + const discussion = utils.findNoteObjectById(state.notes, note.discussion_id); if (discussion) { commit(types.ADD_NEW_REPLY_TO_DISCUSSION, note); @@ -249,11 +224,8 @@ export const poll = ({ commit, state, getters }) => { method: 'poll', data: state, successCallback: resp => - resp - .json() - .then(data => pollSuccessCallBack(data, commit, state, getters)), - errorCallback: () => - Flash('Something went wrong while fetching latest comments.'), + resp.json().then(data => pollSuccessCallBack(data, commit, state, getters)), + errorCallback: () => Flash('Something went wrong while fetching latest comments.'), }); if (!Visibility.hidden()) { @@ -292,14 +264,11 @@ export const fetchData = ({ commit, state, getters }) => { .catch(() => Flash('Something went wrong while fetching latest comments.')); }; -export const toggleAward = ( - { commit, state, getters, dispatch }, - { awardName, noteId }, -) => { +export const toggleAward = ({ commit, getters }, { awardName, noteId }) => { commit(types.TOGGLE_AWARD, { awardName, note: getters.notesById[noteId] }); }; -export const toggleAwardRequest = ({ commit, getters, dispatch }, data) => { +export const toggleAwardRequest = ({ dispatch }, data) => { const { endpoint, awardName } = data; return service diff --git a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue index df21e2f8771..5765eed4d45 100644 --- a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue +++ b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue @@ -59,7 +59,7 @@ export default { ref="form" :action="deleteWikiUrl" method="post" - class="form-horizontal js-requires-input" + class="js-requires-input" > <input ref="method" diff --git a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js index 53030045292..18c7b21cf8c 100644 --- a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js +++ b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js @@ -5,7 +5,7 @@ import $ from 'jquery'; * * Toggling this checkbox adds/removes a `remember_me` parameter to the * login buttons' href, which is passed on to the omniauth callback. - **/ + */ export default class OAuthRememberMe { constructor(opts = {}) { diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue index 7bfe11ab8cd..e64afc94ef9 100644 --- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue @@ -79,12 +79,13 @@ export default { }; </script> <template> - <div class="ci-job-dropdown-container dropdown"> + <div class="ci-job-dropdown-container dropdown dropright"> <button v-tooltip type="button" data-toggle="dropdown" data-container="body" + data-boundary="viewport" class="dropdown-menu-toggle build-content" :title="tooltipText" > diff --git a/app/assets/javascripts/raven/raven_config.js b/app/assets/javascripts/raven/raven_config.js index ae54fa5f1a9..658caeecde1 100644 --- a/app/assets/javascripts/raven/raven_config.js +++ b/app/assets/javascripts/raven/raven_config.js @@ -37,7 +37,7 @@ const IGNORE_URLS = [ /extensions\//i, /^chrome:\/\//i, // Other plugins - /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb + /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb /webappstoolbarba\.texthelp\.com\//i, /metrics\.itunes\.apple\.com\.edgesuite\.net\//i, ]; diff --git a/app/assets/javascripts/registry/stores/actions.js b/app/assets/javascripts/registry/stores/actions.js index 593a43c7cc1..c0de03373d8 100644 --- a/app/assets/javascripts/registry/stores/actions.js +++ b/app/assets/javascripts/registry/stores/actions.js @@ -7,9 +7,10 @@ Vue.use(VueResource); export const fetchRepos = ({ commit, state }) => { commit(types.TOGGLE_MAIN_LOADING); - return Vue.http.get(state.endpoint) + return Vue.http + .get(state.endpoint) .then(res => res.json()) - .then((response) => { + .then(response => { commit(types.TOGGLE_MAIN_LOADING); commit(types.SET_REPOS_LIST, response); }); @@ -18,19 +19,20 @@ export const fetchRepos = ({ commit, state }) => { export const fetchList = ({ commit }, { repo, page }) => { commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo); - return Vue.http.get(repo.tagsPath, { params: { page } }) - .then((response) => { - const headers = response.headers; + return Vue.http.get(repo.tagsPath, { params: { page } }).then(response => { + const headers = response.headers; - return response.json().then((resp) => { - commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo); - commit(types.SET_REGISTRY_LIST, { repo, resp, headers }); - }); + return response.json().then(resp => { + commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo); + commit(types.SET_REGISTRY_LIST, { repo, resp, headers }); }); + }); }; +// eslint-disable-next-line no-unused-vars export const deleteRepo = ({ commit }, repo) => Vue.http.delete(repo.destroyPath); +// eslint-disable-next-line no-unused-vars export const deleteRegistry = ({ commit }, image) => Vue.http.delete(image.destroyPath); export const setMainEndpoint = ({ commit }, data) => commit(types.SET_MAIN_ENDPOINT, data); diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue index 8c7e0664559..eb581b807a2 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue @@ -168,8 +168,8 @@ <a :href="mr.mergeCommitPath" class="commit-sha js-mr-merged-commit-sha" + v-text="mr.shortMergeCommitSha" > - {{ mr.shortMergeCommitSha }} </a> <clipboard-button :title="__('Copy commit SHA to clipboard')" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue index 926a3172412..875c3323dbb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue @@ -1,15 +1,63 @@ -/* -The squash-before-merge button is EE only, but it's located right in the middle -of the readyToMerge state component template. - -If we didn't declare this component in CE, we'd need to maintain a separate copy -of the readyToMergeState template in EE, which is pretty big and likely to change. - -Instead, in CE, we declare the component, but it's hidden and is configured to do nothing. -In EE, the configuration extends this object to add a functioning squash-before-merge -button. -*/ - <script> - export default {}; +import Icon from '~/vue_shared/components/icon.vue'; +import eventHub from '~/vue_merge_request_widget/event_hub'; +import tooltip from '~/vue_shared/directives/tooltip'; + +export default { + components: { + Icon, + }, + directives: { + tooltip, + }, + props: { + mr: { + type: Object, + required: true, + }, + isMergeButtonDisabled: { + type: Boolean, + required: true, + }, + }, + data() { + return { + squashBeforeMerge: this.mr.squash, + }; + }, + methods: { + updateSquashModel() { + eventHub.$emit('MRWidgetUpdateSquash', this.squashBeforeMerge); + }, + }, +}; </script> + +<template> + <div class="accept-control inline"> + <label class="merge-param-checkbox"> + <input + type="checkbox" + name="squash" + class="qa-squash-checkbox" + :disabled="isMergeButtonDisabled" + v-model="squashBeforeMerge" + @change="updateSquashModel" + /> + {{ __('Squash commits') }} + </label> + <a + :href="mr.squashBeforeMergeHelpPath" + data-title="About this feature" + data-placement="bottom" + target="_blank" + rel="noopener noreferrer nofollow" + data-container="body" + v-tooltip + > + <icon + name="question-o" + /> + </a> + </div> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index 1d1c8ebc179..3a194320bd8 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -6,11 +6,13 @@ import MergeRequest from '../../../merge_request'; import Flash from '../../../flash'; import statusIcon from '../mr_widget_status_icon.vue'; import eventHub from '../../event_hub'; +import SquashBeforeMerge from './mr_widget_squash_before_merge.vue'; export default { name: 'ReadyToMerge', components: { statusIcon, + 'squash-before-merge': SquashBeforeMerge, }, props: { mr: { type: Object, required: true }, @@ -101,6 +103,12 @@ export default { return enableSquashBeforeMerge && commitsCount > 1; }, }, + created() { + eventHub.$on('MRWidgetUpdateSquash', this.handleUpdateSquash); + }, + beforeDestroy() { + eventHub.$off('MRWidgetUpdateSquash', this.handleUpdateSquash); + }, methods: { shouldShowMergeControls() { return this.mr.isMergeAllowed || this.shouldShowMergeWhenPipelineSucceedsText; @@ -128,13 +136,9 @@ export default { commit_message: this.commitMessage, merge_when_pipeline_succeeds: this.setToMergeWhenPipelineSucceeds, should_remove_source_branch: this.removeSourceBranch === true, + squash: this.mr.squash, }; - // Only truthy in EE extension of this component - if (this.setAdditionalParams) { - this.setAdditionalParams(options); - } - this.isMakingRequest = true; this.service.merge(options) .then(res => res.data) @@ -154,6 +158,9 @@ export default { new Flash('Something went wrong. Please try again.'); // eslint-disable-line }); }, + handleUpdateSquash(val) { + this.mr.squash = val; + }, initiateMergePolling() { simplePoll((continuePolling, stopPolling) => { this.handleMergePolling(continuePolling, stopPolling); diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index 83b7b054e6f..e5b7e1f1c68 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -15,6 +15,11 @@ export default class MergeRequestStore { const currentUser = data.current_user; const pipelineStatus = data.pipeline ? data.pipeline.details.status : null; + this.squash = data.squash; + this.squashBeforeMergeHelpPath = this.squashBeforeMergeHelpPath || + data.squash_before_merge_help_path; + this.enableSquashBeforeMerge = this.enableSquashBeforeMerge || true; + this.title = data.title; this.targetBranch = data.target_branch; this.sourceBranch = data.source_branch; diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js index 155e6b6698a..4f2412ce520 100644 --- a/app/assets/javascripts/vue_shared/directives/tooltip.js +++ b/app/assets/javascripts/vue_shared/directives/tooltip.js @@ -2,7 +2,9 @@ import $ from 'jquery'; export default { bind(el) { - $(el).tooltip(); + $(el).tooltip({ + trigger: 'hover', + }); }, componentUpdated(el) { diff --git a/app/assets/javascripts/vue_shared/translate.js b/app/assets/javascripts/vue_shared/translate.js index 2c7886ec308..48c63373b77 100644 --- a/app/assets/javascripts/vue_shared/translate.js +++ b/app/assets/javascripts/vue_shared/translate.js @@ -13,7 +13,7 @@ export default (Vue) => { @param text The text to be translated @returns {String} The translated text - **/ + */ __, /** Translate the text with a number @@ -24,7 +24,7 @@ export default (Vue) => { @param pluralText Plural text to translate (eg. '%d days') @param count Number to decide which translation to use (eg. 2) @returns {String} Translated text with the number replaced (eg. '2 days') - **/ + */ n__, /** Translate context based text @@ -36,7 +36,7 @@ export default (Vue) => { (eg. 'Context') @param key Is the dynamic variable you want to be translated @returns {String} Translated context based text - **/ + */ s__, sprintf, }, diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss index e1a47f3d686..4a4da027c92 100644 --- a/app/assets/stylesheets/bootstrap_migration.scss +++ b/app/assets/stylesheets/bootstrap_migration.scss @@ -87,7 +87,8 @@ table { display: none; } -.dropdown-toggle::after { +.dropdown-toggle::after, +.dropright .dropdown-menu-toggle::after { // Remove bootstrap's dropdown caret display: none; } @@ -148,8 +149,14 @@ table { } } -.nav-tabs .nav-link { - border: 0; +.nav-tabs { + .nav-link { + border: 0; + } + + .nav-item { + margin-bottom: 0; + } } pre code { diff --git a/app/assets/stylesheets/errors.scss b/app/assets/stylesheets/errors.scss new file mode 100644 index 00000000000..658e0ff638e --- /dev/null +++ b/app/assets/stylesheets/errors.scss @@ -0,0 +1,120 @@ +/* + * This is a minimal stylesheet, meant to be used for error pages. + */ +@import 'framework/variables'; +@import '../../../node_modules/bootstrap/scss/functions'; +@import '../../../node_modules/bootstrap/scss/variables'; +@import '../../../node_modules/bootstrap/scss/mixins'; +@import '../../../node_modules/bootstrap/scss/reboot'; +@import '../../../node_modules/bootstrap/scss/buttons'; +@import '../../../node_modules/bootstrap/scss/forms'; + +$body-color: #666; +$header-color: #456; + +body { + color: $body-color; + text-align: center; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: auto; + font-size: 14px; +} + +h1 { + font-size: 56px; + line-height: 100px; + font-weight: 400; + color: $header-color; +} + +h2 { + font-size: 24px; + color: $body-color; + line-height: 1.5em; +} + +h3 { + color: $header-color; + font-size: 20px; + font-weight: 400; + line-height: 28px; +} + +img { + max-width: 80vw; + display: block; + margin: 40px auto; +} + +a { + text-decoration: none; + color: $blue-600; +} + +.page-container { + margin: auto 20px; +} + +.container { + margin: auto; + max-width: 600px; + border-bottom: 1px solid $border-color; + padding-bottom: 1em; +} + +.action-container { + padding: 0.5em 0; +} + +.form-inline-flex { + display: flex; + flex-wrap: wrap; + + button { + display: block; + width: 100%; + } + + .field { + display: block; + width: 100%; + margin-bottom: 1em; + } + + @include media-breakpoint-up(sm) { + flex-wrap: nowrap; + + button { + width: auto; + } + + .field { + margin-bottom: 0; + margin-right: 0.5em; + } + } +} + +.error-nav { + padding: 0; + text-align: center; + + li { + display: block; + padding-bottom: 1em; + } + + @include media-breakpoint-up(sm) { + + li { + display: inline-block; + padding-bottom: 0; + + &:not(:first-child)::before { + content: '\00B7'; + display: inline-block; + padding: 0 1em; + } + } + } +} diff --git a/app/assets/stylesheets/framework/gitlab_theme.scss b/app/assets/stylesheets/framework/gitlab_theme.scss index d6ae8cbb416..3bbb50117bc 100644 --- a/app/assets/stylesheets/framework/gitlab_theme.scss +++ b/app/assets/stylesheets/framework/gitlab_theme.scss @@ -169,11 +169,14 @@ color: $color-800; } - .nav-links li a.active { - border-bottom: 2px solid $color-500; + .nav-links li { + &.active a, + a.active { + border-bottom: 2px solid $color-500; - .badge.badge-pill { - font-weight: $gl-font-weight-bold; + .badge.badge-pill { + font-weight: $gl-font-weight-bold; + } } } diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 0ea0b65b95f..d76cf8f8182 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -19,14 +19,23 @@ width: auto; display: inline-block; overflow-x: auto; - border-left: 0; - border-right: 0; - border-bottom: 0; + border: 0; + border-color: $md-area-border; @supports(width: fit-content) { display: block; width: fit-content; } + + tr { + th { + border-bottom: solid 2px $md-area-border; + } + + td { + border-color: $md-area-border; + } + } } /* diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss index 667661d8b5c..ed5a1c91d8f 100644 --- a/app/assets/stylesheets/framework/modal.scss +++ b/app/assets/stylesheets/framework/modal.scss @@ -74,12 +74,6 @@ body.modal-open { } } -@include media-breakpoint-up(lg) { - .modal-full { - width: 98%; - } -} - .modal { background-color: $black-transparent; z-index: 2100; diff --git a/app/assets/stylesheets/framework/secondary_navigation_elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss index c3c64adf3da..847fc8c0792 100644 --- a/app/assets/stylesheets/framework/secondary_navigation_elements.scss +++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss @@ -31,14 +31,15 @@ color: $black; } } + } - &.active { - color: $black; - font-weight: $gl-font-weight-bold; + &.active a, + a.active { + color: $black; + font-weight: $gl-font-weight-bold; - .badge.badge-pill { - color: $black; - } + .badge.badge-pill { + color: $black; } } } diff --git a/app/assets/stylesheets/framework/snippets.scss b/app/assets/stylesheets/framework/snippets.scss index f80e9b1014b..7152ef9bcfd 100644 --- a/app/assets/stylesheets/framework/snippets.scss +++ b/app/assets/stylesheets/framework/snippets.scss @@ -49,26 +49,11 @@ margin-top: 15px; } -.snippet-embed-input { - height: 35px; -} - .embed-snippet { padding-right: 0; padding-top: $gl-padding; - .form-control { - cursor: auto; - width: 101%; - margin-left: -1px; - } - .embed-toggle-list li button { padding: 8px 40px; } - - .embed-toggle, - .snippet-clipboard-btn { - height: 35px; - } } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 89b61530ddb..946223cfff0 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -373,6 +373,7 @@ $dropdown-chevron-size: 10px; $dropdown-toggle-active-border-color: darken($border-color, 14%); $dropdown-item-hover-bg: $gray-darker; $dropdown-fade-mask-height: 32px; +$dropdown-member-form-control-width: 163px; /* * Filtered Search diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index de2b5701e2d..9914555d309 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -36,13 +36,12 @@ } } - .form-horizontal { - margin-top: 20px; + .form-group { + margin-bottom: 0; - @include media-breakpoint-up(sm) { - display: -webkit-flex; - display: flex; - margin-top: 3px; + @include media-breakpoint-down(sm) { + display: block; + margin-left: 5px; } } @@ -62,10 +61,15 @@ } .member-form-control { - @include media-breakpoint-down(xs) { - padding-bottom: 5px; + @include media-breakpoint-down(sm) { + width: $dropdown-member-form-control-width; margin-left: 0; + padding-bottom: 5px; + } + + @include media-breakpoint-down(xs) { margin-right: 0; + width: auto; } } @@ -207,10 +211,6 @@ align-self: flex-start; } - .form-horizontal ~ .btn { - margin-right: 0; - } - @include media-breakpoint-down(xs) { display: block; @@ -220,6 +220,12 @@ display: block; } + .controls > .btn:last-child { + margin-left: 5px; + margin-right: 5px; + width: auto; + } + .form-control { width: 100%; } @@ -232,10 +238,6 @@ .member-controls { margin-top: 5px; } - - .form-horizontal { - margin-top: 10px; - } } } @@ -259,10 +261,6 @@ margin-top: 0; } - .form-horizontal { - display: block; - } - .member-form-control { margin: 5px 0; } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2843d70c645..db8a8cdc0d2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -146,14 +146,15 @@ class ApplicationController < ActionController::Base end def render_403 - head :forbidden + respond_to do |format| + format.any { head :forbidden } + format.html { render "errors/access_denied", layout: "errors", status: 403 } + end end def render_404 respond_to do |format| - format.html do - render file: Rails.root.join("public", "404"), layout: false, status: "404" - end + format.html { render "errors/not_found", layout: "errors", status: 404 } # Prevent the Rails CSRF protector from thinking a missing .js file is a JavaScript file format.js { render json: '', status: :not_found, content_type: 'application/json' } format.any { head :not_found } diff --git a/app/controllers/concerns/issues_action.rb b/app/controllers/concerns/issues_action.rb index 3b11a373368..b6eb7d292fc 100644 --- a/app/controllers/concerns/issues_action.rb +++ b/app/controllers/concerns/issues_action.rb @@ -17,10 +17,23 @@ module IssuesAction end # rubocop:enable Gitlab/ModuleWithInstanceVariables + # rubocop:disable Gitlab/ModuleWithInstanceVariables + def issues_calendar + @issues = issuables_collection + .non_archived + .with_due_date + .limit(100) + + respond_to do |format| + format.ics { response.headers['Content-Disposition'] = 'inline' } + end + end + # rubocop:enable Gitlab/ModuleWithInstanceVariables + private def finder_type (super if defined?(super)) || - (IssuesFinder if action_name == 'issues') + (IssuesFinder if %w(issues issues_calendar).include?(action_name)) end end diff --git a/app/controllers/groups/shared_projects_controller.rb b/app/controllers/groups/shared_projects_controller.rb new file mode 100644 index 00000000000..f2f835767e0 --- /dev/null +++ b/app/controllers/groups/shared_projects_controller.rb @@ -0,0 +1,31 @@ +module Groups + class SharedProjectsController < Groups::ApplicationController + respond_to :json + before_action :group + skip_cross_project_access_check :index + + def index + shared_projects = GroupProjectsFinder.new( + group: group, + current_user: current_user, + params: finder_params, + options: { only_shared: true } + ).execute + serializer = GroupChildSerializer.new(current_user: current_user) + .with_pagination(request, response) + + render json: serializer.represent(shared_projects) + end + + private + + def finder_params + @finder_params ||= begin + # Make the `search` param consistent for the frontend, + # which will be using `filter`. + params[:search] ||= params[:filter] if params[:filter] + params.permit(:sort, :search) + end + end + end +end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 9f5ad23a20f..074db361949 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -34,12 +34,12 @@ class ProfilesController < Profiles::ApplicationController redirect_to profile_personal_access_tokens_path end - def reset_rss_token + def reset_feed_token Users::UpdateService.new(current_user, user: @user).execute! do |user| - user.reset_rss_token! + user.reset_feed_token! end - flash[:notice] = "RSS token was successfully reset" + flash[:notice] = 'Feed token was successfully reset' redirect_to profile_personal_access_tokens_path end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index d69015c8665..35c36c725e2 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -10,8 +10,8 @@ class Projects::IssuesController < Projects::ApplicationController before_action :whitelist_query_limiting, only: [:create, :create_merge_request, :move, :bulk_update] before_action :check_issues_available! - before_action :issue, except: [:index, :new, :create, :bulk_update] - before_action :set_issuables_index, only: [:index] + before_action :issue, except: [:index, :calendar, :new, :create, :bulk_update] + before_action :set_issuables_index, only: [:index, :calendar] # Allow write(create) issue before_action :authorize_create_issue!, only: [:new, :create] @@ -39,6 +39,17 @@ class Projects::IssuesController < Projects::ApplicationController end end + def calendar + @issues = @issuables + .non_archived + .with_due_date + .limit(100) + + respond_to do |format| + format.ics { response.headers['Content-Disposition'] = 'inline' } + end + end + def new params[:issue] ||= ActionController::Parameters.new( assignee_ids: "" diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb index 67d4ea2ca8f..29632bef7e5 100644 --- a/app/controllers/projects/merge_requests/application_controller.rb +++ b/app/controllers/projects/merge_requests/application_controller.rb @@ -24,6 +24,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont :source_branch, :source_project_id, :state_event, + :squash, :target_branch, :target_project_id, :task_num, diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 62b739918e6..ecea6e1b2bf 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -253,7 +253,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def merge_params_attributes - [:should_remove_source_branch, :commit_message] + [:should_remove_source_branch, :commit_message, :squash] end def merge_when_pipeline_succeeds_active? @@ -282,7 +282,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo return :sha_mismatch if params[:sha] != @merge_request.diff_head_sha - @merge_request.update(merge_error: nil) + @merge_request.update(merge_error: nil, squash: merge_params.fetch(:squash, false)) if params[:merge_when_pipeline_succeeds].present? return :failed unless @merge_request.actual_head_pipeline @@ -296,14 +296,14 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo elsif @merge_request.actual_head_pipeline.success? # This can be triggered when a user clicks the auto merge button while # the tests finish at about the same time - @merge_request.merge_async(current_user.id, params) + @merge_request.merge_async(current_user.id, merge_params) :success else :failed end else - @merge_request.merge_async(current_user.id, params) + @merge_request.merge_async(current_user.id, merge_params) :success end diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb index 1787b4899cd..3626670d141 100644 --- a/app/finders/issues_finder.rb +++ b/app/finders/issues_finder.rb @@ -75,6 +75,8 @@ class IssuesFinder < IssuableFinder items = items.due_between(Date.today.beginning_of_week, Date.today.end_of_week) elsif filter_by_due_this_month? items = items.due_between(Date.today.beginning_of_month, Date.today.end_of_month) + elsif filter_by_due_next_month_and_previous_two_weeks? + items = items.due_between(Date.today - 2.weeks, (Date.today + 1.month).end_of_month) end end @@ -97,6 +99,10 @@ class IssuesFinder < IssuableFinder due_date? && params[:due_date] == Issue::DueThisMonth.name end + def filter_by_due_next_month_and_previous_two_weeks? + due_date? && params[:due_date] == Issue::DueNextMonthAndPreviousTwoWeeks.name + end + def due_date? params[:due_date].present? end diff --git a/app/helpers/calendar_helper.rb b/app/helpers/calendar_helper.rb new file mode 100644 index 00000000000..c54b91b0ce5 --- /dev/null +++ b/app/helpers/calendar_helper.rb @@ -0,0 +1,8 @@ +module CalendarHelper + def calendar_url_options + { format: :ics, + feed_token: current_user.try(:feed_token), + due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name, + sort: 'closest_future_date' } + end +end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index c19c5b9cc82..74251c260f0 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -97,8 +97,9 @@ module MergeRequestsHelper { merge_when_pipeline_succeeds: true, should_remove_source_branch: true, - sha: merge_request.diff_head_sha - }.merge(merge_params_ee(merge_request)) + sha: merge_request.diff_head_sha, + squash: merge_request.squash + } end def tab_link_for(merge_request, tab, options = {}, &block) @@ -149,8 +150,4 @@ module MergeRequestsHelper current_user.fork_of(project) end end - - def merge_params_ee(merge_request) - {} - end end diff --git a/app/helpers/rss_helper.rb b/app/helpers/rss_helper.rb index 9ac4df88dc3..7d4fa83a67a 100644 --- a/app/helpers/rss_helper.rb +++ b/app/helpers/rss_helper.rb @@ -1,5 +1,5 @@ module RssHelper def rss_url_options - { format: :atom, rss_token: current_user.try(:rss_token) } + { format: :atom, feed_token: current_user.try(:feed_token) } end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index b12f7a2c83f..3d58a14882f 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -360,17 +360,6 @@ class ApplicationSetting < ActiveRecord::Base Array(read_attribute(:repository_storages)) end - # DEPRECATED - # repository_storage is still required in the API. Remove in 9.0 - # Still used in API v3 - def repository_storage - repository_storages.first - end - - def repository_storage=(value) - self.repository_storages = [value] - end - def default_project_visibility=(level) super(Gitlab::VisibilityLevel.level_value(level)) end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index b45395343cc..44150b37708 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -97,8 +97,6 @@ module Issuable strip_attributes :title - after_save :ensure_metrics, unless: :imported? - # We want to use optimistic lock for cases when only title or description are involved # http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html def locking_enabled? diff --git a/app/models/concerns/project_features_compatibility.rb b/app/models/concerns/project_features_compatibility.rb index b3fec99c816..1f7d78a2efe 100644 --- a/app/models/concerns/project_features_compatibility.rb +++ b/app/models/concerns/project_features_compatibility.rb @@ -1,4 +1,4 @@ -# Makes api V3 compatible with old project features permissions methods +# Makes api V4 compatible with old project features permissions methods # # After migrating issues_enabled merge_requests_enabled builds_enabled snippets_enabled and wiki_enabled # fields to a new table "project_features", support for the old fields is still needed in the API. diff --git a/app/models/issue.rb b/app/models/issue.rb index d0e8fe908e4..d136700836d 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -15,12 +15,13 @@ class Issue < ActiveRecord::Base ignore_column :assignee_id, :branch_name, :deleted_at - DueDateStruct = Struct.new(:title, :name).freeze - NoDueDate = DueDateStruct.new('No Due Date', '0').freeze - AnyDueDate = DueDateStruct.new('Any Due Date', '').freeze - Overdue = DueDateStruct.new('Overdue', 'overdue').freeze - DueThisWeek = DueDateStruct.new('Due This Week', 'week').freeze - DueThisMonth = DueDateStruct.new('Due This Month', 'month').freeze + DueDateStruct = Struct.new(:title, :name).freeze + NoDueDate = DueDateStruct.new('No Due Date', '0').freeze + AnyDueDate = DueDateStruct.new('Any Due Date', '').freeze + Overdue = DueDateStruct.new('Overdue', 'overdue').freeze + DueThisWeek = DueDateStruct.new('Due This Week', 'week').freeze + DueThisMonth = DueDateStruct.new('Due This Month', 'month').freeze + DueNextMonthAndPreviousTwoWeeks = DueDateStruct.new('Due Next Month And Previous Two Weeks', 'next_month_and_previous_two_weeks').freeze belongs_to :project belongs_to :moved_to, class_name: 'Issue' @@ -47,6 +48,7 @@ class Issue < ActiveRecord::Base scope :unassigned, -> { where('NOT EXISTS (SELECT TRUE FROM issue_assignees WHERE issue_id = issues.id)') } scope :assigned_to, ->(u) { where('EXISTS (SELECT TRUE FROM issue_assignees WHERE user_id = ? AND issue_id = issues.id)', u.id)} + scope :with_due_date, -> { where('due_date IS NOT NULL') } scope :without_due_date, -> { where(due_date: nil) } scope :due_before, ->(date) { where('issues.due_date < ?', date) } scope :due_between, ->(from_date, to_date) { where('issues.due_date >= ?', from_date).where('issues.due_date <= ?', to_date) } @@ -54,12 +56,14 @@ class Issue < ActiveRecord::Base scope :order_due_date_asc, -> { reorder('issues.due_date IS NULL, issues.due_date ASC') } scope :order_due_date_desc, -> { reorder('issues.due_date IS NULL, issues.due_date DESC') } + scope :order_closest_future_date, -> { reorder('CASE WHEN due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - due_date) ASC') } scope :preload_associations, -> { preload(:labels, project: :namespace) } scope :public_only, -> { where(confidential: false) } after_save :expire_etag_cache + after_save :ensure_metrics, unless: :imported? attr_spammable :title, spam_title: true attr_spammable :description, spam_description: true @@ -120,6 +124,7 @@ class Issue < ActiveRecord::Base def self.sort_by_attribute(method, excluded_labels: []) case method.to_s + when 'closest_future_date' then order_closest_future_date when 'due_date' then order_due_date_asc when 'due_date_asc' then order_due_date_asc when 'due_date_desc' then order_due_date_desc diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index a00b8d4e2c1..4c1628d2bdb 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -59,6 +59,7 @@ class MergeRequest < ActiveRecord::Base after_create :ensure_merge_request_diff, unless: :importing? after_update :clear_memoized_shas after_update :reload_diff_if_branch_changed + after_save :ensure_metrics # When this attribute is true some MR validation is ignored # It allows us to close or modify broken merge requests @@ -1141,4 +1142,11 @@ class MergeRequest < ActiveRecord::Base maintainer_push_possible? && Ability.allowed?(user, :push_code, source_project) end + + def squash_in_progress? + # The source project can be deleted + return false unless source_project + + source_project.repository.squash_in_progress?(id) + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index 0e1bf11d7c0..82cf47ba04e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -957,6 +957,22 @@ class Repository remote_branch: merge_request.target_branch) end + def blob_data_at(sha, path) + blob = blob_at(sha, path) + return unless blob + + blob.load_all_data! + blob.data + end + + def squash(user, merge_request) + raw.squash(user, merge_request.id, branch: merge_request.target_branch, + start_sha: merge_request.diff_start_sha, + end_sha: merge_request.diff_head_sha, + author: merge_request.author, + message: merge_request.title) + end + private # TODO Generice finder, later split this on finders by Ref or Oid @@ -971,14 +987,6 @@ class Repository ::Commit.new(commit, @project) if commit end - def blob_data_at(sha, path) - blob = blob_at(sha, path) - return unless blob - - blob.load_all_data! - blob.data - end - def cache @cache ||= Gitlab::RepositoryCache.new(self) end diff --git a/app/models/service.rb b/app/models/service.rb index 831c2ea1141..1d259bcfec7 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -206,10 +206,11 @@ class Service < ActiveRecord::Base args.each do |arg| class_eval %{ def #{arg}? + # '!!' is used because nil or empty string is converted to nil if Gitlab.rails5? - !ActiveModel::Type::Boolean::FALSE_VALUES.include?(#{arg}) + !!ActiveRecord::Type::Boolean.new.cast(#{arg}) else - ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(#{arg}) + !!ActiveRecord::Type::Boolean.new.type_cast_from_database(#{arg}) end end } diff --git a/app/models/user.rb b/app/models/user.rb index 0a838d34054..e219ab800ad 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -26,7 +26,7 @@ class User < ActiveRecord::Base ignore_column :authentication_token add_authentication_token_field :incoming_email_token - add_authentication_token_field :rss_token + add_authentication_token_field :feed_token default_value_for :admin, false default_value_for(:external) { Gitlab::CurrentSettings.user_default_external } @@ -1167,11 +1167,11 @@ class User < ActiveRecord::Base save end - # each existing user needs to have an `rss_token`. + # each existing user needs to have an `feed_token`. # we do this on read since migrating all existing users is not a feasible # solution. - def rss_token - ensure_rss_token! + def feed_token + ensure_feed_token! end def sync_attribute?(attribute) diff --git a/app/presenters/commit_status_presenter.rb b/app/presenters/commit_status_presenter.rb index c7f7aa836bd..9a7aaf4ef32 100644 --- a/app/presenters/commit_status_presenter.rb +++ b/app/presenters/commit_status_presenter.rb @@ -1,11 +1,10 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated CALLOUT_FAILURE_MESSAGES = { unknown_failure: 'There is an unknown failure, please try again', - script_failure: 'There has been a script failure. Check the job log for more information', api_failure: 'There has been an API failure, please try again', stuck_or_timeout_failure: 'There has been a timeout failure or the job got stuck. Check your timeout limits or try again', runner_system_failure: 'There has been a runner system failure, please try again', - missing_dependency_failure: 'There has been a missing dependency failure, check the job log for more information' + missing_dependency_failure: 'There has been a missing dependency failure' }.freeze presents :build diff --git a/app/serializers/group_child_entity.rb b/app/serializers/group_child_entity.rb index 15ec0f89bb2..ee150eefd9e 100644 --- a/app/serializers/group_child_entity.rb +++ b/app/serializers/group_child_entity.rb @@ -31,7 +31,7 @@ class GroupChildEntity < Grape::Entity end # Project only attributes - expose :star_count, + expose :star_count, :archived, if: lambda { |_instance, _options| project? } # Group only attributes diff --git a/app/serializers/job_entity.rb b/app/serializers/job_entity.rb index 3076fed1674..960e7291ae6 100644 --- a/app/serializers/job_entity.rb +++ b/app/serializers/job_entity.rb @@ -26,7 +26,7 @@ class JobEntity < Grape::Entity expose :created_at expose :updated_at expose :detailed_status, as: :status, with: StatusEntity - expose :callout_message, if: -> (*) { failed? } + expose :callout_message, if: -> (*) { failed? && !build.script_failure? } expose :recoverable, if: -> (*) { failed? } private diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb index d0165c148eb..141070aef45 100644 --- a/app/serializers/merge_request_widget_entity.rb +++ b/app/serializers/merge_request_widget_entity.rb @@ -10,6 +10,7 @@ class MergeRequestWidgetEntity < IssuableEntity expose :merge_when_pipeline_succeeds expose :source_branch expose :source_project_id + expose :squash expose :target_branch expose :target_project_id expose :allow_maintainer_to_push diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb index ac70a99c2c5..5a961ac89e4 100644 --- a/app/services/boards/issues/list_service.rb +++ b/app/services/boards/issues/list_service.rb @@ -63,7 +63,7 @@ module Boards def without_board_labels(issues) return issues unless board_label_ids.any? - issues.where.not(issues_label_links.limit(1).arel.exists) + issues.where.not('EXISTS (?)', issues_label_links.limit(1)) end def issues_label_links @@ -71,10 +71,8 @@ module Boards end def with_list_label(issues) - issues.where( - LabelLink.where("label_links.target_type = 'Issue' AND label_links.target_id = issues.id") - .where("label_links.label_id = ?", list.label_id).limit(1).arel.exists - ) + issues.where('EXISTS (?)', LabelLink.where("label_links.target_type = 'Issue' AND label_links.target_id = issues.id") + .where("label_links.label_id = ?", list.label_id).limit(1)) end end end diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 2209a60a840..126da891c78 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -34,6 +34,19 @@ module MergeRequests handle_merge_error(log_message: e.message, save_message_on_model: true) end + def source + return merge_request.diff_head_sha unless merge_request.squash + + squash_result = ::MergeRequests::SquashService.new(project, current_user, params).execute(merge_request) + + case squash_result[:status] + when :success + squash_result[:squash_sha] + when :error + raise ::MergeRequests::MergeService::MergeError, squash_result[:message] + end + end + private def error_check! @@ -116,9 +129,5 @@ module MergeRequests def merge_request_info merge_request.to_reference(full: true) end - - def source - @source ||= @merge_request.diff_head_sha - end end end diff --git a/app/services/merge_requests/squash_service.rb b/app/services/merge_requests/squash_service.rb new file mode 100644 index 00000000000..a40fb2786bd --- /dev/null +++ b/app/services/merge_requests/squash_service.rb @@ -0,0 +1,28 @@ +module MergeRequests + class SquashService < MergeRequests::WorkingCopyBaseService + def execute(merge_request) + @merge_request = merge_request + @repository = target_project.repository + + squash || error('Failed to squash. Should be done manually.') + end + + def squash + if merge_request.commits_count < 2 + return success(squash_sha: merge_request.diff_head_sha) + end + + if merge_request.squash_in_progress? + return error('Squash task canceled: another squash is already in progress.') + end + + squash_sha = repository.squash(current_user, merge_request) + + success(squash_sha: squash_sha) + rescue => e + log_error("Failed to squash merge request #{merge_request.to_reference(full: true)}:") + log_error(e.message) + false + end + end +end diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb index 3fd27d9acdc..5bdca26a584 100644 --- a/app/uploaders/object_storage.rb +++ b/app/uploaders/object_storage.rb @@ -11,6 +11,7 @@ module ObjectStorage ObjectStorageUnavailable = Class.new(StandardError) DIRECT_UPLOAD_TIMEOUT = 4.hours + DIRECT_UPLOAD_EXPIRE_OFFSET = 15.minutes TMP_UPLOAD_PATH = 'tmp/uploads'.freeze module Store @@ -174,11 +175,12 @@ module ObjectStorage id = [CarrierWave.generate_cache_id, SecureRandom.hex].join('-') upload_path = File.join(TMP_UPLOAD_PATH, id) connection = ::Fog::Storage.new(self.object_store_credentials) - expire_at = Time.now + DIRECT_UPLOAD_TIMEOUT + expire_at = Time.now + DIRECT_UPLOAD_TIMEOUT + DIRECT_UPLOAD_EXPIRE_OFFSET options = { 'Content-Type' => 'application/octet-stream' } { ID: id, + Timeout: DIRECT_UPLOAD_TIMEOUT, GetURL: connection.get_object_url(remote_store_path, upload_path, expire_at), DeleteURL: connection.delete_object_url(remote_store_path, upload_path, expire_at), StoreURL: connection.put_object_url(remote_store_path, upload_path, expire_at, options) diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml index f40dd347eb3..07f9ea0865b 100644 --- a/app/views/admin/application_settings/_account_and_limit.html.haml +++ b/app/views/admin/application_settings/_account_and_limit.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :gravatar_enabled do - = f.check_box :gravatar_enabled + = f.check_box :gravatar_enabled, class: 'form-check-input' + = f.label :gravatar_enabled, class: 'form-check-label' do Gravatar enabled .form-group.row = f.label :default_projects_limit, class: 'col-form-label col-sm-2' @@ -25,15 +25,15 @@ = f.label :user_oauth_applications, 'User OAuth applications', class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.label :user_oauth_applications do - = f.check_box :user_oauth_applications + = f.check_box :user_oauth_applications, class: 'form-check-input' + = f.label :user_oauth_applications, class: 'form-check-label' do Allow users to register any application to use GitLab as an OAuth provider .form-group.row = f.label :user_default_external, 'New users set to external', class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.label :user_default_external do - = f.check_box :user_default_external + = f.check_box :user_default_external, class: 'form-check-input' + = f.label :user_default_external, class: 'form-check-label' do Newly registered users will by default be external = f.submit 'Save changes', class: 'btn btn-success' diff --git a/app/views/admin/application_settings/_background_jobs.html.haml b/app/views/admin/application_settings/_background_jobs.html.haml index da7248337d2..fc5df02242a 100644 --- a/app/views/admin/application_settings/_background_jobs.html.haml +++ b/app/views/admin/application_settings/_background_jobs.html.haml @@ -9,8 +9,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :sidekiq_throttling_enabled do - = f.check_box :sidekiq_throttling_enabled + = f.check_box :sidekiq_throttling_enabled, class: 'form-check-input' + = f.label :sidekiq_throttling_enabled, class: 'form-check-label' do Enable Sidekiq Job Throttling .form-text.text-muted Limit the amount of resources slow running jobs are assigned. diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml index 6a06271de2a..233821818e6 100644 --- a/app/views/admin/application_settings/_ci_cd.html.haml +++ b/app/views/admin/application_settings/_ci_cd.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :auto_devops_enabled do - = f.check_box :auto_devops_enabled + = f.check_box :auto_devops_enabled, class: 'form-check-input' + = f.label :auto_devops_enabled, class: 'form-check-label' do Enabled Auto DevOps for projects by default .form-text.text-muted It will automatically build, test, and deploy applications based on a predefined CI/CD configuration @@ -20,8 +20,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :shared_runners_enabled do - = f.check_box :shared_runners_enabled + = f.check_box :shared_runners_enabled, class: 'form-check-input' + = f.label :shared_runners_enabled, class: 'form-check-label' do Enable shared runners for new projects .form-group.row = f.label :shared_runners_text, class: 'col-form-label col-sm-2' diff --git a/app/views/admin/application_settings/_email.html.haml b/app/views/admin/application_settings/_email.html.haml index 7443f02ad15..01be5878a60 100644 --- a/app/views/admin/application_settings/_email.html.haml +++ b/app/views/admin/application_settings/_email.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :email_author_in_body do - = f.check_box :email_author_in_body + = f.check_box :email_author_in_body, class: 'form-check-input' + = f.label :email_author_in_body, class: 'form-check-label' do Include author name in notification email body .form-text.text-muted Some email servers do not support overriding the email sender name. @@ -15,8 +15,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :html_emails_enabled do - = f.check_box :html_emails_enabled + = f.check_box :html_emails_enabled, class: 'form-check-input' + = f.label :html_emails_enabled, class: 'form-check-label' do Enable HTML emails .form-text.text-muted By default GitLab sends emails in HTML and plain text formats so mail diff --git a/app/views/admin/application_settings/_help_page.html.haml b/app/views/admin/application_settings/_help_page.html.haml index 97d397788c6..1f6c52d8b1a 100644 --- a/app/views/admin/application_settings/_help_page.html.haml +++ b/app/views/admin/application_settings/_help_page.html.haml @@ -10,8 +10,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :help_page_hide_commercial_content do - = f.check_box :help_page_hide_commercial_content + = f.check_box :help_page_hide_commercial_content, class: 'form-check-input' + = f.label :help_page_hide_commercial_content, class: 'form-check-label' do Hide marketing-related entries from help .form-group.row = f.label :help_page_support_url, 'Support page URL', class: 'col-form-label col-sm-2' diff --git a/app/views/admin/application_settings/_influx.html.haml b/app/views/admin/application_settings/_influx.html.haml index e5d699f9a2f..b40a714ed8f 100644 --- a/app/views/admin/application_settings/_influx.html.haml +++ b/app/views/admin/application_settings/_influx.html.haml @@ -11,8 +11,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :metrics_enabled do - = f.check_box :metrics_enabled + = f.check_box :metrics_enabled, class: 'form-check-input' + = f.label :metrics_enabled, class: 'form-check-label' do Enable InfluxDB Metrics .form-group.row = f.label :metrics_host, 'InfluxDB host', class: 'col-form-label col-sm-2' diff --git a/app/views/admin/application_settings/_ip_limits.html.haml b/app/views/admin/application_settings/_ip_limits.html.haml index 539ff9b5168..320dd52ffc2 100644 --- a/app/views/admin/application_settings/_ip_limits.html.haml +++ b/app/views/admin/application_settings/_ip_limits.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :throttle_unauthenticated_enabled do - = f.check_box :throttle_unauthenticated_enabled + = f.check_box :throttle_unauthenticated_enabled, class: 'form-check-input' + = f.label :throttle_unauthenticated_enabled, class: 'form-check-label' do Enable unauthenticated request rate limit %span.form-text.text-muted Helps reduce request volume (e.g. from crawlers or abusive bots) @@ -21,8 +21,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :throttle_authenticated_api_enabled do - = f.check_box :throttle_authenticated_api_enabled + = f.check_box :throttle_authenticated_api_enabled, class: 'form-check-input' + = f.label :throttle_authenticated_api_enabled, class: 'form-check-label' do Enable authenticated API request rate limit %span.form-text.text-muted Helps reduce request volume (e.g. from crawlers or abusive bots) @@ -37,8 +37,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :throttle_authenticated_web_enabled do - = f.check_box :throttle_authenticated_web_enabled + = f.check_box :throttle_authenticated_web_enabled, class: 'form-check-input' + = f.label :throttle_authenticated_web_enabled, class: 'form-check-label' do Enable authenticated web request rate limit %span.form-text.text-muted Helps reduce request volume (e.g. from crawlers or abusive bots) diff --git a/app/views/admin/application_settings/_koding.html.haml b/app/views/admin/application_settings/_koding.html.haml index 0532f49fd5b..341c7641fcc 100644 --- a/app/views/admin/application_settings/_koding.html.haml +++ b/app/views/admin/application_settings/_koding.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :koding_enabled do - = f.check_box :koding_enabled + = f.check_box :koding_enabled, class: 'form-check-input' + = f.label :koding_enabled, class: 'form-check-label' do Enable Koding .form-text.text-muted Koding integration has been deprecated since GitLab 10.0. If you disable your Koding integration, you will not be able to enable it again. diff --git a/app/views/admin/application_settings/_logging.html.haml b/app/views/admin/application_settings/_logging.html.haml index 4341801b045..f5c1e126c70 100644 --- a/app/views/admin/application_settings/_logging.html.haml +++ b/app/views/admin/application_settings/_logging.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :sentry_enabled do - = f.check_box :sentry_enabled + = f.check_box :sentry_enabled, class: 'form-check-input' + = f.label :sentry_enabled, class: 'form-check-label' do Enable Sentry .form-text.text-muted %p This setting requires a restart to take effect. @@ -21,8 +21,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :clientside_sentry_enabled do - = f.check_box :clientside_sentry_enabled + = f.check_box :clientside_sentry_enabled, class: 'form-check-input' + = f.label :clientside_sentry_enabled, class: 'form-check-label' do Enable Clientside Sentry .form-text.text-muted Sentry can also be used for reporting and logging clientside exceptions. diff --git a/app/views/admin/application_settings/_outbound.html.haml b/app/views/admin/application_settings/_outbound.html.haml index 176cdfe9e1a..5dadb7b814b 100644 --- a/app/views/admin/application_settings/_outbound.html.haml +++ b/app/views/admin/application_settings/_outbound.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :allow_local_requests_from_hooks_and_services do - = f.check_box :allow_local_requests_from_hooks_and_services + = f.check_box :allow_local_requests_from_hooks_and_services, class: 'form-check-input' + = f.label :allow_local_requests_from_hooks_and_services, class: 'form-check-label' do Allow requests to the local network from hooks and services = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml index 0100ef038e2..f1889c3105f 100644 --- a/app/views/admin/application_settings/_pages.html.haml +++ b/app/views/admin/application_settings/_pages.html.haml @@ -10,8 +10,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :pages_domain_verification_enabled do - = f.check_box :pages_domain_verification_enabled + = f.check_box :pages_domain_verification_enabled, class: 'form-check-input' + = f.label :pages_domain_verification_enabled, class: 'form-check-label' do Require users to prove ownership of custom domains .form-text.text-muted Domain verification is an essential security measure for public GitLab diff --git a/app/views/admin/application_settings/_performance.html.haml b/app/views/admin/application_settings/_performance.html.haml index 07d3a8b7cdf..57c22ce563f 100644 --- a/app/views/admin/application_settings/_performance.html.haml +++ b/app/views/admin/application_settings/_performance.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :authorized_keys_enabled do - = f.check_box :authorized_keys_enabled + = f.check_box :authorized_keys_enabled, class: 'form-check-input' + = f.label :authorized_keys_enabled, class: 'form-check-label' do Write to "authorized_keys" file .form-text.text-muted By default, we write to the "authorized_keys" file to support Git diff --git a/app/views/admin/application_settings/_performance_bar.html.haml b/app/views/admin/application_settings/_performance_bar.html.haml index 030e8610b47..ed4de2234f7 100644 --- a/app/views/admin/application_settings/_performance_bar.html.haml +++ b/app/views/admin/application_settings/_performance_bar.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :performance_bar_enabled do - = f.check_box :performance_bar_enabled + = f.check_box :performance_bar_enabled, class: 'form-check-input' + = f.label :performance_bar_enabled, class: 'form-check-label' do Enable the Performance Bar .form-group.row = f.label :performance_bar_allowed_group_path, 'Allowed group', class: 'col-form-label col-sm-2' diff --git a/app/views/admin/application_settings/_plantuml.html.haml b/app/views/admin/application_settings/_plantuml.html.haml index ee6d1d1a888..e0dc058762e 100644 --- a/app/views/admin/application_settings/_plantuml.html.haml +++ b/app/views/admin/application_settings/_plantuml.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :plantuml_enabled do - = f.check_box :plantuml_enabled + = f.check_box :plantuml_enabled, class: 'form-check-input' + = f.label :plantuml_enabled, class: 'form-check-label' do Enable PlantUML .form-group.row = f.label :plantuml_url, 'PlantUML URL', class: 'col-form-label col-sm-2' diff --git a/app/views/admin/application_settings/_prometheus.html.haml b/app/views/admin/application_settings/_prometheus.html.haml index 8c95597e787..d3c3656e96a 100644 --- a/app/views/admin/application_settings/_prometheus.html.haml +++ b/app/views/admin/application_settings/_prometheus.html.haml @@ -14,8 +14,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :prometheus_metrics_enabled do - = f.check_box :prometheus_metrics_enabled + = f.check_box :prometheus_metrics_enabled, class: 'form-check-input' + = f.label :prometheus_metrics_enabled, class: 'form-check-label' do Enable Prometheus Metrics - unless Gitlab::Metrics.metrics_folder_present? .form-text.text-muted diff --git a/app/views/admin/application_settings/_repository_check.html.haml b/app/views/admin/application_settings/_repository_check.html.haml index 739ed359e16..1311f17ecda 100644 --- a/app/views/admin/application_settings/_repository_check.html.haml +++ b/app/views/admin/application_settings/_repository_check.html.haml @@ -7,8 +7,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :repository_checks_enabled do - = f.check_box :repository_checks_enabled + = f.check_box :repository_checks_enabled, class: 'form-check-input' + = f.label :repository_checks_enabled, class: 'form-check-label' do Enable Repository Checks .form-text.text-muted GitLab will periodically run @@ -25,8 +25,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :housekeeping_enabled do - = f.check_box :housekeeping_enabled + = f.check_box :housekeeping_enabled, class: 'form-check-input' + = f.label :housekeeping_enabled, class: 'form-check-label' do Enable automatic repository housekeeping (git repack, git gc) .form-text.text-muted If you keep automatic housekeeping disabled for a long time Git @@ -34,8 +34,8 @@ repositories will use more disk space. We recommend to always leave this enabled. .form-check - = f.label :housekeeping_bitmaps_enabled do - = f.check_box :housekeeping_bitmaps_enabled + = f.check_box :housekeeping_bitmaps_enabled, class: 'form-check-input' + = f.label :housekeeping_bitmaps_enabled, class: 'form-check-label' do Enable Git pack file bitmap creation .form-text.text-muted Creating pack file bitmaps makes housekeeping take a little longer but diff --git a/app/views/admin/application_settings/_repository_mirrors_form.html.haml b/app/views/admin/application_settings/_repository_mirrors_form.html.haml index edd8e5e9eb8..187c6c28bb1 100644 --- a/app/views/admin/application_settings/_repository_mirrors_form.html.haml +++ b/app/views/admin/application_settings/_repository_mirrors_form.html.haml @@ -1,13 +1,13 @@ -= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f| += form_for @application_setting, url: admin_application_settings_path do |f| = form_errors(@application_setting) %fieldset - .form-group - = f.label :mirror_available, 'Enable mirror configuration', class: 'control-label col-sm-2' - .col-sm-10 + .form-group.row + = f.label :mirror_available, 'Enable mirror configuration', class: 'control-label col-sm-4' + .col-sm-8 .form-check - = f.label :mirror_available do - = f.check_box :mirror_available + = f.check_box :mirror_available, class: 'form-check-input' + = f.label :mirror_available, class: 'form-check-label' do Allow mirrors to be setup for projects %span.form-text.text-muted If disabled, only admins will be able to setup mirrors in projects. diff --git a/app/views/admin/application_settings/_repository_storage.html.haml b/app/views/admin/application_settings/_repository_storage.html.haml index be85210934c..89d2c114b22 100644 --- a/app/views/admin/application_settings/_repository_storage.html.haml +++ b/app/views/admin/application_settings/_repository_storage.html.haml @@ -6,8 +6,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :hashed_storage_enabled do - = f.check_box :hashed_storage_enabled + = f.check_box :hashed_storage_enabled, class: 'form-check-input' + = f.label :hashed_storage_enabled, class: 'form-check-label' do Create new projects using hashed storage paths .form-text.text-muted Enable immutable, hash-based paths and repository names to store repositories on disk. This prevents diff --git a/app/views/admin/application_settings/_signin.html.haml b/app/views/admin/application_settings/_signin.html.haml index 83a30504222..2ba26158162 100644 --- a/app/views/admin/application_settings/_signin.html.haml +++ b/app/views/admin/application_settings/_signin.html.haml @@ -5,16 +5,16 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :password_authentication_enabled_for_web do - = f.check_box :password_authentication_enabled_for_web + = f.check_box :password_authentication_enabled_for_web, class: 'form-check-input' + = f.label :password_authentication_enabled_for_web, class: 'form-check-label' do Password authentication enabled for web interface .form-text.text-muted When disabled, an external authentication provider must be used. .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :password_authentication_enabled_for_git do - = f.check_box :password_authentication_enabled_for_git + = f.check_box :password_authentication_enabled_for_git, class: 'form-check-input' + = f.label :password_authentication_enabled_for_git, class: 'form-check-label' do Password authentication enabled for Git over HTTP(S) .form-text.text-muted When disabled, a Personal Access Token @@ -33,8 +33,8 @@ = f.label :two_factor_authentication, 'Two-factor authentication', class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.label :require_two_factor_authentication do - = f.check_box :require_two_factor_authentication + = f.check_box :require_two_factor_authentication, class: 'form-check-input' + = f.label :require_two_factor_authentication, class: 'form-check-label' do Require all users to setup Two-factor authentication .form-group.row = f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'col-form-label col-sm-2' diff --git a/app/views/admin/application_settings/_signup.html.haml b/app/views/admin/application_settings/_signup.html.haml index 50c455f8686..279f96389e9 100644 --- a/app/views/admin/application_settings/_signup.html.haml +++ b/app/views/admin/application_settings/_signup.html.haml @@ -5,14 +5,14 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :signup_enabled do - = f.check_box :signup_enabled + = f.check_box :signup_enabled, class: 'form-check-input' + = f.label :signup_enabled, class: 'form-check-label' do Sign-up enabled .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :send_user_confirmation_email do - = f.check_box :send_user_confirmation_email + = f.check_box :send_user_confirmation_email, class: 'form-check-input' + = f.label :send_user_confirmation_email, class: 'form-check-label' do Send confirmation email on sign-up .form-group.row = f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'col-form-label col-sm-2' @@ -23,19 +23,19 @@ = f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.label :domain_blacklist_enabled do - = f.check_box :domain_blacklist_enabled + = f.check_box :domain_blacklist_enabled, class: 'form-check-input' + = f.label :domain_blacklist_enabled, class: 'form-check-label' do Enable domain blacklist for sign ups .form-group.row .offset-sm-2.col-sm-10 .form-check - = label_tag :blacklist_type_file do - = radio_button_tag :blacklist_type, :file + = radio_button_tag :blacklist_type, :file, class: 'form-check-input' + = label_tag :blacklist_type_file, class: 'form-check-label' do .option-title Upload blacklist file .form-check - = label_tag :blacklist_type_raw do - = radio_button_tag :blacklist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank? + = radio_button_tag :blacklist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank?, class: 'form-check-input' + = label_tag :blacklist_type_raw, class: 'form-check-label' do .option-title Enter blacklist manually .form-group.row.blacklist-file diff --git a/app/views/admin/application_settings/_spam.html.haml b/app/views/admin/application_settings/_spam.html.haml index 58543a0359a..fb38e4ae922 100644 --- a/app/views/admin/application_settings/_spam.html.haml +++ b/app/views/admin/application_settings/_spam.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :recaptcha_enabled do - = f.check_box :recaptcha_enabled + = f.check_box :recaptcha_enabled, class: 'form-check-input' + = f.label :recaptcha_enabled, class: 'form-check-label' do Enable reCAPTCHA %span.form-text.text-muted#recaptcha_help_block Helps prevent bots from creating accounts @@ -26,8 +26,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :akismet_enabled do - = f.check_box :akismet_enabled + = f.check_box :akismet_enabled, class: 'form-check-input' + = f.label :akismet_enabled, class: 'form-check-label' do Enable Akismet %span.form-text.text-muted#akismet_help_block Helps prevent bots from creating issues @@ -42,8 +42,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :unique_ips_limit_enabled do - = f.check_box :unique_ips_limit_enabled + = f.check_box :unique_ips_limit_enabled, class: 'form-check-input' + = f.label :unique_ips_limit_enabled, class: 'form-check-label' do Limit sign in from multiple ips %span.form-text.text-muted#unique_ip_help_block Helps prevent malicious users hide their activity diff --git a/app/views/admin/application_settings/_terms.html.haml b/app/views/admin/application_settings/_terms.html.haml index 44bf7b65a8e..257565ce193 100644 --- a/app/views/admin/application_settings/_terms.html.haml +++ b/app/views/admin/application_settings/_terms.html.haml @@ -1,16 +1,16 @@ -= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f| += form_for @application_setting, url: admin_application_settings_path do |f| = form_errors(@application_setting) %fieldset - .form-group + .form-group.row .col-sm-12 .form-check - = f.label :enforce_terms do - = f.check_box :enforce_terms + = f.check_box :enforce_terms, class: 'form-check-input' + = f.label :enforce_terms, class: 'form-check-label' do = _("Require all users to accept Terms of Service when they access GitLab.") .form-text.text-muted = _("When enabled, users cannot use GitLab until the terms have been accepted.") - .form-group + .form-group.row .col-sm-12 = f.label :terms do = _("Terms of Service Agreement") diff --git a/app/views/admin/application_settings/_usage.html.haml b/app/views/admin/application_settings/_usage.html.haml index 316c8b04dea..c110fd4d60d 100644 --- a/app/views/admin/application_settings/_usage.html.haml +++ b/app/views/admin/application_settings/_usage.html.haml @@ -5,8 +5,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :version_check_enabled do - = f.check_box :version_check_enabled + = f.check_box :version_check_enabled, class: 'form-check-input' + = f.label :version_check_enabled, class: 'form-check-label' do Enable version check .form-text.text-muted GitLab will inform you if a new version is available. @@ -16,8 +16,8 @@ .offset-sm-2.col-sm-10 - can_be_configured = @application_setting.usage_ping_can_be_configured? .form-check - = f.label :usage_ping_enabled do - = f.check_box :usage_ping_enabled, disabled: !can_be_configured + = f.check_box :usage_ping_enabled, disabled: !can_be_configured, class: 'form-check-input' + = f.label :usage_ping_enabled, class: 'form-check-label' do Enable usage ping .form-text.text-muted - if can_be_configured diff --git a/app/views/admin/application_settings/_visibility_and_access.html.haml b/app/views/admin/application_settings/_visibility_and_access.html.haml index 0f2524047e3..2b4d3bab54d 100644 --- a/app/views/admin/application_settings/_visibility_and_access.html.haml +++ b/app/views/admin/application_settings/_visibility_and_access.html.haml @@ -46,8 +46,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = f.label :project_export_enabled do - = f.check_box :project_export_enabled + = f.check_box :project_export_enabled, class: 'form-check-input' + = f.label :project_export_enabled, class: 'form-check-label' do Project export enabled .form-group.row diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml index b5d79e1da13..7f14cddebd8 100644 --- a/app/views/admin/applications/_form.html.haml +++ b/app/views/admin/applications/_form.html.haml @@ -1,13 +1,13 @@ = form_for [:admin, @application], url: @url, html: {role: 'form'} do |f| = form_errors(application) - = content_tag :div, class: 'form-group' do + = content_tag :div, class: 'form-group row' do = f.label :name, class: 'col-sm-2 col-form-label' .col-sm-10 = f.text_field :name, class: 'form-control' = doorkeeper_errors_for application, :name - = content_tag :div, class: 'form-group' do + = content_tag :div, class: 'form-group row' do = f.label :redirect_uri, class: 'col-sm-2 col-form-label' .col-sm-10 = f.text_area :redirect_uri, class: 'form-control' @@ -20,7 +20,7 @@ %code= Doorkeeper.configuration.native_redirect_uri for local tests - = content_tag :div, class: 'form-group' do + = content_tag :div, class: 'form-group row' do = f.label :trusted, class: 'col-sm-2 col-form-label' .col-sm-10 = f.check_box :trusted diff --git a/app/views/admin/hooks/_form.html.haml b/app/views/admin/hooks/_form.html.haml index e54dbd20ef4..3abde755f0f 100644 --- a/app/views/admin/hooks/_form.html.haml +++ b/app/views/admin/hooks/_form.html.haml @@ -47,6 +47,6 @@ .form-group = form.label :enable_ssl_verification, 'SSL verification', class: 'label-light checkbox' .form-check - = form.label :enable_ssl_verification do - = form.check_box :enable_ssl_verification + = form.check_box :enable_ssl_verification, class: 'form-check-input' + = form.label :enable_ssl_verification, class: 'form-check-label' do %strong Enable SSL verification diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 4bf04dadf01..86a21e24ac9 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -7,8 +7,7 @@ .top-area = render 'shared/issuable/nav', type: :issues, display_count: !@no_filters_set .nav-controls - = link_to safe_params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe' do - = icon('rss') + = render 'shared/issuable/feed_buttons' = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues = render 'shared/issuable/filter', type: :issues diff --git a/app/views/dashboard/issues_calendar.ics.haml b/app/views/dashboard/issues_calendar.ics.haml new file mode 100644 index 00000000000..59573e5fecf --- /dev/null +++ b/app/views/dashboard/issues_calendar.ics.haml @@ -0,0 +1 @@ += render 'issues/issues_calendar', issues: @issues diff --git a/app/views/errors/_footer.html.haml b/app/views/errors/_footer.html.haml new file mode 100644 index 00000000000..e67a3a142f6 --- /dev/null +++ b/app/views/errors/_footer.html.haml @@ -0,0 +1,11 @@ +%nav + %ul.error-nav + %li + = link_to s_('Nav|Home'), root_path + %li + - if current_user + = link_to s_('Nav|Sign out and sign in with a different account'), destroy_user_session_path + - else + = link_to s_('Nav|Sign In / Register'), new_session_path(:user, redirect_to_referer: 'yes') + %li + = link_to s_('Nav|Help'), help_path diff --git a/app/views/errors/access_denied.html.haml b/app/views/errors/access_denied.html.haml index bf540439c79..227c7884915 100644 --- a/app/views/errors/access_denied.html.haml +++ b/app/views/errors/access_denied.html.haml @@ -1,15 +1,16 @@ - message = local_assigns.fetch(:message) - - content_for(:title, 'Access Denied') -%img{ :alt => "GitLab Logo", :src => image_path('logo.svg') } - %h1 - 403 + += image_tag('illustrations/error-403.svg', alt: '403', lazy: false) .container - %h3 Access Denied - %hr + %h3 + = s_("403|You don't have the permission to access this page.") - if message %p = message - - else - %p You are not allowed to access this page. - %p Read more about project permissions #{link_to "here", help_page_path("user/permissions"), class: "vlink"} + %p + = s_('403|Please contact your GitLab administrator to get the permission.') + .action-container.js-go-back{ style: 'display: none' } + %a{ href: 'javascript:history.back()', class: 'btn btn-success' } + = s_('Go Back') += render "errors/footer" diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml index a0b9a632e22..ae055f398ac 100644 --- a/app/views/errors/not_found.html.haml +++ b/app/views/errors/not_found.html.haml @@ -1,8 +1,15 @@ - content_for(:title, 'Not Found') -%img{ :alt => "GitLab Logo", :src => image_path('logo.svg') } - %h1 - 404 += image_tag('illustrations/error-404.svg', alt: '404', lazy: false) .container - %h3 The resource you were looking for doesn't exist. - %hr - %p You may have mistyped the address or the page may have moved. + %h3 + = s_('404|Page Not Found') + %p + = s_("404|Make sure the address is correct and the page hasn't moved.") + %p + = s_('404|Please contact your GitLab administrator if you think this is a mistake.') + .action-container + = form_tag search_path, method: :get, class: 'form-inline-flex' do |f| + .field + = search_field_tag :search, '', placeholder: _('Search for projects, issues, etc.'), class: 'form-control' + = button_tag 'Search', class: 'btn btn-success', name: nil, type: 'submit' += render 'errors/footer' diff --git a/app/views/groups/_create_chat_team.html.haml b/app/views/groups/_create_chat_team.html.haml index 9a3ff0313b5..f950968030f 100644 --- a/app/views/groups/_create_chat_team.html.haml +++ b/app/views/groups/_create_chat_team.html.haml @@ -5,8 +5,8 @@ Mattermost .col-sm-10 .form-check.js-toggle-container - = f.label :create_chat_team do - .js-toggle-button= f.check_box(:create_chat_team, { checked: true }, true, false) + .js-toggle-button.form-check-input= f.check_box(:create_chat_team, { checked: true }, true, false) + = f.label :create_chat_team, class: 'form-check-label' do Create a Mattermost team for this group %br %small.light.js-toggle-content diff --git a/app/views/groups/_group_admin_settings.html.haml b/app/views/groups/_group_admin_settings.html.haml index 3cd3fb32b9c..f7cc62c6929 100644 --- a/app/views/groups/_group_admin_settings.html.haml +++ b/app/views/groups/_group_admin_settings.html.haml @@ -2,8 +2,8 @@ = f.label :lfs_enabled, 'Large File Storage', class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.label :lfs_enabled do - = f.check_box :lfs_enabled, checked: @group.lfs_enabled? + = f.check_box :lfs_enabled, checked: @group.lfs_enabled?, class: 'form-check-input' + = f.label :lfs_enabled, class: 'form-check-label' do %strong Allow projects within this group to use Git LFS = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') @@ -14,8 +14,8 @@ = f.label :require_two_factor_authentication, 'Two-factor authentication', class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.label :require_two_factor_authentication do - = f.check_box :require_two_factor_authentication + = f.check_box :require_two_factor_authentication, class: 'form-check-input' + = f.label :require_two_factor_authentication, class: 'form-check-label' do %strong Require all users in this group to setup Two-factor authentication = link_to icon('question-circle'), help_page_path('security/two_factor_authentication', anchor: 'enforcing-2fa-for-all-users-in-a-group') diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 662db18cf86..8037cf4b69d 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -8,10 +8,7 @@ .top-area = render 'shared/issuable/nav', type: :issues .nav-controls - = link_to safe_params.merge(rss_url_options), class: 'btn' do - = icon('rss') - %span.icon-label - Subscribe + = render 'shared/issuable/feed_buttons' = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues = render 'shared/issuable/search_bar', type: :issues diff --git a/app/views/groups/issues_calendar.ics.haml b/app/views/groups/issues_calendar.ics.haml new file mode 100644 index 00000000000..59573e5fecf --- /dev/null +++ b/app/views/groups/issues_calendar.ics.haml @@ -0,0 +1 @@ += render 'issues/issues_calendar', issues: @issues diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml index 15a5ecf791c..f1f67af1d1e 100644 --- a/app/views/groups/settings/_permissions.html.haml +++ b/app/views/groups/settings/_permissions.html.haml @@ -13,8 +13,8 @@ = s_('GroupSettings|Share with group lock') .col-sm-10 .form-check - = f.label :share_with_group_lock do - = f.check_box :share_with_group_lock, disabled: !can_change_share_with_group_lock?(@group) + = f.check_box :share_with_group_lock, disabled: !can_change_share_with_group_lock?(@group), class: 'form-check-input' + = f.label :share_with_group_lock, class: 'form-check-label' do %strong - group_link = link_to @group.name, group_path(@group) = s_('GroupSettings|Prevent sharing a project within %{group} with other groups').html_safe % { group: group_link } diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index a06db85ef6f..de8369ed7b9 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -472,8 +472,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - %label - %input{ :type => "checkbox" }/ + %input.form-check-input{ :type => "checkbox" }/ + %label.form-check-label Remember me .form-group.row .offset-sm-2.col-sm-10 @@ -492,8 +492,8 @@ %label{ :for => "exampleInputPassword1" } Password %input#exampleInputPassword1.form-control{ :placeholder => "Password", :type => "password" }/ .form-check - %label - %input{ :type => "checkbox" }/ + %input.form-check-input{ :type => "checkbox" }/ + %label.form-check-label Remember me %button.btn.btn-default{ :type => "submit" } Sign in diff --git a/app/views/import/fogbugz/new.html.haml b/app/views/import/fogbugz/new.html.haml index d5a37095365..74d686b6703 100644 --- a/app/views/import/fogbugz/new.html.haml +++ b/app/views/import/fogbugz/new.html.haml @@ -11,16 +11,16 @@ In the next steps, you'll be able to map users and select the projects you want to import. .form-group.row - = label_tag :uri, 'FogBugz URL', class: 'col-form-label col-sm-8' - .col-sm-4 + = label_tag :uri, 'FogBugz URL', class: 'col-form-label col-md-2' + .col-md-4 = text_field_tag :uri, nil, placeholder: 'https://mycompany.fogbugz.com', class: 'form-control' .form-group.row - = label_tag :email, 'FogBugz Email', class: 'col-form-label col-sm-8' - .col-sm-4 + = label_tag :email, 'FogBugz Email', class: 'col-form-label col-md-2' + .col-md-4 = text_field_tag :email, nil, class: 'form-control' .form-group.row - = label_tag :password, 'FogBugz Password', class: 'col-form-label col-sm-8' - .col-sm-4 + = label_tag :password, 'FogBugz Password', class: 'col-form-label col-md-2' + .col-md-4 = password_field_tag :password, nil, class: 'form-control' .form-actions = submit_tag 'Continue to the next step', class: 'btn btn-create' diff --git a/app/views/issues/_issues_calendar.ics.ruby b/app/views/issues/_issues_calendar.ics.ruby new file mode 100644 index 00000000000..3563635d33d --- /dev/null +++ b/app/views/issues/_issues_calendar.ics.ruby @@ -0,0 +1,15 @@ +cal = Icalendar::Calendar.new +cal.prodid = '-//GitLab//NONSGML GitLab//EN' +cal.x_wr_calname = 'GitLab Issues' + +@issues.includes(project: :namespace).each do |issue| + cal.event do |event| + event.dtstart = Icalendar::Values::Date.new(issue.due_date) + event.summary = "#{issue.title} (in #{issue.project.full_path})" + event.description = "Find out more at #{issue_url(issue)}" + event.url = issue_url(issue) + event.transp = 'TRANSPARENT' + end +end + +cal.to_ical diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml index 9382ee8715e..06069a72951 100644 --- a/app/views/layouts/errors.html.haml +++ b/app/views/layouts/errors.html.haml @@ -3,57 +3,17 @@ %head %meta{ :content => "width=device-width, initial-scale=1, maximum-scale=1", :name => "viewport" } %title= yield(:title) - :css - body { - color: #666; - text-align: center; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - margin: auto; - font-size: 14px; - } + %style + = Rails.application.assets_manifest.find_sources('errors.css').first.to_s.html_safe + %body + .page-container + = yield + -# haml-lint:disable InlineJavaScript + :javascript + (function(){ + var goBackElement = document.querySelector('.js-go-back'); - h1 { - font-size: 56px; - line-height: 100px; - font-weight: 400; - color: #456; - } - - h2 { - font-size: 24px; - color: #666; - line-height: 1.5em; - } - - h3 { - color: #456; - font-size: 20px; - font-weight: 400; - line-height: 28px; - } - - hr { - max-width: 800px; - margin: 18px auto; - border: 0; - border-top: 1px solid #EEE; - border-bottom: 1px solid white; - } - - img { - max-width: 40vw; - display: block; - margin: 40px auto; - } - - .container { - margin: auto 20px; - } - - ul { - margin: auto; - text-align: left; - display:inline-block; - } -%body - = yield + if (goBackElement && history.length > 1) { + goBackElement.style.display = 'block'; + } + }()); diff --git a/app/views/peek/_bar.html.haml b/app/views/peek/_bar.html.haml index cb0cccb8f8a..89d3b931f88 100644 --- a/app/views/peek/_bar.html.haml +++ b/app/views/peek/_bar.html.haml @@ -2,6 +2,6 @@ #js-peek{ data: { env: Peek.env, request_id: Peek.request_id, - peek_url: peek_routes.results_url, + peek_url: "#{peek_routes_path}/results", profile_url: url_for(safe_params.merge(lineprofiler: 'true')) }, class: Peek.env } diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml index d253e8e456e..d111113c646 100644 --- a/app/views/profiles/personal_access_tokens/index.html.haml +++ b/app/views/profiles/personal_access_tokens/index.html.haml @@ -34,18 +34,18 @@ .row.prepend-top-default .col-lg-4.profile-settings-sidebar %h4.prepend-top-0 - RSS token + Feed token %p - Your RSS token is used to authenticate you when your RSS reader loads a personalized RSS feed, and is included in your personal RSS feed URLs. + Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when when your calendar application loads a personalized calendar, and is included in those feed URLs. %p It cannot be used to access any other data. - .col-lg-8.rss-token-reset - = label_tag :rss_token, 'RSS token', class: "label-light" - = text_field_tag :rss_token, current_user.rss_token, class: 'form-control', readonly: true, onclick: 'this.select()' + .col-lg-8.feed-token-reset + = label_tag :feed_token, 'Feed token', class: "label-light" + = text_field_tag :feed_token, current_user.feed_token, class: 'form-control', readonly: true, onclick: 'this.select()' %p.form-text.text-muted - Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds as if they were you. + Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds or your calendar feed as if they were you. You should - = link_to 'reset it', [:reset, :rss_token, :profile], method: :put, data: { confirm: 'Are you sure? Any RSS URLs currently in use will stop working.' } + = link_to 'reset it', [:reset, :feed_token, :profile], method: :put, data: { confirm: 'Are you sure? Any RSS or calendar URLs currently in use will stop working.' } if that ever happens. - if incoming_email_token_enabled? diff --git a/app/views/projects/_import_project_pane.html.haml b/app/views/projects/_import_project_pane.html.haml index 4bee6cb97eb..8f535b9d789 100644 --- a/app/views/projects/_import_project_pane.html.haml +++ b/app/views/projects/_import_project_pane.html.haml @@ -1,51 +1,49 @@ - active_tab = local_assigns.fetch(:active_tab, 'blank') - f = local_assigns.fetch(:f) -.project-import.row - .col-lg-12 - .form-group.import-btn-container.clearfix - = f.label :visibility_level, class: 'label-light' do #the label here seems wrong - Import project from - .import-buttons - - if gitlab_project_import_enabled? - .import_gitlab_project.has-tooltip{ data: { container: 'body' } } - = link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do - = icon('gitlab', text: 'GitLab export') - %div - - if github_import_enabled? - = link_to new_import_github_path, class: 'btn js-import-github' do - = icon('github', text: 'GitHub') - %div - - if bitbucket_import_enabled? - = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}" do - = icon('bitbucket', text: 'Bitbucket') - - unless bitbucket_import_configured? - = render 'bitbucket_import_modal' - %div - - if gitlab_import_enabled? - = link_to status_import_gitlab_path, class: "btn import_gitlab #{'how_to_import_link' unless gitlab_import_configured?}" do - = icon('gitlab', text: 'GitLab.com') - - unless gitlab_import_configured? - = render 'gitlab_import_modal' - %div - - if google_code_import_enabled? - = link_to new_import_google_code_path, class: 'btn import_google_code' do - = icon('google', text: 'Google Code') - %div - - if fogbugz_import_enabled? - = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do - = icon('bug', text: 'Fogbugz') - %div - - if gitea_import_enabled? - = link_to new_import_gitea_path, class: 'btn import_gitea' do - = custom_icon('go_logo') - Gitea - %div - - if git_import_enabled? - %button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active' } } - = icon('git', text: 'Repo by URL') - .col-lg-12 - .js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') } - %hr - = render "shared/import_form", f: f - = render 'new_project_fields', f: f, project_name_id: "import-url-name" +.project-import + .form-group.import-btn-container.clearfix + = f.label :visibility_level, class: 'label-light' do #the label here seems wrong + Import project from + .import-buttons + - if gitlab_project_import_enabled? + .import_gitlab_project.has-tooltip{ data: { container: 'body' } } + = link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do + = icon('gitlab', text: 'GitLab export') + %div + - if github_import_enabled? + = link_to new_import_github_path, class: 'btn js-import-github' do + = icon('github', text: 'GitHub') + %div + - if bitbucket_import_enabled? + = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}" do + = icon('bitbucket', text: 'Bitbucket') + - unless bitbucket_import_configured? + = render 'bitbucket_import_modal' + %div + - if gitlab_import_enabled? + = link_to status_import_gitlab_path, class: "btn import_gitlab #{'how_to_import_link' unless gitlab_import_configured?}" do + = icon('gitlab', text: 'GitLab.com') + - unless gitlab_import_configured? + = render 'gitlab_import_modal' + %div + - if google_code_import_enabled? + = link_to new_import_google_code_path, class: 'btn import_google_code' do + = icon('google', text: 'Google Code') + %div + - if fogbugz_import_enabled? + = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do + = icon('bug', text: 'Fogbugz') + %div + - if gitea_import_enabled? + = link_to new_import_gitea_path, class: 'btn import_gitea' do + = custom_icon('go_logo') + Gitea + %div + - if git_import_enabled? + %button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active' } } + = icon('git', text: 'Repo by URL') + .js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') } + %hr + = render "shared/import_form", f: f + = render 'new_project_fields', f: f, project_name_id: "import-url-name" diff --git a/app/views/projects/_merge_request_fast_forward_settings.html.haml b/app/views/projects/_merge_request_fast_forward_settings.html.haml deleted file mode 100644 index 2f08a28e26e..00000000000 --- a/app/views/projects/_merge_request_fast_forward_settings.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -- form = local_assigns.fetch(:form) -- project = local_assigns.fetch(:project) - -.form-check - = label_tag :project_merge_method_ff do - = form.radio_button :merge_method, :ff, class: "js-merge-method-radio qa-radio-button-merge-ff" - %strong Fast-forward merge - %br - %span.descr - No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. - %br - %span.descr - When fast-forward merge is not possible, the user is given the option to rebase. diff --git a/app/views/projects/_merge_request_merge_method_settings.html.haml b/app/views/projects/_merge_request_merge_method_settings.html.haml new file mode 100644 index 00000000000..3bb220ac6d0 --- /dev/null +++ b/app/views/projects/_merge_request_merge_method_settings.html.haml @@ -0,0 +1,36 @@ +- form = local_assigns.fetch(:form) +- project = local_assigns.fetch(:project) + +.form-group + = label_tag :merge_method_merge, class: 'label-light' do + Merge method + .form-check + = form.radio_button :merge_method, :merge, class: "js-merge-method-radio form-check-input" + = label_tag :project_merge_method_merge, class: 'form-check-label' do + %strong Merge commit + %br + %span.descr + A merge commit is created for every merge, and merging is allowed as long as there are no conflicts. + + .form-check + = form.radio_button :merge_method, :rebase_merge, class: "js-merge-method-radio form-check-input" + = label_tag :project_merge_method_rebase_merge, class: 'form-check-label' do + %strong Merge commit with semi-linear history + %br + %span.descr + A merge commit is created for every merge, but merging is only allowed if fast-forward merge is possible. + This way you could make sure that if this merge request would build, after merging to target branch it would also build. + %br + %span.descr + When fast-forward merge is not possible, the user is given the option to rebase. + + .form-check + = form.radio_button :merge_method, :ff, class: "js-merge-method-radio qa-radio-button-merge-ff form-check-input" + = label_tag :project_merge_method_ff, class: 'form-check-label' do + %strong Fast-forward merge + %br + %span.descr + No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. + %br + %span.descr + When fast-forward merge is not possible, the user is given the option to rebase. diff --git a/app/views/projects/_merge_request_merge_settings.html.haml b/app/views/projects/_merge_request_merge_settings.html.haml index 762a263656d..f178c94e008 100644 --- a/app/views/projects/_merge_request_merge_settings.html.haml +++ b/app/views/projects/_merge_request_merge_settings.html.haml @@ -2,22 +2,22 @@ .form-group .form-check.builds-feature{ class: ("hidden" if @project && @project.project_feature.send(:builds_access_level) == 0) } - = form.label :only_allow_merge_if_pipeline_succeeds do - = form.check_box :only_allow_merge_if_pipeline_succeeds + = form.check_box :only_allow_merge_if_pipeline_succeeds, class: 'form-check-input' + = form.label :only_allow_merge_if_pipeline_succeeds, class: 'form-check-label' do %strong Only allow merge requests to be merged if the pipeline succeeds %br %span.descr Pipelines need to be configured to enable this feature. = link_to icon('question-circle'), help_page_path('user/project/merge_requests/merge_when_pipeline_succeeds', anchor: 'only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds'), target: '_blank' .form-check - = form.label :only_allow_merge_if_all_discussions_are_resolved do - = form.check_box :only_allow_merge_if_all_discussions_are_resolved + = form.check_box :only_allow_merge_if_all_discussions_are_resolved, class: 'form-check-input' + = form.label :only_allow_merge_if_all_discussions_are_resolved, class: 'form-check-label' do %strong Only allow merge requests to be merged if all discussions are resolved .form-check - = form.label :resolve_outdated_diff_discussions do - = form.check_box :resolve_outdated_diff_discussions + = form.check_box :resolve_outdated_diff_discussions, class: 'form-check-input' + = form.label :resolve_outdated_diff_discussions, class: 'form-check-label' do %strong Automatically resolve merge request diff discussions when they become outdated .form-check - = form.label :printing_merge_request_link_enabled do - = form.check_box :printing_merge_request_link_enabled + = form.check_box :printing_merge_request_link_enabled, class: 'form-check-input' + = form.label :printing_merge_request_link_enabled, class: 'form-check-label' do %strong Show link to create/view merge request when pushing from the command line diff --git a/app/views/projects/_merge_request_rebase_settings.html.haml b/app/views/projects/_merge_request_rebase_settings.html.haml deleted file mode 100644 index 93895a55435..00000000000 --- a/app/views/projects/_merge_request_rebase_settings.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -- form = local_assigns.fetch(:form) - -.form-check - = label_tag :project_merge_method_rebase_merge do - = form.radio_button :merge_method, :rebase_merge, class: "js-merge-method-radio" - %strong Merge commit with semi-linear history - %br - %span.descr - A merge commit is created for every merge, but merging is only allowed if fast-forward merge is possible. - This way you could make sure that if this merge request would build, after merging to target branch it would also build. - %br - %span.descr - When fast-forward merge is not possible, the user is given the option to rebase. diff --git a/app/views/projects/_merge_request_settings.html.haml b/app/views/projects/_merge_request_settings.html.haml index a9ddcd94865..c80e831dd33 100644 --- a/app/views/projects/_merge_request_settings.html.haml +++ b/app/views/projects/_merge_request_settings.html.haml @@ -1,18 +1,5 @@ - form = local_assigns.fetch(:form) -.form-group - = label_tag :merge_method_merge, class: 'label-light' do - Merge method - .form-check - = label_tag :project_merge_method_merge do - = form.radio_button :merge_method, :merge, class: "js-merge-method-radio" - %strong Merge commit - %br - %span.descr - A merge commit is created for every merge, and merging is allowed as long as there are no conflicts. - - = render 'merge_request_rebase_settings', form: form - - = render 'merge_request_fast_forward_settings', project: @project, form: form += render 'projects/merge_request_merge_method_settings', project: @project, form: form = render 'projects/merge_request_merge_settings', form: form diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index 6366a2f729a..cfbd0459e3e 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -35,11 +35,10 @@ %span (optional) = f.text_area :description, placeholder: 'Description format', class: "form-control", rows: 3, maxlength: 250 -.form-group.visibility-level-setting - = f.label :visibility_level, class: 'label-light' do - Visibility Level - = link_to icon('question-circle'), help_page_path("public_access/public_access"), aria: { label: 'Documentation for Visibility Level' }, target: '_blank', rel: 'noopener noreferrer' - = render 'shared/visibility_level', f: f, visibility_level: visibility_level.to_i, can_change_visibility_level: true, form_model: @project, with_label: false += f.label :visibility_level, class: 'label-light' do + Visibility Level + = link_to icon('question-circle'), help_page_path("public_access/public_access"), aria: { label: 'Documentation for Visibility Level' }, target: '_blank', rel: 'noopener noreferrer' += render 'shared/visibility_level', f: f, visibility_level: visibility_level.to_i, can_change_visibility_level: true, form_model: @project, with_label: false = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 = link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel' diff --git a/app/views/projects/clusters/gcp/login.html.haml b/app/views/projects/clusters/gcp/login.html.haml index f1771349a53..55a42ac4847 100644 --- a/app/views/projects/clusters/gcp/login.html.haml +++ b/app/views/projects/clusters/gcp/login.html.haml @@ -12,8 +12,7 @@ .row .col-sm-8.offset-sm-4.signin-with-google - if @authorize_url - = link_to @authorize_url do - = image_tag('auth_buttons/signin_with_google.png', width: '191px') + = link_to(image_tag('auth_buttons/signin_with_google.png', width: '191px'), @authorize_url) = _('or') = link_to('create a new Google account', 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral', target: '_blank', rel: 'noopener noreferrer') - else diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 79b22766bc7..77ba422e87e 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -33,10 +33,15 @@ %span.light (optional) = f.text_area :description, class: "form-control", rows: 3, maxlength: 250 + = render_if_exists 'projects/classification_policy_settings', f: f + - unless @project.empty_repo? .form-group = f.label :default_branch, "Default Branch", class: 'label-light' = f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'}) + + = render_if_exists 'shared/repository_size_limit_setting', form: f, type: :project + .form-group = f.label :tag_list, "Tags", class: 'label-light' = f.text_field :tag_list, value: @project.tag_list.sort.join(', '), maxlength: 2000, class: "form-control" @@ -75,6 +80,8 @@ .js-project-permissions-form = f.submit 'Save changes', class: "btn btn-save" + = render_if_exists 'projects/issues_settings' + %section.settings.merge-requests-feature.no-animate{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)] } .settings-header %h4 @@ -84,10 +91,14 @@ %p Customize your merge request restrictions. .settings-content + = render_if_exists 'shared/promotions/promote_mr_features' + = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "merge-request-settings-form" }, authenticity_token: true do |f| - = render 'merge_request_settings', form: f + = render 'projects/merge_request_settings', form: f = f.submit 'Save changes', class: "btn btn-save qa-save-merge-request-changes" + = render_if_exists 'projects/service_desk_settings' + = render 'export', project: @project %section.settings.advanced-settings.no-animate{ class: ('expanded' if expanded) } diff --git a/app/views/projects/issues/_nav_btns.html.haml b/app/views/projects/issues/_nav_btns.html.haml index 297b928f020..0dd2d2e6c5d 100644 --- a/app/views/projects/issues/_nav_btns.html.haml +++ b/app/views/projects/issues/_nav_btns.html.haml @@ -1,5 +1,5 @@ -= link_to safe_params.merge(rss_url_options), class: 'btn btn-default append-right-10 has-tooltip', title: 'Subscribe' do - = icon('rss') += render 'shared/issuable/feed_buttons' + - if @can_bulk_update = button_tag "Edit issues", class: "btn btn-default append-right-10 js-bulk-update-toggle" - if show_new_issue_link?(@project) diff --git a/app/views/projects/issues/calendar.ics.haml b/app/views/projects/issues/calendar.ics.haml new file mode 100644 index 00000000000..59573e5fecf --- /dev/null +++ b/app/views/projects/issues/calendar.ics.haml @@ -0,0 +1 @@ += render 'issues/issues_calendar', issues: @issues diff --git a/app/views/projects/mattermosts/_team_selection.html.haml b/app/views/projects/mattermosts/_team_selection.html.haml index 361d3c61d99..37c09f12f63 100644 --- a/app/views/projects/mattermosts/_team_selection.html.haml +++ b/app/views/projects/mattermosts/_team_selection.html.haml @@ -13,9 +13,9 @@ = f.hidden_field(:team_id, value: selected_id, required: true) if @teams.one? .form-text.text-muted - if @teams.one? - This is the only available team. + This is the only available team that you are a member of. - else - The list shows all available teams. + The list shows all available teams that you are a member of. To create a team, = link_to "#{Gitlab.config.mattermost.host}/create_team" do use Mattermost's interface diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index aa3fb623e58..01e38ffee20 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -20,6 +20,8 @@ window.gl = window.gl || {}; window.gl.mrWidgetData = #{serialize_issuable(@merge_request, serializer: 'widget')} + window.gl.mrWidgetData.squash_before_merge_help_path = '#{help_page_path("user/project/merge_requests/squash_and_merge")}'; + #js-vue-mr-widget.mr-widget .content-block.content-block-small.emoji-list-container.js-noteable-awards diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index 75cb8245d36..2d3f9116703 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -10,8 +10,8 @@ = icon('search') .inline.prepend-left-20 .form-check.light - = label_tag :filter_ref do - = check_box_tag :filter_ref, 1, @options[:filter_ref] + = check_box_tag :filter_ref, 1, @options[:filter_ref], class: 'form-check-input' + = label_tag :filter_ref, class: 'form-check-label' do %span= _("Begin with the selected commit") - if @commit diff --git a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml index 414df15feeb..bbabb98dafe 100644 --- a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml +++ b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml @@ -11,22 +11,22 @@ = message.html_safe = f.fields_for :auto_devops_attributes, @auto_devops do |form| .form-check - = form.label :enabled_true do - = form.radio_button :enabled, 'true' + = form.radio_button :enabled, 'true', class: 'form-check-input' + = form.label :enabled_true, class: 'form-check-label' do %strong= s_('CICD|Enable Auto DevOps') %br = s_('CICD|The Auto DevOps pipeline configuration will be used when there is no %{ci_file} in the project.').html_safe % { ci_file: ci_file_formatted } .form-check - = form.label :enabled_false do - = form.radio_button :enabled, 'false' + = form.radio_button :enabled, 'false', class: 'form-check-input' + = form.label :enabled_false, class: 'form-check-label' do %strong= s_('CICD|Disable Auto DevOps') %br = s_('CICD|An explicit %{ci_file} needs to be specified before you can begin using Continuous Integration and Delivery.').html_safe % { ci_file: ci_file_formatted } .form-check - = form.label :enabled_ do - = form.radio_button :enabled, '' + = form.radio_button :enabled, '', class: 'form-check-input' + = form.label :enabled_, class: 'form-check-label' do %strong= s_('CICD|Instance default (%{state})') % { state: "#{Gitlab::CurrentSettings.auto_devops_enabled? ? _('enabled') : _('disabled')}" } %br = s_('CICD|Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific %{ci_file}.').html_safe % { ci_file: ci_file_formatted } diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml index 50175f5258c..e93b240a007 100644 --- a/app/views/projects/settings/ci_cd/_form.html.haml +++ b/app/views/projects/settings/ci_cd/_form.html.haml @@ -20,15 +20,15 @@ Choose between <code>clone</code> or <code>fetch</code> to get the recent application code = link_to icon('question-circle'), help_page_path('user/project/pipelines/settings', anchor: 'git-strategy'), target: '_blank' .form-check - = f.label :build_allow_git_fetch_false do - = f.radio_button :build_allow_git_fetch, 'false' + = f.radio_button :build_allow_git_fetch, 'false', { class: 'form-check-input' } + = f.label :build_allow_git_fetch_false, class: 'form-check-label' do %strong git clone %br %span.descr Slower but makes sure the project workspace is pristine as it clones the repository from scratch for every job .form-check - = f.label :build_allow_git_fetch_true do - = f.radio_button :build_allow_git_fetch, 'true' + = f.radio_button :build_allow_git_fetch, 'true', { class: 'form-check-input' } + = f.label :build_allow_git_fetch_true, class: 'form-check-label' do %strong git fetch %br %span.descr @@ -53,8 +53,8 @@ %hr .form-group .form-check - = f.label :public_builds do - = f.check_box :public_builds + = f.check_box :public_builds, { class: 'form-check-input' } + = f.label :public_builds, class: 'form-check-label' do %strong Public pipelines .form-text.text-muted Allow public access to pipelines and job details, including output logs and artifacts @@ -75,8 +75,8 @@ %hr .form-group .form-check - = f.label :auto_cancel_pending_pipelines do - = f.check_box :auto_cancel_pending_pipelines, {}, 'enabled', 'disabled' + = f.check_box :auto_cancel_pending_pipelines, { class: 'form-check-input' }, 'enabled', 'disabled' + = f.label :auto_cancel_pending_pipelines, class: 'form-check-label' do %strong Auto-cancel redundant, pending pipelines .form-text.text-muted New pipelines will cancel older, pending pipelines on the same branch diff --git a/app/views/shared/_allow_request_access.html.haml b/app/views/shared/_allow_request_access.html.haml index 0e698570d7d..92268e74b1e 100644 --- a/app/views/shared/_allow_request_access.html.haml +++ b/app/views/shared/_allow_request_access.html.haml @@ -1,6 +1,6 @@ .form-check - = form.label :request_access_enabled do - = form.check_box :request_access_enabled + = form.check_box :request_access_enabled, class: 'form-check-input' + = form.label :request_access_enabled, class: 'form-check-label' do %strong Allow users to request access %br %span.descr Allow users to request access if visibility is public or internal. diff --git a/app/views/shared/_import_form.html.haml b/app/views/shared/_import_form.html.haml index 35673303b85..356e12cf9f8 100644 --- a/app/views/shared/_import_form.html.haml +++ b/app/views/shared/_import_form.html.haml @@ -1,19 +1,20 @@ - ci_cd_only = local_assigns.fetch(:ci_cd_only, false) -.form-group.row.import-url-data +.form-group.import-url-data = f.label :import_url, class: 'label-light' do %span = _('Git repository URL') = f.text_field :import_url, autocomplete: 'off', class: 'form-control', placeholder: 'https://username:password@gitlab.company.com/group/project.git', required: true - .card.prepend-top-20 - %ul - %li - = _('The repository must be accessible over <code>http://</code>, <code>https://</code> or <code>git://</code>.').html_safe - %li - = _('If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>.').html_safe - %li - = import_will_timeout_message(ci_cd_only) - %li - = import_svn_message(ci_cd_only) + .info-well.prepend-top-20 + .well-segment + %ul + %li + = _('The repository must be accessible over <code>http://</code>, <code>https://</code> or <code>git://</code>.').html_safe + %li + = _('If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>.').html_safe + %li + = import_will_timeout_message(ci_cd_only) + %li + = import_svn_message(ci_cd_only) diff --git a/app/views/shared/_new_merge_request_checkbox.html.haml b/app/views/shared/_new_merge_request_checkbox.html.haml index 8dbdf63f9f4..165109b6b70 100644 --- a/app/views/shared/_new_merge_request_checkbox.html.haml +++ b/app/views/shared/_new_merge_request_checkbox.html.haml @@ -1,7 +1,7 @@ .form-check - nonce = SecureRandom.hex - = label_tag "create_merge_request-#{nonce}" do - = check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request', id: "create_merge_request-#{nonce}" + = check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request form-check-input', id: "create_merge_request-#{nonce}" + = label_tag "create_merge_request-#{nonce}", class: 'form-check-label' do - translation_variables = { new_merge_request: "<strong>#{_('new merge request')}</strong>" } - translation = _('Start a %{new_merge_request} with these changes') % translation_variables #{ translation.html_safe } diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml index 38c6f560dc6..d67409ffe14 100644 --- a/app/views/shared/_visibility_level.html.haml +++ b/app/views/shared/_visibility_level.html.haml @@ -1,6 +1,6 @@ - with_label = local_assigns.fetch(:with_label, true) -.form-group.row.visibility-level-setting +.form-group.visibility-level-setting - if with_label = f.label :visibility_level, class: 'col-form-label col-sm-2' do Visibility Level diff --git a/app/views/shared/_visibility_radios.html.haml b/app/views/shared/_visibility_radios.html.haml index bdf550cd8b6..dd6b9cce58e 100644 --- a/app/views/shared/_visibility_radios.html.haml +++ b/app/views/shared/_visibility_radios.html.haml @@ -2,9 +2,9 @@ - disallowed = disallowed_visibility_level?(form_model, level) - restricted = restricted_visibility_levels.include?(level) - disabled = disallowed || restricted - .form-check.pl-0{ class: [('disabled' if disabled), ('restricted' if restricted)] } - = form.label "#{model_method}_#{level}" do - = form.radio_button model_method, level, checked: (selected_level == level), disabled: disabled + .form-check{ class: [('disabled' if disabled), ('restricted' if restricted)] } + = form.radio_button model_method, level, checked: (selected_level == level), disabled: disabled, class: 'form-check-input' + = form.label "#{model_method}_#{level}", class: 'form-check-label' do = visibility_level_icon(level) .option-title = visibility_level_label(level) diff --git a/app/views/shared/dashboard/_no_filter_selected.html.haml b/app/views/shared/dashboard/_no_filter_selected.html.haml index b2e6967f6aa..32246dac4c7 100644 --- a/app/views/shared/dashboard/_no_filter_selected.html.haml +++ b/app/views/shared/dashboard/_no_filter_selected.html.haml @@ -1,8 +1,8 @@ .row.empty-state.text-center - .col-xs-12 + .col-12 .svg-130.prepend-top-default = image_tag 'illustrations/issue-dashboard_results-without-filter.svg' - .col-xs-12 + .col-12 .text-content %h4 = _("Please select at least one filter to see results") diff --git a/app/views/shared/empty_states/_wikis_layout.html.haml b/app/views/shared/empty_states/_wikis_layout.html.haml index 6fae6104ca2..a5f100e3469 100644 --- a/app/views/shared/empty_states/_wikis_layout.html.haml +++ b/app/views/shared/empty_states/_wikis_layout.html.haml @@ -1,7 +1,7 @@ .row.empty-state - .col-xs-12 + .col-12 .svg-content = image_tag image_path - .col-xs-12 + .col-12 .text-content.text-center = yield diff --git a/app/views/shared/icons/_icon_calendar.svg b/app/views/shared/icons/_icon_calendar.svg new file mode 100644 index 00000000000..4d0a703f9a0 --- /dev/null +++ b/app/views/shared/icons/_icon_calendar.svg @@ -0,0 +1 @@ +<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M15 5v7a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V5a2 2 0 0 1 2-2h1V2a1 1 0 1 1 2 0v1h4V2a1 1 0 1 1 2 0v1h1a2 2 0 0 1 2 2zM3 6v6a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V6H3zm2 2h2a1 1 0 1 1 0 2H5a1 1 0 1 1 0-2z" fill="#000" fill-rule="evenodd"/></svg>
\ No newline at end of file diff --git a/app/views/shared/issuable/_feed_buttons.html.haml b/app/views/shared/issuable/_feed_buttons.html.haml new file mode 100644 index 00000000000..d4834090413 --- /dev/null +++ b/app/views/shared/issuable/_feed_buttons.html.haml @@ -0,0 +1,4 @@ += link_to safe_params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe to RSS feed' do + = icon('rss') += link_to safe_params.merge(calendar_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe to calendar' do + = custom_icon('icon_calendar') diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index fbc608b207a..8497e3220ee 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -23,8 +23,8 @@ .form-group.row .offset-sm-2.col-sm-10 .form-check - = form.label :confidential do - = form.check_box :confidential + = form.check_box :confidential, class: 'form-check-input' + = form.label :confidential, class: 'form-check-label' do This issue is confidential and should only be visible to team members with at least Reporter access. = render 'shared/issuable/form/metadata', issuable: issuable, form: form diff --git a/app/views/shared/issuable/form/_contribution.html.haml b/app/views/shared/issuable/form/_contribution.html.haml index f12c23cbc64..b34549240e0 100644 --- a/app/views/shared/issuable/form/_contribution.html.haml +++ b/app/views/shared/issuable/form/_contribution.html.haml @@ -12,8 +12,8 @@ = _('Contribution') .col-sm-10 .form-check - = form.label :allow_maintainer_to_push do - = form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user) + = form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user), class: 'form-check-input' + = form.label :allow_maintainer_to_push, class: 'form-check-label' do = _('Allow edits from maintainers.') = link_to 'About this feature', help_page_path('user/project/merge_requests/maintainer_access') .form-text.text-muted diff --git a/app/views/shared/issuable/form/_default_templates.html.haml b/app/views/shared/issuable/form/_default_templates.html.haml new file mode 100644 index 00000000000..49a5ce926b3 --- /dev/null +++ b/app/views/shared/issuable/form/_default_templates.html.haml @@ -0,0 +1,4 @@ +%p.form-text.text-muted + Add + = link_to 'description templates', help_page_path('user/project/description_templates'), tabindex: -1 + to help your contributors communicate effectively! diff --git a/app/views/shared/issuable/form/_merge_params.html.haml b/app/views/shared/issuable/form/_merge_params.html.haml index 1df881e4102..1bcdddd0df0 100644 --- a/app/views/shared/issuable/form/_merge_params.html.haml +++ b/app/views/shared/issuable/form/_merge_params.html.haml @@ -11,7 +11,16 @@ .col-sm-10.offset-sm-2 - if issuable.can_remove_source_branch?(current_user) .form-check - = label_tag 'merge_request[force_remove_source_branch]' do - = hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil - = check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch? + = hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil + = check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch?, class: 'form-check-input' + = label_tag 'merge_request[force_remove_source_branch]', class: 'form-check-label' do Remove source branch when merge request is accepted. + +.form-group.row + .col-sm-10.offset-sm-2 + .form-check + = hidden_field_tag 'merge_request[squash]', '0', id: nil + = check_box_tag 'merge_request[squash]', '1', issuable.squash, class: 'form-check-input' + = label_tag 'merge_request[squash]', class: 'form-check-label' do + Squash commits when merge request is accepted. + = link_to 'About this feature', help_page_path('user/project/merge_requests/squash_and_merge') diff --git a/app/views/shared/issuable/form/_title.html.haml b/app/views/shared/issuable/form/_title.html.haml index c4f30f5f4d9..c35d0b3751f 100644 --- a/app/views/shared/issuable/form/_title.html.haml +++ b/app/views/shared/issuable/form/_title.html.haml @@ -30,7 +30,4 @@ merge request from being merged before it's ready. - if no_issuable_templates && can?(current_user, :push_code, issuable.project) - %p.form-text.text-muted - Add - = link_to 'description templates', help_page_path('user/project/description_templates'), tabindex: -1 - to help your contributors communicate effectively! + = render 'shared/issuable/form/default_templates' diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 42b2d27c44a..46debe1f2b9 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -61,7 +61,7 @@ title: 'Resend invite' - if user != current_user && member.can_update? - = form_for member, remote: true, html: { class: 'js-edit-member-form form-horizontal' } do |f| + = form_for member, remote: true, html: { class: 'js-edit-member-form form-group row append-right-5' } do |f| = f.hidden_field :access_level .member-form-control.dropdown.append-right-5 %button.dropdown-menu-toggle.js-member-permissions-dropdown{ type: "button", diff --git a/app/views/shared/milestones/_tabs.html.haml b/app/views/shared/milestones/_tabs.html.haml index e6a65161ed6..55460acab8f 100644 --- a/app/views/shared/milestones/_tabs.html.haml +++ b/app/views/shared/milestones/_tabs.html.haml @@ -5,25 +5,25 @@ .fade-right= icon('angle-right') %ul.nav-links.scrolling-tabs.js-milestone-tabs.nav.nav-tabs - if issues_accessible - %li.active - = link_to '#tab-issues', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do + %li.nav-item + = link_to '#tab-issues', class: 'nav-link active', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do Issues %span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size - %li - = link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do + %li.nav-item + = link_to '#tab-merge-requests', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do Merge Requests %span.badge.badge-pill= milestone.merge_requests.size - else - %li.active - = link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do + %li.nav-item + = link_to '#tab-merge-requests', class: 'nav-link active', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do Merge Requests %span.badge.badge-pill= milestone.merge_requests.size - %li - = link_to '#tab-participants', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do + %li.nav-item + = link_to '#tab-participants', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do Participants %span.badge.badge-pill= milestone.participants.count - %li - = link_to '#tab-labels', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do + %li.nav-item + = link_to '#tab-labels', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do Labels %span.badge.badge-pill= milestone.labels.count diff --git a/app/views/shared/notifications/_custom_notifications.html.haml b/app/views/shared/notifications/_custom_notifications.html.haml index d830225d169..51d912b4a66 100644 --- a/app/views/shared/notifications/_custom_notifications.html.haml +++ b/app/views/shared/notifications/_custom_notifications.html.haml @@ -23,8 +23,8 @@ - field_id = "#{notifications_menu_identifier("modal", notification_setting)}_notification_setting[#{event}]" .form-group .form-check{ class: ("prepend-top-0" if index == 0) } - %label{ for: field_id } - = check_box("notification_setting", event, id: field_id, class: "js-custom-notification-event", checked: notification_setting.public_send(event)) + = check_box("notification_setting", event, id: field_id, class: "js-custom-notification-event form-check-input", checked: notification_setting.public_send(event)) + %label.form-check-label{ for: field_id } %strong = notification_event_name(event) = icon("spinner spin", class: "custom-notification-event-loading") diff --git a/app/views/shared/runners/_form.html.haml b/app/views/shared/runners/_form.html.haml index 660123d8b07..0337680d79b 100644 --- a/app/views/shared/runners/_form.html.haml +++ b/app/views/shared/runners/_form.html.haml @@ -4,26 +4,26 @@ = label :active, "Active", class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.check_box :active + = f.check_box :active, { class: 'form-check-input' } %span.light Paused Runners don't accept new jobs .form-group.row = label :protected, "Protected", class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.check_box :access_level, {}, 'ref_protected', 'not_protected' + = f.check_box :access_level, { class: 'form-check-input' }, 'ref_protected', 'not_protected' %span.light This runner will only run on pipelines triggered on protected branches .form-group.row = label :run_untagged, 'Run untagged jobs', class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.check_box :run_untagged + = f.check_box :run_untagged, { class: 'form-check-input' } %span.light Indicates whether this runner can pick jobs without tags - unless runner.group_type? .form-group.row = label :locked, _('Lock to current projects'), class: 'col-form-label col-sm-2' .col-sm-10 .form-check - = f.check_box :locked + = f.check_box :locked, { class: 'form-check-input' } %span.light= _('When a runner is locked, it cannot be assigned to other projects') .form-group.row = label_tag :token, class: 'col-form-label col-sm-2' do diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml index ddf54866b99..828ec870dc0 100644 --- a/app/views/shared/snippets/_header.html.haml +++ b/app/views/shared/snippets/_header.html.haml @@ -32,10 +32,10 @@ - if public_snippet? .embed-snippet .input-group - .input-group-btn - %button.btn.embed-toggle{ 'data-toggle': 'dropdown', type: 'button' } + .input-group-prepend + %button.btn.btn-svg.embed-toggle.input-group-text{ 'data-toggle': 'dropdown', type: 'button' } %span.js-embed-action= _("Embed") - = sprite_icon('angle-down', size: 12) + = sprite_icon('angle-down', size: 12, css_class: 'caret-down') %ul.dropdown-menu.dropdown-menu-selectable.embed-toggle-list %li %button.js-embed-btn.btn.btn-transparent.is-active{ type: 'button' } @@ -44,7 +44,6 @@ %button.js-share-btn.btn.btn-transparent{ type: 'button' } %strong.embed-toggle-list-item= _("Share") %input.js-snippet-url-area.snippet-embed-input.form-control{ type: "text", autocomplete: 'off', value: snippet_embed } - .input-group-btn - %button.js-clipboard-btn.snippet-clipboard-btn.btn.btn-default.has-tooltip{ title: "Copy to clipboard", 'data-clipboard-target': '.js-snippet-url-area' } - = sprite_icon('duplicate', size: 16) + .input-group-append + = clipboard_button(title: s_('Copy to clipboard'), class: 'js-clipboard-btn snippet-clipboard-btn btn btn-default', target: '.js-snippet-url-area') .clearfix diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml index 0d1c007dd78..660769fa50d 100644 --- a/app/views/shared/web_hooks/_form.html.haml +++ b/app/views/shared/web_hooks/_form.html.haml @@ -10,80 +10,70 @@ Use this token to validate received payloads. It will be sent with the request in the X-Gitlab-Token HTTP header. .form-group = form.label :url, 'Trigger', class: 'label-light' - %ul.list-unstyled + %ul.list-unstyled.prepend-left-20 %li - = form.check_box :push_events, class: 'float-left' - .prepend-left-20 - = form.label :push_events, class: 'list-label' do - %strong Push events - %p.light - This URL will be triggered by a push to the repository + = form.check_box :push_events, class: 'form-check-input' + = form.label :push_events, class: 'list-label form-check-label ml-1' do + %strong Push events + %p.light.ml-1 + This URL will be triggered by a push to the repository %li - = form.check_box :tag_push_events, class: 'float-left' - .prepend-left-20 - = form.label :tag_push_events, class: 'list-label' do - %strong Tag push events - %p.light - This URL will be triggered when a new tag is pushed to the repository + = form.check_box :tag_push_events, class: 'form-check-input' + = form.label :tag_push_events, class: 'list-label form-check-label ml-1' do + %strong Tag push events + %p.light.ml-1 + This URL will be triggered when a new tag is pushed to the repository %li - = form.check_box :note_events, class: 'float-left' - .prepend-left-20 - = form.label :note_events, class: 'list-label' do - %strong Comments - %p.light - This URL will be triggered when someone adds a comment + = form.check_box :note_events, class: 'form-check-input' + = form.label :note_events, class: 'list-label form-check-label ml-1' do + %strong Comments + %p.light.ml-1 + This URL will be triggered when someone adds a comment %li - = form.check_box :confidential_note_events, class: 'float-left' - .prepend-left-20 - = form.label :confidential_note_events, class: 'list-label' do - %strong Confidential Comments - %p.light - This URL will be triggered when someone adds a comment on a confidential issue + = form.check_box :confidential_note_events, class: 'form-check-input' + = form.label :confidential_note_events, class: 'list-label form-check-label ml-1' do + %strong Confidential Comments + %p.light.ml-1 + This URL will be triggered when someone adds a comment on a confidential issue %li - = form.check_box :issues_events, class: 'float-left' - .prepend-left-20 - = form.label :issues_events, class: 'list-label' do - %strong Issues events - %p.light - This URL will be triggered when an issue is created/updated/merged + = form.check_box :issues_events, class: 'form-check-input' + = form.label :issues_events, class: 'list-label form-check-label ml-1' do + %strong Issues events + %p.light.ml-1 + This URL will be triggered when an issue is created/updated/merged %li - = form.check_box :confidential_issues_events, class: 'float-left' - .prepend-left-20 - = form.label :confidential_issues_events, class: 'list-label' do - %strong Confidential Issues events - %p.light - This URL will be triggered when a confidential issue is created/updated/merged + = form.check_box :confidential_issues_events, class: 'form-check-input' + = form.label :confidential_issues_events, class: 'list-label form-check-label ml-1' do + %strong Confidential Issues events + %p.light.ml-1 + This URL will be triggered when a confidential issue is created/updated/merged %li - = form.check_box :merge_requests_events, class: 'float-left' - .prepend-left-20 - = form.label :merge_requests_events, class: 'list-label' do - %strong Merge request events - %p.light - This URL will be triggered when a merge request is created/updated/merged + = form.check_box :merge_requests_events, class: 'form-check-input' + = form.label :merge_requests_events, class: 'list-label form-check-label ml-1' do + %strong Merge request events + %p.light.ml-1 + This URL will be triggered when a merge request is created/updated/merged %li - = form.check_box :job_events, class: 'float-left' - .prepend-left-20 - = form.label :job_events, class: 'list-label' do - %strong Job events - %p.light - This URL will be triggered when the job status changes + = form.check_box :job_events, class: 'form-check-input' + = form.label :job_events, class: 'list-label form-check-label ml-1' do + %strong Job events + %p.light.ml-1 + This URL will be triggered when the job status changes %li - = form.check_box :pipeline_events, class: 'float-left' - .prepend-left-20 - = form.label :pipeline_events, class: 'list-label' do - %strong Pipeline events - %p.light - This URL will be triggered when the pipeline status changes + = form.check_box :pipeline_events, class: 'form-check-input' + = form.label :pipeline_events, class: 'list-label form-check-label ml-1' do + %strong Pipeline events + %p.light.ml-1 + This URL will be triggered when the pipeline status changes %li - = form.check_box :wiki_page_events, class: 'float-left' - .prepend-left-20 - = form.label :wiki_page_events, class: 'list-label' do - %strong Wiki Page events - %p.light - This URL will be triggered when a wiki page is created/updated + = form.check_box :wiki_page_events, class: 'form-check-input' + = form.label :wiki_page_events, class: 'list-label form-check-label ml-1' do + %strong Wiki Page events + %p.light.ml-1 + This URL will be triggered when a wiki page is created/updated .form-group = form.label :enable_ssl_verification, 'SSL verification', class: 'label-light checkbox' .form-check - = form.label :enable_ssl_verification do - = form.check_box :enable_ssl_verification + = form.check_box :enable_ssl_verification, class: 'form-check-input' + = form.label :enable_ssl_verification, class: 'form-check-label ml-1' do %strong Enable SSL verification |