Commit b7bfa9d4 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 40df9a8a a2e9af71
......@@ -179,9 +179,9 @@ const Api = {
});
},
groupLabels(namespace) {
groupLabels(namespace, options = {}) {
const url = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespace);
return axios.get(url).then(({ data }) => data);
return axios.get(url, options).then(({ data }) => data);
},
// Return namespaces list. Filtered by query
......
......@@ -139,6 +139,12 @@ export default {
<div class="issuable-main-info">
<div data-testid="issuable-title" class="issue-title title">
<span class="issue-title-text" dir="auto">
<gl-icon
v-if="issuable.confidential"
v-gl-tooltip
name="eye-slash"
:title="__('Confidential')"
/>
<gl-link :href="issuable.webUrl" v-bind="issuableTitleProps"
>{{ issuable.title
}}<gl-icon v-if="isIssuableUrlExternal" name="external-link" class="gl-ml-2"
......
......@@ -230,7 +230,7 @@ export default {
:initial-sort-by="initialSortBy"
:show-checkbox="showBulkEditSidebar"
:checkbox-checked="allIssuablesChecked"
class="gl-flex-grow-1 row-content-block"
class="gl-flex-grow-1 gl-border-t-none row-content-block"
@checked-input="handleAllIssuablesCheckedInput"
@onFilter="$emit('filter', $event)"
@onSort="$emit('sort', $event)"
......
......@@ -32,7 +32,10 @@ export default {
<template>
<div class="top-area">
<gl-tabs class="nav-links mobile-separator issuable-state-filters">
<gl-tabs
class="gl-display-flex gl-flex-fill-1 gl-p-0 gl-m-0 mobile-separator issuable-state-filters"
nav-class="gl-border-b-0"
>
<gl-tab
v-for="tab in tabs"
:key="tab.id"
......@@ -41,7 +44,7 @@ export default {
>
<template #title>
<span :title="tab.titleTooltip">{{ tab.title }}</span>
<gl-badge v-if="tabCounts" variant="neutral" size="sm" class="gl-px-2 gl-py-1!">{{
<gl-badge v-if="tabCounts" variant="neutral" size="sm" class="gl-tab-counter-badge">{{
tabCounts[tab.name]
}}</gl-badge>
</template>
......
......@@ -475,6 +475,15 @@
}
}
.sort-dropdown-container {
// This property is set to have borders
// around sort dropdown match with filter
// input field.
.gl-button {
box-shadow: inset 0 0 0 1px $gray-400;
}
}
@include media-breakpoint-up(md) {
.sort-dropdown-container {
margin-left: 10px;
......
......@@ -20,6 +20,10 @@ module RuboCop
(def :down ...)
PATTERN
def_node_matcher :set_text_limit?, <<~PATTERN
(send _ :text_limit ...)
PATTERN
def_node_matcher :add_text_limit?, <<~PATTERN
(send _ :add_text_limit ...)
PATTERN
......@@ -111,20 +115,31 @@ module RuboCop
limit_found = false
node.each_descendant(:send) do |send_node|
next unless add_text_limit?(send_node)
limit_table = send_node.children[2].value
limit_attribute = send_node.children[3].value
if limit_table == table_name && limit_attribute == attribute_name
limit_found = true
break
if set_text_limit?(send_node)
limit_found = matching_set_text_limit?(send_node, attribute_name)
elsif add_text_limit?(send_node)
limit_found = matching_add_text_limit?(send_node, table_name, attribute_name)
end
break if limit_found
end
!limit_found
end
def matching_set_text_limit?(send_node, attribute_name)
limit_attribute = send_node.children[2].value
limit_attribute == attribute_name
end
def matching_add_text_limit?(send_node, table_name, attribute_name)
limit_table = send_node.children[2].value
limit_attribute = send_node.children[3].value
limit_table == table_name && limit_attribute == attribute_name
end
def encrypted_attribute_name?(attribute_name)
attribute_name.to_s.start_with?('encrypted_')
end
......
......@@ -19,7 +19,7 @@ module RuboCop
# or through a create/alter table (TABLE_METHODS)
ADD_COLUMN_METHODS = %i(add_column add_column_with_default change_column_type_concurrently).freeze
TABLE_METHODS = %i(create_table create_table_if_not_exists change_table).freeze
TABLE_METHODS = %i(create_table create_table_if_not_exists change_table create_table_with_constraints).freeze
def high_traffic_tables
@high_traffic_tables ||= rubocop_migrations_config.dig('Migration/UpdateLargeTable', 'HighTrafficTables')
......
......@@ -260,6 +260,28 @@ describe('Api', () => {
});
});
describe('groupLabels', () => {
it('fetches group labels', (done) => {
const options = { params: { search: 'foo' } };
const expectedGroup = 'gitlab-org';
const expectedUrl = `${dummyUrlRoot}/groups/${expectedGroup}/-/labels`;
mock.onGet(expectedUrl).reply(httpStatus.OK, [
{
id: 1,
title: 'Foo Label',
},
]);
Api.groupLabels(expectedGroup, options)
.then((res) => {
expect(res.length).toBe(1);
expect(res[0].title).toBe('Foo Label');
})
.then(done)
.catch(done.fail);
});
});
describe('namespaces', () => {
it('fetches namespaces', (done) => {
const query = 'dummy query';
......
......@@ -257,6 +257,23 @@ describe('IssuableItem', () => {
);
});
it('renders issuable confidential icon when issuable is confidential', async () => {
wrapper.setProps({
issuable: {
...mockIssuable,
confidential: true,
},
});
await wrapper.vm.$nextTick();
const confidentialEl = wrapper.find('[data-testid="issuable-title"]').find(GlIcon);
expect(confidentialEl.exists()).toBe(true);
expect(confidentialEl.props('name')).toBe('eye-slash');
expect(confidentialEl.attributes('title')).toBe('Confidential');
});
it('renders issuable reference', () => {
const referenceEl = wrapper.find('[data-testid="issuable-reference"]');
......
import Vue from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import { removeBreakLine } from 'helpers/text_helper';
import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue';
import { shallowMount, mount } from '@vue/test-utils';
import PipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue';
describe('MRWidgetPipelineBlocked', () => {
let vm;
beforeEach(() => {
const Component = Vue.extend(pipelineBlockedComponent);
vm = mountComponent(Component);
});
let wrapper;
const createWrapper = (mountFn = shallowMount) => {
wrapper = mountFn(PipelineBlockedComponent);
};
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
it('renders warning icon', () => {
expect(vm.$el.querySelector('.ci-status-icon-warning')).not.toBe(null);
createWrapper(mount);
expect(wrapper.find('.ci-status-icon-warning').exists()).toBe(true);
});
it('renders information text', () => {
expect(removeBreakLine(vm.$el.textContent).trim()).toContain(
createWrapper();
expect(wrapper.text()).toBe(
'Pipeline blocked. The pipeline for this merge request requires a manual action to proceed',
);
});
......
......@@ -28,6 +28,15 @@ RSpec.describe RuboCop::Cop::Migration::AddLimitToTextColumns do
^^^^ #{described_class::MSG}
end
create_table_with_constraints :test_text_limits_create do |t|
t.integer :test_id, null: false
t.text :title
t.text :description
^^^^ #{described_class::MSG}
t.text_limit :title, 100
end
add_column :test_text_limits, :email, :text
^^^^^^^^^^ #{described_class::MSG}
......@@ -57,6 +66,15 @@ RSpec.describe RuboCop::Cop::Migration::AddLimitToTextColumns do
t.text :name
end
create_table_with_constraints :test_text_limits_create do |t|
t.integer :test_id, null: false
t.text :title
t.text :description
t.text_limit :title, 100
t.text_limit :description, 255
end
add_column :test_text_limits, :email, :text
add_column_with_default :test_text_limits, :role, :text, default: 'default'
change_column_type_concurrently :test_text_limits, :test_id, :text
......
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