Commit 311342ae authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '344918-replace-the-runner-active-state-with-a-new-filter-paused' into 'master'

Replace runners 'active' filters with 'paused'

See merge request gitlab-org/gitlab!83865
parents 9a228147 65f2450e
...@@ -16,6 +16,7 @@ import RunnerPagination from '../components/runner_pagination.vue'; ...@@ -16,6 +16,7 @@ import RunnerPagination from '../components/runner_pagination.vue';
import RunnerTypeTabs from '../components/runner_type_tabs.vue'; import RunnerTypeTabs from '../components/runner_type_tabs.vue';
import RunnerActionsCell from '../components/cells/runner_actions_cell.vue'; import RunnerActionsCell from '../components/cells/runner_actions_cell.vue';
import { pausedTokenConfig } from '../components/search_tokens/paused_token_config';
import { statusTokenConfig } from '../components/search_tokens/status_token_config'; import { statusTokenConfig } from '../components/search_tokens/status_token_config';
import { tagTokenConfig } from '../components/search_tokens/tag_token_config'; import { tagTokenConfig } from '../components/search_tokens/tag_token_config';
import { import {
...@@ -178,6 +179,7 @@ export default { ...@@ -178,6 +179,7 @@ export default {
}, },
searchTokens() { searchTokens() {
return [ return [
pausedTokenConfig,
statusTokenConfig, statusTokenConfig,
{ {
...tagTokenConfig, ...tagTokenConfig,
......
import { __, s__ } from '~/locale';
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { PARAM_KEY_PAUSED } from '../../constants';
const options = [
{ value: 'true', title: __('Yes') },
{ value: 'false', title: __('No') },
];
export const pausedTokenConfig = {
icon: 'pause',
title: s__('Runners|Paused'),
type: PARAM_KEY_PAUSED,
token: BaseToken,
unique: true,
options: options.map(({ value, title }) => ({
value,
// Replace whitespace with a special character to avoid
// splitting this value.
// Replacing in each option, as translations may also
// contain spaces!
// see: https://gitlab.com/gitlab-org/gitlab/-/issues/344142
// see: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1438
title: title.replace(' ', '\u00a0'),
})),
operators: OPERATOR_IS_ONLY,
};
...@@ -2,8 +2,6 @@ import { __, s__ } from '~/locale'; ...@@ -2,8 +2,6 @@ import { __, s__ } from '~/locale';
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue'; import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { import {
STATUS_ACTIVE,
STATUS_PAUSED,
STATUS_ONLINE, STATUS_ONLINE,
STATUS_OFFLINE, STATUS_OFFLINE,
STATUS_NEVER_CONTACTED, STATUS_NEVER_CONTACTED,
...@@ -12,8 +10,6 @@ import { ...@@ -12,8 +10,6 @@ import {
} from '../../constants'; } from '../../constants';
const options = [ const options = [
{ value: STATUS_ACTIVE, title: s__('Runners|Active') },
{ value: STATUS_PAUSED, title: s__('Runners|Paused') },
{ value: STATUS_ONLINE, title: s__('Runners|Online') }, { value: STATUS_ONLINE, title: s__('Runners|Online') },
{ value: STATUS_OFFLINE, title: s__('Runners|Offline') }, { value: STATUS_OFFLINE, title: s__('Runners|Offline') },
{ value: STATUS_NEVER_CONTACTED, title: s__('Runners|Never contacted') }, { value: STATUS_NEVER_CONTACTED, title: s__('Runners|Never contacted') },
......
...@@ -95,6 +95,7 @@ export const RUNNER_TAG_BG_CLASS = 'gl-bg-blue-100'; ...@@ -95,6 +95,7 @@ export const RUNNER_TAG_BG_CLASS = 'gl-bg-blue-100';
// - GlFilteredSearch tokens type // - GlFilteredSearch tokens type
export const PARAM_KEY_STATUS = 'status'; export const PARAM_KEY_STATUS = 'status';
export const PARAM_KEY_PAUSED = 'paused';
export const PARAM_KEY_RUNNER_TYPE = 'runner_type'; export const PARAM_KEY_RUNNER_TYPE = 'runner_type';
export const PARAM_KEY_TAG = 'tag'; export const PARAM_KEY_TAG = 'tag';
export const PARAM_KEY_SEARCH = 'search'; export const PARAM_KEY_SEARCH = 'search';
...@@ -112,9 +113,6 @@ export const PROJECT_TYPE = 'PROJECT_TYPE'; ...@@ -112,9 +113,6 @@ export const PROJECT_TYPE = 'PROJECT_TYPE';
// CiRunnerStatus // CiRunnerStatus
export const STATUS_ACTIVE = 'ACTIVE';
export const STATUS_PAUSED = 'PAUSED';
export const STATUS_ONLINE = 'ONLINE'; export const STATUS_ONLINE = 'ONLINE';
export const STATUS_NEVER_CONTACTED = 'NEVER_CONTACTED'; export const STATUS_NEVER_CONTACTED = 'NEVER_CONTACTED';
export const STATUS_OFFLINE = 'OFFLINE'; export const STATUS_OFFLINE = 'OFFLINE';
......
...@@ -6,6 +6,7 @@ query getRunners( ...@@ -6,6 +6,7 @@ query getRunners(
$after: String $after: String
$first: Int $first: Int
$last: Int $last: Int
$paused: Boolean
$status: CiRunnerStatus $status: CiRunnerStatus
$type: CiRunnerType $type: CiRunnerType
$tagList: [String!] $tagList: [String!]
...@@ -17,6 +18,7 @@ query getRunners( ...@@ -17,6 +18,7 @@ query getRunners(
after: $after after: $after
first: $first first: $first
last: $last last: $last
paused: $paused
status: $status status: $status
type: $type type: $type
tagList: $tagList tagList: $tagList
......
query getRunnersCount( query getRunnersCount(
$paused: Boolean
$status: CiRunnerStatus $status: CiRunnerStatus
$type: CiRunnerType $type: CiRunnerType
$tagList: [String!] $tagList: [String!]
$search: String $search: String
) { ) {
runners(status: $status, type: $type, tagList: $tagList, search: $search) { runners(paused: $paused, status: $status, type: $type, tagList: $tagList, search: $search) {
count count
} }
} }
...@@ -7,6 +7,7 @@ query getGroupRunners( ...@@ -7,6 +7,7 @@ query getGroupRunners(
$after: String $after: String
$first: Int $first: Int
$last: Int $last: Int
$paused: Boolean
$status: CiRunnerStatus $status: CiRunnerStatus
$type: CiRunnerType $type: CiRunnerType
$search: String $search: String
...@@ -20,6 +21,7 @@ query getGroupRunners( ...@@ -20,6 +21,7 @@ query getGroupRunners(
after: $after after: $after
first: $first first: $first
last: $last last: $last
paused: $paused
status: $status status: $status
type: $type type: $type
search: $search search: $search
......
query getGroupRunnersCount( query getGroupRunnersCount(
$groupFullPath: ID! $groupFullPath: ID!
$paused: Boolean
$status: CiRunnerStatus $status: CiRunnerStatus
$type: CiRunnerType $type: CiRunnerType
$tagList: [String!] $tagList: [String!]
...@@ -9,6 +10,7 @@ query getGroupRunnersCount( ...@@ -9,6 +10,7 @@ query getGroupRunnersCount(
id # Apollo required id # Apollo required
runners( runners(
membership: DESCENDANTS membership: DESCENDANTS
paused: $paused
status: $status status: $status
type: $type type: $type
tagList: $tagList tagList: $tagList
......
...@@ -14,6 +14,7 @@ import RunnerPagination from '../components/runner_pagination.vue'; ...@@ -14,6 +14,7 @@ import RunnerPagination from '../components/runner_pagination.vue';
import RunnerTypeTabs from '../components/runner_type_tabs.vue'; import RunnerTypeTabs from '../components/runner_type_tabs.vue';
import RunnerActionsCell from '../components/cells/runner_actions_cell.vue'; import RunnerActionsCell from '../components/cells/runner_actions_cell.vue';
import { pausedTokenConfig } from '../components/search_tokens/paused_token_config';
import { statusTokenConfig } from '../components/search_tokens/status_token_config'; import { statusTokenConfig } from '../components/search_tokens/status_token_config';
import { import {
GROUP_FILTERED_SEARCH_NAMESPACE, GROUP_FILTERED_SEARCH_NAMESPACE,
...@@ -189,7 +190,7 @@ export default { ...@@ -189,7 +190,7 @@ export default {
return !this.runnersLoading && !this.runners.items.length; return !this.runnersLoading && !this.runners.items.length;
}, },
searchTokens() { searchTokens() {
return [statusTokenConfig]; return [pausedTokenConfig, statusTokenConfig];
}, },
filteredSearchNamespace() { filteredSearchNamespace() {
return `${GROUP_FILTERED_SEARCH_NAMESPACE}/${this.groupFullPath}`; return `${GROUP_FILTERED_SEARCH_NAMESPACE}/${this.groupFullPath}`;
......
...@@ -5,7 +5,9 @@ import { ...@@ -5,7 +5,9 @@ import {
urlQueryToFilter, urlQueryToFilter,
prepareTokens, prepareTokens,
} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils'; } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import { parseBoolean } from '~/lib/utils/common_utils';
import { import {
PARAM_KEY_PAUSED,
PARAM_KEY_STATUS, PARAM_KEY_STATUS,
PARAM_KEY_RUNNER_TYPE, PARAM_KEY_RUNNER_TYPE,
PARAM_KEY_TAG, PARAM_KEY_TAG,
...@@ -83,6 +85,19 @@ const getPaginationFromParams = (params) => { ...@@ -83,6 +85,19 @@ const getPaginationFromParams = (params) => {
// Outdated URL parameters // Outdated URL parameters
const STATUS_NOT_CONNECTED = 'NOT_CONNECTED'; const STATUS_NOT_CONNECTED = 'NOT_CONNECTED';
const STATUS_ACTIVE = 'ACTIVE';
const STATUS_PAUSED = 'PAUSED';
/**
* Replaces params into a URL
*
* @param {String} url - Original URL
* @param {Object} params - Query parameters to update
* @returns Updated URL
*/
const updateUrlParams = (url, params = {}) => {
return setUrlParams(params, url, false, true, true);
};
/** /**
* Returns an updated URL for old (or deprecated) admin runner URLs. * Returns an updated URL for old (or deprecated) admin runner URLs.
...@@ -98,14 +113,26 @@ export const updateOutdatedUrl = (url = window.location.href) => { ...@@ -98,14 +113,26 @@ export const updateOutdatedUrl = (url = window.location.href) => {
const params = queryToObject(query, { gatherArrays: true }); const params = queryToObject(query, { gatherArrays: true });
const runnerType = params[PARAM_KEY_STATUS]?.[0] || null; const status = params[PARAM_KEY_STATUS]?.[0] || null;
if (runnerType === STATUS_NOT_CONNECTED) {
const updatedParams = { switch (status) {
[PARAM_KEY_STATUS]: [STATUS_NEVER_CONTACTED], case STATUS_NOT_CONNECTED:
}; return updateUrlParams(url, {
return setUrlParams(updatedParams, url, false, true, true); [PARAM_KEY_STATUS]: [STATUS_NEVER_CONTACTED],
});
case STATUS_ACTIVE:
return updateUrlParams(url, {
[PARAM_KEY_PAUSED]: ['false'],
[PARAM_KEY_STATUS]: [], // Important! clear PARAM_KEY_STATUS to avoid a redirection loop!
});
case STATUS_PAUSED:
return updateUrlParams(url, {
[PARAM_KEY_PAUSED]: ['true'],
[PARAM_KEY_STATUS]: [], // Important! clear PARAM_KEY_STATUS to avoid a redirection loop!
});
default:
return null;
} }
return null;
}; };
/** /**
...@@ -121,7 +148,7 @@ export const fromUrlQueryToSearch = (query = window.location.search) => { ...@@ -121,7 +148,7 @@ export const fromUrlQueryToSearch = (query = window.location.search) => {
runnerType, runnerType,
filters: prepareTokens( filters: prepareTokens(
urlQueryToFilter(query, { urlQueryToFilter(query, {
filterNamesAllowList: [PARAM_KEY_STATUS, PARAM_KEY_TAG], filterNamesAllowList: [PARAM_KEY_PAUSED, PARAM_KEY_STATUS, PARAM_KEY_TAG],
filteredSearchTermKey: PARAM_KEY_SEARCH, filteredSearchTermKey: PARAM_KEY_SEARCH,
}), }),
), ),
...@@ -195,6 +222,12 @@ export const fromSearchToVariables = ({ ...@@ -195,6 +222,12 @@ export const fromSearchToVariables = ({
filterVariables.search = queryObj[PARAM_KEY_SEARCH]; filterVariables.search = queryObj[PARAM_KEY_SEARCH];
filterVariables.tagList = queryObj[PARAM_KEY_TAG]; filterVariables.tagList = queryObj[PARAM_KEY_TAG];
if (queryObj[PARAM_KEY_PAUSED]) {
filterVariables.paused = parseBoolean(queryObj[PARAM_KEY_PAUSED]);
} else {
filterVariables.paused = undefined;
}
if (runnerType) { if (runnerType) {
filterVariables.type = runnerType; filterVariables.type = runnerType;
} }
......
...@@ -154,35 +154,69 @@ RSpec.describe "Admin Runners" do ...@@ -154,35 +154,69 @@ RSpec.describe "Admin Runners" do
end end
end end
describe 'filter by paused' do
before do
create(:ci_runner, :instance, description: 'runner-active')
create(:ci_runner, :instance, description: 'runner-paused', active: false)
visit admin_runners_path
end
it 'shows all runners' do
expect(page).to have_link('All 2')
expect(page).to have_content 'runner-active'
expect(page).to have_content 'runner-paused'
end
it 'shows paused runners' do
input_filtered_search_filter_is_only('Paused', 'Yes')
expect(page).to have_link('All 1')
expect(page).not_to have_content 'runner-active'
expect(page).to have_content 'runner-paused'
end
it 'shows active runners' do
input_filtered_search_filter_is_only('Paused', 'No')
expect(page).to have_link('All 1')
expect(page).to have_content 'runner-active'
expect(page).not_to have_content 'runner-paused'
end
end
describe 'filter by status' do describe 'filter by status' do
let!(:never_contacted) { create(:ci_runner, :instance, description: 'runner-never-contacted', contacted_at: nil) } let!(:never_contacted) { create(:ci_runner, :instance, description: 'runner-never-contacted', contacted_at: nil) }
before do before do
create(:ci_runner, :instance, description: 'runner-1', contacted_at: Time.zone.now) create(:ci_runner, :instance, description: 'runner-1', contacted_at: Time.zone.now)
create(:ci_runner, :instance, description: 'runner-2', contacted_at: Time.zone.now) create(:ci_runner, :instance, description: 'runner-2', contacted_at: Time.zone.now)
create(:ci_runner, :instance, description: 'runner-paused', active: false, contacted_at: Time.zone.now) create(:ci_runner, :instance, description: 'runner-offline', contacted_at: 1.week.ago)
visit admin_runners_path visit admin_runners_path
end end
it 'shows all runners' do it 'shows all runners' do
expect(page).to have_link('All 4')
expect(page).to have_content 'runner-1' expect(page).to have_content 'runner-1'
expect(page).to have_content 'runner-2' expect(page).to have_content 'runner-2'
expect(page).to have_content 'runner-paused' expect(page).to have_content 'runner-offline'
expect(page).to have_content 'runner-never-contacted' expect(page).to have_content 'runner-never-contacted'
expect(page).to have_link('All 4')
end end
it 'shows correct runner when status matches' do it 'shows correct runner when status matches' do
input_filtered_search_filter_is_only('Status', 'Active') input_filtered_search_filter_is_only('Status', 'Online')
expect(page).to have_link('All 3') expect(page).to have_link('All 2')
expect(page).to have_content 'runner-1' expect(page).to have_content 'runner-1'
expect(page).to have_content 'runner-2' expect(page).to have_content 'runner-2'
expect(page).to have_content 'runner-never-contacted' expect(page).not_to have_content 'runner-offline'
expect(page).not_to have_content 'runner-paused' expect(page).not_to have_content 'runner-never-contacted'
end end
it 'shows no runner when status does not match' do it 'shows no runner when status does not match' do
...@@ -194,15 +228,15 @@ RSpec.describe "Admin Runners" do ...@@ -194,15 +228,15 @@ RSpec.describe "Admin Runners" do
end end
it 'shows correct runner when status is selected and search term is entered' do it 'shows correct runner when status is selected and search term is entered' do
input_filtered_search_filter_is_only('Status', 'Active') input_filtered_search_filter_is_only('Status', 'Online')
input_filtered_search_keys('runner-1') input_filtered_search_keys('runner-1')
expect(page).to have_link('All 1') expect(page).to have_link('All 1')
expect(page).to have_content 'runner-1' expect(page).to have_content 'runner-1'
expect(page).not_to have_content 'runner-2' expect(page).not_to have_content 'runner-2'
expect(page).not_to have_content 'runner-offline'
expect(page).not_to have_content 'runner-never-contacted' expect(page).not_to have_content 'runner-never-contacted'
expect(page).not_to have_content 'runner-paused'
end end
it 'shows correct runner when status filter is entered' do it 'shows correct runner when status filter is entered' do
...@@ -308,7 +342,7 @@ RSpec.describe "Admin Runners" do ...@@ -308,7 +342,7 @@ RSpec.describe "Admin Runners" do
visit admin_runners_path visit admin_runners_path
input_filtered_search_filter_is_only('Status', 'Active') input_filtered_search_filter_is_only('Paused', 'No')
expect(page).to have_content 'runner-project' expect(page).to have_content 'runner-project'
expect(page).to have_content 'runner-group' expect(page).to have_content 'runner-group'
...@@ -427,6 +461,18 @@ RSpec.describe "Admin Runners" do ...@@ -427,6 +461,18 @@ RSpec.describe "Admin Runners" do
expect(page).to have_current_path(admin_runners_path('status[]': 'NEVER_CONTACTED') ) expect(page).to have_current_path(admin_runners_path('status[]': 'NEVER_CONTACTED') )
end end
it 'updates ACTIVE runner status to paused=false' do
visit admin_runners_path('status[]': 'ACTIVE')
expect(page).to have_current_path(admin_runners_path('paused[]': 'false') )
end
it 'updates PAUSED runner status to paused=true' do
visit admin_runners_path('status[]': 'PAUSED')
expect(page).to have_current_path(admin_runners_path('paused[]': 'true') )
end
end end
describe 'runners registration' do describe 'runners registration' do
......
...@@ -31,9 +31,10 @@ import { ...@@ -31,9 +31,10 @@ import {
INSTANCE_TYPE, INSTANCE_TYPE,
GROUP_TYPE, GROUP_TYPE,
PROJECT_TYPE, PROJECT_TYPE,
PARAM_KEY_PAUSED,
PARAM_KEY_STATUS, PARAM_KEY_STATUS,
PARAM_KEY_TAG, PARAM_KEY_TAG,
STATUS_ACTIVE, STATUS_ONLINE,
RUNNER_PAGE_SIZE, RUNNER_PAGE_SIZE,
} from '~/runner/constants'; } from '~/runner/constants';
import adminRunnersQuery from '~/runner/graphql/list/admin_runners.query.graphql'; import adminRunnersQuery from '~/runner/graphql/list/admin_runners.query.graphql';
...@@ -242,6 +243,10 @@ describe('AdminRunnersApp', () => { ...@@ -242,6 +243,10 @@ describe('AdminRunnersApp', () => {
createComponent({ mountFn: mountExtended }); createComponent({ mountFn: mountExtended });
expect(findFilteredSearch().props('tokens')).toEqual([ expect(findFilteredSearch().props('tokens')).toEqual([
expect.objectContaining({
type: PARAM_KEY_PAUSED,
options: expect.any(Array),
}),
expect.objectContaining({ expect.objectContaining({
type: PARAM_KEY_STATUS, type: PARAM_KEY_STATUS,
options: expect.any(Array), options: expect.any(Array),
...@@ -297,7 +302,7 @@ describe('AdminRunnersApp', () => { ...@@ -297,7 +302,7 @@ describe('AdminRunnersApp', () => {
describe('when a filter is preselected', () => { describe('when a filter is preselected', () => {
beforeEach(async () => { beforeEach(async () => {
setWindowLocation(`?status[]=${STATUS_ACTIVE}&runner_type[]=${INSTANCE_TYPE}&tag[]=tag1`); setWindowLocation(`?status[]=${STATUS_ONLINE}&runner_type[]=${INSTANCE_TYPE}&tag[]=tag1`);
createComponent(); createComponent();
await waitForPromises(); await waitForPromises();
...@@ -307,7 +312,7 @@ describe('AdminRunnersApp', () => { ...@@ -307,7 +312,7 @@ describe('AdminRunnersApp', () => {
expect(findRunnerFilteredSearchBar().props('value')).toEqual({ expect(findRunnerFilteredSearchBar().props('value')).toEqual({
runnerType: INSTANCE_TYPE, runnerType: INSTANCE_TYPE,
filters: [ filters: [
{ type: 'status', value: { data: STATUS_ACTIVE, operator: '=' } }, { type: 'status', value: { data: STATUS_ONLINE, operator: '=' } },
{ type: 'tag', value: { data: 'tag1', operator: '=' } }, { type: 'tag', value: { data: 'tag1', operator: '=' } },
], ],
sort: 'CREATED_DESC', sort: 'CREATED_DESC',
...@@ -317,7 +322,7 @@ describe('AdminRunnersApp', () => { ...@@ -317,7 +322,7 @@ describe('AdminRunnersApp', () => {
it('requests the runners with filter parameters', () => { it('requests the runners with filter parameters', () => {
expect(mockRunnersQuery).toHaveBeenLastCalledWith({ expect(mockRunnersQuery).toHaveBeenLastCalledWith({
status: STATUS_ACTIVE, status: STATUS_ONLINE,
type: INSTANCE_TYPE, type: INSTANCE_TYPE,
tagList: ['tag1'], tagList: ['tag1'],
sort: DEFAULT_SORT, sort: DEFAULT_SORT,
...@@ -330,7 +335,7 @@ describe('AdminRunnersApp', () => { ...@@ -330,7 +335,7 @@ describe('AdminRunnersApp', () => {
beforeEach(() => { beforeEach(() => {
findRunnerFilteredSearchBar().vm.$emit('input', { findRunnerFilteredSearchBar().vm.$emit('input', {
runnerType: null, runnerType: null,
filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ACTIVE, operator: '=' } }], filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
sort: CREATED_ASC, sort: CREATED_ASC,
}); });
}); });
...@@ -338,13 +343,13 @@ describe('AdminRunnersApp', () => { ...@@ -338,13 +343,13 @@ describe('AdminRunnersApp', () => {
it('updates the browser url', () => { it('updates the browser url', () => {
expect(updateHistory).toHaveBeenLastCalledWith({ expect(updateHistory).toHaveBeenLastCalledWith({
title: expect.any(String), title: expect.any(String),
url: 'http://test.host/admin/runners?status[]=ACTIVE&sort=CREATED_ASC', url: 'http://test.host/admin/runners?status[]=ONLINE&sort=CREATED_ASC',
}); });
}); });
it('requests the runners with filters', () => { it('requests the runners with filters', () => {
expect(mockRunnersQuery).toHaveBeenLastCalledWith({ expect(mockRunnersQuery).toHaveBeenLastCalledWith({
status: STATUS_ACTIVE, status: STATUS_ONLINE,
sort: CREATED_ASC, sort: CREATED_ASC,
first: RUNNER_PAGE_SIZE, first: RUNNER_PAGE_SIZE,
}); });
......
...@@ -4,7 +4,7 @@ import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_ ...@@ -4,7 +4,7 @@ import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_
import { statusTokenConfig } from '~/runner/components/search_tokens/status_token_config'; import { statusTokenConfig } from '~/runner/components/search_tokens/status_token_config';
import TagToken from '~/runner/components/search_tokens/tag_token.vue'; import TagToken from '~/runner/components/search_tokens/tag_token.vue';
import { tagTokenConfig } from '~/runner/components/search_tokens/tag_token_config'; import { tagTokenConfig } from '~/runner/components/search_tokens/tag_token_config';
import { PARAM_KEY_STATUS, PARAM_KEY_TAG, STATUS_ACTIVE, INSTANCE_TYPE } from '~/runner/constants'; import { PARAM_KEY_STATUS, PARAM_KEY_TAG, STATUS_ONLINE, INSTANCE_TYPE } from '~/runner/constants';
import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue'; import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
...@@ -18,7 +18,7 @@ describe('RunnerList', () => { ...@@ -18,7 +18,7 @@ describe('RunnerList', () => {
const mockDefaultSort = 'CREATED_DESC'; const mockDefaultSort = 'CREATED_DESC';
const mockOtherSort = 'CONTACTED_DESC'; const mockOtherSort = 'CONTACTED_DESC';
const mockFilters = [ const mockFilters = [
{ type: PARAM_KEY_STATUS, value: { data: STATUS_ACTIVE, operator: '=' } }, { type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } },
{ type: 'filtered-search-term', value: { data: '' } }, { type: 'filtered-search-term', value: { data: '' } },
]; ];
......
...@@ -28,8 +28,9 @@ import { ...@@ -28,8 +28,9 @@ import {
INSTANCE_TYPE, INSTANCE_TYPE,
GROUP_TYPE, GROUP_TYPE,
PROJECT_TYPE, PROJECT_TYPE,
PARAM_KEY_PAUSED,
PARAM_KEY_STATUS, PARAM_KEY_STATUS,
STATUS_ACTIVE, STATUS_ONLINE,
RUNNER_PAGE_SIZE, RUNNER_PAGE_SIZE,
I18N_EDIT, I18N_EDIT,
} from '~/runner/constants'; } from '~/runner/constants';
...@@ -188,13 +189,16 @@ describe('GroupRunnersApp', () => { ...@@ -188,13 +189,16 @@ describe('GroupRunnersApp', () => {
const tokens = findFilteredSearch().props('tokens'); const tokens = findFilteredSearch().props('tokens');
expect(tokens).toHaveLength(1); expect(tokens).toEqual([
expect(tokens[0]).toEqual( expect.objectContaining({
type: PARAM_KEY_PAUSED,
options: expect.any(Array),
}),
expect.objectContaining({ expect.objectContaining({
type: PARAM_KEY_STATUS, type: PARAM_KEY_STATUS,
options: expect.any(Array), options: expect.any(Array),
}), }),
); ]);
}); });
describe('Single runner row', () => { describe('Single runner row', () => {
...@@ -253,7 +257,7 @@ describe('GroupRunnersApp', () => { ...@@ -253,7 +257,7 @@ describe('GroupRunnersApp', () => {
describe('when a filter is preselected', () => { describe('when a filter is preselected', () => {
beforeEach(async () => { beforeEach(async () => {
setWindowLocation(`?status[]=${STATUS_ACTIVE}&runner_type[]=${INSTANCE_TYPE}`); setWindowLocation(`?status[]=${STATUS_ONLINE}&runner_type[]=${INSTANCE_TYPE}`);
createComponent(); createComponent();
await waitForPromises(); await waitForPromises();
...@@ -262,7 +266,7 @@ describe('GroupRunnersApp', () => { ...@@ -262,7 +266,7 @@ describe('GroupRunnersApp', () => {
it('sets the filters in the search bar', () => { it('sets the filters in the search bar', () => {
expect(findRunnerFilteredSearchBar().props('value')).toEqual({ expect(findRunnerFilteredSearchBar().props('value')).toEqual({
runnerType: INSTANCE_TYPE, runnerType: INSTANCE_TYPE,
filters: [{ type: 'status', value: { data: STATUS_ACTIVE, operator: '=' } }], filters: [{ type: 'status', value: { data: STATUS_ONLINE, operator: '=' } }],
sort: 'CREATED_DESC', sort: 'CREATED_DESC',
pagination: { page: 1 }, pagination: { page: 1 },
}); });
...@@ -271,7 +275,7 @@ describe('GroupRunnersApp', () => { ...@@ -271,7 +275,7 @@ describe('GroupRunnersApp', () => {
it('requests the runners with filter parameters', () => { it('requests the runners with filter parameters', () => {
expect(mockGroupRunnersQuery).toHaveBeenLastCalledWith({ expect(mockGroupRunnersQuery).toHaveBeenLastCalledWith({
groupFullPath: mockGroupFullPath, groupFullPath: mockGroupFullPath,
status: STATUS_ACTIVE, status: STATUS_ONLINE,
type: INSTANCE_TYPE, type: INSTANCE_TYPE,
sort: DEFAULT_SORT, sort: DEFAULT_SORT,
first: RUNNER_PAGE_SIZE, first: RUNNER_PAGE_SIZE,
...@@ -283,7 +287,7 @@ describe('GroupRunnersApp', () => { ...@@ -283,7 +287,7 @@ describe('GroupRunnersApp', () => {
beforeEach(async () => { beforeEach(async () => {
findRunnerFilteredSearchBar().vm.$emit('input', { findRunnerFilteredSearchBar().vm.$emit('input', {
runnerType: null, runnerType: null,
filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ACTIVE, operator: '=' } }], filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
sort: CREATED_ASC, sort: CREATED_ASC,
}); });
...@@ -293,14 +297,14 @@ describe('GroupRunnersApp', () => { ...@@ -293,14 +297,14 @@ describe('GroupRunnersApp', () => {
it('updates the browser url', () => { it('updates the browser url', () => {
expect(updateHistory).toHaveBeenLastCalledWith({ expect(updateHistory).toHaveBeenLastCalledWith({
title: expect.any(String), title: expect.any(String),
url: 'http://test.host/groups/group1/-/runners?status[]=ACTIVE&sort=CREATED_ASC', url: 'http://test.host/groups/group1/-/runners?status[]=ONLINE&sort=CREATED_ASC',
}); });
}); });
it('requests the runners with filters', () => { it('requests the runners with filters', () => {
expect(mockGroupRunnersQuery).toHaveBeenLastCalledWith({ expect(mockGroupRunnersQuery).toHaveBeenLastCalledWith({
groupFullPath: mockGroupFullPath, groupFullPath: mockGroupFullPath,
status: STATUS_ACTIVE, status: STATUS_ONLINE,
sort: CREATED_ASC, sort: CREATED_ASC,
first: RUNNER_PAGE_SIZE, first: RUNNER_PAGE_SIZE,
}); });
......
...@@ -181,6 +181,28 @@ describe('search_params.js', () => { ...@@ -181,6 +181,28 @@ describe('search_params.js', () => {
first: RUNNER_PAGE_SIZE, first: RUNNER_PAGE_SIZE,
}, },
}, },
{
name: 'paused runners',
urlQuery: '?paused[]=true',
search: {
runnerType: null,
filters: [{ type: 'paused', value: { data: 'true', operator: '=' } }],
pagination: { page: 1 },
sort: 'CREATED_DESC',
},
graphqlVariables: { paused: true, sort: 'CREATED_DESC', first: RUNNER_PAGE_SIZE },
},
{
name: 'active runners',
urlQuery: '?paused[]=false',
search: {
runnerType: null,
filters: [{ type: 'paused', value: { data: 'false', operator: '=' } }],
pagination: { page: 1 },
sort: 'CREATED_DESC',
},
graphqlVariables: { paused: false, sort: 'CREATED_DESC', first: RUNNER_PAGE_SIZE },
},
]; ];
describe('searchValidator', () => { describe('searchValidator', () => {
...@@ -197,14 +219,18 @@ describe('search_params.js', () => { ...@@ -197,14 +219,18 @@ describe('search_params.js', () => {
expect(updateOutdatedUrl('http://test.host/?a=b')).toBe(null); expect(updateOutdatedUrl('http://test.host/?a=b')).toBe(null);
}); });
it('returns updated url for updating NOT_CONNECTED to NEVER_CONTACTED', () => { it.each`
expect(updateOutdatedUrl('http://test.host/admin/runners?status[]=NOT_CONNECTED')).toBe( query | updatedQuery
'http://test.host/admin/runners?status[]=NEVER_CONTACTED', ${'status[]=NOT_CONNECTED'} | ${'status[]=NEVER_CONTACTED'}
); ${'status[]=NOT_CONNECTED&a=b'} | ${'status[]=NEVER_CONTACTED&a=b'}
${'status[]=ACTIVE'} | ${'paused[]=false'}
${'status[]=ACTIVE&a=b'} | ${'a=b&paused[]=false'}
${'status[]=ACTIVE'} | ${'paused[]=false'}
${'status[]=PAUSED'} | ${'paused[]=true'}
`('updates "$query" to "$updatedQuery"', ({ query, updatedQuery }) => {
const mockUrl = 'http://test.host/admin/runners?';
expect(updateOutdatedUrl('http://test.host/admin/runners?status[]=NOT_CONNECTED&a=b')).toBe( expect(updateOutdatedUrl(`${mockUrl}${query}`)).toBe(`${mockUrl}${updatedQuery}`);
'http://test.host/admin/runners?status[]=NEVER_CONTACTED&a=b',
);
}); });
}); });
......
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