Commit 72157766 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'master' into sh-headless-chrome-support

* master: (33 commits)
  Ignore SQL CACHE hits in Sherlock
  Fix SQL timings for the performance bar
  Find the LFS-objects for a fork within a the fork network
  Remove bottom-border from last responsive table row
  Add system hooks user_rename and group_rename
  Unlink a project from a fork network when it's source was deleted.
  Make sure the settings page renders when root of a fork is deleted
  Remove Peek's original keyboard shortcut (numpad 0, keycode 96)
  Add application setting to Auto DevOps docs
  Enable MergeableSelector in scss-lint (for !14567)
  Enable MergeableSelector in scss-lint (for !14055)
  Enable MergeableSelector in scss-lint (for !14062)
  Enable MergeableSelector in scss-lint (for !14398)
  Enable MergeableSelector in scss-lint (for !13480)
  Enable MergeableSelector in scss-lint (for !13473)
  Enable MergeableSelector in scss-lint (for !13600)
  Enable MergeableSelector in scss-lint
  Resolve ""To do" should be "Todos" on Todos list page"
  Avoid regenerating the ref path for the environment
  Remove white space at bottom of issue boards
  ...
parents 817c7fb1 4841c3cb
...@@ -112,7 +112,7 @@ linters: ...@@ -112,7 +112,7 @@ linters:
# Reports when you define the same selector twice in a single sheet. # Reports when you define the same selector twice in a single sheet.
MergeableSelector: MergeableSelector:
enabled: false enabled: true
# Functions, mixins, variables, and placeholders should be declared # Functions, mixins, variables, and placeholders should be declared
# with all lowercase letters and hyphens instead of underscores. # with all lowercase letters and hyphens instead of underscores.
......
...@@ -2,6 +2,30 @@ ...@@ -2,6 +2,30 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 10.1.1 (2017-10-31)
- [FIXED] Auto Devops kubernetes default namespace is now correctly built out of gitlab project group-name. !14642 (Mircea Danila Dumitrescu)
- [FIXED] Forbid the usage of `Redis#keys`. !14889
- [FIXED] Make the circuitbreaker more robust by adding higher thresholds, and multiple access attempts. !14933
- [FIXED] Only cache last push event for existing projects when pushing to a fork. !14989
- [FIXED] Fix bug preventing secondary emails from being confirmed. !15010
- [FIXED] Fix broken wiki pages that link to a wiki file. !15019
- [FIXED] Don't rename paths that were freed up when upgrading. !15029
- [FIXED] Fix bitbucket login. !15051
- [FIXED] Update gitaly in Gitlab 10.1 to 0.43.1 for temp file cleanup. !15055
- [FIXED] Use the correct visibility attribute for projects in system hooks. !15065
- [FIXED] Normalize LDAP DN when looking up identity.
- [FIXED] Adds callback functions for initial request in clusters page.
- [FIXED] Fix missing Import/Export issue assignees.
- [FIXED] Allow boards as top level route.
- [FIXED] Fix widget of locked merge requests not being presented.
- [FIXED] Fix editing issue description in mobile view.
- [FIXED] Fix deletion of container registry or images returning an error.
- [FIXED] Fix the writing of invalid environment refs.
- [CHANGED] Store circuitbreaker settings in the database instead of config. !14842
- [CHANGED] Update default disabled merge request widget message to reflect a general failure. !14960
- [PERFORMANCE] Stop merge requests with thousands of commits from timing out. !15063
## 10.1.0 (2017-10-22) ## 10.1.0 (2017-10-22)
- [SECURITY] Use a timeout on certain git operations. !14872 - [SECURITY] Use a timeout on certain git operations. !14872
......
/* globals Flash */ /* globals Flash */
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import axios from 'axios'; import axios from 'axios';
import setAxiosCsrfToken from './lib/utils/axios_utils';
import Poll from './lib/utils/poll'; import Poll from './lib/utils/poll';
import { s__ } from './locale'; import { s__ } from './locale';
import initSettingsPanels from './settings_panels'; import initSettingsPanels from './settings_panels';
...@@ -17,6 +18,7 @@ import Flash from './flash'; ...@@ -17,6 +18,7 @@ import Flash from './flash';
class ClusterService { class ClusterService {
constructor(options = {}) { constructor(options = {}) {
this.options = options; this.options = options;
setAxiosCsrfToken();
} }
fetchData() { fetchData() {
return axios.get(this.options.endpoint); return axios.get(this.options.endpoint);
......
import axios from 'axios';
import csrf from './csrf';
export default function setAxiosCsrfToken() {
axios.defaults.headers.common[csrf.headerKey] = csrf.token;
}
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
&.top-block { &.top-block {
border-top: none; border-top: none;
.container-fluid {
background-color: inherit;
}
} }
&.middle-block { &.middle-block {
...@@ -98,10 +102,6 @@ ...@@ -98,10 +102,6 @@
background-color: $white-light; background-color: $white-light;
border-top: none; border-top: none;
} }
&.top-block .container-fluid {
background-color: inherit;
}
} }
.sub-header-block { .sub-header-block {
......
...@@ -12,15 +12,15 @@ ...@@ -12,15 +12,15 @@
border-left: 3px solid $border-color; border-left: 3px solid $border-color;
color: $text-color; color: $text-color;
background: $gray-light; background: $gray-light;
}
.bs-callout h4 { h4 {
margin-top: 0; margin-top: 0;
margin-bottom: 5px; margin-bottom: 5px;
} }
.bs-callout p:last-child { p:last-child {
margin-bottom: 0; margin-bottom: 0;
}
} }
/* Variations */ /* Variations */
......
...@@ -53,6 +53,14 @@ hr { ...@@ -53,6 +53,14 @@ hr {
.str-truncated { .str-truncated {
@include str-truncated; @include str-truncated;
&-60 {
@include str-truncated(60%);
}
&-100 {
@include str-truncated(100%);
}
} }
.block-truncated { .block-truncated {
...@@ -78,10 +86,17 @@ hr { ...@@ -78,10 +86,17 @@ hr {
font-size: 14px; font-size: 14px;
} }
table a code { table {
position: relative; a code {
top: -2px; position: relative;
margin-right: 3px; top: -2px;
margin-right: 3px;
}
td.permission-x {
background: $table-permission-x-bg !important;
text-align: center;
}
} }
.loading { .loading {
...@@ -266,13 +281,6 @@ img.emoji { ...@@ -266,13 +281,6 @@ img.emoji {
margin-bottom: 10px; margin-bottom: 10px;
} }
table {
td.permission-x {
background: $table-permission-x-bg !important;
text-align: center;
}
}
.btn-sign-in { .btn-sign-in {
text-shadow: none; text-shadow: none;
...@@ -338,10 +346,11 @@ table { ...@@ -338,10 +346,11 @@ table {
.dropzone .dz-preview .dz-progress { .dropzone .dz-preview .dz-progress {
border-color: $border-color !important; border-color: $border-color !important;
}
.dropzone .dz-preview .dz-progress .dz-upload { .dz-upload {
background: $gl-success !important; background: $gl-success !important;
}
} }
.dz-message { .dz-message {
...@@ -402,16 +411,6 @@ table { ...@@ -402,16 +411,6 @@ table {
border-radius: $border-radius-default; border-radius: $border-radius-default;
} }
.str-truncated {
&-60 {
@include str-truncated(60%);
}
&-100 {
@include str-truncated(100%);
}
}
.tooltip { .tooltip {
.tooltip-inner { .tooltip-inner {
word-wrap: break-word; word-wrap: break-word;
......
...@@ -141,15 +141,15 @@ ...@@ -141,15 +141,15 @@
svg { svg {
fill: $gl-text-color-secondary; fill: $gl-text-color-secondary;
} }
}
.nav-item-name { .nav-item-name {
flex: 1; flex: 1;
} }
li.active { &.active {
> a { > a {
font-weight: $gl-font-weight-bold; font-weight: $gl-font-weight-bold;
}
} }
} }
......
...@@ -727,11 +727,11 @@ ...@@ -727,11 +727,11 @@
.pika-single.animate-picker.is-bound { .pika-single.animate-picker.is-bound {
@include set-visible; @include set-visible;
}
.pika-single.animate-picker.is-bound.is-hidden { &.is-hidden {
@include set-invisible; @include set-invisible;
overflow: hidden; overflow: hidden;
}
} }
@mixin dropdown-item-hover { @mixin dropdown-item-hover {
...@@ -938,9 +938,7 @@ header.header-content .dropdown-menu.projects-dropdown-menu { ...@@ -938,9 +938,7 @@ header.header-content .dropdown-menu.projects-dropdown-menu {
border-right: 0; border-right: 0;
} }
} }
}
.projects-dropdown-container {
.projects-list-frequent-container, .projects-list-frequent-container,
.projects-list-search-container, { .projects-list-search-container, {
padding: 8px 0; padding: 8px 0;
...@@ -951,11 +949,6 @@ header.header-content .dropdown-menu.projects-dropdown-menu { ...@@ -951,11 +949,6 @@ header.header-content .dropdown-menu.projects-dropdown-menu {
.projects-list-frequent-container li.section-empty, .projects-list-frequent-container li.section-empty,
.projects-list-search-container li.section-empty { .projects-list-search-container li.section-empty {
padding: 0 15px; padding: 0 15px;
}
.section-header,
.projects-list-frequent-container li.section-empty,
.projects-list-search-container li.section-empty {
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
font-size: $gl-font-size; font-size: $gl-font-size;
} }
......
...@@ -165,22 +165,36 @@ ...@@ -165,22 +165,36 @@
&:last-child { &:last-child {
border-right: none; border-right: none;
} }
}
td.blame-commit { &.blame-commit {
padding: 5px 10px; padding: 5px 10px;
min-width: 400px; min-width: 400px;
max-width: 400px; max-width: 400px;
background: $gray-light; background: $gray-light;
border-left: 3px solid; border-left: 3px solid;
.commit-row-title {
display: flex;
}
.item-title {
flex: 1;
margin-right: 0.5em;
}
}
&.line-numbers {
float: none;
border-left: 1px solid $blame-line-numbers-border;
.commit-row-title { i {
display: flex; float: none;
margin-right: 0;
}
} }
.item-title { &.lines {
flex: 1; padding: 0;
margin-right: 0.5em;
} }
} }
...@@ -195,20 +209,6 @@ ...@@ -195,20 +209,6 @@
border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%); border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%);
} }
} }
td.line-numbers {
float: none;
border-left: 1px solid $blame-line-numbers-border;
i {
float: none;
margin-right: 0;
}
}
td.lines {
padding: 0;
}
} }
&.logs { &.logs {
......
...@@ -463,10 +463,10 @@ ...@@ -463,10 +463,10 @@
word-break: break-all; word-break: break-all;
} }
} }
}
.filter-dropdown-item.droplab-item-active .btn { &.droplab-item-active .btn {
@extend %filter-dropdown-item-btn-hover; @extend %filter-dropdown-item-btn-hover;
}
} }
.filter-dropdown-loading { .filter-dropdown-loading {
......
...@@ -352,7 +352,77 @@ ...@@ -352,7 +352,77 @@
.header-user .dropdown-menu-nav, .header-user .dropdown-menu-nav,
.header-new .dropdown-menu-nav { .header-new .dropdown-menu-nav {
margin-top: $dropdown-vertical-offset; margin-top: 4px;
}
.search {
margin: 4px 8px 0;
form {
height: 32px;
border: 0;
border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, background-color ease-in-out 0.15s;
&:hover {
box-shadow: none;
}
}
.search-input {
color: $white-light;
background: none;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
transition: color ease-in-out 0.15s;
}
.location-badge {
font-size: 12px;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: 2px 0 0 2px;
height: 32px;
transition: border-color ease-in-out 0.15s;
}
&.search-active {
form {
background-color: rgba($indigo-200, .3);
box-shadow: none;
.search-input {
color: $gl-text-color;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
color: $gl-text-color-tertiary;
}
.search-input-wrap {
.search-icon,
.clear-icon {
color: $gl-text-color-tertiary;
transition: color ease-in-out 0.15s;
}
}
}
.location-badge {
background-color: $nav-badge-bg;
border-color: $border-color;
}
.search-input-wrap {
.clear-icon {
color: $white-light;
}
}
}
} }
.breadcrumbs { .breadcrumbs {
......
...@@ -30,10 +30,10 @@ body { ...@@ -30,10 +30,10 @@ body {
.container { .container {
padding-top: 0; padding-top: 0;
z-index: 5; z-index: 5;
}
.container .content { .content {
margin: 0; margin: 0;
}
} }
.navless-container { .navless-container {
...@@ -82,26 +82,26 @@ body { ...@@ -82,26 +82,26 @@ body {
transition: background-color 0.15s, border-color 0.15s; transition: background-color 0.15s, border-color 0.15s;
background-color: $orange-500; background-color: $orange-500;
border-color: $orange-500; border-color: $orange-500;
}
.alert-warning + .alert-warning { &:only-of-type {
background-color: $orange-600; background-color: $orange-500;
border-color: $orange-600; border-color: $orange-500;
} }
.alert-warning + .alert-warning + .alert-warning { + .alert-warning {
background-color: $orange-700; background-color: $orange-600;
border-color: $orange-700; border-color: $orange-600;
}
.alert-warning + .alert-warning + .alert-warning + .alert-warning { + .alert-warning {
background-color: $orange-800; background-color: $orange-700;
border-color: $orange-800; border-color: $orange-700;
}
.alert-warning:only-of-type { + .alert-warning {
background-color: $orange-500; background-color: $orange-800;
border-color: $orange-500; border-color: $orange-800;
}
}
}
} }
} }
......
...@@ -299,40 +299,40 @@ ul.indent-list { ...@@ -299,40 +299,40 @@ ul.indent-list {
} }
} }
.group-list-tree .avatar-container.content-loading { .group-list-tree {
position: relative; .avatar-container.content-loading {
position: relative;
> a, > a,
> a .avatar { > a .avatar {
height: 100%; height: 100%;
border-radius: 50%; border-radius: 50%;
} }
> a { > a {
padding: 2px; padding: 2px;
}
> a .avatar { .avatar {
border: 2px solid $white-normal; border: 2px solid $white-normal;
&.identicon { &.identicon {
line-height: 30px; line-height: 30px;
}
}
} }
}
&::after { &::after {
content: ""; content: "";
position: absolute; position: absolute;
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: transparent; background-color: transparent;
border: 2px outset $kdb-border; border: 2px outset $kdb-border;
border-radius: 50%; border-radius: 50%;
animation: spin-avatar 3s infinite linear; animation: spin-avatar 3s infinite linear;
}
} }
}
.group-list-tree {
.folder-toggle-wrap { .folder-toggle-wrap {
float: left; float: left;
line-height: $list-text-height; line-height: $list-text-height;
......
...@@ -173,21 +173,8 @@ ...@@ -173,21 +173,8 @@
ul > li { ul > li {
white-space: nowrap; white-space: nowrap;
} }
}
@media(max-width: $screen-xs-max) {
.atwho-view-ul {
width: 350px;
}
.atwho-view ul li {
overflow: hidden;
text-overflow: ellipsis;
}
}
// TODO: fallback to global style // TODO: fallback to global style
.atwho-view {
.atwho-view-ul { .atwho-view-ul {
padding: 8px 1px; padding: 8px 1px;
...@@ -220,3 +207,14 @@ ...@@ -220,3 +207,14 @@
} }
} }
} }
@media(max-width: $screen-xs-max) {
.atwho-view-ul {
width: 350px;
}
.atwho-view ul li {
overflow: hidden;
text-overflow: ellipsis;
}
}
...@@ -25,7 +25,10 @@ ...@@ -25,7 +25,10 @@
margin: 0; margin: 0;
padding: $gl-padding 0; padding: $gl-padding 0;
border: none; border: none;
border-bottom: 1px solid $white-normal;
&:not(:last-child) {
border-bottom: 1px solid $white-normal;
}
} }
} }
......
...@@ -340,11 +340,64 @@ ...@@ -340,11 +340,64 @@
} }
} }
.project-item-select-holder.btn-group { .page-with-layout-nav {
display: flex; .right-sidebar {
max-width: 350px; top: ($header-height + 1) * 2;
overflow: hidden; }
float: right;
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3;
&.affix {
top: $header-height;
}
}
}
}
.with-performance-bar .page-with-layout-nav {
.right-sidebar {
top: ($header-height + 1) * 2 + $performance-bar-height;
}
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3 + $performance-bar-height;
&.affix {
top: $header-height + $performance-bar-height;
}
}
}
}
@media (max-width: $screen-xs-max) {
.top-area {
flex-flow: row wrap;
.nav-controls {
$controls-margin: $btn-xs-side-margin - 2px;
flex: 0 0 100%;
&.controls-flex {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
padding: 0 0 $gl-padding-top;
}
.controls-item,
.controls-item-full,
.controls-item:last-child {
flex: 1 1 35%;
display: block;
width: 100%;
margin: $controls-margin;
}
}
}
.new-project-item-link { .new-project-item-link {
white-space: nowrap; white-space: nowrap;
......
...@@ -60,22 +60,12 @@ ...@@ -60,22 +60,12 @@
border-radius: $border-radius-base; border-radius: $border-radius-base;
border: 1px solid $dropdown-border-color; border: 1px solid $dropdown-border-color;
min-width: 175px; min-width: 175px;
color: $gl-text-color; color: $gl-grayish-blue;
z-index: 999;
} }
.select2-drop-mask { .select2-results .select2-result-label,
z-index: 998; .select2-more-results {
} padding: 10px 15px;
.select2-drop.select2-drop-above.select2-drop-active {
border-top: 1px solid $dropdown-border-color;
margin-top: -6px;
}
.select2-results li.select2-result-with-children > .select2-result-label {
font-weight: $gl-font-weight-bold;
color: $gl-text-color;
} }
.select2-container-active { .select2-container-active {
...@@ -144,58 +134,46 @@ ...@@ -144,58 +134,46 @@
.select2-drop-auto-width & { .select2-drop-auto-width & {
padding: 15px 15px 5px; padding: 15px 15px 5px;
} }
}
.select2-search input { input {
padding: 2px 25px 2px 5px; padding: 2px 25px 2px 5px;
background: $white-light image-url('select2.png'); background: $white-light image-url('select2.png');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 0 bottom 6px; background-position: right 0 bottom 6px;
border: 1px solid $input-border; border: 1px solid $input-border;
border-radius: $border-radius-default; border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus { &:focus {
border-color: $input-border-focus; border-color: $input-border-focus;
}
&.select2-active {
background-color: $white-light;
background-image: image-url('select2-spinner.gif') !important;
background-repeat: no-repeat;
background-position: right 5px center !important;
background-size: 16px 16px !important;
}
} }
} }
.select2-search input.select2-active { .select2-results .select2-no-results,
background-color: $white-light; .select2-results .select2-searching,
background-image: image-url('select2-spinner.gif') !important; .select2-results .select2-ajax-error,
background-repeat: no-repeat; .select2-results .select2-selection-limit {
background-position: right 5px center !important; background: $gray-light;
background-size: 16px 16px !important; display: list-item;
padding: 10px 15px;
} }
.select2-results { .select2-results {
margin: 0; margin: 0;
padding: #{$gl-padding / 2} 0; padding: 10px 0;
.select2-no-results,
.select2-searching,
.select2-ajax-error,
.select2-selection-limit {
background: transparent;
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-result-label,
.select2-more-results {
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-highlighted { li.select2-result-with-children > .select2-result-label {
background: transparent; font-weight: $gl-font-weight-bold;
color: $gl-text-color; color: $gl-text-color;
.select2-result-label {
background: $dropdown-item-hover-bg;
}
}
.select2-result {
padding: 0 1px;
} }
} }
...@@ -212,6 +190,8 @@ ...@@ -212,6 +190,8 @@
} }
.select2-highlighted { .select2-highlighted {
background: $gl-link-color !important;
.group-result { .group-result {
.group-path { .group-path {
color: $white-light; color: $white-light;
......
...@@ -217,13 +217,31 @@ $white-gc-bg: #eaf2f5; ...@@ -217,13 +217,31 @@ $white-gc-bg: #eaf2f5;
.cp { color: $white-cp; font-weight: $gl-font-weight-bold; } .cp { color: $white-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $white-c1; font-style: italic; } .c1 { color: $white-c1; font-style: italic; }
.cs { color: $white-cs; font-weight: $gl-font-weight-bold; font-style: italic; } .cs { color: $white-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $white-gd; background-color: $white-gd-bg; }
.gd .x { color: $white-gd-x; background-color: $white-gd-x-bg; } .gd {
color: $white-gd;
background-color: $white-gd-bg;
.x {
color: $white-gd-x;
background-color: $white-gd-x-bg;
}
}
.ge { font-style: italic; } .ge { font-style: italic; }
.gr { color: $white-gr; } .gr { color: $white-gr; }
.gh { color: $white-gh; } .gh { color: $white-gh; }
.gi { color: $white-gi; background-color: $white-gi-bg; }
.gi .x { color: $white-gi-x; background-color: $white-gi-x-bg; } .gi {
color: $white-gi;
background-color: $white-gi-bg;
.x {
color: $white-gi-x;
background-color: $white-gi-x-bg;
}
}
.go { color: $white-go; } .go { color: $white-go; }
.gp { color: $white-gp; } .gp { color: $white-gp; }
.gs { font-weight: $gl-font-weight-bold; } .gs { font-weight: $gl-font-weight-bold; }
......
...@@ -158,13 +158,31 @@ span.highlight_word { ...@@ -158,13 +158,31 @@ span.highlight_word {
.cp { color: $highlighted-cp; font-weight: $gl-font-weight-bold; } .cp { color: $highlighted-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $highlighted-c1; font-style: italic; } .c1 { color: $highlighted-c1; font-style: italic; }
.cs { color: $highlighted-cs; font-weight: $gl-font-weight-bold; font-style: italic; } .cs { color: $highlighted-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $highlighted-gd; background-color: $highlighted-gd-bg; }
.gd .x { color: $highlighted-gd; background-color: $highlighted-gd-x-bg; } .gd {
color: $highlighted-gd;
background-color: $highlighted-gd-bg;
.x {
color: $highlighted-gd;
background-color: $highlighted-gd-x-bg;
}
}
.ge { font-style: italic; } .ge { font-style: italic; }
.gr { color: $highlighted-gr; } .gr { color: $highlighted-gr; }
.gh { color: $highlighted-gh; } .gh { color: $highlighted-gh; }
.gi { color: $highlighted-gi; background-color: $highlighted-gi-bg; }
.gi .x { color: $highlighted-gi; background-color: $highlighted-gi-x-bg; } .gi {
color: $highlighted-gi;
background-color: $highlighted-gi-bg;
.x {
color: $highlighted-gi;
background-color: $highlighted-gi-x-bg;
}
}
.go { color: $highlighted-go; } .go { color: $highlighted-go; }
.gp { color: $highlighted-gp; } .gp { color: $highlighted-gp; }
.gs { font-weight: $gl-font-weight-bold; } .gs { font-weight: $gl-font-weight-bold; }
......
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
} }
.boards-list { .boards-list {
height: calc(100vh - 152px); height: calc(100vh - 105px);
width: 100%; width: 100%;
padding-top: 25px; padding-top: 25px;
padding-bottom: 25px; padding-bottom: 25px;
...@@ -81,8 +81,12 @@ ...@@ -81,8 +81,12 @@
overflow-x: scroll; overflow-x: scroll;
white-space: nowrap; white-space: nowrap;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
height: calc(100vh - 222px); height: calc(100vh - 90px);
}
@media (min-width: $screen-md-min) {
height: calc(100vh - 160px);
min-height: 475px; min-height: 475px;
} }
} }
......
...@@ -68,18 +68,18 @@ ...@@ -68,18 +68,18 @@
&.affix { &.affix {
top: $header-height; top: $header-height;
}
// with sidebar // with sidebar
&.affix.sidebar-expanded { &.sidebar-expanded {
right: 306px; right: 306px;
left: 16px; left: 16px;
} }
// without sidebar // without sidebar
&.affix.sidebar-collapsed { &.sidebar-collapsed {
right: 16px; right: 16px;
left: 16px; left: 16px;
}
} }
&.affix-top { &.affix-top {
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
} }
} }
} }
svg {
width: 136px;
height: 136px;
}
} }
.col-headers { .col-headers {
...@@ -155,11 +160,6 @@ ...@@ -155,11 +160,6 @@
} }
} }
.landing svg {
width: 136px;
height: 136px;
}
.fa-spinner { .fa-spinner {
font-size: 28px; font-size: 28px;
position: relative; position: relative;
......
...@@ -380,6 +380,10 @@ ...@@ -380,6 +380,10 @@
} }
} }
} }
.line_content {
white-space: pre-wrap;
}
} }
.file-content .diff-file { .file-content .diff-file {
...@@ -387,10 +391,6 @@ ...@@ -387,10 +391,6 @@
border: none; border: none;
} }
.diff-file .line_content {
white-space: pre-wrap;
}
.diff-wrap-lines .line_content { .diff-wrap-lines .line_content {
white-space: pre-wrap; white-space: pre-wrap;
} }
......
...@@ -255,23 +255,6 @@ ...@@ -255,23 +255,6 @@
width: 100%; width: 100%;
padding: 0; padding: 0;
padding-bottom: 100%; padding-bottom: 100%;
}
.prometheus-svg-container > svg {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
text {
fill: $gl-text-color;
stroke-width: 0;
}
.text-metric-bold {
font-weight: $gl-font-weight-bold;
}
.label-axis-text { .label-axis-text {
fill: $black; fill: $black;
...@@ -286,42 +269,51 @@ ...@@ -286,42 +269,51 @@
font-size: 12px; font-size: 12px;
} }
.legend-axis-text { > svg {
fill: $black; position: absolute;
} height: 100%;
width: 100%;
left: 0;
top: 0;
.tick { .label-axis-text,
> line { .text-metric-usage {
stroke: $gray-darker; fill: $black;
font-weight: $gl-font-weight-normal;
font-size: 12px;
} }
> text { .legend-axis-text {
font-size: 12px; fill: $black;
} }
}
.text-metric-title { .tick > text {
font-size: 12px; font-size: 12px;
} }
.y-label-text, .text-metric-title {
.x-label-text { font-size: 12px;
fill: $gray-darkest; }
}
.axis-tick { .y-label-text,
stroke: $gray-darker; .x-label-text {
} fill: $gray-darkest;
}
@media (max-width: $screen-sm-max) { .axis-tick {
.label-axis-text, stroke: $gray-darker;
.text-metric-usage,
.legend-axis-text {
font-size: 8px;
} }
.tick > text { @media (max-width: $screen-sm-max) {
font-size: 8px; .label-axis-text,
.text-metric-usage,
.legend-axis-text {
font-size: 8px;
}
.tick > text {
font-size: 8px;
}
} }
} }
} }
...@@ -127,7 +127,16 @@ ...@@ -127,7 +127,16 @@
} }
.right-sidebar { .right-sidebar {
a:not(.btn-retry), position: absolute;
top: $header-height;
bottom: 0;
right: 0;
transition: width .3s;
background: $gray-light;
z-index: 200;
overflow: hidden;
a,
.btn-link { .btn-link {
color: inherit; color: inherit;
} }
...@@ -228,17 +237,6 @@ ...@@ -228,17 +237,6 @@
.btn-clipboard:hover { .btn-clipboard:hover {
color: $gl-text-color; color: $gl-text-color;
} }
}
.right-sidebar {
position: absolute;
top: $header-height;
bottom: 0;
right: 0;
transition: width $right-sidebar-transition-duration;
background: $gray-light;
z-index: 200;
overflow: hidden;
.issuable-sidebar { .issuable-sidebar {
width: calc(100% + 100px); width: calc(100% + 100px);
......
...@@ -109,6 +109,30 @@ ...@@ -109,6 +109,30 @@
border-top-right-radius: $border-radius-default; border-top-right-radius: $border-radius-default;
border-top-left-radius: $border-radius-default; border-top-left-radius: $border-radius-default;
// Ldap configurations may need more tabs & the tab labels are user generated (arbitrarily long).
// These styles prevent this from breaking the layout, and only applied when providers are configured.
&.custom-provider-tabs {
flex-wrap: wrap;
li {
min-width: 85px;
flex-basis: auto;
// This styles tab elements that have wrapped to a second line. We cannot easily predict when this will happen.
// We are making somewhat of an assumption about the configuration here: that users do not have more than
// 3 LDAP servers configured (in addition to standard login) and they are not using especially long names for any
// of them. If either condition is false, this will work as expected. If both are true, there may be a missing border
// above one of the bottom row elements. If you know a better way, please implement it!
&:nth-child(n+5) {
border-top: 1px solid $border-color;
}
}
a {
font-size: 16px;
}
}
li { li {
flex: 1; flex: 1;
text-align: center; text-align: center;
...@@ -154,32 +178,6 @@ ...@@ -154,32 +178,6 @@
} }
} }
// Ldap configurations may need more tabs & the tab labels are user generated (arbitrarily long).
// These styles prevent this from breaking the layout, and only applied when providers are configured.
.new-session-tabs.custom-provider-tabs {
flex-wrap: wrap;
li {
min-width: 85px;
flex-basis: auto;
// This styles tab elements that have wrapped to a second line. We cannot easily predict when this will happen.
// We are making somewhat of an assumption about the configuration here: that users do not have more than
// 3 LDAP servers configured (in addition to standard login) and they are not using especially long names for any
// of them. If either condition is false, this will work as expected. If both are true, there may be a missing border
// above one of the bottom row elements. If you know a better way, please implement it!
&:nth-child(n+5) {
border-top: 1px solid $border-color;
}
}
a {
font-size: 16px;
}
}
.form-control { .form-control {
&:active, &:active,
&:focus { &:focus {
...@@ -231,35 +229,35 @@ ...@@ -231,35 +229,35 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100%; height: 100%;
}
// Fixes footer container to bottom of viewport // Fixes footer container to bottom of viewport
.devise-layout-html body { body {
// offset height of fixed header + 1 to avoid scroll // offset height of fixed header + 1 to avoid scroll
height: calc(100% - 51px); height: calc(100% - 51px);
margin: 0; margin: 0;
padding: 0; padding: 0;
.page-wrap { .page-wrap {
min-height: 100%; min-height: 100%;
position: relative; position: relative;
} }
.footer-container, .footer-container,
hr.footer-fixed { hr.footer-fixed {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
height: 40px; height: 40px;
background: $white-light; background: $white-light;
} }
.navless-container { .navless-container {
padding: 65px 15px; // height of footer + bottom padding of email confirmation link padding: 65px 15px; // height of footer + bottom padding of email confirmation link
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
padding: 0 15px 65px; padding: 0 15px 65px;
}
} }
} }
} }
...@@ -49,9 +49,17 @@ ...@@ -49,9 +49,17 @@
width: auto; width: auto;
} }
} }
&.existing-title {
@media (min-width: $screen-sm-min) {
float: left;
}
}
} }
.member-form-control { .member-form-control {
@include new-style-dropdown;
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
padding-bottom: 5px; padding-bottom: 5px;
margin-left: 0; margin-left: 0;
...@@ -64,12 +72,6 @@ ...@@ -64,12 +72,6 @@
line-height: 43px; line-height: 43px;
} }
.member.existing-title {
@media (min-width: $screen-sm-min) {
float: left;
}
}
.member-search-form { .member-search-form {
@include new-style-dropdown; @include new-style-dropdown;
...@@ -281,7 +283,3 @@ ...@@ -281,7 +283,3 @@
} }
} }
} }
.member-form-control {
@include new-style-dropdown;
}
...@@ -156,6 +156,10 @@ ...@@ -156,6 +156,10 @@
&.media > *:first-child { &.media > *:first-child {
margin-right: 10px; margin-right: 10px;
} }
.approve-btn {
margin-right: 5px;
}
} }
.mr-widget-pipeline-graph { .mr-widget-pipeline-graph {
...@@ -191,6 +195,10 @@ ...@@ -191,6 +195,10 @@
overflow: hidden; overflow: hidden;
word-break: break-all; word-break: break-all;
&.media > *:first-child {
margin-right: 10px;
}
&.label-truncated { &.label-truncated {
position: relative; position: relative;
display: inline-block; display: inline-block;
...@@ -208,14 +216,7 @@ ...@@ -208,14 +216,7 @@
background-color: $gray-light; background-color: $gray-light;
} }
} }
}
.mr-widget-help {
padding: 10px 16px 10px 48px;
font-style: italic;
}
.mr-widget-body {
h4 { h4 {
float: left; float: left;
font-weight: $gl-font-weight-bold; font-weight: $gl-font-weight-bold;
...@@ -238,6 +239,10 @@ ...@@ -238,6 +239,10 @@
margin-right: 7px; margin-right: 7px;
} }
.approve-btn {
margin-right: 5px;
}
label { label {
font-weight: $gl-font-weight-normal; font-weight: $gl-font-weight-normal;
} }
...@@ -337,6 +342,22 @@ ...@@ -337,6 +342,22 @@
} }
} }
.mini-pipeline-graph-dropdown-menu .mini-pipeline-graph-dropdown-item {
display: flex;
align-items: center;
.ci-status-text,
.ci-status-icon {
top: 0;
margin-right: 10px;
}
}
.mr-widget-help {
padding: 10px 16px 10px 48px;
font-style: italic;
}
.ci-coverage { .ci-coverage {
float: right; float: right;
} }
...@@ -351,12 +372,6 @@ ...@@ -351,12 +372,6 @@
} }
} }
.mr-state-widget .mr-widget-body {
.approve-btn {
margin-right: 5px;
}
}
.mr-widget-body-controls { .mr-widget-body-controls {
flex-wrap: wrap; flex-wrap: wrap;
} }
...@@ -470,16 +485,16 @@ ...@@ -470,16 +485,16 @@
padding-bottom: 0; padding-bottom: 0;
} }
} }
}
.mr-info-list.mr-memory-usage { &.mr-memory-usage {
p { p {
float: left; float: left;
} }
.memory-graph-container { .memory-graph-container {
float: left; float: left;
margin-left: 5px; margin-left: 5px;
}
} }
} }
......
...@@ -66,6 +66,15 @@ ...@@ -66,6 +66,15 @@
height: 6px; height: 6px;
margin: 0; margin: 0;
} }
.sidebar-collapsed-icon {
clear: both;
padding: 15px 5px 5px;
.progress {
margin: 5px 0;
}
}
} }
.collapsed-milestone-date { .collapsed-milestone-date {
...@@ -93,17 +102,6 @@ ...@@ -93,17 +102,6 @@
margin-right: 0; margin-right: 0;
} }
.milestone-progress {
.sidebar-collapsed-icon {
clear: both;
padding: 15px 5px 5px;
.progress {
margin: 5px 0;
}
}
}
.right-sidebar-collapsed & { .right-sidebar-collapsed & {
.reference { .reference {
border-top: 1px solid $border-gray-normal; border-top: 1px solid $border-gray-normal;
...@@ -156,18 +154,16 @@ ...@@ -156,18 +154,16 @@
.status-box { .status-box {
margin-top: 0; margin-top: 0;
}
.milestone-buttons {
margin-left: auto;
}
.status-box {
order: 1; order: 1;
} }
.milestone-buttons { .milestone-buttons {
margin-left: auto;
order: 2; order: 2;
.verbose {
display: none;
}
} }
.header-text-content { .header-text-content {
...@@ -175,10 +171,6 @@ ...@@ -175,10 +171,6 @@
width: 100%; width: 100%;
} }
.milestone-buttons .verbose {
display: none;
}
@media (min-width: $screen-xs-min) { @media (min-width: $screen-xs-min) {
.milestone-buttons .verbose { .milestone-buttons .verbose {
display: inline; display: inline;
......
...@@ -111,24 +111,9 @@ ...@@ -111,24 +111,9 @@
margin: auto; margin: auto;
align-items: center; align-items: center;
.icon { + .md-area {
margin-right: $issuable-warning-icon-margin; border-top-left-radius: 0;
} border-top-right-radius: 0;
}
.disabled-comment .issuable-note-warning {
border: none;
border-radius: $label-border-radius;
padding-top: $gl-vert-padding;
padding-bottom: $gl-vert-padding;
.icon svg {
position: relative;
top: 2px;
margin-right: $btn-xs-side-margin;
width: $gl-font-size;
height: $gl-font-size;
fill: $orange-600;
} }
} }
...@@ -155,11 +140,6 @@ ...@@ -155,11 +140,6 @@
} }
} }
.issuable-note-warning + .md-area {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.discussion-form { .discussion-form {
background-color: $white-light; background-color: $white-light;
} }
......
...@@ -312,57 +312,72 @@ ul.notes { ...@@ -312,57 +312,72 @@ ul.notes {
} }
} }
.diff-file .notes_holder { .diff-file {
font-family: $regular_font; .is-over {
.add-diff-note {
display: inline-block;
}
}
td { // Merge request notes in diffs
border: 1px solid $white-normal; // Diff is inline
border-left: none; .notes_content .note-header .note-headline-light {
display: inline-block;
position: relative;
}
&.notes_line { .notes_holder {
vertical-align: middle; font-family: $regular_font;
text-align: center;
padding: 10px 0;
background: $gray-light;
color: $text-color;
}
&.notes_line2 { td {
text-align: center; border: 1px solid $white-normal;
padding: 10px 0; border-left: none;
border-left: 1px solid $note-line2-border !important;
}
&.notes_content { &.notes_line {
background-color: $gray-light; vertical-align: middle;
border-width: 1px 0; text-align: center;
padding: 0; padding: 10px 0;
vertical-align: top; background: $gray-light;
white-space: normal; color: $text-color;
}
&.parallel { &.notes_line2 {
border-width: 1px; text-align: center;
padding: 10px 0;
border-left: 1px solid $note-line2-border !important;
} }
.discussion-notes { &.notes_content {
&:not(:first-child) { background-color: $gray-light;
border-top: 1px solid $white-normal; border-width: 1px 0;
margin-top: 20px; padding: 0;
vertical-align: top;
white-space: normal;
&.parallel {
border-width: 1px;
} }
&:not(:last-child) { .discussion-notes {
border-bottom: 1px solid $white-normal; &:not(:first-child) {
margin-bottom: 20px; border-top: 1px solid $white-normal;
margin-top: 20px;
}
&:not(:last-child) {
border-bottom: 1px solid $white-normal;
margin-bottom: 20px;
}
} }
}
.notes { .notes {
background-color: $white-light; background-color: $white-light;
} }
a code { a code {
top: 0; top: 0;
margin-right: 0; margin-right: 0;
}
} }
} }
} }
...@@ -457,8 +472,9 @@ ul.notes { ...@@ -457,8 +472,9 @@ ul.notes {
margin-left: 10px; margin-left: 10px;
color: $gray-darkest; color: $gray-darkest;
.btn-group > .discussion-next-btn { @include notes-media('max', $screen-md-max) {
margin-left: -1px; float: none;
margin-left: 0;
} }
} }
...@@ -499,13 +515,6 @@ ul.notes { ...@@ -499,13 +515,6 @@ ul.notes {
min-width: 180px; min-width: 180px;
} }
.discussion-actions {
@include notes-media('max', $screen-md-max) {
float: none;
margin-left: 0;
}
}
.note-actions-item { .note-actions-item {
margin-left: 12px; margin-left: 12px;
display: flex; display: flex;
...@@ -662,14 +671,6 @@ ul.notes { ...@@ -662,14 +671,6 @@ ul.notes {
} }
} }
.diff-file {
.is-over {
.add-diff-note {
display: inline-block;
}
}
}
.disabled-comment { .disabled-comment {
background-color: $gray-light; background-color: $gray-light;
border-radius: $border-radius-base; border-radius: $border-radius-base;
...@@ -711,20 +712,20 @@ ul.notes { ...@@ -711,20 +712,20 @@ ul.notes {
svg path { svg path {
fill: $gray-darkest; fill: $gray-darkest;
} }
}
.btn.discussion-create-issue-btn { &.discussion-create-issue-btn {
margin-left: -4px; margin-left: -4px;
border-radius: 0; border-radius: 0;
border-right: 0; border-right: 0;
a { a {
padding: 0; padding: 0;
line-height: 0; line-height: 0;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
border: 0; border: 0;
}
} }
} }
} }
...@@ -798,12 +799,3 @@ ul.notes { ...@@ -798,12 +799,3 @@ ul.notes {
.line-resolve-text { .line-resolve-text {
vertical-align: middle; vertical-align: middle;
} }
// Merge request notes in diffs
.diff-file {
// Diff is inline
.notes_content .note-header .note-headline-light {
display: inline-block;
position: relative;
}
}
...@@ -175,6 +175,25 @@ ...@@ -175,6 +175,25 @@
} }
} }
/**
* Play button with icon in dropdowns
*/
.no-btn {
border: none;
background: none;
outline: none;
width: 100%;
text-align: left;
.icon-play {
position: relative;
top: 2px;
margin-right: 5px;
height: 13px;
width: 12px;
}
}
.duration, .duration,
.finished-at { .finished-at {
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
...@@ -450,48 +469,48 @@ ...@@ -450,48 +469,48 @@
@extend .build-content:hover; @extend .build-content:hover;
} }
// Action Icons in big pipeline-graph nodes .ci-action-icon-container {
.ci-action-icon-container.ci-action-icon-wrapper { position: absolute;
height: 30px; right: 5px;
width: 30px; top: 5px;
background: $white-light;
border: 1px solid $border-color;
border-radius: 100%;
display: block;
&:hover { // Action Icons in big pipeline-graph nodes
background-color: $stage-hover-bg; &.ci-action-icon-wrapper {
border: 1px solid $dropdown-toggle-active-border-color; height: 30px;
} width: 30px;
background: $white-light;
border: 1px solid $border-color;
border-radius: 100%;
display: block;
svg { &:hover {
fill: $gl-text-color-secondary; background-color: $stage-hover-bg;
position: relative; border: 1px solid $dropdown-toggle-active-border-color;
left: 5px;
top: 2px; svg {
width: 18px; fill: $gl-text-color;
height: 18px; }
} }
&.play {
svg { svg {
width: #{$ci-action-icon-size - 8}; fill: $gl-text-color-secondary;
height: #{$ci-action-icon-size - 8}; position: relative;
left: 8px; left: 5px;
top: 2px;
width: 18px;
height: 18px;
} }
}
&:hover svg { &.play {
fill: $gl-text-color; svg {
width: #{$ci-action-icon-size - 8};
height: #{$ci-action-icon-size - 8};
left: 8px;
}
}
} }
} }
.ci-action-icon-container {
position: absolute;
right: 5px;
top: 5px;
}
.ci-status-icon svg { .ci-status-icon svg {
height: 20px; height: 20px;
width: 20px; width: 20px;
...@@ -735,6 +754,28 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -735,6 +754,28 @@ button.mini-pipeline-graph-dropdown-toggle {
left: -3px; left: -3px;
position: relative; position: relative;
top: -2px; top: -2px;
&.icon-action-stop,
&.icon-action-cancel {
width: 12px;
height: 12px;
top: 1px;
left: -1px;
}
&.icon-action-play {
width: 11px;
height: 11px;
top: 1px;
left: 1px;
}
&.icon-action-retry {
width: 16px;
height: 16px;
top: 0;
left: -3px;
}
} }
&:hover svg, &:hover svg,
...@@ -751,27 +792,6 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -751,27 +792,6 @@ button.mini-pipeline-graph-dropdown-toggle {
} }
} }
svg.icon-action-stop,
svg.icon-action-cancel {
width: 12px;
height: 12px;
top: 1px;
left: -1px;
}
svg.icon-action-play {
width: 11px;
height: 11px;
top: 1px;
left: 1px;
}
svg.icon-action-retry {
width: 16px;
height: 16px;
top: 0;
left: -3px;
}
} }
...@@ -840,13 +860,10 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -840,13 +860,10 @@ button.mini-pipeline-graph-dropdown-toggle {
left: 100%; left: 100%;
top: -10px; top: -10px;
box-shadow: 0 1px 5px $black-transparent; box-shadow: 0 1px 5px $black-transparent;
}
/**
* Top arrow in the dropdown in the big pipeline graph
*/
.big-pipeline-graph-dropdown-menu {
/**
* Top arrow in the dropdown in the big pipeline graph
*/
&::before, &::before,
&::after { &::after {
content: ''; content: '';
...@@ -908,22 +925,23 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -908,22 +925,23 @@ button.mini-pipeline-graph-dropdown-toggle {
margin-top: 1px; margin-top: 1px;
border-bottom-color: $white-light; border-bottom-color: $white-light;
} }
}
/** /**
* Center dropdown menu in mini graph * Center dropdown menu in mini graph
*/ */
.mini-pipeline-graph-dropdown-menu.dropdown-menu { &.dropdown-menu {
transform: translate(-80%, 0); transform: translate(-80%, 0);
min-width: 150px; min-width: 150px;
@media(min-width: $screen-md-min) { @media(min-width: $screen-md-min) {
transform: translate(-50%, 0); transform: translate(-50%, 0);
right: auto; right: auto;
left: 50%; left: 50%;
min-width: 240px; min-width: 240px;
}
} }
} }
/** /**
* Terminal * Terminal
*/ */
...@@ -947,25 +965,6 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -947,25 +965,6 @@ button.mini-pipeline-graph-dropdown-toggle {
} }
} }
/**
* Play button with icon in dropdowns
*/
.ci-table .no-btn {
border: none;
background: none;
outline: none;
width: 100%;
text-align: left;
.icon-play {
position: relative;
top: 2px;
margin-right: 5px;
height: 13px;
width: 12px;
}
}
.ci-header-container { .ci-header-container {
min-height: 55px; min-height: 55px;
......
...@@ -88,7 +88,8 @@ ...@@ -88,7 +88,8 @@
transition: background 2s ease-out; transition: background 2s ease-out;
&:disabled { &:disabled {
opacity: 0.75; opacity: 0.5;
pointer-events: none;
} }
.highlight-changes & { .highlight-changes & {
...@@ -778,35 +779,35 @@ a.deploy-project-label { ...@@ -778,35 +779,35 @@ a.deploy-project-label {
.nav { .nav {
padding-top: 12px; padding-top: 12px;
padding-bottom: 12px; padding-bottom: 12px;
}
.nav > li { > li {
display: inline-block; display: inline-block;
&:not(:last-child) { &:not(:last-child) {
margin-right: $gl-padding; margin-right: $gl-padding;
} }
&.right { &.right {
vertical-align: top; vertical-align: top;
margin-top: 0; margin-top: 0;
@media (min-width: $screen-lg-min) { @media (min-width: $screen-lg-min) {
float: right; float: right;
}
} }
}
}
.nav > li > a { > a {
padding: 0; padding: 0;
background-color: transparent; background-color: transparent;
font-size: 14px; font-size: 14px;
line-height: 29px; line-height: 29px;
color: $notes-light-color; color: $notes-light-color;
&:hover, &:hover,
&:focus { &:focus {
color: $gl-text-color; color: $gl-text-color;
}
}
} }
} }
...@@ -1160,13 +1161,6 @@ pre.light-well { ...@@ -1160,13 +1161,6 @@ pre.light-well {
} }
} }
.project-repo-select {
&.disabled {
opacity: 0.5;
pointer-events: none;
}
}
.variables-table { .variables-table {
table-layout: fixed; table-layout: fixed;
......
...@@ -78,6 +78,10 @@ input[type="checkbox"]:hover { ...@@ -78,6 +78,10 @@ input[type="checkbox"]:hover {
} }
.search-input-wrap { .search-input-wrap {
// Fallback if flexbox is not supported
display: inline-block;
width: 100%;
.search-icon, .search-icon,
.clear-icon { .clear-icon {
position: absolute; position: absolute;
......
...@@ -241,11 +241,11 @@ ...@@ -241,11 +241,11 @@
margin-left: 5px; margin-left: 5px;
background: $badge-bg; background: $badge-bg;
} }
}
/* Ensure we don't add border if there's only single li */ /* Ensure we don't add border if there's only single li */
li + li { + li {
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
}
} }
} }
} }
...@@ -5,10 +5,10 @@ table .sherlock-code { ...@@ -5,10 +5,10 @@ table .sherlock-code {
.sherlock-code { .sherlock-code {
pre { pre {
word-wrap: normal; word-wrap: normal;
}
pre code { code {
white-space: pre; white-space: pre;
}
} }
} }
...@@ -21,13 +21,13 @@ table .sherlock-code { ...@@ -21,13 +21,13 @@ table .sherlock-code {
text-align: right; text-align: right;
padding: 0 10px !important; padding: 0 10px !important;
} }
.slow {
color: $red-500;
font-weight: $gl-font-weight-bold;
}
} }
.sherlock-file-sample pre { .sherlock-file-sample pre {
padding-top: 28px !important; padding-top: 28px !important;
} }
.sherlock-line-samples-table .slow {
color: $red-500;
font-weight: $gl-font-weight-bold;
}
...@@ -40,16 +40,16 @@ ...@@ -40,16 +40,16 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
width: 100%; width: 100%;
} }
}
.person .spark { .spark {
display: block; display: block;
background: $stat-graph-common-bg; background: $stat-graph-common-bg;
width: 100%; width: 100%;
} }
.person .area-contributor { .area-contributor {
fill: $stat-graph-orange-fill; fill: $stat-graph-orange-fill;
}
} }
} }
......
...@@ -161,10 +161,10 @@ ul.wiki-pages-list.content-list { ...@@ -161,10 +161,10 @@ ul.wiki-pages-list.content-list {
list-style: none; list-style: none;
margin-left: 0; margin-left: 0;
padding-left: 15px; padding-left: 15px;
}
ul li { li {
padding: 5px 0; padding: 5px 0;
}
} }
} }
......
...@@ -19,10 +19,12 @@ class Admin::ApplicationsController < Admin::ApplicationController ...@@ -19,10 +19,12 @@ class Admin::ApplicationsController < Admin::ApplicationController
end end
def create def create
@application = Doorkeeper::Application.new(application_params) @application = Applications::CreateService.new(current_user, application_params).execute(request)
if @application.save if @application.persisted?
redirect_to_admin_page flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to admin_application_url(@application)
else else
render :new render :new
end end
...@@ -41,13 +43,6 @@ class Admin::ApplicationsController < Admin::ApplicationController ...@@ -41,13 +43,6 @@ class Admin::ApplicationsController < Admin::ApplicationController
redirect_to admin_applications_url, status: 302, notice: 'Application was successfully destroyed.' redirect_to admin_applications_url, status: 302, notice: 'Application was successfully destroyed.'
end end
protected
def redirect_to_admin_page
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to admin_application_url(@application)
end
private private
def set_application def set_application
......
...@@ -94,10 +94,9 @@ module LfsRequest ...@@ -94,10 +94,9 @@ module LfsRequest
@storage_project ||= begin @storage_project ||= begin
result = project result = project
loop do # TODO: Make this go to the fork_network root immeadiatly
break unless result.forked? # dependant on the discussion in: https://gitlab.com/gitlab-org/gitlab-ce/issues/39769
result = result.forked_from_project result = result.fork_source while result.forked?
end
result result
end end
......
...@@ -16,25 +16,18 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController ...@@ -16,25 +16,18 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
end end
def create def create
@application = Doorkeeper::Application.new(application_params) @application = Applications::CreateService.new(current_user, create_application_params).execute(request)
@application.owner = current_user if @application.persisted?
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
if @application.save redirect_to oauth_application_url(@application)
redirect_to_oauth_application_page
else else
set_index_vars set_index_vars
render :index render :index
end end
end end
protected
def redirect_to_oauth_application_page
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to oauth_application_url(@application)
end
private private
def verify_user_oauth_applications_enabled def verify_user_oauth_applications_enabled
...@@ -61,4 +54,10 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController ...@@ -61,4 +54,10 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
rescue_from ActiveRecord::RecordNotFound do |exception| rescue_from ActiveRecord::RecordNotFound do |exception|
render "errors/not_found", layout: "errors", status: 404 render "errors/not_found", layout: "errors", status: 404
end end
def create_application_params
application_params.tap do |params|
params[:owner] = current_user
end
end
end end
...@@ -11,10 +11,10 @@ class Profiles::KeysController < Profiles::ApplicationController ...@@ -11,10 +11,10 @@ class Profiles::KeysController < Profiles::ApplicationController
end end
def create def create
@key = Keys::CreateService.new(current_user, key_params).execute @key = Keys::CreateService.new(current_user, key_params.merge(ip_address: request.remote_ip)).execute
if @key.persisted? if @key.persisted?
redirect_to_profile_key_path redirect_to profile_key_path(@key)
else else
@keys = current_user.keys.select(&:persisted?) @keys = current_user.keys.select(&:persisted?)
render :index render :index
...@@ -50,12 +50,6 @@ class Profiles::KeysController < Profiles::ApplicationController ...@@ -50,12 +50,6 @@ class Profiles::KeysController < Profiles::ApplicationController
end end
end end
protected
def redirect_to_profile_key_path
redirect_to profile_key_path(@key)
end
private private
def key_params def key_params
......
...@@ -110,7 +110,15 @@ module ProjectsHelper ...@@ -110,7 +110,15 @@ module ProjectsHelper
def remove_fork_project_message(project) def remove_fork_project_message(project)
_("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") % _("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") %
{ forked_from_project: @project.forked_from_project.name_with_namespace } { forked_from_project: fork_source_name(project) }
end
def fork_source_name(project)
if @project.fork_source
@project.fork_source.full_name
else
@project.fork_network&.deleted_root_project_name
end
end end
def project_nav_tabs def project_nav_tabs
...@@ -140,8 +148,8 @@ module ProjectsHelper ...@@ -140,8 +148,8 @@ module ProjectsHelper
def can_change_visibility_level?(project, current_user) def can_change_visibility_level?(project, current_user)
return false unless can?(current_user, :change_visibility_level, project) return false unless can?(current_user, :change_visibility_level, project)
if project.forked? if project.fork_source
project.forked_from_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE project.fork_source.visibility_level > Gitlab::VisibilityLevel::PRIVATE
else else
true true
end end
......
...@@ -110,7 +110,7 @@ class Environment < ActiveRecord::Base ...@@ -110,7 +110,7 @@ class Environment < ActiveRecord::Base
end end
def ref_path def ref_path
"refs/#{Repository::REF_ENVIRONMENTS}/#{generate_slug}" "refs/#{Repository::REF_ENVIRONMENTS}/#{slug}"
end end
def formatted_external_url def formatted_external_url
...@@ -164,6 +164,10 @@ class Environment < ActiveRecord::Base ...@@ -164,6 +164,10 @@ class Environment < ActiveRecord::Base
end end
end end
def slug
super.presence || generate_slug
end
# An environment name is not necessarily suitable for use in URLs, DNS # An environment name is not necessarily suitable for use in URLs, DNS
# or other third-party contexts, so provide a slugified version. A slug has # or other third-party contexts, so provide a slugified version. A slug has
# the following properties: # the following properties:
......
# Placeholder class for model that is implemented in EE # Placeholder class for model that is implemented in EE
# It will reserve (ee#3853) '&' as a reference prefix, but the table does not exists in CE # It will reserve (ee#3853) '&' as a reference prefix, but the table does not exists in CE
class Epic < ActiveRecord::Base class Epic < ActiveRecord::Base
prepend EE::Epic
# TODO: this will be implemented as part of #3853 # TODO: this will be implemented as part of #3853
def to_reference def to_reference
end end
......
...@@ -12,4 +12,8 @@ class ForkNetwork < ActiveRecord::Base ...@@ -12,4 +12,8 @@ class ForkNetwork < ActiveRecord::Base
def find_forks_in(other_projects) def find_forks_in(other_projects)
projects.where(id: other_projects) projects.where(id: other_projects)
end end
def merge_requests
MergeRequest.where(target_project: projects)
end
end end
...@@ -42,6 +42,7 @@ class Group < Namespace ...@@ -42,6 +42,7 @@ class Group < Namespace
after_create :post_create_hook after_create :post_create_hook
after_destroy :post_destroy_hook after_destroy :post_destroy_hook
after_save :update_two_factor_requirement after_save :update_two_factor_requirement
after_update :path_changed_hook, if: :path_changed?
class << self class << self
def supports_nested_groups? def supports_nested_groups?
...@@ -295,6 +296,12 @@ class Group < Namespace ...@@ -295,6 +296,12 @@ class Group < Namespace
list_of_ids.reverse.map { |group| variables[group.id] }.compact.flatten list_of_ids.reverse.map { |group| variables[group.id] }.compact.flatten
end end
def full_path_was
return path_was unless has_parent?
"#{parent.full_path}/#{path_was}"
end
private private
def update_two_factor_requirement def update_two_factor_requirement
...@@ -303,6 +310,10 @@ class Group < Namespace ...@@ -303,6 +310,10 @@ class Group < Namespace
users.find_each(&:update_two_factor_requirement) users.find_each(&:update_two_factor_requirement)
end end
def path_changed_hook
system_hook_service.execute_hooks_for(self, :rename)
end
def visibility_level_allowed_by_parent def visibility_level_allowed_by_parent
return if visibility_level_allowed_by_parent? return if visibility_level_allowed_by_parent?
......
...@@ -1040,6 +1040,10 @@ class Project < ActiveRecord::Base ...@@ -1040,6 +1040,10 @@ class Project < ActiveRecord::Base
!(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
end end
def fork_source
forked_from_project || fork_network&.root_project
end
def personal? def personal?
!group !group
end end
......
...@@ -168,6 +168,7 @@ class User < ActiveRecord::Base ...@@ -168,6 +168,7 @@ class User < ActiveRecord::Base
before_save :skip_reconfirmation!, if: ->(user) { user.email_changed? && user.read_only_attribute?(:email) } before_save :skip_reconfirmation!, if: ->(user) { user.email_changed? && user.read_only_attribute?(:email) }
before_save :check_for_verified_email, if: ->(user) { user.email_changed? && !user.new_record? } before_save :check_for_verified_email, if: ->(user) { user.email_changed? && !user.new_record? }
after_save :ensure_namespace_correct after_save :ensure_namespace_correct
after_update :username_changed_hook, if: :username_changed?
after_destroy :post_destroy_hook after_destroy :post_destroy_hook
after_commit :update_emails_with_primary_email, on: :update, if: -> { previous_changes.key?('email') } after_commit :update_emails_with_primary_email, on: :update, if: -> { previous_changes.key?('email') }
after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') } after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') }
...@@ -871,6 +872,10 @@ class User < ActiveRecord::Base ...@@ -871,6 +872,10 @@ class User < ActiveRecord::Base
end end
end end
def username_changed_hook
system_hook_service.execute_hooks_for(self, :rename)
end
def post_destroy_hook def post_destroy_hook
log_info("User \"#{name}\" (#{email}) was removed") log_info("User \"#{name}\" (#{email}) was removed")
system_hook_service.execute_hooks_for(self, :destroy) system_hook_service.execute_hooks_for(self, :destroy)
......
module Applications
class CreateService
def initialize(current_user, params)
@current_user = current_user
@params = params
@ip_address = @params.delete(:ip_address)
end
def execute(request = nil)
Doorkeeper::Application.create(@params)
end
end
end
...@@ -4,6 +4,7 @@ module Keys ...@@ -4,6 +4,7 @@ module Keys
def initialize(user, params) def initialize(user, params)
@user, @params = user, params @user, @params = user, params
@ip_address = @params.delete(:ip_address)
end end
def notification_service def notification_service
......
...@@ -3,18 +3,24 @@ module Projects ...@@ -3,18 +3,24 @@ module Projects
def execute def execute
return unless @project.forked? return unless @project.forked?
@project.forked_from_project.lfs_objects.find_each do |lfs_object| if fork_source = @project.fork_source
lfs_object.projects << @project fork_source.lfs_objects.find_each do |lfs_object|
lfs_object.projects << @project
end
refresh_forks_count(fork_source)
end end
merge_requests = @project.forked_from_project.merge_requests.opened.from_project(@project) merge_requests = @project.fork_network
.merge_requests
.opened
.where.not(target_project: @project)
.from_project(@project)
merge_requests.each do |mr| merge_requests.each do |mr|
::MergeRequests::CloseService.new(@project, @current_user).execute(mr) ::MergeRequests::CloseService.new(@project, @current_user).execute(mr)
end end
refresh_forks_count(@project.forked_from_project)
@project.fork_network_member.destroy @project.fork_network_member.destroy
@project.forked_project_link.destroy @project.forked_project_link.destroy
end end
......
...@@ -35,24 +35,22 @@ class SystemHooksService ...@@ -35,24 +35,22 @@ class SystemHooksService
data[:old_path_with_namespace] = model.old_path_with_namespace data[:old_path_with_namespace] = model.old_path_with_namespace
end end
when User when User
data.merge!({ data.merge!(user_data(model))
name: model.name,
email: model.email, if event == :rename
user_id: model.id, data[:old_username] = model.username_was
username: model.username end
})
when ProjectMember when ProjectMember
data.merge!(project_member_data(model)) data.merge!(project_member_data(model))
when Group when Group
owner = model.owner data.merge!(group_data(model))
data.merge!( if event == :rename
name: model.name, data.merge!(
path: model.path, old_path: model.path_was,
group_id: model.id, old_full_path: model.full_path_was
owner_name: owner.respond_to?(:name) ? owner.name : nil, )
owner_email: owner.respond_to?(:email) ? owner.email : nil end
)
when GroupMember when GroupMember
data.merge!(group_member_data(model)) data.merge!(group_member_data(model))
end end
...@@ -104,6 +102,19 @@ class SystemHooksService ...@@ -104,6 +102,19 @@ class SystemHooksService
} }
end end
def group_data(model)
owner = model.owner
{
name: model.name,
path: model.path,
full_path: model.full_path,
group_id: model.id,
owner_name: owner.try(:name),
owner_email: owner.try(:email)
}
end
def group_member_data(model) def group_member_data(model)
{ {
group_name: model.group.name, group_name: model.group.name,
...@@ -116,4 +127,13 @@ class SystemHooksService ...@@ -116,4 +127,13 @@ class SystemHooksService
group_access: model.human_access group_access: model.human_access
} }
end end
def user_data(model)
{
name: model.name,
email: model.email,
user_id: model.id,
username: model.username
}
end
end end
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
%li.todos-pending{ class: active_when(params[:state].blank? || params[:state] == 'pending') }> %li.todos-pending{ class: active_when(params[:state].blank? || params[:state] == 'pending') }>
= link_to todos_filter_path(state: 'pending') do = link_to todos_filter_path(state: 'pending') do
%span %span
To do Todos
%span.badge %span.badge
= number_with_delimiter(todos_pending_count) = number_with_delimiter(todos_pending_count)
%li.todos-done{ class: active_when(params[:state] == 'done') }> %li.todos-done{ class: active_when(params[:state] == 'done') }>
......
- empty_repo = @project.empty_repo? - empty_repo = @project.empty_repo?
- fork_network = @project.fork_network - fork_network = @project.fork_network
- forked_from_project = @project.forked_from_project || fork_network&.root_project
.project-home-panel.text-center{ class: ("empty-project" if empty_repo) } .project-home-panel.text-center{ class: ("empty-project" if empty_repo) }
.limit-container-width{ class: container_class } .limit-container-width{ class: container_class }
.avatar-container.s70.project-avatar .avatar-container.s70.project-avatar
...@@ -16,13 +15,13 @@ ...@@ -16,13 +15,13 @@
- if @project.forked? - if @project.forked?
%p %p
- if forked_from_project - if @project.fork_source
#{ s_('ForkedFromProjectPath|Forked from') } #{ s_('ForkedFromProjectPath|Forked from') }
= link_to project_path(forked_from_project) do = link_to project_path(@project.fork_source) do
= forked_from_project.full_name = fork_source_name(@project)
- else - else
- deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)') - deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)')
= deleted_message % { project_name: fork_network.deleted_root_project_name } = deleted_message % { project_name: fork_source_name(@project) }
.project-repo-buttons .project-repo-buttons
.count-buttons .count-buttons
......
...@@ -173,7 +173,10 @@ ...@@ -173,7 +173,10 @@
%p %p
This will remove the fork relationship to source project This will remove the fork relationship to source project
= succeed "." do = succeed "." do
= link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project) - if @project.fork_source
= link_to(fork_source_name(@project), project_path(@project.fork_source))
- else
= fork_source_name(@project)
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_project_path(@project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f| = form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_project_path(@project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f|
%p %p
%strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source. %strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
......
---
title: Stop merge requests with thousands of commits from timing out
merge_request: 15063
author:
type: performance
---
title: Update default disabled merge request widget message to reflect a general failure
merge_request: 14960
author:
type: changed
---
title: 'Fix bug preventing secondary emails from being confirmed'
merge_request: 15010
author:
type: fixed
---
title: Todos spelled correctly on Todos list page
merge_request: 15015
author:
type: changed
---
title: Fix editing issue description in mobile view
merge_request:
author:
type: fixed
---
title: Fix bitbucket login
merge_request: 15051
author:
type: fixed
--- ---
title: Adds callback functions for initial request in clusters page title: Fix double border UI bug on pipelines/environments table and pagination
merge_request: merge_request:
author: author:
type: fixed type: fixed
---
title: Make the circuitbreaker more robust by adding higher thresholds, and multiple
access attempts.
merge_request: 14933
author:
type: fixed
---
title: Store circuitbreaker settings in the database instead of config
merge_request: 14842
author:
type: changed
---
title: Forbid the usage of `Redis#keys`
merge_request: 14889
author:
type: fixed
---
title: Don't rename paths that were freed up when upgrading
merge_request: 15029
author:
type: fixed
---
title: Only cache last push event for existing projects when pushing to a fork
merge_request: 14989
author:
type: fixed
---
title: Use the correct visibility attribute for projects in system hooks
merge_request: 15065
author:
type: fixed
---
title: Fix issues with forked projects of which the source was deleted
merge_request: 15150
author:
type: fixed
---
title: Normalize LDAP DN when looking up identity
merge_request:
author:
type: fixed
---
title: Enable MergeableSelector in scss-lint
merge_request: 12810
author: Takuya Noguchi
---
title: Fix broken wiki pages that link to a wiki file
merge_request: 15019
author:
type: fixed
---
title: Fix missing Import/Export issue assignees
merge_request:
author:
type: fixed
---
title: Fix widget of locked merge requests not being presented
merge_request:
author:
type: fixed
---
title: Auto Devops kubernetes default namespace is now correctly built out of gitlab
project group-name
merge_request: 14642
author: Mircea Danila Dumitrescu
type: fixed
---
title: Fix deletion of container registry or images returning an error
merge_request:
author:
type: fixed
--- ---
title: Allow boards as top level route title: Avoid regenerating the ref path for the environment
merge_request: merge_request:
author: author:
type: fixed type: fixed
---
title: Fix the writing of invalid environment refs
merge_request:
author:
type: fixed
---
title: Add system hooks user_rename and group_rename
merge_request: 15123
author:
type: changed
...@@ -501,7 +501,7 @@ production: &base ...@@ -501,7 +501,7 @@ production: &base
# Gitaly settings # Gitaly settings
gitaly: gitaly:
# Path to the directory containing Gitaly client executables. # Path to the directory containing Gitaly client executables.
client_path: /home/git/gitaly client_path: /home/git/gitaly/bin
# Default Gitaly authentication token. Can be overriden per storage. Can # Default Gitaly authentication token. Can be overriden per storage. Can
# be left blank when Gitaly is running locally on a Unix socket, which # be left blank when Gitaly is running locally on a Unix socket, which
# is the normal way to deploy Gitaly. # is the normal way to deploy Gitaly.
......
# System hooks # System hooks
Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `project_rename`, `project_transfer`, `project_update`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create`, `key_destroy`, `group_create`, `group_destroy`, `user_add_to_group` and `user_remove_from_group`. Your GitLab instance can perform HTTP POST requests on the following events:
- `project_create`
- `project_destroy`
- `project_rename`
- `project_transfer`
- `project_update`
- `user_add_to_team`
- `user_remove_from_team`
- `user_create`
- `user_destroy`
- `user_rename`
- `key_create`
- `key_destroy`
- `group_create`
- `group_destroy`
- `group_rename`
- `user_add_to_group`
- `user_remove_from_group`
The triggers for most of these are self-explanatory, but `project_update` and `project_rename` deserve some clarification: `project_update` is fired any time an attribute of a project is changed (name, description, tags, etc.) *unless* the `path` attribute is also changed. In that case, a `project_rename` is triggered instead (so that, for instance, if all you care about is the repo URL, you can just listen for `project_rename`). The triggers for most of these are self-explanatory, but `project_update` and `project_rename` deserve some clarification: `project_update` is fired any time an attribute of a project is changed (name, description, tags, etc.) *unless* the `path` attribute is also changed. In that case, a `project_rename` is triggered instead (so that, for instance, if all you care about is the repo URL, you can just listen for `project_rename`).
...@@ -72,6 +90,9 @@ X-Gitlab-Event: System Hook ...@@ -72,6 +90,9 @@ X-Gitlab-Event: System Hook
} }
``` ```
Note that `project_rename` is not triggered if the namespace changes.
Please refer to `group_rename` and `user_rename` for that case.
**Project transferred:** **Project transferred:**
```json ```json
...@@ -175,6 +196,21 @@ X-Gitlab-Event: System Hook ...@@ -175,6 +196,21 @@ X-Gitlab-Event: System Hook
} }
``` ```
**User renamed:**
```json
{
"event_name": "user_rename",
"created_at": "2017-11-01T11:21:04Z",
"updated_at": "2017-11-01T14:04:47Z",
"name": "new-name",
"email": "best-email@example.tld",
"user_id": 58,
"username": "new-exciting-name",
"old_username": "old-boring-name"
}
```
**Key added** **Key added**
```json ```json
...@@ -209,13 +245,15 @@ X-Gitlab-Event: System Hook ...@@ -209,13 +245,15 @@ X-Gitlab-Event: System Hook
"updated_at": "2012-07-21T07:38:22Z", "updated_at": "2012-07-21T07:38:22Z",
"event_name": "group_create", "event_name": "group_create",
"name": "StoreCloud", "name": "StoreCloud",
"owner_email": "johnsmith@gmail.com", "owner_email": null,
"owner_name": "John Smith", "owner_name": null,
"path": "storecloud", "path": "storecloud",
"group_id": 78 "group_id": 78
} }
``` ```
`owner_name` and `owner_email` are always `null`. Please see https://gitlab.com/gitlab-org/gitlab-ce/issues/39675.
**Group removed:** **Group removed:**
```json ```json
...@@ -224,13 +262,35 @@ X-Gitlab-Event: System Hook ...@@ -224,13 +262,35 @@ X-Gitlab-Event: System Hook
"updated_at": "2012-07-21T07:38:22Z", "updated_at": "2012-07-21T07:38:22Z",
"event_name": "group_destroy", "event_name": "group_destroy",
"name": "StoreCloud", "name": "StoreCloud",
"owner_email": "johnsmith@gmail.com", "owner_email": null,
"owner_name": "John Smith", "owner_name": null,
"path": "storecloud", "path": "storecloud",
"group_id": 78 "group_id": 78
} }
``` ```
`owner_name` and `owner_email` are always `null`. Please see https://gitlab.com/gitlab-org/gitlab-ce/issues/39675.
**Group renamed:**
```json
{
"event_name": "group_rename",
"created_at": "2017-10-30T15:09:00Z",
"updated_at": "2017-11-01T10:23:52Z",
"name": "Better Name",
"path": "better-name",
"full_path": "parent-group/better-name",
"group_id": 64,
"owner_name": null,
"owner_email": null,
"old_path": "old-name",
"old_full_path": "parent-group/old-name"
}
```
`owner_name` and `owner_email` are always `null`. Please see https://gitlab.com/gitlab-org/gitlab-ce/issues/39675.
**New Group Member:** **New Group Member:**
```json ```json
......
...@@ -144,6 +144,12 @@ has a `.gitlab-ci.yml` or not: ...@@ -144,6 +144,12 @@ has a `.gitlab-ci.yml` or not:
All you need to do is remove your existing `.gitlab-ci.yml`, and you can even All you need to do is remove your existing `.gitlab-ci.yml`, and you can even
do that in a branch to test Auto DevOps before committing to `master`. do that in a branch to test Auto DevOps before committing to `master`.
NOTE: **Note:**
If you are a GitLab Administrator, you can enable Auto DevOps instance wide
in **Admin Area > Settings > Continuous Integration and Deployment**. Doing that,
all the projects that haven't explicitly set an option will have Auto DevOps
enabled by default.
## Stages of Auto DevOps ## Stages of Auto DevOps
The following sections describe the stages of Auto DevOps. Read them carefully The following sections describe the stages of Auto DevOps. Read them carefully
......
...@@ -36,7 +36,7 @@ module Gitlab ...@@ -36,7 +36,7 @@ module Gitlab
end end
def track_query(raw_query, bindings, start, finish) def track_query(raw_query, bindings, start, finish)
duration = finish - start duration = (finish - start) * 1000.0
query_info = { duration: duration.round(3), sql: raw_query } query_info = { duration: duration.round(3), sql: raw_query }
PEEK_DB_CLIENT.query_details << query_info PEEK_DB_CLIENT.query_details << query_info
......
...@@ -89,7 +89,9 @@ module Gitlab ...@@ -89,7 +89,9 @@ module Gitlab
ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data| ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data|
next unless same_thread? next unless same_thread?
track_query(data[:sql].strip, data[:binds], start, finish) unless data.fetch(:cached, data[:name] == 'CACHE')
track_query(data[:sql].strip, data[:binds], start, finish)
end
end end
end end
......
require 'spec_helper'
describe LfsRequest do
include ProjectForksHelper
controller(Projects::GitHttpClientController) do
# `described_class` is not available in this context
include LfsRequest # rubocop:disable RSpec/DescribedClass
def show
storage_project
render nothing: true
end
def project
@project ||= Project.find(params[:id])
end
def download_request?
true
end
def ci?
false
end
end
let(:project) { create(:project, :public) }
before do
stub_lfs_setting(enabled: true)
end
describe '#storage_project' do
it 'assigns the project as storage project' do
get :show, id: project.id
expect(assigns(:storage_project)).to eq(project)
end
it 'assigns the source of a forked project' do
forked_project = fork_project(project)
get :show, id: forked_project.id
expect(assigns(:storage_project)).to eq(project)
end
end
end
...@@ -52,7 +52,7 @@ feature 'Dashboard Todos' do ...@@ -52,7 +52,7 @@ feature 'Dashboard Todos' do
end end
it 'updates todo count' do it 'updates todo count' do
expect(page).to have_content 'To do 0' expect(page).to have_content 'Todos 0'
expect(page).to have_content 'Done 1' expect(page).to have_content 'Done 1'
end end
...@@ -81,7 +81,7 @@ feature 'Dashboard Todos' do ...@@ -81,7 +81,7 @@ feature 'Dashboard Todos' do
end end
it 'updates todo count' do it 'updates todo count' do
expect(page).to have_content 'To do 1' expect(page).to have_content 'Todos 1'
expect(page).to have_content 'Done 0' expect(page).to have_content 'Done 0'
end end
end end
...@@ -200,7 +200,7 @@ feature 'Dashboard Todos' do ...@@ -200,7 +200,7 @@ feature 'Dashboard Todos' do
end end
it 'updates todo count' do it 'updates todo count' do
expect(page).to have_content 'To do 1' expect(page).to have_content 'Todos 1'
expect(page).to have_content 'Done 0' expect(page).to have_content 'Done 0'
end end
end end
...@@ -256,7 +256,7 @@ feature 'Dashboard Todos' do ...@@ -256,7 +256,7 @@ feature 'Dashboard Todos' do
end end
it 'shows "All done" message!' do it 'shows "All done" message!' do
expect(page).to have_content 'To do 0' expect(page).to have_content 'Todos 0'
expect(page).to have_content "You're all done!" expect(page).to have_content "You're all done!"
expect(page).not_to have_selector('.gl-pagination') expect(page).not_to have_selector('.gl-pagination')
end end
...@@ -283,7 +283,7 @@ feature 'Dashboard Todos' do ...@@ -283,7 +283,7 @@ feature 'Dashboard Todos' do
it 'updates todo count' do it 'updates todo count' do
mark_all_and_undo mark_all_and_undo
expect(page).to have_content 'To do 2' expect(page).to have_content 'Todos 2'
expect(page).to have_content 'Done 0' expect(page).to have_content 'Done 0'
end end
......
require 'spec_helper'
feature 'Settings for a forked project', :js do
include ProjectForksHelper
let(:user) { create(:user) }
let(:original_project) { create(:project) }
let(:forked_project) { fork_project(original_project, user) }
before do
original_project.add_master(user)
forked_project.add_master(user)
sign_in(user)
end
shared_examples 'project settings for a forked projects' do
it 'allows deleting the link to the forked project' do
visit edit_project_path(forked_project)
click_button 'Remove fork relationship'
wait_for_requests
fill_in('confirm_name_input', with: forked_project.name)
click_button('Confirm')
expect(page).to have_content('The fork relationship has been removed.')
expect(forked_project.reload.forked?).to be_falsy
end
end
it_behaves_like 'project settings for a forked projects'
context 'when the original project is deleted' do
before do
original_project.destroy!
end
it_behaves_like 'project settings for a forked projects'
end
end
...@@ -134,6 +134,7 @@ describe Group, 'Routable' do ...@@ -134,6 +134,7 @@ describe Group, 'Routable' do
context 'with RequestStore active', :request_store do context 'with RequestStore active', :request_store do
it 'does not load the route table more than once' do it 'does not load the route table more than once' do
group.expires_full_path_cache
expect(group).to receive(:uncached_full_path).once.and_call_original expect(group).to receive(:uncached_full_path).once.and_call_original
3.times { group.full_path } 3.times { group.full_path }
......
...@@ -547,6 +547,15 @@ describe Environment do ...@@ -547,6 +547,15 @@ describe Environment do
expect(environment.slug).to eq(original_slug) expect(environment.slug).to eq(original_slug)
end end
it "regenerates the slug if nil" do
environment = build(:environment, slug: nil)
new_slug = environment.slug
expect(new_slug).not_to be_nil
expect(environment.slug).to eq(new_slug)
end
end end
describe '#generate_slug' do describe '#generate_slug' do
...@@ -583,6 +592,12 @@ describe Environment do ...@@ -583,6 +592,12 @@ describe Environment do
it 'returns a path that uses the slug and does not have spaces' do it 'returns a path that uses the slug and does not have spaces' do
expect(environment.ref_path).to start_with('refs/environments/staging-review-1-') expect(environment.ref_path).to start_with('refs/environments/staging-review-1-')
end end
it "doesn't change when the slug is nil initially" do
environment.slug = nil
expect(environment.ref_path).to eq(environment.ref_path)
end
end end
describe '#external_url_for' do describe '#external_url_for' do
......
...@@ -24,6 +24,16 @@ describe ForkNetwork do ...@@ -24,6 +24,16 @@ describe ForkNetwork do
end end
end end
describe '#merge_requests' do
it 'finds merge requests within the fork network' do
project = create(:project)
forked_project = fork_project(project)
merge_request = create(:merge_request, source_project: forked_project, target_project: project)
expect(project.fork_network.merge_requests).to include(merge_request)
end
end
context 'for a deleted project' do context 'for a deleted project' do
it 'keeps the fork network' do it 'keeps the fork network' do
project = create(:project, :public) project = create(:project, :public)
......
...@@ -488,6 +488,47 @@ describe Group do ...@@ -488,6 +488,47 @@ describe Group do
end end
end end
describe '#path_changed_hook' do
let(:system_hook_service) { SystemHooksService.new }
context 'for a new group' do
let(:group) { build(:group) }
before do
expect(group).to receive(:system_hook_service).and_return(system_hook_service)
end
it 'does not trigger system hook' do
expect(system_hook_service).to receive(:execute_hooks_for).with(group, :create)
group.save!
end
end
context 'for an existing group' do
let(:group) { create(:group, path: 'old-path') }
context 'when the path is changed' do
let(:new_path) { 'very-new-path' }
it 'triggers the rename system hook' do
expect(group).to receive(:system_hook_service).and_return(system_hook_service)
expect(system_hook_service).to receive(:execute_hooks_for).with(group, :rename)
group.update_attributes!(path: new_path)
end
end
context 'when the path is not changed' do
it 'does not trigger system hook' do
expect(group).not_to receive(:system_hook_service)
group.update_attributes!(name: 'new name')
end
end
end
end
describe '#secret_variables_for' do describe '#secret_variables_for' do
let(:project) { create(:project, group: group) } let(:project) { create(:project, group: group) }
......
...@@ -1923,6 +1923,20 @@ describe Project do ...@@ -1923,6 +1923,20 @@ describe Project do
expect(forked_project.in_fork_network_of?(other_project)).to be_falsy expect(forked_project.in_fork_network_of?(other_project)).to be_falsy
end end
end end
describe '#fork_source' do
let!(:second_fork) { fork_project(forked_project) }
it 'returns the direct source if it exists' do
expect(second_fork.fork_source).to eq(forked_project)
end
it 'returns the root of the fork network when the directs source was deleted' do
forked_project.destroy
expect(second_fork.fork_source).to eq(project)
end
end
end end
describe '#pushes_since_gc' do describe '#pushes_since_gc' do
......
...@@ -2217,6 +2217,42 @@ describe User do ...@@ -2217,6 +2217,42 @@ describe User do
end end
end end
describe '#username_changed_hook' do
context 'for a new user' do
let(:user) { build(:user) }
it 'does not trigger system hook' do
expect(user).not_to receive(:system_hook_service)
user.save!
end
end
context 'for an existing user' do
let(:user) { create(:user, username: 'old-username') }
context 'when the username is changed' do
let(:new_username) { 'very-new-name' }
it 'triggers the rename system hook' do
system_hook_service = SystemHooksService.new
expect(system_hook_service).to receive(:execute_hooks_for).with(user, :rename)
expect(user).to receive(:system_hook_service).and_return(system_hook_service)
user.update_attributes!(username: new_username)
end
end
context 'when the username is not changed' do
it 'does not trigger system hook' do
expect(user).not_to receive(:system_hook_service)
user.update_attributes!(email: 'asdf@asdf.com')
end
end
end
end
describe '#sync_attribute?' do describe '#sync_attribute?' do
let(:user) { described_class.new } let(:user) { described_class.new }
......
require 'spec_helper'
describe ::Applications::CreateService do
let(:user) { create(:user) }
let(:params) { attributes_for(:application) }
let(:request) { ActionController::TestRequest.new(remote_ip: '127.0.0.1') }
subject { described_class.new(user, params) }
it 'creates an application' do
expect { subject.execute(request) }.to change { Doorkeeper::Application.count }.by(1)
end
end
...@@ -12,6 +12,9 @@ describe Projects::UnlinkForkService do ...@@ -12,6 +12,9 @@ describe Projects::UnlinkForkService do
context 'with opened merge request on the source project' do context 'with opened merge request on the source project' do
let(:merge_request) { create(:merge_request, source_project: forked_project, target_project: fork_link.forked_from_project) } let(:merge_request) { create(:merge_request, source_project: forked_project, target_project: fork_link.forked_from_project) }
let(:merge_request2) { create(:merge_request, source_project: forked_project, target_project: fork_project(project)) }
let(:merge_request_in_fork) { create(:merge_request, source_project: forked_project, target_project: forked_project) }
let(:mr_close_service) { MergeRequests::CloseService.new(forked_project, user) } let(:mr_close_service) { MergeRequests::CloseService.new(forked_project, user) }
before do before do
...@@ -22,9 +25,14 @@ describe Projects::UnlinkForkService do ...@@ -22,9 +25,14 @@ describe Projects::UnlinkForkService do
it 'close all pending merge requests' do it 'close all pending merge requests' do
expect(mr_close_service).to receive(:execute).with(merge_request) expect(mr_close_service).to receive(:execute).with(merge_request)
expect(mr_close_service).to receive(:execute).with(merge_request2)
subject.execute subject.execute
end end
it 'does not close merge requests for the project being unlinked' do
expect(mr_close_service).not_to receive(:execute).with(merge_request_in_fork)
end
end end
it 'remove fork relation' do it 'remove fork relation' do
...@@ -53,4 +61,14 @@ describe Projects::UnlinkForkService do ...@@ -53,4 +61,14 @@ describe Projects::UnlinkForkService do
expect(source.forks_count).to be_zero expect(source.forks_count).to be_zero
end end
context 'when the original project was deleted' do
it 'does not fail when the original project is deleted' do
source = forked_project.forked_from_project
source.destroy
forked_project.reload
expect { subject.execute }.not_to raise_error
end
end
end end
...@@ -69,11 +69,48 @@ describe SystemHooksService do ...@@ -69,11 +69,48 @@ describe SystemHooksService do
expect(data[:project_visibility]).to eq('private') expect(data[:project_visibility]).to eq('private')
end end
context 'group_rename' do
it 'contains old and new path' do
allow(group).to receive(:path_was).and_return('old-path')
data = event_data(group, :rename)
expect(data).to include(:event_name, :name, :created_at, :updated_at, :full_path, :path, :group_id, :old_path, :old_full_path)
expect(data[:path]).to eq(group.path)
expect(data[:full_path]).to eq(group.path)
expect(data[:old_path]).to eq(group.path_was)
expect(data[:old_full_path]).to eq(group.path_was)
end
it 'contains old and new full_path for subgroup' do
subgroup = create(:group, parent: group)
allow(subgroup).to receive(:path_was).and_return('old-path')
data = event_data(subgroup, :rename)
expect(data[:full_path]).to eq(subgroup.full_path)
expect(data[:old_path]).to eq('old-path')
end
end
context 'user_rename' do
it 'contains old and new username' do
allow(user).to receive(:username_was).and_return('old-username')
data = event_data(user, :rename)
expect(data).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username, :old_username)
expect(data[:username]).to eq(user.username)
expect(data[:old_username]).to eq(user.username_was)
end
end
end end
context 'event names' do context 'event names' do
it { expect(event_name(user, :create)).to eq "user_create" } it { expect(event_name(user, :create)).to eq "user_create" }
it { expect(event_name(user, :destroy)).to eq "user_destroy" } it { expect(event_name(user, :destroy)).to eq "user_destroy" }
it { expect(event_name(user, :rename)).to eq 'user_rename' }
it { expect(event_name(project, :create)).to eq "project_create" } it { expect(event_name(project, :create)).to eq "project_create" }
it { expect(event_name(project, :destroy)).to eq "project_destroy" } it { expect(event_name(project, :destroy)).to eq "project_destroy" }
it { expect(event_name(project, :rename)).to eq "project_rename" } it { expect(event_name(project, :rename)).to eq "project_rename" }
...@@ -85,6 +122,7 @@ describe SystemHooksService do ...@@ -85,6 +122,7 @@ describe SystemHooksService do
it { expect(event_name(key, :destroy)).to eq 'key_destroy' } it { expect(event_name(key, :destroy)).to eq 'key_destroy' }
it { expect(event_name(group, :create)).to eq 'group_create' } it { expect(event_name(group, :create)).to eq 'group_create' }
it { expect(event_name(group, :destroy)).to eq 'group_destroy' } it { expect(event_name(group, :destroy)).to eq 'group_destroy' }
it { expect(event_name(group, :rename)).to eq 'group_rename' }
it { expect(event_name(group_member, :create)).to eq 'user_add_to_group' } it { expect(event_name(group_member, :create)).to eq 'user_add_to_group' }
it { expect(event_name(group_member, :destroy)).to eq 'user_remove_from_group' } it { expect(event_name(group_member, :destroy)).to eq 'user_remove_from_group' }
end end
......
...@@ -38,6 +38,10 @@ module StubConfiguration ...@@ -38,6 +38,10 @@ module StubConfiguration
allow(Gitlab.config.backup).to receive_messages(to_settings(messages)) allow(Gitlab.config.backup).to receive_messages(to_settings(messages))
end end
def stub_lfs_setting(messages)
allow(Gitlab.config.lfs).to receive_messages(to_settings(messages))
end
def stub_storage_settings(messages) def stub_storage_settings(messages)
# Default storage is always required # Default storage is always required
messages['default'] ||= Gitlab.config.repositories.storages.default messages['default'] ||= Gitlab.config.repositories.storages.default
......
/*
* This is a modified version of https://github.com/peek/peek/blob/master/app/assets/javascripts/peek.js
*
* - Removed the dependency on jquery.tipsy
* - Removed the initializeTipsy and toggleBar functions
* - Customized updatePerformanceBar to handle SQL queries report specificities
* - Changed /peek/results to /-/peek/results
* - Removed the keypress, pjax:end, page:change, and turbolinks:load handlers
*/
(function($) { (function($) {
var fetchRequestResults, getRequestId, peekEnabled, toggleBar, updatePerformanceBar; var fetchRequestResults, getRequestId, peekEnabled, updatePerformanceBar;
getRequestId = function() { getRequestId = function() {
return $('#peek').data('request-id'); return $('#peek').data('request-id');
}; };
...@@ -41,22 +50,6 @@ ...@@ -41,22 +50,6 @@
}); });
return $(document).trigger('peek:render', [getRequestId(), results]); return $(document).trigger('peek:render', [getRequestId(), results]);
}; };
toggleBar = function(event) {
var wrapper;
if ($(event.target).is(':input')) {
return;
}
if (event.which === 96 && !event.metaKey) {
wrapper = $('#peek');
if (wrapper.hasClass('disabled')) {
wrapper.removeClass('disabled');
return document.cookie = "peek=true; path=/";
} else {
wrapper.addClass('disabled');
return document.cookie = "peek=false; path=/";
}
}
};
fetchRequestResults = function() { fetchRequestResults = function() {
return $.ajax('/-/peek/results', { return $.ajax('/-/peek/results', {
data: { data: {
...@@ -68,7 +61,6 @@ ...@@ -68,7 +61,6 @@
error: function(xhr, textStatus, error) {} error: function(xhr, textStatus, error) {}
}); });
}; };
$(document).on('keypress', toggleBar);
$(document).on('peek:update', fetchRequestResults); $(document).on('peek:update', fetchRequestResults);
return $(function() { return $(function() {
if (peekEnabled()) { if (peekEnabled()) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment