Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-01-22 12:08:53 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-01-22 12:08:53 +0300
commit4dff02cf71591bd7ab47e44f3e1f2206f61c06eb (patch)
tree70a7286bbc624c264a06c6693f5e94ebede93dd0 /app/assets
parent16e3c34cac856092627cc41a8a9d9c69f3b26c03 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/boards/components/board_card.vue3
-rw-r--r--app/assets/javascripts/boards/components/board_card_layout.vue24
-rw-r--r--app/assets/javascripts/boards/components/board_card_layout_deprecated.vue102
-rw-r--r--app/assets/javascripts/boards/components/board_configuration_options.vue6
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue1
-rw-r--r--app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue12
-rw-r--r--app/assets/javascripts/boards/graphql/project_milestones.query.graphql (renamed from app/assets/javascripts/boards/graphql/group_milestones.query.graphql)6
-rw-r--r--app/assets/javascripts/boards/stores/actions.js11
-rw-r--r--app/assets/javascripts/boards/stores/mutation_types.js2
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js12
-rw-r--r--app/assets/javascripts/boards/stores/state.js1
-rw-r--r--app/assets/javascripts/notes/components/toggle_replies_widget.vue21
-rw-r--r--app/assets/javascripts/pages/search/show/index.js4
-rw-r--r--app/assets/javascripts/pages/search/show/search.js54
-rw-r--r--app/assets/javascripts/search/highlight_blob_search_result.js4
-rw-r--r--app/assets/javascripts/search/index.js11
-rw-r--r--app/assets/javascripts/search/topbar/components/app.vue73
-rw-r--r--app/assets/javascripts/search/topbar/components/group_filter.vue1
-rw-r--r--app/assets/javascripts/search/topbar/components/project_filter.vue1
-rw-r--r--app/assets/javascripts/search/topbar/components/searchable_dropdown.vue2
-rw-r--r--app/assets/javascripts/search/topbar/index.js31
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue5
-rw-r--r--app/assets/stylesheets/pages/notes.scss19
23 files changed, 266 insertions, 140 deletions
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue
index 31050eef83d..4d3ce50275b 100644
--- a/app/assets/javascripts/boards/components/board_card.vue
+++ b/app/assets/javascripts/boards/components/board_card.vue
@@ -1,5 +1,6 @@
<script>
import BoardCardLayout from './board_card_layout.vue';
+import BoardCardLayoutDeprecated from './board_card_layout_deprecated.vue';
import eventHub from '../eventhub';
import sidebarEventHub from '~/sidebar/event_hub';
import boardsStore from '../stores/boards_store';
@@ -7,7 +8,7 @@ import boardsStore from '../stores/boards_store';
export default {
name: 'BoardsIssueCard',
components: {
- BoardCardLayout,
+ BoardCardLayout: gon.features?.graphqlBoardLists ? BoardCardLayout : BoardCardLayoutDeprecated,
},
props: {
list: {
diff --git a/app/assets/javascripts/boards/components/board_card_layout.vue b/app/assets/javascripts/boards/components/board_card_layout.vue
index 0a2301394c1..9a2cd10a361 100644
--- a/app/assets/javascripts/boards/components/board_card_layout.vue
+++ b/app/assets/javascripts/boards/components/board_card_layout.vue
@@ -1,17 +1,13 @@
<script>
-import { mapActions, mapGetters } from 'vuex';
+import { mapActions, mapGetters, mapState } from 'vuex';
import IssueCardInner from './issue_card_inner.vue';
-import IssueCardInnerDeprecated from './issue_card_inner_deprecated.vue';
-import boardsStore from '../stores/boards_store';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ISSUABLE } from '~/boards/constants';
export default {
name: 'BoardCardLayout',
components: {
- IssueCardInner: gon.features?.graphqlBoardLists ? IssueCardInner : IssueCardInnerDeprecated,
+ IssueCardInner,
},
- mixins: [glFeatureFlagMixin()],
props: {
list: {
type: Object,
@@ -42,17 +38,17 @@ export default {
data() {
return {
showDetail: false,
- multiSelect: boardsStore.multiSelect,
};
},
computed: {
+ ...mapState(['selectedBoardItems']),
...mapGetters(['isSwimlanesOn']),
multiSelectVisible() {
- return this.multiSelect.list.findIndex((issue) => issue.id === this.issue.id) > -1;
+ return this.selectedBoardItems.findIndex((boardItem) => boardItem.id === this.issue.id) > -1;
},
},
methods: {
- ...mapActions(['setActiveId']),
+ ...mapActions(['setActiveId', 'toggleBoardItemMultiSelection']),
mouseDown() {
this.showDetail = true;
},
@@ -63,16 +59,16 @@ export default {
// Don't do anything if this happened on a no trigger element
if (e.target.classList.contains('js-no-trigger')) return;
- if (this.glFeatures.graphqlBoardLists || this.isSwimlanesOn) {
+ const isMultiSelect = e.ctrlKey || e.metaKey;
+
+ if (!isMultiSelect) {
this.setActiveId({ id: this.issue.id, sidebarType: ISSUABLE });
- return;
+ } else {
+ this.toggleBoardItemMultiSelection(this.issue);
}
- const isMultiSelect = e.ctrlKey || e.metaKey;
-
if (this.showDetail || isMultiSelect) {
this.showDetail = false;
- this.$emit('show', { event: e, isMultiSelect });
}
},
},
diff --git a/app/assets/javascripts/boards/components/board_card_layout_deprecated.vue b/app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
new file mode 100644
index 00000000000..0a2301394c1
--- /dev/null
+++ b/app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
@@ -0,0 +1,102 @@
+<script>
+import { mapActions, mapGetters } from 'vuex';
+import IssueCardInner from './issue_card_inner.vue';
+import IssueCardInnerDeprecated from './issue_card_inner_deprecated.vue';
+import boardsStore from '../stores/boards_store';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { ISSUABLE } from '~/boards/constants';
+
+export default {
+ name: 'BoardCardLayout',
+ components: {
+ IssueCardInner: gon.features?.graphqlBoardLists ? IssueCardInner : IssueCardInnerDeprecated,
+ },
+ mixins: [glFeatureFlagMixin()],
+ props: {
+ list: {
+ type: Object,
+ default: () => ({}),
+ required: false,
+ },
+ issue: {
+ type: Object,
+ default: () => ({}),
+ required: false,
+ },
+ disabled: {
+ type: Boolean,
+ default: false,
+ required: false,
+ },
+ index: {
+ type: Number,
+ default: 0,
+ required: false,
+ },
+ isActive: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ showDetail: false,
+ multiSelect: boardsStore.multiSelect,
+ };
+ },
+ computed: {
+ ...mapGetters(['isSwimlanesOn']),
+ multiSelectVisible() {
+ return this.multiSelect.list.findIndex((issue) => issue.id === this.issue.id) > -1;
+ },
+ },
+ methods: {
+ ...mapActions(['setActiveId']),
+ mouseDown() {
+ this.showDetail = true;
+ },
+ mouseMove() {
+ this.showDetail = false;
+ },
+ showIssue(e) {
+ // Don't do anything if this happened on a no trigger element
+ if (e.target.classList.contains('js-no-trigger')) return;
+
+ if (this.glFeatures.graphqlBoardLists || this.isSwimlanesOn) {
+ this.setActiveId({ id: this.issue.id, sidebarType: ISSUABLE });
+ return;
+ }
+
+ const isMultiSelect = e.ctrlKey || e.metaKey;
+
+ if (this.showDetail || isMultiSelect) {
+ this.showDetail = false;
+ this.$emit('show', { event: e, isMultiSelect });
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <li
+ :class="{
+ 'multi-select': multiSelectVisible,
+ 'user-can-drag': !disabled && issue.id,
+ 'is-disabled': disabled || !issue.id,
+ 'is-active': isActive,
+ }"
+ :index="index"
+ :data-issue-id="issue.id"
+ :data-issue-iid="issue.iid"
+ :data-issue-path="issue.referencePath"
+ data-testid="board_card"
+ class="board-card gl-p-5 gl-rounded-base"
+ @mousedown="mouseDown"
+ @mousemove="mouseMove"
+ @mouseup="showIssue($event)"
+ >
+ <issue-card-inner :list="list" :issue="issue" :update-filters="true" />
+ </li>
+</template>
diff --git a/app/assets/javascripts/boards/components/board_configuration_options.vue b/app/assets/javascripts/boards/components/board_configuration_options.vue
index b8ee930a8c9..4d79f2a4bc6 100644
--- a/app/assets/javascripts/boards/components/board_configuration_options.vue
+++ b/app/assets/javascripts/boards/components/board_configuration_options.vue
@@ -14,6 +14,10 @@ export default {
type: Boolean,
required: true,
},
+ readonly: {
+ type: Boolean,
+ required: true,
+ },
},
};
</script>
@@ -28,12 +32,14 @@ export default {
</p>
<gl-form-checkbox
:checked="!hideBacklogList"
+ :disabled="readonly"
data-testid="backlog-list-checkbox"
@change="$emit('update:hideBacklogList', !hideBacklogList)"
>{{ __('Show the Open list') }}
</gl-form-checkbox>
<gl-form-checkbox
:checked="!hideClosedList"
+ :disabled="readonly"
data-testid="closed-list-checkbox"
@change="$emit('update:hideClosedList', !hideClosedList)"
>{{ __('Show the Closed list') }}
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index c701ecd3040..f9a81746851 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -308,6 +308,7 @@ export default {
<board-configuration-options
:hide-backlog-list.sync="board.hide_backlog_list"
:hide-closed-list.sync="board.hide_closed_list"
+ :readonly="readonly"
/>
<board-scope
diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
index ef7b4a83b47..cb702bb5781 100644
--- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
+++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_milestone_select.vue
@@ -8,9 +8,8 @@ import {
GlDropdownDivider,
GlLoadingIcon,
} from '@gitlab/ui';
-import { fetchPolicies } from '~/lib/graphql';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
-import groupMilestones from '../../graphql/group_milestones.query.graphql';
+import projectMilestones from '../../graphql/project_milestones.query.graphql';
import createFlash from '~/flash';
import { __, s__ } from '~/locale';
@@ -34,22 +33,21 @@ export default {
},
apollo: {
milestones: {
- fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
- query: groupMilestones,
+ query: projectMilestones,
debounce: 250,
skip() {
return !this.edit;
},
variables() {
return {
- fullPath: this.groupFullPath,
+ fullPath: this.projectPath,
searchTitle: this.searchTitle,
state: 'active',
- includeDescendants: true,
+ includeAncestors: true,
};
},
update(data) {
- const edges = data?.group?.milestones?.edges ?? [];
+ const edges = data?.project?.milestones?.edges ?? [];
return edges.map((item) => item.node);
},
error() {
diff --git a/app/assets/javascripts/boards/graphql/group_milestones.query.graphql b/app/assets/javascripts/boards/graphql/project_milestones.query.graphql
index f2ab12ef4a7..776530ebb83 100644
--- a/app/assets/javascripts/boards/graphql/group_milestones.query.graphql
+++ b/app/assets/javascripts/boards/graphql/project_milestones.query.graphql
@@ -1,11 +1,11 @@
query groupMilestones(
$fullPath: ID!
$state: MilestoneStateEnum
- $includeDescendants: Boolean
+ $includeAncestors: Boolean
$searchTitle: String
) {
- group(fullPath: $fullPath) {
- milestones(state: $state, includeDescendants: $includeDescendants, searchTitle: $searchTitle) {
+ project(fullPath: $fullPath) {
+ milestones(state: $state, includeAncestors: $includeAncestors, searchTitle: $searchTitle) {
edges {
node {
id
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index 585e0615e90..f51cc547f32 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -534,6 +534,17 @@ export default {
commit(types.SET_SELECTED_PROJECT, project);
},
+ toggleBoardItemMultiSelection: ({ commit, state }, boardItem) => {
+ const { selectedBoardItems } = state;
+ const index = selectedBoardItems.indexOf(boardItem);
+
+ if (index === -1) {
+ commit(types.ADD_BOARD_ITEM_TO_SELECTION, boardItem);
+ } else {
+ commit(types.REMOVE_BOARD_ITEM_FROM_SELECTION, boardItem);
+ }
+ },
+
fetchBacklog: () => {
notImplemented();
},
diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js
index 2db754b7ac8..443c3461012 100644
--- a/app/assets/javascripts/boards/stores/mutation_types.js
+++ b/app/assets/javascripts/boards/stores/mutation_types.js
@@ -40,3 +40,5 @@ export const REQUEST_GROUP_PROJECTS = 'REQUEST_GROUP_PROJECTS';
export const RECEIVE_GROUP_PROJECTS_SUCCESS = 'RECEIVE_GROUP_PROJECTS_SUCCESS';
export const RECEIVE_GROUP_PROJECTS_FAILURE = 'RECEIVE_GROUP_PROJECTS_FAILURE';
export const SET_SELECTED_PROJECT = 'SET_SELECTED_PROJECT';
+export const ADD_BOARD_ITEM_TO_SELECTION = 'ADD_BOARD_ITEM_TO_SELECTION';
+export const REMOVE_BOARD_ITEM_FROM_SELECTION = 'REMOVE_BOARD_ITEM_FROM_SELECTION';
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index 76476fce5a3..82a0ba578dc 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -258,4 +258,16 @@ export default {
[mutationTypes.SET_SELECTED_PROJECT]: (state, project) => {
state.selectedProject = project;
},
+
+ [mutationTypes.ADD_BOARD_ITEM_TO_SELECTION]: (state, boardItem) => {
+ state.selectedBoardItems = [...state.selectedBoardItems, boardItem];
+ },
+
+ [mutationTypes.REMOVE_BOARD_ITEM_FROM_SELECTION]: (state, boardItem) => {
+ Vue.set(
+ state,
+ 'selectedBoardItems',
+ state.selectedBoardItems.filter((obj) => obj !== boardItem),
+ );
+ },
};
diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js
index 215195a2a4f..d2e10fbf29b 100644
--- a/app/assets/javascripts/boards/stores/state.js
+++ b/app/assets/javascripts/boards/stores/state.js
@@ -15,6 +15,7 @@ export default () => ({
filterParams: {},
boardConfig: {},
labels: [],
+ selectedBoardItems: [],
groupProjects: [],
groupProjectsFlags: {
isLoading: false,
diff --git a/app/assets/javascripts/notes/components/toggle_replies_widget.vue b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
index ab7fa793bdc..06de3104a47 100644
--- a/app/assets/javascripts/notes/components/toggle_replies_widget.vue
+++ b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
@@ -39,13 +39,17 @@ export default {
this.$emit('toggle');
},
},
+ ICON_CLASS: 'gl-mr-3 gl-cursor-pointer',
};
</script>
<template>
- <li :class="className" class="replies-toggle js-toggle-replies">
+ <li
+ :class="className"
+ class="replies-toggle js-toggle-replies gl-display-flex! gl-align-items-center gl-flex-wrap"
+ >
<template v-if="collapsed">
- <gl-icon name="chevron-right" @click.native="toggle" />
+ <gl-icon :class="$options.ICON_CLASS" name="chevron-right" @click.native="toggle" />
<div>
<user-avatar-link
v-for="author in uniqueAuthors"
@@ -59,7 +63,7 @@ export default {
/>
</div>
<gl-button
- class="js-replies-text"
+ class="js-replies-text gl-mr-2"
category="tertiary"
variant="link"
data-qa-selector="expand_replies_button"
@@ -68,18 +72,19 @@ export default {
{{ replies.length }} {{ n__('reply', 'replies', replies.length) }}
</gl-button>
{{ __('Last reply by') }}
- <a :href="lastReply.author.path" class="btn btn-link author-link">
+ <a :href="lastReply.author.path" class="btn btn-link author-link gl-mx-2">
{{ lastReply.author.name }}
</a>
<time-ago-tooltip :time="lastReply.created_at" tooltip-placement="bottom" />
</template>
- <span
+ <div
v-else
- class="collapse-replies-btn js-collapse-replies"
+ class="collapse-replies-btn js-collapse-replies gl-display-flex align-items-center"
data-qa-selector="collapse_replies_button"
@click="toggle"
>
- <gl-icon name="chevron-down" /> {{ s__('Notes|Collapse replies') }}
- </span>
+ <gl-icon :class="$options.ICON_CLASS" name="chevron-down" />
+ <span class="gl-cursor-pointer">{{ s__('Notes|Collapse replies') }}</span>
+ </div>
</li>
</template>
diff --git a/app/assets/javascripts/pages/search/show/index.js b/app/assets/javascripts/pages/search/show/index.js
index b6171e08e01..a8c288c3663 100644
--- a/app/assets/javascripts/pages/search/show/index.js
+++ b/app/assets/javascripts/pages/search/show/index.js
@@ -1,7 +1,5 @@
-import Search from './search';
import { initSearchApp } from '~/search';
document.addEventListener('DOMContentLoaded', () => {
- initSearchApp(); // Vue Bootstrap
- return new Search(); // Legacy Search Methods
+ initSearchApp();
});
diff --git a/app/assets/javascripts/pages/search/show/search.js b/app/assets/javascripts/pages/search/show/search.js
deleted file mode 100644
index cbef5ab1bbc..00000000000
--- a/app/assets/javascripts/pages/search/show/search.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import $ from 'jquery';
-import setHighlightClass from 'ee_else_ce/search/highlight_blob_search_result';
-import Project from '~/pages/projects/project';
-import { visitUrl } from '~/lib/utils/url_utility';
-import refreshCounts from './refresh_counts';
-
-export default class Search {
- constructor() {
- this.searchInput = '.js-search-input';
- this.searchClear = '.js-search-clear';
-
- setHighlightClass(); // Code Highlighting
- this.eventListeners(); // Search Form Actions
- refreshCounts(); // Other Scope Tab Counts
- Project.initRefSwitcher(); // Code Search Branch Picker
- }
-
- eventListeners() {
- $(document).off('keyup', this.searchInput).on('keyup', this.searchInput, this.searchKeyUp);
- $(document)
- .off('click', this.searchClear)
- .on('click', this.searchClear, this.clearSearchField.bind(this));
-
- $('a.js-search-clear').off('click', this.clearSearchFilter).on('click', this.clearSearchFilter);
- }
-
- static submitSearch() {
- return $('.js-search-form').submit();
- }
-
- searchKeyUp() {
- const $input = $(this);
- if ($input.val() === '') {
- $('.js-search-clear').addClass('hidden');
- } else {
- $('.js-search-clear').removeClass('hidden');
- }
- }
-
- clearSearchField() {
- return $(this.searchInput).val('').trigger('keyup').focus();
- }
-
- // We need to manually follow the link on the anchors
- // that have this event bound, as their `click` default
- // behavior is prevented by the toggle logic.
- /* eslint-disable-next-line class-methods-use-this */
- clearSearchFilter(ev) {
- const $target = $(ev.currentTarget);
-
- visitUrl($target.href);
- ev.stopPropagation();
- }
-}
diff --git a/app/assets/javascripts/search/highlight_blob_search_result.js b/app/assets/javascripts/search/highlight_blob_search_result.js
index 3c3ac3582d0..c553d5b14a0 100644
--- a/app/assets/javascripts/search/highlight_blob_search_result.js
+++ b/app/assets/javascripts/search/highlight_blob_search_result.js
@@ -1,7 +1,7 @@
-export default () => {
+export default (search = '') => {
const highlightLineClass = 'hll';
const contentBody = document.getElementById('content-body');
- const searchTerm = contentBody.querySelector('.js-search-input').value.toLowerCase();
+ const searchTerm = search.toLowerCase();
const blobs = contentBody.querySelectorAll('.blob-result');
blobs.forEach((blob) => {
diff --git a/app/assets/javascripts/search/index.js b/app/assets/javascripts/search/index.js
index d2bb1ccfc44..0674bff2795 100644
--- a/app/assets/javascripts/search/index.js
+++ b/app/assets/javascripts/search/index.js
@@ -1,3 +1,6 @@
+import setHighlightClass from 'ee_else_ce/search/highlight_blob_search_result';
+import Project from '~/pages/projects/project';
+import refreshCounts from '~/pages/search/show/refresh_counts';
import { queryToObject } from '~/lib/utils/url_utility';
import createStore from './store';
import { initTopbar } from './topbar';
@@ -7,8 +10,14 @@ export const initSearchApp = () => {
// Similar to url_utility.decodeUrlParameter
// Our query treats + as %20. This replaces the query + symbols with %20.
const sanitizedSearch = window.location.search.replace(/\+/g, '%20');
- const store = createStore({ query: queryToObject(sanitizedSearch) });
+ const query = queryToObject(sanitizedSearch);
+
+ const store = createStore({ query });
initTopbar(store);
initSidebar(store);
+
+ setHighlightClass(query.search); // Code Highlighting
+ refreshCounts(); // Other Scope Tab Counts
+ Project.initRefSwitcher(); // Code Search Branch Picker
};
diff --git a/app/assets/javascripts/search/topbar/components/app.vue b/app/assets/javascripts/search/topbar/components/app.vue
new file mode 100644
index 00000000000..8c9c4e58722
--- /dev/null
+++ b/app/assets/javascripts/search/topbar/components/app.vue
@@ -0,0 +1,73 @@
+<script>
+import { mapState, mapActions } from 'vuex';
+import { GlForm, GlSearchBoxByType, GlButton } from '@gitlab/ui';
+import GroupFilter from './group_filter.vue';
+import ProjectFilter from './project_filter.vue';
+
+export default {
+ name: 'GlobalSearchTopbar',
+ components: {
+ GlForm,
+ GlSearchBoxByType,
+ GroupFilter,
+ ProjectFilter,
+ GlButton,
+ },
+ props: {
+ groupInitialData: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ projectInitialData: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ },
+ computed: {
+ ...mapState(['query']),
+ search: {
+ get() {
+ return this.query ? this.query.search : '';
+ },
+ set(value) {
+ this.setQuery({ key: 'search', value });
+ },
+ },
+ showFilters() {
+ return !this.query.snippets || this.query.snippets === 'false';
+ },
+ },
+ methods: {
+ ...mapActions(['applyQuery', 'setQuery']),
+ },
+};
+</script>
+
+<template>
+ <gl-form class="search-page-form" @submit.prevent="applyQuery">
+ <section class="gl-display-lg-flex gl-align-items-flex-end">
+ <div class="gl-flex-fill-1 gl-mb-4 gl-lg-mb-0 gl-lg-mr-2">
+ <label>{{ __('What are you searching for?') }}</label>
+ <gl-search-box-by-type
+ id="dashboard_search"
+ v-model="search"
+ name="search"
+ :placeholder="__(`Search for projects, issues, etc.`)"
+ />
+ </div>
+ <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-2">
+ <label class="gl-display-block">{{ __('Group') }}</label>
+ <group-filter :initial-data="groupInitialData" />
+ </div>
+ <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-2">
+ <label class="gl-display-block">{{ __('Project') }}</label>
+ <project-filter :initial-data="projectInitialData" />
+ </div>
+ <gl-button class="btn-search gl-lg-ml-2" variant="success" type="submit">{{
+ __('Search')
+ }}</gl-button>
+ </section>
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/search/topbar/components/group_filter.vue b/app/assets/javascripts/search/topbar/components/group_filter.vue
index fce9ec17d23..efd753270f6 100644
--- a/app/assets/javascripts/search/topbar/components/group_filter.vue
+++ b/app/assets/javascripts/search/topbar/components/group_filter.vue
@@ -37,6 +37,7 @@ export default {
<template>
<searchable-dropdown
+ data-testid="group-filter"
:header-text="$options.GROUP_DATA.headerText"
:selected-display-value="$options.GROUP_DATA.selectedDisplayValue"
:items-display-value="$options.GROUP_DATA.itemsDisplayValue"
diff --git a/app/assets/javascripts/search/topbar/components/project_filter.vue b/app/assets/javascripts/search/topbar/components/project_filter.vue
index effaafb72c1..52d5073cb07 100644
--- a/app/assets/javascripts/search/topbar/components/project_filter.vue
+++ b/app/assets/javascripts/search/topbar/components/project_filter.vue
@@ -40,6 +40,7 @@ export default {
<template>
<searchable-dropdown
+ data-testid="project-filter"
:header-text="$options.PROJECT_DATA.headerText"
:selected-display-value="$options.PROJECT_DATA.selectedDisplayValue"
:items-display-value="$options.PROJECT_DATA.itemsDisplayValue"
diff --git a/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue b/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue
index 14577fd7d7a..5fb7217db74 100644
--- a/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue
+++ b/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue
@@ -101,7 +101,7 @@ export default {
@keydown.enter.stop="resetDropdown"
@click.stop="resetDropdown"
>
- <gl-icon name="clear" class="gl-text-gray-200! gl-hover-text-blue-800!" />
+ <gl-icon name="clear" />
</gl-button>
<gl-icon name="chevron-down" />
</template>
diff --git a/app/assets/javascripts/search/topbar/index.js b/app/assets/javascripts/search/topbar/index.js
index f0308109b32..87316e10e8d 100644
--- a/app/assets/javascripts/search/topbar/index.js
+++ b/app/assets/javascripts/search/topbar/index.js
@@ -1,44 +1,31 @@
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
-import GroupFilter from './components/group_filter.vue';
-import ProjectFilter from './components/project_filter.vue';
+import GlobalSearchTopbar from './components/app.vue';
Vue.use(Translate);
-const mountSearchableDropdown = (store, { id, component }) => {
- const el = document.getElementById(id);
+export const initTopbar = (store) => {
+ const el = document.getElementById('js-search-topbar');
if (!el) {
return false;
}
- let { initialData } = el.dataset;
+ let { groupInitialData, projectInitialData } = el.dataset;
- initialData = JSON.parse(initialData);
+ groupInitialData = JSON.parse(groupInitialData);
+ projectInitialData = JSON.parse(projectInitialData);
return new Vue({
el,
store,
render(createElement) {
- return createElement(component, {
+ return createElement(GlobalSearchTopbar, {
props: {
- initialData,
+ groupInitialData,
+ projectInitialData,
},
});
},
});
};
-
-const searchableDropdowns = [
- {
- id: 'js-search-group-dropdown',
- component: GroupFilter,
- },
- {
- id: 'js-search-project-dropdown',
- component: ProjectFilter,
- },
-];
-
-export const initTopbar = (store) =>
- searchableDropdowns.map((dropdown) => mountSearchableDropdown(store, dropdown));
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index b6e167524aa..40b5cc688ff 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -110,11 +110,6 @@ export default {
return this.referencedUsers.length >= referencedUsersThreshold;
},
lineContent() {
- const [firstSuggestion] = this.suggestions;
- if (firstSuggestion) {
- return firstSuggestion.from_content;
- }
-
if (this.line) {
const { rich_text: richText, text } = this.line;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 4216091e8a9..e05e71d9105 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -91,29 +91,10 @@ $note-form-margin-left: 72px;
color: $blue-600;
}
- &.expanded {
- span {
- cursor: pointer;
- }
-
- svg {
- position: relative;
- top: 3px;
- }
- }
-
&.collapsed {
color: $gl-text-color-secondary;
border-radius: 0 0 $border-radius-default $border-radius-default;
- svg {
- float: left;
- position: relative;
- top: $gl-padding-4;
- margin-right: $gl-padding-8;
- cursor: pointer;
- }
-
img {
margin: -2px 4px 0 0;
}