...@@ -13,18 +13,43 @@ export default { ...@@ -13,18 +13,43 @@ export default {
Icon, Icon,
FileRow, FileRow,
}, },
data() {
return {
search: '',
};
},
computed: { computed: {
...mapState('diffs', ['tree', 'renderTreeList']), ...mapState('diffs', ['tree', 'renderTreeList']),
...mapGetters('diffs', ['allBlobs']), ...mapGetters('diffs', ['allBlobs']),
filteredTreeList() { filteredTreeList() {
const search = this.search.toLowerCase().trim();
if (search === '' || this.$options.fuzzyFileFinderEnabled)
return this.renderTreeList ? this.tree : this.allBlobs; return this.renderTreeList ? this.tree : this.allBlobs;
return this.allBlobs.reduce((acc, folder) => {
const tree = folder.tree.filter(f => f.path.toLowerCase().indexOf(search) >= 0);
if (tree.length) {
return acc.concat({
...folder,
tree,
});
}
return acc;
}, []);
}, },
}, },
methods: { methods: {
...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile', 'toggleFileFinder']), ...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile', 'toggleFileFinder']),
clearSearch() {
this.search = '';
},
}, },
shortcutKeyCharacter: `${/Mac/i.test(navigator.userAgent) ? '⌘' : 'Ctrl'}+P`, shortcutKeyCharacter: `${/Mac/i.test(navigator.userAgent) ? '⌘' : 'Ctrl'}+P`,
FileRowStats, FileRowStats,
diffTreeFiltering: gon.features && gon.features.diffTreeFiltering,
}; };
</script> </script>
...@@ -33,6 +58,24 @@ export default { ...@@ -33,6 +58,24 @@ export default {
<div class="append-bottom-8 position-relative tree-list-search d-flex"> <div class="append-bottom-8 position-relative tree-list-search d-flex">
<div class="flex-fill d-flex"> <div class="flex-fill d-flex">
<icon name="search" class="position-absolute tree-list-icon" /> <icon name="search" class="position-absolute tree-list-icon" />
<template v-if="$options.diffTreeFiltering">
<input
v-model="search"
:placeholder="s__('MergeRequest|Filter files')"
type="search"
class="form-control"
/>
<button
v-show="search"
:aria-label="__('Clear search')"
type="button"
class="position-absolute bg-transparent tree-list-icon tree-list-clear-icon border-0 p-0"
@click="clearSearch"
>
<icon name="close" />
</button>
</template>
<template v-else>
<button <button
type="button" type="button"
class="form-control text-left text-secondary" class="form-control text-left text-secondary"
...@@ -44,6 +87,7 @@ export default { ...@@ -44,6 +87,7 @@ export default {
class="position-absolute text-secondary diff-tree-search-shortcut" class="position-absolute text-secondary diff-tree-search-shortcut"
v-html="$options.shortcutKeyCharacter" v-html="$options.shortcutKeyCharacter"
></span> ></span>
</template>
</div> </div>
</div> </div>
<div :class="{ 'pt-0 tree-list-blobs': !renderTreeList }" class="tree-list-scroll"> <div :class="{ 'pt-0 tree-list-blobs': !renderTreeList }" class="tree-list-scroll">
...@@ -79,7 +123,7 @@ export default { ...@@ -79,7 +123,7 @@ export default {
pointer-events: none; pointer-events: none;
} }
.tree-list-icon { .tree-list-icon:not(button) {
pointer-events: none; pointer-events: none;
} }
</style> </style>
...@@ -6,6 +6,7 @@ import ide from './components/ide.vue'; ...@@ -6,6 +6,7 @@ import ide from './components/ide.vue';
import store from './stores'; import store from './stores';
import router from './ide_router'; import router from './ide_router';
import { parseBoolean } from '../lib/utils/common_utils'; import { parseBoolean } from '../lib/utils/common_utils';
import { resetServiceWorkersPublicPath } from '../lib/utils/webpack';
Vue.use(Translate); Vue.use(Translate);
...@@ -60,16 +61,6 @@ export function initIde(el, options = {}) { ...@@ -60,16 +61,6 @@ export function initIde(el, options = {}) {
}); });
} }
// tell webpack to load assets from origin so that web workers don't break
export function resetServiceWorkersPublicPath() {
// __webpack_public_path__ is a global variable that can be used to adjust
// the webpack publicPath setting at runtime.
// see: https://webpack.js.org/guides/public-path/
const relativeRootPath = (gon && gon.relative_url_root) || '';
const webpackAssetPath = `${relativeRootPath}/assets/webpack/`;
__webpack_public_path__ = webpackAssetPath; // eslint-disable-line camelcase
}
/** /**
* Start the IDE. * Start the IDE.
* *
... ...
......
// tell webpack to load assets from origin so that web workers don't break
// eslint-disable-next-line import/prefer-default-export
export function resetServiceWorkersPublicPath() {
// __webpack_public_path__ is a global variable that can be used to adjust
// the webpack publicPath setting at runtime.
// see: https://webpack.js.org/guides/public-path/
const relativeRootPath = (gon && gon.relative_url_root) || '';
const webpackAssetPath = `${relativeRootPath}/assets/webpack/`;
__webpack_public_path__ = webpackAssetPath; // eslint-disable-line camelcase
}
...@@ -7,8 +7,11 @@ import discussionCounter from '../notes/components/discussion_counter.vue'; ...@@ -7,8 +7,11 @@ import discussionCounter from '../notes/components/discussion_counter.vue';
import initDiscussionFilters from '../notes/discussion_filters'; import initDiscussionFilters from '../notes/discussion_filters';
import store from './stores'; import store from './stores';
import MergeRequest from '../merge_request'; import MergeRequest from '../merge_request';
import { resetServiceWorkersPublicPath } from '../lib/utils/webpack';
export default function initMrNotes() { export default function initMrNotes() {
resetServiceWorkersPublicPath();
const mrShowNode = document.querySelector('.merge-request'); const mrShowNode = document.querySelector('.merge-request');
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new MergeRequest({ new MergeRequest({
... ...
......
...@@ -16,6 +16,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -16,6 +16,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :authenticate_user!, only: [:assign_related_issues] before_action :authenticate_user!, only: [:assign_related_issues]
before_action :check_user_can_push_to_source_branch!, only: [:rebase] before_action :check_user_can_push_to_source_branch!, only: [:rebase]
before_action only: [:show] do
push_frontend_feature_flag(:diff_tree_filtering, default_enabled: true)
end
def index def index
@merge_requests = @issuables @merge_requests = @issuables
... ...
......
...@@ -12,11 +12,14 @@ ...@@ -12,11 +12,14 @@
- mr_status_class = 'closed' - mr_status_class = 'closed'
- else - else
- mr_status_date = merge_request.created_at - mr_status_date = merge_request.created_at
- mr_status_title = _('Opened') - mr_status_title = mr_status_date ? _('Opened') : _('Open')
- mr_status_icon = 'issue-open-m' - mr_status_icon = 'issue-open-m'
- mr_status_class = 'open' - mr_status_class = 'open'
- if mr_status_date
- mr_status_tooltip = "<div><span class=\"bold\">#{mr_status_title}</span> #{time_ago_in_words(mr_status_date)} ago</div><span class=\"text-tertiary\">#{l(mr_status_date.to_time, format: time_format)}</span>" - mr_status_tooltip = "<div><span class=\"bold\">#{mr_status_title}</span> #{time_ago_in_words(mr_status_date)} ago</div><span class=\"text-tertiary\">#{l(mr_status_date.to_time, format: time_format)}</span>"
- else
- mr_status_tooltip = "<div><span class=\"bold\">#{mr_status_title}</span></div>"
%span.mr-status-wrapper.suggestion-help-hover{ class: css_class, data: { toggle: 'tooltip', placement: 'bottom', html: 'true', title: mr_status_tooltip } } %span.mr-status-wrapper.suggestion-help-hover{ class: css_class, data: { toggle: 'tooltip', placement: 'bottom', html: 'true', title: mr_status_tooltip } }
= sprite_icon(mr_status_icon, size: 16, css_class: "merge-request-status #{mr_status_class}") = sprite_icon(mr_status_icon, size: 16, css_class: "merge-request-status #{mr_status_class}")
# Container Registry API # Container Registry API
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/55978) in GitLab 11.8.
This is the API docs of the [GitLab Container Registry](../user/project/container_registry.md). This is the API docs of the [GitLab Container Registry](../user/project/container_registry.md).
## List registry repositories ## List registry repositories
...@@ -42,7 +44,7 @@ Example response: ...@@ -42,7 +44,7 @@ Example response:
## Delete registry repository ## Delete registry repository
Get a list of repository commits in a project. Delete a repository in registry.
This operation is executed asynchronously and might take some time to get executed. This operation is executed asynchronously and might take some time to get executed.
... ...
......
...@@ -128,7 +128,7 @@ Auto Deploy, and Auto Monitoring will be silently skipped. ...@@ -128,7 +128,7 @@ Auto Deploy, and Auto Monitoring will be silently skipped.
NOTE: **Note** NOTE: **Note**
`AUTO_DEVOPS_DOMAIN` environment variable is deprecated and `AUTO_DEVOPS_DOMAIN` environment variable is deprecated and
[is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959) in GitLab 12.0. [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959).
The Auto DevOps base domain is required if you want to make use of [Auto The Auto DevOps base domain is required if you want to make use of [Auto
Review Apps](#auto-review-apps) and [Auto Deploy](#auto-deploy). It can be defined Review Apps](#auto-review-apps) and [Auto Deploy](#auto-deploy). It can be defined
...@@ -211,8 +211,7 @@ other environments. ...@@ -211,8 +211,7 @@ other environments.
NOTE: **Note:** NOTE: **Note:**
From GitLab 11.8, `KUBE_INGRESS_BASE_DOMAIN` replaces `AUTO_DEVOPS_DOMAIN`. From GitLab 11.8, `KUBE_INGRESS_BASE_DOMAIN` replaces `AUTO_DEVOPS_DOMAIN`.
`AUTO_DEVOPS_DOMAIN` [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959) `AUTO_DEVOPS_DOMAIN` [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959).
in GitLab 12.0.
## Enabling/Disabling Auto DevOps ## Enabling/Disabling Auto DevOps
...@@ -685,7 +684,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac ...@@ -685,7 +684,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac
| **Variable** | **Description** | | **Variable** | **Description** |
| ------------ | --------------- | | ------------ | --------------- |
| `AUTO_DEVOPS_DOMAIN` | The [Auto DevOps domain](#auto-devops-domain). By default, set automatically by the [Auto DevOps setting](#enabling-auto-devops). This variable is deprecated and [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959) in GitLab 12.0. Use `KUBE_INGRESS_BASE_DOMAIN` instead. | | `AUTO_DEVOPS_DOMAIN` | The [Auto DevOps domain](#auto-devops-domain). By default, set automatically by the [Auto DevOps setting](#enabling-auto-devops). This variable is deprecated and [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959). Use `KUBE_INGRESS_BASE_DOMAIN` instead. |
| `AUTO_DEVOPS_CHART` | The Helm Chart used to deploy your apps; defaults to the one [provided by GitLab](https://gitlab.com/charts/auto-deploy-app). | | `AUTO_DEVOPS_CHART` | The Helm Chart used to deploy your apps; defaults to the one [provided by GitLab](https://gitlab.com/charts/auto-deploy-app). |
| `AUTO_DEVOPS_CHART_REPOSITORY` | The Helm Chart repository used to search for charts; defaults to `https://charts.gitlab.io`. | | `AUTO_DEVOPS_CHART_REPOSITORY` | The Helm Chart repository used to search for charts; defaults to `https://charts.gitlab.io`. |
| `REPLICAS` | The number of replicas to deploy; defaults to 1. | | `REPLICAS` | The number of replicas to deploy; defaults to 1. |
... ...
......
...@@ -4581,6 +4581,9 @@ msgstr "" ...@@ -4581,6 +4581,9 @@ msgstr ""
msgid "MergeRequest| %{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}" msgid "MergeRequest| %{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}"
msgstr "" msgstr ""
msgid "MergeRequest|Filter files"
msgstr ""
msgid "MergeRequest|No files found" msgid "MergeRequest|No files found"
msgstr "" msgstr ""
... ...
......
...@@ -26,7 +26,7 @@ module QA ...@@ -26,7 +26,7 @@ module QA
def choose_test_namespace def choose_test_namespace
click_element :project_namespace_select click_element :project_namespace_select
select_item(Runtime::Namespace.path) search_and_select(Runtime::Namespace.path)
end end
def go_to_import_project def go_to_import_project
... ...
......
# frozen_string_literal: true
require 'spec_helper'
describe 'projects/issues/_merge_requests_status.html.haml' do
it 'shows date of status change in tooltip' do
merge_request = create(:merge_request, created_at: 1.month.ago)
render partial: 'projects/issues/merge_requests_status',
locals: { merge_request: merge_request, css_class: '' }
expect(rendered).to match("Opened.*about 1 month ago")
end
it 'shows only status in tooltip if date is not set' do
merge_request = create(:merge_request, state: :closed)
render partial: 'projects/issues/merge_requests_status',
locals: { merge_request: merge_request, css_class: '' }
expect(rendered).to match("Closed")
end
end