Commit 00124398 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 83d8c1d6
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
GlDropdownItem, GlDropdownItem,
GlFormGroup, GlFormGroup,
GlModal, GlModal,
GlSearchBoxByType,
GlModalDirective, GlModalDirective,
GlTooltipDirective, GlTooltipDirective,
} from '@gitlab/ui'; } from '@gitlab/ui';
...@@ -15,6 +16,7 @@ import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue'; ...@@ -15,6 +16,7 @@ import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import createFlash from '~/flash'; import createFlash from '~/flash';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { getParameterValues, mergeUrlParams, redirectTo } from '~/lib/utils/url_utility'; import { getParameterValues, mergeUrlParams, redirectTo } from '~/lib/utils/url_utility';
import invalidUrl from '~/lib/utils/invalid_url'; import invalidUrl from '~/lib/utils/invalid_url';
...@@ -38,6 +40,7 @@ export default { ...@@ -38,6 +40,7 @@ export default {
GlButton, GlButton,
GlDropdown, GlDropdown,
GlDropdownItem, GlDropdownItem,
GlSearchBoxByType,
GlFormGroup, GlFormGroup,
GlModal, GlModal,
...@@ -52,6 +55,7 @@ export default { ...@@ -52,6 +55,7 @@ export default {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
TrackEvent: TrackEventDirective, TrackEvent: TrackEventDirective,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
externalDashboardUrl: { externalDashboardUrl: {
type: String, type: String,
...@@ -198,13 +202,12 @@ export default { ...@@ -198,13 +202,12 @@ export default {
'dashboard', 'dashboard',
'emptyState', 'emptyState',
'showEmptyState', 'showEmptyState',
'environments',
'deploymentData', 'deploymentData',
'useDashboardEndpoint', 'useDashboardEndpoint',
'allDashboards', 'allDashboards',
'additionalPanelTypesEnabled', 'additionalPanelTypesEnabled',
]), ]),
...mapGetters('monitoringDashboard', ['getMetricStates']), ...mapGetters('monitoringDashboard', ['getMetricStates', 'filteredEnvironments']),
firstDashboard() { firstDashboard() {
return this.environmentsEndpoint.length > 0 && this.allDashboards.length > 0 return this.environmentsEndpoint.length > 0 && this.allDashboards.length > 0
? this.allDashboards[0] ? this.allDashboards[0]
...@@ -227,6 +230,9 @@ export default { ...@@ -227,6 +230,9 @@ export default {
this.externalDashboardUrl.length this.externalDashboardUrl.length
); );
}, },
shouldRenderSearchableEnvironmentsDropdown() {
return this.glFeatures.searchableEnvironmentsDropdown;
},
}, },
created() { created() {
this.setEndpoints({ this.setEndpoints({
...@@ -255,6 +261,7 @@ export default { ...@@ -255,6 +261,7 @@ export default {
'setGettingStartedEmptyState', 'setGettingStartedEmptyState',
'setEndpoints', 'setEndpoints',
'setPanelGroupMetrics', 'setPanelGroupMetrics',
'setEnvironmentsSearchTerm',
]), ]),
updatePanels(key, panels) { updatePanels(key, panels) {
this.setPanelGroupMetrics({ this.setPanelGroupMetrics({
...@@ -296,6 +303,9 @@ export default { ...@@ -296,6 +303,9 @@ export default {
setFormValidity(isValid) { setFormValidity(isValid) {
this.formIsValid = isValid; this.formIsValid = isValid;
}, },
debouncedEnvironmentsSearch: _.debounce(function environmentsSearchOnInput(searchTerm) {
this.setEnvironmentsSearchTerm(searchTerm);
}, 500),
submitCustomMetricsForm() { submitCustomMetricsForm() {
this.$refs.customMetricsForm.submit(); this.$refs.customMetricsForm.submit();
}, },
...@@ -374,17 +384,36 @@ export default { ...@@ -374,17 +384,36 @@ export default {
data-qa-selector="environments_dropdown" data-qa-selector="environments_dropdown"
class="mb-0 d-flex" class="mb-0 d-flex"
toggle-class="dropdown-menu-toggle" toggle-class="dropdown-menu-toggle"
menu-class="monitor-environment-dropdown-menu"
:text="currentEnvironmentName" :text="currentEnvironmentName"
:disabled="environments.length === 0" :disabled="filteredEnvironments.length === 0"
> >
<gl-dropdown-item <div class="d-flex flex-column overflow-hidden">
v-for="environment in environments" <gl-search-box-by-type
:key="environment.id" v-if="shouldRenderSearchableEnvironmentsDropdown"
:active="environment.name === currentEnvironmentName" ref="monitorEnvironmentsDropdownSearch"
active-class="is-active" class="m-2"
:href="environment.metrics_path" @input="debouncedEnvironmentsSearch"
>{{ environment.name }}</gl-dropdown-item />
> <div class="flex-fill overflow-auto">
<gl-dropdown-item
v-for="environment in filteredEnvironments"
:key="environment.id"
:active="environment.name === currentEnvironmentName"
active-class="is-active"
:href="environment.metrics_path"
>{{ environment.name }}</gl-dropdown-item
>
</div>
<div
v-if="shouldRenderSearchableEnvironmentsDropdown"
v-show="filteredEnvironments.length === 0"
ref="monitorEnvironmentsDropdownMsg"
class="text-secondary no-matches-message"
>
{{ s__('No matching results') }}
</div>
</div>
</gl-dropdown> </gl-dropdown>
</gl-form-group> </gl-form-group>
...@@ -415,18 +444,16 @@ export default { ...@@ -415,18 +444,16 @@ export default {
variant="default" variant="default"
class="mr-2 mt-1 js-rearrange-button" class="mr-2 mt-1 js-rearrange-button"
@click="toggleRearrangingPanels" @click="toggleRearrangingPanels"
>{{ __('Arrange charts') }}</gl-button
> >
{{ __('Arrange charts') }}
</gl-button>
<gl-button <gl-button
v-if="addingMetricsAvailable" v-if="addingMetricsAvailable"
ref="addMetricBtn" ref="addMetricBtn"
v-gl-modal="$options.addMetric.modalId" v-gl-modal="$options.addMetric.modalId"
variant="outline-success" variant="outline-success"
class="mr-2 mt-1" class="mr-2 mt-1"
>{{ $options.addMetric.title }}</gl-button
> >
{{ $options.addMetric.title }}
</gl-button>
<gl-modal <gl-modal
v-if="addingMetricsAvailable" v-if="addingMetricsAvailable"
ref="addMetricModal" ref="addMetricModal"
...@@ -448,9 +475,8 @@ export default { ...@@ -448,9 +475,8 @@ export default {
:disabled="!formIsValid" :disabled="!formIsValid"
variant="success" variant="success"
@click="submitCustomMetricsForm" @click="submitCustomMetricsForm"
>{{ __('Save changes') }}</gl-button
> >
{{ __('Save changes') }}
</gl-button>
</div> </div>
</gl-modal> </gl-modal>
...@@ -458,9 +484,8 @@ export default { ...@@ -458,9 +484,8 @@ export default {
v-if="selectedDashboard.can_edit" v-if="selectedDashboard.can_edit"
class="mt-1 js-edit-link" class="mt-1 js-edit-link"
:href="selectedDashboard.project_blob_path" :href="selectedDashboard.project_blob_path"
>{{ __('Edit dashboard') }}</gl-button
> >
{{ __('Edit dashboard') }}
</gl-button>
<gl-button <gl-button
v-if="externalDashboardUrl.length" v-if="externalDashboardUrl.length"
...@@ -506,9 +531,9 @@ export default { ...@@ -506,9 +531,9 @@ export default {
class="draggable-remove js-draggable-remove p-2 w-100 position-absolute d-flex justify-content-end" class="draggable-remove js-draggable-remove p-2 w-100 position-absolute d-flex justify-content-end"
@click="removePanel(groupData.key, groupData.panels, graphIndex)" @click="removePanel(groupData.key, groupData.panels, graphIndex)"
> >
<a class="mx-2 p-2 draggable-remove-link" :aria-label="__('Remove')" <a class="mx-2 p-2 draggable-remove-link" :aria-label="__('Remove')">
><icon name="close" <icon name="close" />
/></a> </a>
</div> </div>
<panel-type <panel-type
......
...@@ -30,6 +30,10 @@ export const setEndpoints = ({ commit }, endpoints) => { ...@@ -30,6 +30,10 @@ export const setEndpoints = ({ commit }, endpoints) => {
commit(types.SET_ENDPOINTS, endpoints); commit(types.SET_ENDPOINTS, endpoints);
}; };
export const setEnvironmentsSearchTerm = ({ commit }, searchTerm) => {
commit(types.SET_ENVIRONMENTS_SEARCH_TERM, searchTerm);
};
export const setShowErrorBanner = ({ commit }, enabled) => { export const setShowErrorBanner = ({ commit }, enabled) => {
commit(types.SET_SHOW_ERROR_BANNER, enabled); commit(types.SET_SHOW_ERROR_BANNER, enabled);
}; };
......
...@@ -58,5 +58,20 @@ export const metricsWithData = state => groupKey => { ...@@ -58,5 +58,20 @@ export const metricsWithData = state => groupKey => {
return res; return res;
}; };
/**
* Filter environments by names.
*
* This is used in the environments dropdown with searchable input.
* Also, this searchable dropdown is behind `searchable_environments_dropdown`
* feature flag
*
* @param {Object} state
* @returns {Array} List of environments
*/
export const filteredEnvironments = state =>
state.environments.filter(env =>
env.name.toLowerCase().includes((state.environmentsSearchTerm || '').trim().toLowerCase()),
);
// prevent babel-plugin-rewire from generating an invalid default during karma tests // prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {}; export default () => {};
...@@ -21,3 +21,5 @@ export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE' ...@@ -21,3 +21,5 @@ export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE'
export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE'; export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE';
export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER'; export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER';
export const SET_PANEL_GROUP_METRICS = 'SET_PANEL_GROUP_METRICS'; export const SET_PANEL_GROUP_METRICS = 'SET_PANEL_GROUP_METRICS';
export const SET_ENVIRONMENTS_SEARCH_TERM = 'SET_ENVIRONMENTS_SEARCH_TERM';
...@@ -196,4 +196,7 @@ export default { ...@@ -196,4 +196,7 @@ export default {
const panelGroup = state.dashboard.panel_groups.find(pg => payload.key === pg.key); const panelGroup = state.dashboard.panel_groups.find(pg => payload.key === pg.key);
panelGroup.panels = payload.panels; panelGroup.panels = payload.panels;
}, },
[types.SET_ENVIRONMENTS_SEARCH_TERM](state, searchTerm) {
state.environmentsSearchTerm = searchTerm;
},
}; };
...@@ -15,6 +15,7 @@ export default () => ({ ...@@ -15,6 +15,7 @@ export default () => ({
deploymentData: [], deploymentData: [],
environments: [], environments: [],
environmentsSearchTerm: '',
allDashboards: [], allDashboards: [],
currentDashboard: null, currentDashboard: null,
projectPath: null, projectPath: null,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
max-width: 900px; max-width: 900px;
&.navless-container { &.navless-container {
padding: 35px $gl-padding;
// overriding .devise-layout-html.navless-container to support the sticky footer // overriding .devise-layout-html.navless-container to support the sticky footer
// without having a header on size xs // without having a header on size xs
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
.signup-heading h2 { .signup-heading h2 {
font-weight: $gl-font-weight-bold; font-weight: $gl-font-weight-bold;
padding: 0 $gl-padding; padding: 0 $gl-padding;
font-size: $gl-font-size-28;
@include media-breakpoint-down(md) { @include media-breakpoint-down(md) {
font-size: $gl-font-size-large; font-size: $gl-font-size-large;
...@@ -49,4 +51,35 @@ ...@@ -49,4 +51,35 @@
color: $red-700; color: $red-700;
} }
} }
.omniauth-divider {
&::before,
&::after {
content: '';
flex: 1;
border-bottom: 1px solid $gray-dark;
margin: $gl-padding-24 0;
}
&::before {
margin-right: $gl-padding;
}
&::after {
margin-left: $gl-padding;
}
}
.omniauth-btn {
width: 48%;
@include media-breakpoint-down(md) {
width: 100%;
}
img {
width: $default-icon-size;
height: $default-icon-size;
}
}
} }
...@@ -58,6 +58,18 @@ ...@@ -58,6 +58,18 @@
.custom-time-range-form-group > label { .custom-time-range-form-group > label {
padding-bottom: $gl-padding; padding-bottom: $gl-padding;
} }
.monitor-environment-dropdown-menu {
&.show {
display: flex;
flex-direction: column;
overflow: hidden;
}
.no-matches-message {
padding: $gl-padding-8 $gl-padding-12;
}
}
} }
.prometheus-panel { .prometheus-panel {
......
...@@ -14,6 +14,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -14,6 +14,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? } before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? }
before_action only: [:metrics, :additional_metrics, :metrics_dashboard] do before_action only: [:metrics, :additional_metrics, :metrics_dashboard] do
push_frontend_feature_flag(:prometheus_computed_alerts) push_frontend_feature_flag(:prometheus_computed_alerts)
push_frontend_feature_flag(:searchable_environments_dropdown)
end end
before_action do before_action do
push_frontend_feature_flag(:auto_stop_environments) push_frontend_feature_flag(:auto_stop_environments)
......
...@@ -89,7 +89,17 @@ module AuthHelper ...@@ -89,7 +89,17 @@ module AuthHelper
def enabled_button_based_providers def enabled_button_based_providers
disabled_providers = Gitlab::CurrentSettings.disabled_oauth_sign_in_sources || [] disabled_providers = Gitlab::CurrentSettings.disabled_oauth_sign_in_sources || []
button_based_providers.map(&:to_s) - disabled_providers providers = button_based_providers.map(&:to_s) - disabled_providers
providers.sort_by do |provider|
case provider
when 'google_oauth2'
0
when 'github'
1
else
2
end
end
end end
def button_based_providers_enabled? def button_based_providers_enabled?
......
...@@ -394,6 +394,11 @@ class User < ApplicationRecord ...@@ -394,6 +394,11 @@ class User < ApplicationRecord
Gitlab::CurrentSettings.minimum_password_length..Devise.password_length.max Gitlab::CurrentSettings.minimum_password_length..Devise.password_length.max
end end
# Generate a random password that conforms to the current password length settings
def random_password
Devise.friendly_token(password_length.max)
end
# Devise method overridden to allow sign in with email or username # Devise method overridden to allow sign in with email or username
def find_for_database_authentication(warden_conditions) def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup conditions = warden_conditions.dup
......
...@@ -38,13 +38,9 @@ module Metrics ...@@ -38,13 +38,9 @@ module Metrics
# Determines whether users should be able to view # Determines whether users should be able to view
# dashboards at all. # dashboards at all.
def allowed? def allowed?
if params[:environment] return false unless params[:environment]
Ability.allowed?(current_user, :read_environment, project)
elsif params[:cluster] Ability.allowed?(current_user, :read_environment, project)
true # Authorization handled at controller level
else
false
end
end end
# Returns a new dashboard Hash, supplemented with DB info # Returns a new dashboard Hash, supplemented with DB info
......
...@@ -23,7 +23,7 @@ module Users ...@@ -23,7 +23,7 @@ module Users
@reset_token = user.generate_reset_token if params[:reset_password] @reset_token = user.generate_reset_token if params[:reset_password]
if user_params[:force_random_password] if user_params[:force_random_password]
random_password = Devise.friendly_token.first(User.password_length.min) random_password = User.random_password
user.password = user.password_confirmation = random_password user.password = user.password_confirmation = random_password
end end
end end
......
...@@ -41,3 +41,5 @@ ...@@ -41,3 +41,5 @@
= recaptcha_tags = recaptcha_tags
.submit-container.mt-3 .submit-container.mt-3
= f.submit _("Register"), class: "btn-register btn btn-block btn-success mb-0 p-2", data: { qa_selector: 'new_user_register_button' } = f.submit _("Register"), class: "btn-register btn btn-block btn-success mb-0 p-2", data: { qa_selector: 'new_user_register_button' }
- if omniauth_enabled? && button_based_providers_enabled?
= render 'devise/shared/experimental_separate_sign_up_flow_omniauth_box'
.omniauth-divider.d-flex.align-items-center.text-center
= _("or")
%label.label-bold.d-block
= _("Create an account using:")
- providers = enabled_button_based_providers
.d-flex.justify-content-between.flex-wrap
- providers.each do |provider|
- has_icon = provider_has_icon?(provider)
= link_to omniauth_authorize_path(:user, provider), method: :post, class: "btn d-flex align-items-center omniauth-btn text-left oauth-login mb-2 p-2 #{qa_class_for_provider(provider)}", id: "oauth-login-#{provider}" do
- if has_icon
= provider_image_tag(provider)
%span.ml-2
= label_for_provider(provider)
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
= render "layouts/broadcast" = render "layouts/broadcast"
.content .content
= render "layouts/flash" = render "layouts/flash"
.row.mb-3 .row.mb-6
.col-sm-8.offset-sm-2.col-md-6.offset-md-3.new-session-forms-container .col-sm-8.offset-sm-2.col-md-6.offset-md-3.new-session-forms-container
= render_if_exists 'layouts/devise_help_text' = render_if_exists 'layouts/devise_help_text'
.text-center.signup-heading.mt-3.mb-3 .text-center.signup-heading.mb-3
= image_tag(image_url('logo.svg'), class: 'gitlab-logo', alt: 'GitLab Logo') = image_tag(image_url('logo.svg'), class: 'gitlab-logo', alt: 'GitLab Logo')
- if content_for?(:page_title) - if content_for?(:page_title)
%h2= yield :page_title %h2= yield :page_title
......
---
title: Fixes random passwords generated not conforming to minimum_password_length setting
merge_request: 23387
author:
type: fixed
---
title: Reorder signup omniauth options
merge_request: 23082
author:
type: changed
...@@ -34,7 +34,7 @@ module Gitlab ...@@ -34,7 +34,7 @@ module Gitlab
end end
def password def password
@password ||= Gitlab::Utils.force_utf8(Devise.friendly_token[0, 8].downcase) @password ||= Gitlab::Utils.force_utf8(::User.random_password.downcase)
end end
def location def location
......
...@@ -5361,6 +5361,9 @@ msgstr "" ...@@ -5361,6 +5361,9 @@ msgstr ""
msgid "Create a personal access token on your account to pull or push via %{protocol}." msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "" msgstr ""
msgid "Create an account using:"
msgstr ""
msgid "Create an issue" msgid "Create an issue"
msgstr "" msgstr ""
...@@ -22721,6 +22724,9 @@ msgstr "" ...@@ -22721,6 +22724,9 @@ msgstr ""
msgid "opened %{timeAgo}" msgid "opened %{timeAgo}"
msgstr "" msgstr ""
msgid "or"
msgstr ""
msgid "out of %d total test" msgid "out of %d total test"
msgid_plural "out of %d total tests" msgid_plural "out of %d total tests"
msgstr[0] "" msgstr[0] ""
......
...@@ -28,6 +28,15 @@ describe('Dashboard', () => { ...@@ -28,6 +28,15 @@ describe('Dashboard', () => {
let wrapper; let wrapper;
let mock; let mock;
const findEnvironmentsDropdown = () => wrapper.find({ ref: 'monitorEnvironmentsDropdown' });
const findAllEnvironmentsDropdownItems = () => findEnvironmentsDropdown().findAll(GlDropdownItem);
const setSearchTerm = searchTerm => {
wrapper.vm.$store.commit(
`monitoringDashboard/${types.SET_ENVIRONMENTS_SEARCH_TERM}`,
searchTerm,
);
};
const createShallowWrapper = (props = {}, options = {}) => { const createShallowWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(Dashboard, { wrapper = shallowMount(Dashboard, {
localVue, localVue,
...@@ -52,9 +61,6 @@ describe('Dashboard', () => { ...@@ -52,9 +61,6 @@ describe('Dashboard', () => {
}); });
}; };
const findEnvironmentsDropdown = () => wrapper.find({ ref: 'monitorEnvironmentsDropdown' });
const findAllEnvironmentsDropdownItems = () => findEnvironmentsDropdown().findAll(GlDropdownItem);
beforeEach(() => { beforeEach(() => {
store = createStore(); store = createStore();
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
...@@ -155,12 +161,9 @@ describe('Dashboard', () => { ...@@ -155,12 +161,9 @@ describe('Dashboard', () => {
wrapper.vm wrapper.vm
.$nextTick() .$nextTick()
.then(() => { .then(() => {
const environmentDropdownItems = findAllEnvironmentsDropdownItems(); expect(findAllEnvironmentsDropdownItems().length).toEqual(environmentData.length);
expect(wrapper.vm.environments.length).toEqual(environmentData.length); findAllEnvironmentsDropdownItems().wrappers.forEach((itemWrapper, index) => {
expect(environmentDropdownItems.length).toEqual(wrapper.vm.environments.length);
environmentDropdownItems.wrappers.forEach((itemWrapper, index) => {
const anchorEl = itemWrapper.find('a'); const anchorEl = itemWrapper.find('a');
if (anchorEl.exists() && environmentData[index].metrics_path) { if (anchorEl.exists() && environmentData[index].metrics_path) {
const href = anchorEl.attributes('href'); const href = anchorEl.attributes('href');
...@@ -248,6 +251,70 @@ describe('Dashboard', () => { ...@@ -248,6 +251,70 @@ describe('Dashboard', () => {
}); });
}); });
describe('searchable environments dropdown', () => {
beforeEach(() => {
createMountedWrapper(
{ hasMetrics: true },
{
attachToDocument: true,
stubs: ['graph-group', 'panel-type'],
provide: {
glFeatures: { searchableEnvironmentsDropdown: true },
},
},
);
setupComponentStore(wrapper);
return wrapper.vm.$nextTick();
});
afterEach(() => {
wrapper.destroy();
});
it('renders a search input', () => {
expect(wrapper.find({ ref: 'monitorEnvironmentsDropdownSearch' }).exists()).toBe(true);
});
it('renders dropdown items', () => {
findAllEnvironmentsDropdownItems().wrappers.forEach((itemWrapper, index) => {
const anchorEl = itemWrapper.find('a');
if (anchorEl.exists()) {
expect(anchorEl.text()).toBe(environmentData[index].name);
}
});
});
it('filters rendered dropdown items', () => {
const searchTerm = 'production';
const resultEnvs = environmentData.filter(({ name }) => name.indexOf(searchTerm) !== -1);
setSearchTerm(searchTerm);
return wrapper.vm.$nextTick(() => {
expect(findAllEnvironmentsDropdownItems().length).toEqual(resultEnvs.length);
});
});
it('does not filter dropdown items if search term is empty string', () => {
const searchTerm = '';
setSearchTerm(searchTerm);
return wrapper.vm.$nextTick(() => {
expect(findAllEnvironmentsDropdownItems().length).toEqual(environmentData.length);
});
});
it("shows error message if search term doesn't match", () => {
const searchTerm = 'does-not-exist';
setSearchTerm(searchTerm);
return wrapper.vm.$nextTick(() => {
expect(wrapper.find({ ref: 'monitorEnvironmentsDropdownMsg' }).isVisible()).toBe(true);
});
});
});
describe('drag and drop function', () => { describe('drag and drop function', () => {
const findDraggables = () => wrapper.findAll(VueDraggable); const findDraggables = () => wrapper.findAll(VueDraggable);
const findEnabledDraggables = () => findDraggables().filter(f => !f.attributes('disabled')); const findEnabledDraggables = () => findDraggables().filter(f => !f.attributes('disabled'));
......
...@@ -331,6 +331,14 @@ export const mockedQueryResultPayloadCoresTotal = { ...@@ -331,6 +331,14 @@ export const mockedQueryResultPayloadCoresTotal = {
], ],
}; };
const extraEnvironmentData = new Array(15).fill(null).map((_, idx) => ({
id: 136 + idx,
name: `no-deployment/noop-branch-${idx}`,
state: 'available',
created_at: '2018-07-04T18:39:41.702Z',
updated_at: '2018-07-04T18:44:54.010Z',
}));
export const environmentData = [ export const environmentData = [
{ {
id: 34, id: 34,
...@@ -368,14 +376,7 @@ export const environmentData = [ ...@@ -368,14 +376,7 @@ export const environmentData = [
id: 128, id: 128,
}, },
}, },
{ ].concat(extraEnvironmentData);
id: 36,
name: 'no-deployment/noop-branch',
state: 'available',
created_at: '2018-07-04T18:39:41.702Z',
updated_at: '2018-07-04T18:44:54.010Z',
},
];
export const metricsDashboardResponse = { export const metricsDashboardResponse = {
dashboard: { dashboard: {
......
...@@ -3,6 +3,7 @@ import mutations from '~/monitoring/stores/mutations'; ...@@ -3,6 +3,7 @@ import mutations from '~/monitoring/stores/mutations';
import * as types from '~/monitoring/stores/mutation_types'; import * as types from '~/monitoring/stores/mutation_types';
import { metricStates } from '~/monitoring/constants'; import { metricStates } from '~/monitoring/constants';
import { import {
environmentData,
metricsDashboardPayload, metricsDashboardPayload,
mockedEmptyResult, mockedEmptyResult,
mockedQueryResultPayload, mockedQueryResultPayload,
...@@ -214,4 +215,58 @@ describe('Monitoring store Getters', () => { ...@@ -214,4 +215,58 @@ describe('Monitoring store Getters', () => {
}); });
}); });
}); });
describe('filteredEnvironments', () => {
let state;
const setupState = (initState = {}) => {
state = {
...state,
...initState,
};
};
beforeAll(() => {
setupState({
environments: environmentData,
});
});
afterAll(() => {
state = null;
});
[
{
input: '',
output: 17,
},
{
input: ' ',
output: 17,
},
{
input: null,
output: 17,
},
{
input: 'does-not-exist',
output: 0,
},
{
input: 'noop-branch-',
output: 15,
},
{
input: 'noop-branch-9',
output: 1,
},
].forEach(({ input, output }) => {
it(`filteredEnvironments returns ${output} items for ${input}`, () => {
setupState({
environmentsSearchTerm: input,
});
expect(getters.filteredEnvironments(state).length).toBe(output);
});
});
});
}); });
...@@ -73,12 +73,17 @@ describe AuthHelper do ...@@ -73,12 +73,17 @@ describe AuthHelper do
describe 'enabled_button_based_providers' do describe 'enabled_button_based_providers' do
before do before do
allow(helper).to receive(:auth_providers) { [:twitter, :github] } allow(helper).to receive(:auth_providers) { [:twitter, :github, :google_oauth2] }
end end
context 'all providers are enabled to sign in' do context 'all providers are enabled to sign in' do
it 'returns all the enabled providers from settings' do it 'returns all the enabled providers from settings' do
expect(helper.enabled_button_based_providers).to include('twitter', 'github') expect(helper.enabled_button_based_providers).to include('twitter', 'github', 'google_oauth2')
end
it 'puts google and github in the beginning' do
expect(helper.enabled_button_based_providers.first).to eq('google_oauth2')
expect(helper.enabled_button_based_providers.second).to eq('github')
end end
end end
......
...@@ -139,6 +139,18 @@ describe Gitlab::Auth::LDAP::User do ...@@ -139,6 +139,18 @@ describe Gitlab::Auth::LDAP::User do
expect(gl_user).to be_confirmed expect(gl_user).to be_confirmed
end end
end end
context 'when the current minimum password length is different from the default minimum password length' do
before do
stub_application_setting minimum_password_length: 21
end
it 'creates the user' do
ldap_user.save
expect(gl_user).to be_persisted
end
end
end end
describe 'updating email' do describe 'updating email' do
......
...@@ -86,6 +86,20 @@ describe Gitlab::Auth::OAuth::User do ...@@ -86,6 +86,20 @@ describe Gitlab::Auth::OAuth::User do
end end
end end
context 'when the current minimum password length is different from the default minimum password length' do
before do
stub_application_setting minimum_password_length: 21
end
it 'creates the user' do
stub_omniauth_config(allow_single_sign_on: [provider])
oauth_user.save
expect(gl_user).to be_persisted
end
end
it 'marks user as having password_automatically_set' do it 'marks user as having password_automatically_set' do
stub_omniauth_config(allow_single_sign_on: [provider], external_providers: [provider]) stub_omniauth_config(allow_single_sign_on: [provider], external_providers: [provider])
......
...@@ -325,6 +325,18 @@ describe Gitlab::Auth::Saml::User do ...@@ -325,6 +325,18 @@ describe Gitlab::Auth::Saml::User do
expect(gl_user).to be_confirmed expect(gl_user).to be_confirmed
end end
end end
context 'when the current minimum password length is different from the default minimum password length' do
before do
stub_application_setting minimum_password_length: 21
end
it 'creates the user' do
saml_user.save
expect(gl_user).to be_persisted
end
end
end end
describe 'blocking' do describe 'blocking' do
......
...@@ -508,6 +508,20 @@ describe User, :do_not_mock_admin_mode do ...@@ -508,6 +508,20 @@ describe User, :do_not_mock_admin_mode do
end end
end end
describe '.random_password' do
let(:random_password) { described_class.random_password }
before do
expect(User).to receive(:password_length).and_return(88..128)
end
context 'length' do
it 'conforms to the current password length settings' do
expect(random_password.length).to eq(128)
end
end
end
describe '.password_length' do describe '.password_length' do
let(:password_length) { described_class.password_length } let(:password_length) { described_class.password_length }
......
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