summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-11-21 09:06:16 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-21 09:06:16 +0000
commita048261403ea7e12992ccffe704f0779235712d7 (patch)
tree59254549db6d39a4da824379a7bf354e7c8e7e67 /app
parent80e5134020483299c039114e76b734436f006c66 (diff)
downloadgitlab-ce-a048261403ea7e12992ccffe704f0779235712d7.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/autosave.js16
-rw-r--r--app/assets/javascripts/clusters/components/crossplane_provider_stack.vue10
-rw-r--r--app/assets/javascripts/issuable_form.js54
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js32
-rw-r--r--app/assets/javascripts/monitoring/components/graph_group.vue3
-rw-r--r--app/assets/javascripts/pages/projects/project.js24
-rw-r--r--app/models/diff_note.rb6
-rw-r--r--app/models/discussion.rb4
-rw-r--r--app/models/note.rb4
-rw-r--r--app/services/issuable/common_system_notes_service.rb26
-rw-r--r--app/services/issuable_base_service.rb14
-rw-r--r--app/services/notes/base_service.rb2
-rw-r--r--app/views/notify/_note_email.html.haml2
-rw-r--r--app/views/notify/_note_email.text.erb2
14 files changed, 131 insertions, 68 deletions
diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js
index 7652b67ae1e..07d79ea1c70 100644
--- a/app/assets/javascripts/autosave.js
+++ b/app/assets/javascripts/autosave.js
@@ -1,9 +1,9 @@
-/* eslint-disable no-param-reassign, no-void, consistent-return */
+/* eslint-disable no-param-reassign, consistent-return */
import AccessorUtilities from './lib/utils/accessor';
export default class Autosave {
- constructor(field, key) {
+ constructor(field, key, fallbackKey) {
this.field = field;
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
@@ -11,6 +11,7 @@ export default class Autosave {
key = key.join('/');
}
this.key = `autosave/${key}`;
+ this.fallbackKey = fallbackKey;
this.field.data('autosave', this);
this.restore();
this.field.on('input', () => this.save());
@@ -21,9 +22,12 @@ export default class Autosave {
if (!this.field.length) return;
const text = window.localStorage.getItem(this.key);
+ const fallbackText = window.localStorage.getItem(this.fallbackKey);
- if ((text != null ? text.length : void 0) > 0) {
+ if (text) {
this.field.val(text);
+ } else if (fallbackText) {
+ this.field.val(fallbackText);
}
this.field.trigger('input');
@@ -41,7 +45,10 @@ export default class Autosave {
const text = this.field.val();
- if (this.isLocalStorageAvailable && (text != null ? text.length : void 0) > 0) {
+ if (this.isLocalStorageAvailable && text) {
+ if (this.fallbackKey) {
+ window.localStorage.setItem(this.fallbackKey, text);
+ }
return window.localStorage.setItem(this.key, text);
}
@@ -51,6 +58,7 @@ export default class Autosave {
reset() {
if (!this.isLocalStorageAvailable) return;
+ window.localStorage.removeItem(this.fallbackKey);
return window.localStorage.removeItem(this.key);
}
diff --git a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
index 966918ae636..6b99bb09504 100644
--- a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
+++ b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
@@ -1,6 +1,5 @@
<script>
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import Icon from '~/vue_shared/components/icon.vue';
+import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui';
import { s__ } from '../../locale';
export default {
@@ -8,7 +7,7 @@ export default {
components: {
GlDropdown,
GlDropdownItem,
- Icon,
+ GlIcon,
},
props: {
stacks: {
@@ -86,8 +85,9 @@ export default {
href="https://crossplane.io/docs/master/stacks-guide.html"
target="_blank"
rel="noopener noreferrer"
- >{{ __('Crossplane') }}</a
- >
+ >{{ __('Crossplane') }}
+ <gl-icon name="external-link" class="vertical-align-middle" />
+ </a>
</p>
</div>
</template>
diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js
index 7576d36f27d..1d0807dc15d 100644
--- a/app/assets/javascripts/issuable_form.js
+++ b/app/assets/javascripts/issuable_form.js
@@ -6,6 +6,36 @@ import UsersSelect from './users_select';
import ZenMode from './zen_mode';
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
+import { queryToObject, objectToQuery } from './lib/utils/url_utility';
+
+function organizeQuery(obj, isFallbackKey = false) {
+ const sourceBranch = 'merge_request[source_branch]';
+ const targetBranch = 'merge_request[target_branch]';
+
+ if (isFallbackKey) {
+ return {
+ [sourceBranch]: obj[sourceBranch],
+ };
+ }
+
+ return {
+ [sourceBranch]: obj[sourceBranch],
+ [targetBranch]: obj[targetBranch],
+ };
+}
+
+function format(searchTerm, isFallbackKey = false) {
+ const queryObject = queryToObject(searchTerm);
+ const organizeQueryObject = organizeQuery(queryObject, isFallbackKey);
+ const formattedQuery = objectToQuery(organizeQueryObject);
+
+ return formattedQuery;
+}
+
+function getFallbackKey() {
+ const searchTerm = format(document.location.search, true);
+ return ['autosave', document.location.pathname, searchTerm].join('/');
+}
export default class IssuableForm {
constructor(form) {
@@ -57,16 +87,20 @@ export default class IssuableForm {
}
initAutosave() {
- this.autosave = new Autosave(this.titleField, [
- document.location.pathname,
- document.location.search,
- 'title',
- ]);
- return new Autosave(this.descriptionField, [
- document.location.pathname,
- document.location.search,
- 'description',
- ]);
+ const searchTerm = format(document.location.search);
+ const fallbackKey = getFallbackKey();
+
+ this.autosave = new Autosave(
+ this.titleField,
+ [document.location.pathname, searchTerm, 'title'],
+ `${fallbackKey}=title`,
+ );
+
+ return new Autosave(
+ this.descriptionField,
+ [document.location.pathname, searchTerm, 'description'],
+ `${fallbackKey}=description`,
+ );
}
handleSubmit() {
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 4be0d05a9b7..202a44d5694 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -181,4 +181,36 @@ export function getWebSocketUrl(path) {
return `${getWebSocketProtocol()}//${joinPaths(window.location.host, path)}`;
}
+/**
+ * Convert search query into an object
+ *
+ * @param {String} query from "document.location.search"
+ * @returns {Object}
+ *
+ * ex: "?one=1&two=2" into {one: 1, two: 2}
+ */
+export function queryToObject(query) {
+ const removeQuestionMarkFromQuery = String(query).startsWith('?') ? query.slice(1) : query;
+ return removeQuestionMarkFromQuery.split('&').reduce((accumulator, curr) => {
+ const p = curr.split('=');
+ accumulator[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ return accumulator;
+ }, {});
+}
+
+/**
+ * Convert search query object back into a search query
+ *
+ * @param {Object} obj that needs to be converted
+ * @returns {String}
+ *
+ * ex: {one: 1, two: 2} into "one=1&two=2"
+ *
+ */
+export function objectToQuery(obj) {
+ return Object.keys(obj)
+ .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`)
+ .join('&');
+}
+
export { joinPaths };
diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue
index 3cb6ccb64b1..e01324372a7 100644
--- a/app/assets/javascripts/monitoring/components/graph_group.vue
+++ b/app/assets/javascripts/monitoring/components/graph_group.vue
@@ -30,9 +30,6 @@ export default {
return this.collapseGroup && this.showGroup ? 'angle-down' : 'angle-right';
},
},
- created() {
- this.showGroup = this.collapseGroup;
- },
methods: {
collapse() {
this.showGroup = !this.showGroup;
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index 01acfca158f..739ae1cea16 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -1,4 +1,4 @@
-/* eslint-disable func-names, no-var, no-return-assign */
+/* eslint-disable func-names, no-return-assign */
import $ from 'jquery';
import Cookies from 'js-cookie';
@@ -90,19 +90,19 @@ export default class Project {
}
static initRefSwitcher() {
- var refListItem = document.createElement('li');
- var refLink = document.createElement('a');
+ const refListItem = document.createElement('li');
+ const refLink = document.createElement('a');
refLink.href = '#';
return $('.js-project-refs-dropdown').each(function() {
- var $dropdown = $(this);
- var selected = $dropdown.data('selected');
- var fieldName = $dropdown.data('fieldName');
- var shouldVisit = Boolean($dropdown.data('visit'));
- var $form = $dropdown.closest('form');
- var action = $form.attr('action');
- var linkTarget = mergeUrlParams(serializeForm($form[0]), action);
+ const $dropdown = $(this);
+ const selected = $dropdown.data('selected');
+ const fieldName = $dropdown.data('fieldName');
+ const shouldVisit = Boolean($dropdown.data('visit'));
+ const $form = $dropdown.closest('form');
+ const action = $form.attr('action');
+ const linkTarget = mergeUrlParams(serializeForm($form[0]), action);
return $dropdown.glDropdown({
data(term, callback) {
@@ -123,9 +123,9 @@ export default class Project {
inputFieldName: $dropdown.data('inputFieldName'),
fieldName,
renderRow(ref) {
- var li = refListItem.cloneNode(false);
+ const li = refListItem.cloneNode(false);
- var link = refLink.cloneNode(false);
+ const link = refLink.cloneNode(false);
if (ref === selected) {
link.className = 'is-active';
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 65e87bb08a7..0623ba746c2 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -88,10 +88,6 @@ class DiffNote < Note
line&.suggestible?
end
- def discussion_first_note?
- self == discussion.first_note
- end
-
def banzai_render_context(field)
super.merge(suggestions_filter_enabled: true)
end
@@ -108,7 +104,7 @@ class DiffNote < Note
end
def should_create_diff_file?
- on_text? && note_diff_file.nil? && discussion_first_note?
+ on_text? && note_diff_file.nil? && start_of_discussion?
end
def fetch_diff_file
diff --git a/app/models/discussion.rb b/app/models/discussion.rb
index b8525f7b135..d0a7db39a30 100644
--- a/app/models/discussion.rb
+++ b/app/models/discussion.rb
@@ -139,10 +139,6 @@ class Discussion
false
end
- def new_discussion?
- notes.length == 1
- end
-
def last_note
@last_note ||= notes.last
end
diff --git a/app/models/note.rb b/app/models/note.rb
index ce60413b8a0..1996fd4bff5 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -409,6 +409,10 @@ class Note < ApplicationRecord
full_discussion || to_discussion
end
+ def start_of_discussion?
+ discussion.first_note == self
+ end
+
def part_of_discussion?
!to_discussion.individual_note?
end
diff --git a/app/services/issuable/common_system_notes_service.rb b/app/services/issuable/common_system_notes_service.rb
index a170a4dcae2..846b881e819 100644
--- a/app/services/issuable/common_system_notes_service.rb
+++ b/app/services/issuable/common_system_notes_service.rb
@@ -7,20 +7,24 @@ module Issuable
def execute(issuable, old_labels: [], is_update: true)
@issuable = issuable
- if is_update
- if issuable.previous_changes.include?('title')
- create_title_change_note(issuable.previous_changes['title'].first)
+ # We disable touch so that created system notes do not update
+ # the noteable's updated_at field
+ ActiveRecord::Base.no_touching do
+ if is_update
+ if issuable.previous_changes.include?('title')
+ create_title_change_note(issuable.previous_changes['title'].first)
+ end
+
+ handle_description_change_note
+
+ handle_time_tracking_note if issuable.is_a?(TimeTrackable)
+ create_discussion_lock_note if issuable.previous_changes.include?('discussion_locked')
end
- handle_description_change_note
-
- handle_time_tracking_note if issuable.is_a?(TimeTrackable)
- create_discussion_lock_note if issuable.previous_changes.include?('discussion_locked')
+ create_due_date_note if issuable.previous_changes.include?('due_date')
+ create_milestone_note if issuable.previous_changes.include?('milestone_id')
+ create_labels_note(old_labels) if old_labels && issuable.labels != old_labels
end
-
- create_due_date_note if issuable.previous_changes.include?('due_date')
- create_milestone_note if issuable.previous_changes.include?('milestone_id')
- create_labels_note(old_labels) if old_labels && issuable.labels != old_labels
end
private
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 200eca0e43c..bb65a8f402d 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -164,9 +164,7 @@ class IssuableBaseService < BaseService
before_create(issuable)
if issuable.save
- ActiveRecord::Base.no_touching do
- Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, is_update: false)
- end
+ Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, is_update: false)
after_create(issuable)
execute_hooks(issuable)
@@ -227,10 +225,7 @@ class IssuableBaseService < BaseService
ensure_milestone_available(issuable)
if issuable.with_transaction_returning_status { issuable.save(touch: should_touch) }
- # We do not touch as it will affect a update on updated_at field
- ActiveRecord::Base.no_touching do
- Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: old_associations[:labels])
- end
+ Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: old_associations[:labels])
handle_changes(issuable, old_associations: old_associations)
@@ -264,10 +259,7 @@ class IssuableBaseService < BaseService
before_update(issuable, skip_spam_check: true)
if issuable.with_transaction_returning_status { issuable.save }
- # We do not touch as it will affect a update on updated_at field
- ActiveRecord::Base.no_touching do
- Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: nil)
- end
+ Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: nil)
handle_task_changes(issuable)
invalidate_cache_counts(issuable, users: issuable.assignees.to_a)
diff --git a/app/services/notes/base_service.rb b/app/services/notes/base_service.rb
index b4d04c47cc0..87f7cb0e8ac 100644
--- a/app/services/notes/base_service.rb
+++ b/app/services/notes/base_service.rb
@@ -4,7 +4,7 @@ module Notes
class BaseService < ::BaseService
def clear_noteable_diffs_cache(note)
if note.is_a?(DiffNote) &&
- note.discussion_first_note? &&
+ note.start_of_discussion? &&
note.position.unfolded_diff?(project.repository)
note.noteable.diffs.clear_cache
end
diff --git a/app/views/notify/_note_email.html.haml b/app/views/notify/_note_email.html.haml
index dc5529b489b..c558358725c 100644
--- a/app/views/notify/_note_email.html.haml
+++ b/app/views/notify/_note_email.html.haml
@@ -11,7 +11,7 @@
- if discussion.nil?
commented
- else
- - if discussion.new_discussion?
+ - if note.start_of_discussion?
started a new
- else
commented on a
diff --git a/app/views/notify/_note_email.text.erb b/app/views/notify/_note_email.text.erb
index a25daad8458..8e2f7e6f76e 100644
--- a/app/views/notify/_note_email.text.erb
+++ b/app/views/notify/_note_email.text.erb
@@ -7,7 +7,7 @@
<% if discussion.nil? -%>
<%= 'commented' -%>:
<% else -%>
-<% if discussion.new_discussion? -%>
+<% if note.start_of_discussion? -%>
<%= 'started a new discussion' -%>
<% else -%>
<%= 'commented on a discussion' -%>