Commit b3bb56d4 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'ce-to-ee-2018-11-26' into 'master'

CE upstream - 2018-11-26 10:21 UTC

Closes gitaly#1406

See merge request gitlab-org/gitlab-ee!8582
parents afb7260e 4eb852cf
......@@ -938,6 +938,7 @@ qa:selectors:
- yarn install --frozen-lockfile --cache-folder .yarn-cache
- date
- yarn run webpack-prod
<<: *except-docs
qa-frontend-node:6:
<<: *qa-frontend-node
......
......@@ -126,6 +126,7 @@ export default {
:text="commitMessage"
:placeholder="preBuiltCommitMessage"
@input="updateCommitMessage"
@submit="commitChanges"
/>
<div class="clearfix prepend-top-15">
<actions />
......
......@@ -49,6 +49,10 @@ export default {
onInput(e) {
this.$emit('input', e.target.value);
},
onCtrlEnter() {
if (!this.isFocused) return;
this.$emit('submit');
},
updateIsFocused(isFocused) {
this.isFocused = isFocused;
},
......@@ -109,6 +113,8 @@ export default {
@input="onInput"
@focus="updateIsFocused(true);"
@blur="updateIsFocused(false);"
@keydown.ctrl.enter="onCtrlEnter"
@keydown.meta.enter="onCtrlEnter"
>
</textarea>
</div>
......
......@@ -19,7 +19,7 @@ export default class LazyLoader {
}
searchLazyImages() {
requestIdleCallback(
window.requestIdleCallback(
() => {
const lazyImages = [].slice.call(document.querySelectorAll('.lazy'));
......@@ -107,7 +107,7 @@ export default class LazyLoader {
}
scrollCheck() {
requestAnimationFrame(() => this.checkElementsInView());
window.requestAnimationFrame(() => this.checkElementsInView());
}
checkElementsInView() {
......@@ -122,7 +122,7 @@ export default class LazyLoader {
const imgBound = imgTop + imgBoundRect.height;
if (scrollTop <= imgBound && visHeight >= imgTop) {
requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
LazyLoader.loadImage(selectedImage);
});
return false;
......
......@@ -249,6 +249,13 @@
- else
%kbd ctrl p
%td Go to file
%tr
%td.shortcut
- if browser.platform.mac?
%kbd &#8984; enter
- else
%kbd ctrl enter
%td Commit (when editing commit message)
.col-lg-4
%table.shortcut-mappings
%tbody.hidden-shortcut{ style: 'display:none' }
......
......@@ -2,7 +2,7 @@
%hr
%p.lead To start serving your jobs you can either add specific Runners to your project or use shared Runners
%p.lead= _('To start serving your jobs you can either add specific Runners to your project or use shared Runners')
.row
.col-sm-6
= render 'projects/runners/specific_runners'
......
......@@ -5,21 +5,19 @@
- if Gitlab::CurrentSettings.shared_runners_text.present?
= markdown_field(Gitlab::CurrentSettings.current_application_settings, :shared_runners_text)
- else
GitLab Shared Runners execute code of different projects on the same Runner
unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is
on GitLab.com).
= _('GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com).')
%hr
- if @project.shared_runners_enabled?
= link_to toggle_shared_runners_project_runners_path(@project), class: 'btn btn-close', method: :post do
Disable shared Runners
= _('Disable shared Runners')
- else
= link_to toggle_shared_runners_project_runners_path(@project), class: 'btn btn-success', method: :post do
Enable shared Runners
= _('Enable shared Runners')
&nbsp; for this project
- if @shared_runners_count.zero?
= _('This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area.')
- else
%h4.underlined-title Available shared Runners : #{@shared_runners_count}
%h4.underlined-title #{_('Available shared Runners :')} #{@shared_runners_count}
%ul.bordered-list.available-shared-runners
= render partial: 'projects/runners/runner', collection: @shared_runners, as: :runner
......@@ -31,12 +31,12 @@
reset_token_url: reset_registration_token_namespace_project_settings_ci_cd_path }
- if @project_runners.any?
%h4.underlined-title Runners activated for this project
%h4.underlined-title= _('Runners activated for this project')
%ul.bordered-list.activated-specific-runners
= render partial: 'projects/runners/runner', collection: @project_runners, as: :runner
- if @assignable_runners.any?
%h4.underlined-title Available specific runners
%h4.underlined-title= _('Available specific runners')
%ul.bordered-list.available-specific-runners
= render partial: 'projects/runners/runner', collection: @assignable_runners, as: :runner
= paginate @assignable_runners, theme: "gitlab", :params => { :anchor => '#js-runners-settings' }
- page_title _('Edit'), "#{@runner.description} ##{@runner.id}", 'Runners'
- page_title _('Edit'), "#{@runner.description} ##{@runner.id}", _('Runners')
%h4 Runner ##{@runner.id}
......
---
title: "WebIDE: Pressing Ctrl-Enter while typing on the commit message now performs the commit action"
merge_request: 23049
author: Thomas Pathier
type: added
---
title: Externalize strings from `/app/views/project/runners`
merge_request: 23208
author: Tao Wang
type: other
......@@ -72,8 +72,8 @@ GET /users
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `order_by` | string | no | Return projects ordered by `id`, `name`, `username`, `created_at`, or `updated_at` fields. Default is `id` |
| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
| `order_by` | string | no | Return users ordered by `id`, `name`, `username`, `created_at`, or `updated_at` fields. Default is `id` |
| `sort` | string | no | Return users sorted in `asc` or `desc` order. Default is `desc` |
| `two_factor` | string | no | Filter users by Two-factor authentication. Filter values are `enabled` or `disabled`. By default it returns all users |
```json
......
......@@ -17,6 +17,9 @@ This merge is done automatically in a
1. If all conflicts are resolved after your resolution is pushed, keep the merge
request assigned to you: **you are now responsible for the merge request to be
green**
1. If you are the last person to resolve the conflicts, the pipeline is green,
and you have merge rights, merge the MR, but **do not** choose to squash.
Otherwise, assign the MR to someone that can merge.
1. If you need any help, you can ping the current [release managers], or ask in
the `#ce-to-ee` Slack channel
......
......@@ -47,13 +47,13 @@ The source of these Yarn scripts can be found in `/scripts/frontend/prettier.js`
### Scripts during Conversion period
```
node ./scripts/frontend/prettier.js check ./vendor/
node ./scripts/frontend/prettier.js check-all ./vendor/
```
This will go over all files in a specific folder check it.
```
node ./scripts/frontend/prettier.js save ./vendor/
node ./scripts/frontend/prettier.js save-all ./vendor/
```
This will go over all files in a specific folder and save it.
......@@ -102,3 +102,4 @@ You can see GitLab's keyboard shortcuts by using 'shift + ?'
| Keyboard Shortcut | Description |
| ----------------- | ----------- |
| <kbd>Cmd</kbd>/<kbd>Ctrl</kbd> + <kbd>p</kbd> | Go to file |
| <kbd>Cmd</kbd>/<kbd>Ctrl</kbd> + <kbd>Enter</kbd> | Commit (when editing the commit message) |
......@@ -992,6 +992,12 @@ msgstr ""
msgid "Available group Runners : %{runners}."
msgstr ""
msgid "Available shared Runners :"
msgstr ""
msgid "Available specific runners"
msgstr ""
msgid "Avatar will be removed. Are you sure?"
msgstr ""
......@@ -2878,6 +2884,9 @@ msgstr ""
msgid "Disable group Runners"
msgstr ""
msgid "Disable shared Runners"
msgstr ""
msgid "Discard"
msgstr ""
......@@ -3058,6 +3067,9 @@ msgstr ""
msgid "Enable self approval of merge requests"
msgstr ""
msgid "Enable shared Runners"
msgstr ""
msgid "Enable the Performance Bar for a given group."
msgstr ""
......@@ -4030,6 +4042,9 @@ msgstr ""
msgid "GitLab Import"
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
msgid "GitLab User"
msgstr ""
......@@ -7106,6 +7121,9 @@ msgstr ""
msgid "Runners API"
msgstr ""
msgid "Runners activated for this project"
msgstr ""
msgid "Runners can be placed on separate users, servers, and even on your local machine."
msgstr ""
......@@ -8650,6 +8668,9 @@ msgstr ""
msgid "To start serving your jobs you can add Runners to your group"
msgstr ""
msgid "To start serving your jobs you can either add specific Runners to your project or use shared Runners"
msgstr ""
msgid "To this GitLab instance"
msgstr ""
......
export default function scrollIntoViewPromise(intersectionTarget, timeout = 100, maxTries = 5) {
return new Promise((resolve, reject) => {
let intersectionObserver;
let retry = 0;
const intervalId = setInterval(() => {
if (retry >= maxTries) {
intersectionObserver.disconnect();
clearInterval(intervalId);
reject(new Error(`Could not scroll target into viewPort within ${timeout * maxTries} ms`));
}
retry += 1;
intersectionTarget.scrollIntoView();
}, timeout);
intersectionObserver = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
intersectionObserver.disconnect();
clearInterval(intervalId);
resolve();
}
});
intersectionObserver.observe(intersectionTarget);
intersectionTarget.scrollIntoView();
});
}
export default (domElement, attributes, timeout = 1500) =>
new Promise((resolve, reject) => {
let observer;
const timeoutId = setTimeout(() => {
observer.disconnect();
reject(new Error(`Could not see an attribute update within ${timeout} ms`));
}, timeout);
observer = new MutationObserver(() => {
clearTimeout(timeoutId);
observer.disconnect();
resolve();
});
observer.observe(domElement, { attributes: true, attributeFilter: attributes });
});
import LazyLoader from '~/lazy_loader';
import { TEST_HOST } from './test_constants';
let lazyLoader = null;
import scrollIntoViewPromise from './helpers/scroll_into_view_promise';
import waitForPromises from './helpers/wait_for_promises';
import waitForAttributeChange from './helpers/wait_for_attribute_change';
const execImmediately = callback => {
callback();
};
describe('LazyLoader', function() {
let lazyLoader = null;
preloadFixtures('issues/issue_with_comment.html.raw');
describe('with IntersectionObserver disabled', () => {
describe('without IntersectionObserver', () => {
beforeEach(function() {
loadFixtures('issues/issue_with_comment.html.raw');
......@@ -36,14 +39,15 @@ describe('LazyLoader', function() {
it('should copy value from data-src to src for img 1', function(done) {
const img = document.querySelectorAll('img[data-src]')[0];
const originalDataSrc = img.getAttribute('data-src');
img.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([scrollIntoViewPromise(img), waitForAttributeChange(img, ['data-src', 'src'])])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should lazy load dynamically added data-src images', function(done) {
......@@ -52,14 +56,18 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not alter normal images', function(done) {
......@@ -67,13 +75,15 @@ describe('LazyLoader', function() {
const testPath = `${TEST_HOST}/img/testimg.png`;
newImg.setAttribute('src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not load dynamically added pictures if content observer is turned off', done => {
......@@ -84,13 +94,15 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should load dynamically added pictures if content observer is turned off and on again', done => {
......@@ -102,17 +114,22 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
});
describe('with IntersectionObserver enabled', () => {
describe('with IntersectionObserver', () => {
beforeEach(function() {
loadFixtures('issues/issue_with_comment.html.raw');
......@@ -136,14 +153,15 @@ describe('LazyLoader', function() {
it('should copy value from data-src to src for img 1', function(done) {
const img = document.querySelectorAll('img[data-src]')[0];
const originalDataSrc = img.getAttribute('data-src');
img.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([scrollIntoViewPromise(img), waitForAttributeChange(img, ['data-src', 'src'])])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should lazy load dynamically added data-src images', function(done) {
......@@ -152,14 +170,18 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not alter normal images', function(done) {
......@@ -167,13 +189,15 @@ describe('LazyLoader', function() {
const testPath = `${TEST_HOST}/img/testimg.png`;
newImg.setAttribute('src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not load dynamically added pictures if content observer is turned off', done => {
......@@ -184,13 +208,15 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should load dynamically added pictures if content observer is turned off and on again', done => {
......@@ -202,13 +228,17 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
});
});
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