Commit 27ba1b90 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch '344671-replace-not-connected-to-never-contacted-for-runner-status' into 'master'

Use "never contacted" wording in runner's frontend

See merge request gitlab-org/gitlab!77375
parents 013c320f 2048b5e1
...@@ -2,6 +2,8 @@ import { GlToast } from '@gitlab/ui'; ...@@ -2,6 +2,8 @@ import { GlToast } from '@gitlab/ui';
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import { visitUrl } from '~/lib/utils/url_utility';
import { updateOutdatedUrl } from '~/runner/runner_search_utils';
import AdminRunnersApp from './admin_runners_app.vue'; import AdminRunnersApp from './admin_runners_app.vue';
Vue.use(GlToast); Vue.use(GlToast);
...@@ -14,6 +16,15 @@ export const initAdminRunners = (selector = '#js-admin-runners') => { ...@@ -14,6 +16,15 @@ export const initAdminRunners = (selector = '#js-admin-runners') => {
return null; return null;
} }
// Redirect outdated URLs
const updatedUrlQuery = updateOutdatedUrl();
if (updatedUrlQuery) {
visitUrl(updatedUrlQuery);
// Prevent mounting the rest of the app, redirecting now.
return null;
}
// TODO `activeRunnersCount` should be implemented using a GraphQL API // TODO `activeRunnersCount` should be implemented using a GraphQL API
// https://gitlab.com/gitlab-org/gitlab/-/issues/333806 // https://gitlab.com/gitlab-org/gitlab/-/issues/333806
const { const {
......
...@@ -28,7 +28,15 @@ export default { ...@@ -28,7 +28,15 @@ export default {
<template> <template>
<div> <div>
<runner-status-badge :runner="runner" size="sm" /> <runner-status-badge
<runner-paused-badge v-if="paused" size="sm" /> :runner="runner"
size="sm"
class="gl-display-inline-block gl-max-w-full gl-text-truncate"
/>
<runner-paused-badge
v-if="paused"
size="sm"
class="gl-display-inline-block gl-max-w-full gl-text-truncate"
/>
</div> </div>
</template> </template>
...@@ -4,11 +4,10 @@ import { __, s__, sprintf } from '~/locale'; ...@@ -4,11 +4,10 @@ import { __, s__, sprintf } from '~/locale';
import { getTimeago } from '~/lib/utils/datetime_utility'; import { getTimeago } from '~/lib/utils/datetime_utility';
import { import {
I18N_ONLINE_RUNNER_TIMEAGO_DESCRIPTION, I18N_ONLINE_RUNNER_TIMEAGO_DESCRIPTION,
I18N_NOT_CONNECTED_RUNNER_DESCRIPTION, I18N_NEVER_CONTACTED_RUNNER_DESCRIPTION,
I18N_OFFLINE_RUNNER_TIMEAGO_DESCRIPTION, I18N_OFFLINE_RUNNER_TIMEAGO_DESCRIPTION,
I18N_STALE_RUNNER_DESCRIPTION, I18N_STALE_RUNNER_DESCRIPTION,
STATUS_ONLINE, STATUS_ONLINE,
STATUS_NOT_CONNECTED,
STATUS_NEVER_CONTACTED, STATUS_NEVER_CONTACTED,
STATUS_OFFLINE, STATUS_OFFLINE,
STATUS_STALE, STATUS_STALE,
...@@ -45,12 +44,11 @@ export default { ...@@ -45,12 +44,11 @@ export default {
timeAgo: this.contactedAtTimeAgo, timeAgo: this.contactedAtTimeAgo,
}), }),
}; };
case STATUS_NOT_CONNECTED:
case STATUS_NEVER_CONTACTED: case STATUS_NEVER_CONTACTED:
return { return {
variant: 'muted', variant: 'muted',
label: s__('Runners|not connected'), label: s__('Runners|never contacted'),
tooltip: I18N_NOT_CONNECTED_RUNNER_DESCRIPTION, tooltip: I18N_NEVER_CONTACTED_RUNNER_DESCRIPTION,
}; };
case STATUS_OFFLINE: case STATUS_OFFLINE:
return { return {
......
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
STATUS_PAUSED, STATUS_PAUSED,
STATUS_ONLINE, STATUS_ONLINE,
STATUS_OFFLINE, STATUS_OFFLINE,
STATUS_NOT_CONNECTED, STATUS_NEVER_CONTACTED,
STATUS_STALE, STATUS_STALE,
PARAM_KEY_STATUS, PARAM_KEY_STATUS,
} from '../../constants'; } from '../../constants';
...@@ -16,7 +16,7 @@ const options = [ ...@@ -16,7 +16,7 @@ const options = [
{ value: STATUS_PAUSED, title: s__('Runners|Paused') }, { 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_NOT_CONNECTED, title: s__('Runners|Not connected') }, { value: STATUS_NEVER_CONTACTED, title: s__('Runners|Never contacted') },
{ value: STATUS_STALE, title: s__('Runners|Stale') }, { value: STATUS_STALE, title: s__('Runners|Stale') },
]; ];
......
...@@ -18,8 +18,8 @@ export const I18N_PROJECT_RUNNER_DESCRIPTION = s__('Runners|Associated with one ...@@ -18,8 +18,8 @@ export const I18N_PROJECT_RUNNER_DESCRIPTION = s__('Runners|Associated with one
export const I18N_ONLINE_RUNNER_TIMEAGO_DESCRIPTION = s__( export const I18N_ONLINE_RUNNER_TIMEAGO_DESCRIPTION = s__(
'Runners|Runner is online; last contact was %{timeAgo}', 'Runners|Runner is online; last contact was %{timeAgo}',
); );
export const I18N_NOT_CONNECTED_RUNNER_DESCRIPTION = s__( export const I18N_NEVER_CONTACTED_RUNNER_DESCRIPTION = s__(
'Runners|This runner has never connected to this instance', 'Runners|This runner has never contacted this instance',
); );
export const I18N_OFFLINE_RUNNER_TIMEAGO_DESCRIPTION = s__( export const I18N_OFFLINE_RUNNER_TIMEAGO_DESCRIPTION = s__(
'Runners|No recent contact from this runner; last contact was %{timeAgo}', 'Runners|No recent contact from this runner; last contact was %{timeAgo}',
...@@ -60,7 +60,6 @@ export const STATUS_ACTIVE = 'ACTIVE'; ...@@ -60,7 +60,6 @@ export const STATUS_ACTIVE = 'ACTIVE';
export const STATUS_PAUSED = 'PAUSED'; export const STATUS_PAUSED = 'PAUSED';
export const STATUS_ONLINE = 'ONLINE'; export const STATUS_ONLINE = 'ONLINE';
export const STATUS_NOT_CONNECTED = 'NOT_CONNECTED';
export const STATUS_NEVER_CONTACTED = 'NEVER_CONTACTED'; export const STATUS_NEVER_CONTACTED = 'NEVER_CONTACTED';
export const STATUS_OFFLINE = 'OFFLINE'; export const STATUS_OFFLINE = 'OFFLINE';
export const STATUS_STALE = 'STALE'; export const STATUS_STALE = 'STALE';
......
...@@ -16,6 +16,7 @@ import { ...@@ -16,6 +16,7 @@ import {
PARAM_KEY_BEFORE, PARAM_KEY_BEFORE,
DEFAULT_SORT, DEFAULT_SORT,
RUNNER_PAGE_SIZE, RUNNER_PAGE_SIZE,
STATUS_NEVER_CONTACTED,
} from './constants'; } from './constants';
/** /**
...@@ -79,6 +80,33 @@ const getPaginationFromParams = (params) => { ...@@ -79,6 +80,33 @@ const getPaginationFromParams = (params) => {
}; };
}; };
// Outdated URL parameters
const STATUS_NOT_CONNECTED = 'NOT_CONNECTED';
/**
* Returns an updated URL for old (or deprecated) admin runner URLs.
*
* Use for redirecting users to currently used URLs.
*
* @param {String?} URL
* @returns Updated URL if outdated, `null` otherwise
*/
export const updateOutdatedUrl = (url = window.location.href) => {
const urlObj = new URL(url);
const query = urlObj.search;
const params = queryToObject(query, { gatherArrays: true });
const runnerType = params[PARAM_KEY_STATUS]?.[0] || null;
if (runnerType === STATUS_NOT_CONNECTED) {
const updatedParams = {
[PARAM_KEY_STATUS]: [STATUS_NEVER_CONTACTED],
};
return setUrlParams(updatedParams, url, false, true, true);
}
return null;
};
/** /**
* Takes a URL query and transforms it into a "search" object * Takes a URL query and transforms it into a "search" object
* @param {String?} query * @param {String?} query
......
...@@ -24,7 +24,7 @@ module Ci ...@@ -24,7 +24,7 @@ module Ci
span_class = 'gl-text-gray-600' span_class = 'gl-text-gray-600'
end end
when :not_connected, :never_contacted when :not_connected, :never_contacted
title = s_("Runners|New runner, has not connected yet") title = s_("Runners|New runner, has not contacted yet")
icon = 'warning-solid' icon = 'warning-solid'
when :offline when :offline
title = s_("Runners|Runner is offline, last contact was %{runner_contact} ago") % { runner_contact: time_ago_in_words(runner.contacted_at) } title = s_("Runners|Runner is offline, last contact was %{runner_contact} ago") % { runner_contact: time_ago_in_words(runner.contacted_at) }
......
...@@ -30540,10 +30540,13 @@ msgstr "" ...@@ -30540,10 +30540,13 @@ msgstr ""
msgid "Runners|Name" msgid "Runners|Name"
msgstr "" msgstr ""
msgid "Runners|Never contacted"
msgstr ""
msgid "Runners|New registration token generated!" msgid "Runners|New registration token generated!"
msgstr "" msgstr ""
msgid "Runners|New runner, has not connected yet" msgid "Runners|New runner, has not contacted yet"
msgstr "" msgstr ""
msgid "Runners|No contact from this runner in over 3 months" msgid "Runners|No contact from this runner in over 3 months"
...@@ -30555,9 +30558,6 @@ msgstr "" ...@@ -30555,9 +30558,6 @@ msgstr ""
msgid "Runners|Not available to run jobs" msgid "Runners|Not available to run jobs"
msgstr "" msgstr ""
msgid "Runners|Not connected"
msgstr ""
msgid "Runners|Offline" msgid "Runners|Offline"
msgstr "" msgstr ""
...@@ -30672,7 +30672,7 @@ msgstr "" ...@@ -30672,7 +30672,7 @@ msgstr ""
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?" msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr "" msgstr ""
msgid "Runners|This runner has never connected to this instance" msgid "Runners|This runner has never contacted this instance"
msgstr "" msgstr ""
msgid "Runners|This runner is associated with one or more projects." msgid "Runners|This runner is associated with one or more projects."
...@@ -30741,7 +30741,7 @@ msgstr "" ...@@ -30741,7 +30741,7 @@ msgstr ""
msgid "Runners|locked" msgid "Runners|locked"
msgstr "" msgstr ""
msgid "Runners|not connected" msgid "Runners|never contacted"
msgstr "" msgstr ""
msgid "Runners|offline" msgid "Runners|offline"
......
...@@ -192,17 +192,21 @@ RSpec.describe "Admin Runners" do ...@@ -192,17 +192,21 @@ RSpec.describe "Admin Runners" do
expect(page).not_to have_content 'runner-a-2' expect(page).not_to have_content 'runner-a-2'
end end
it 'shows correct runner when type is selected and search term is entered' do it 'shows correct runner when status filter is entered' do
create(:ci_runner, :instance, description: 'runner-connected', contacted_at: Time.now) never_connected = create(:ci_runner, :instance, description: 'runner-never-contacted', contacted_at: nil)
create(:ci_runner, :instance, description: 'runner-not-connected', contacted_at: nil) create(:ci_runner, :instance, description: 'runner-contacted', contacted_at: Time.now)
visit admin_runners_path visit admin_runners_path
# use the string "Not" to avoid using space and trigger an early selection # use the string "Never" to avoid using space and trigger an early selection
input_filtered_search_filter_is_only('Status', 'Not') input_filtered_search_filter_is_only('Status', 'Never')
expect(page).to have_content 'runner-never-contacted'
expect(page).not_to have_content 'runner-contacted'
expect(page).not_to have_content 'runner-connected' within "[data-testid='runner-row-#{never_connected.id}']" do
expect(page).to have_content 'runner-not-connected' expect(page).to have_selector '.badge', text: 'never contacted'
end
end end
end end
...@@ -378,6 +382,14 @@ RSpec.describe "Admin Runners" do ...@@ -378,6 +382,14 @@ RSpec.describe "Admin Runners" do
end end
end end
context "when visiting outdated URLs" do
it 'updates NOT_CONNECTED runner status to NEVER_CONNECTED' do
visit admin_runners_path('status[]': 'NOT_CONNECTED')
expect(page).to have_current_path(admin_runners_path('status[]': 'NEVER_CONTACTED') )
end
end
describe 'runners registration' do describe 'runners registration' do
let!(:token) { Gitlab::CurrentSettings.runners_registration_token } let!(:token) { Gitlab::CurrentSettings.runners_registration_token }
......
...@@ -69,7 +69,9 @@ describe('RunnerList', () => { ...@@ -69,7 +69,9 @@ describe('RunnerList', () => {
const { id, description, version, ipAddress, shortSha } = mockRunners[0]; const { id, description, version, ipAddress, shortSha } = mockRunners[0];
// Badges // Badges
expect(findCell({ fieldKey: 'status' }).text()).toMatchInterpolatedText('not connected paused'); expect(findCell({ fieldKey: 'status' }).text()).toMatchInterpolatedText(
'never contacted paused',
);
// Runner summary // Runner summary
expect(findCell({ fieldKey: 'summary' }).text()).toContain( expect(findCell({ fieldKey: 'summary' }).text()).toContain(
......
...@@ -6,7 +6,6 @@ import { ...@@ -6,7 +6,6 @@ import {
STATUS_ONLINE, STATUS_ONLINE,
STATUS_OFFLINE, STATUS_OFFLINE,
STATUS_STALE, STATUS_STALE,
STATUS_NOT_CONNECTED,
STATUS_NEVER_CONTACTED, STATUS_NEVER_CONTACTED,
} from '~/runner/constants'; } from '~/runner/constants';
...@@ -50,20 +49,7 @@ describe('RunnerTypeBadge', () => { ...@@ -50,20 +49,7 @@ describe('RunnerTypeBadge', () => {
expect(getTooltip().value).toBe('Runner is online; last contact was 1 minute ago'); expect(getTooltip().value).toBe('Runner is online; last contact was 1 minute ago');
}); });
it('renders not connected state', () => { it('renders never contacted state', () => {
createComponent({
runner: {
contactedAt: null,
status: STATUS_NOT_CONNECTED,
},
});
expect(wrapper.text()).toBe('not connected');
expect(findBadge().props('variant')).toBe('muted');
expect(getTooltip().value).toMatch('This runner has never connected');
});
it('renders never contacted state as not connected, for backwards compatibility', () => {
createComponent({ createComponent({
runner: { runner: {
contactedAt: null, contactedAt: null,
...@@ -71,9 +57,9 @@ describe('RunnerTypeBadge', () => { ...@@ -71,9 +57,9 @@ describe('RunnerTypeBadge', () => {
}, },
}); });
expect(wrapper.text()).toBe('not connected'); expect(wrapper.text()).toBe('never contacted');
expect(findBadge().props('variant')).toBe('muted'); expect(findBadge().props('variant')).toBe('muted');
expect(getTooltip().value).toMatch('This runner has never connected'); expect(getTooltip().value).toMatch('This runner has never contacted');
}); });
it('renders offline state', () => { it('renders offline state', () => {
......
import { RUNNER_PAGE_SIZE } from '~/runner/constants'; import { RUNNER_PAGE_SIZE } from '~/runner/constants';
import { import {
searchValidator, searchValidator,
updateOutdatedUrl,
fromUrlQueryToSearch, fromUrlQueryToSearch,
fromSearchToUrl, fromSearchToUrl,
fromSearchToVariables, fromSearchToVariables,
...@@ -190,6 +191,23 @@ describe('search_params.js', () => { ...@@ -190,6 +191,23 @@ describe('search_params.js', () => {
}); });
}); });
describe('updateOutdatedUrl', () => {
it('returns null for urls that do not need updating', () => {
expect(updateOutdatedUrl('http://test.host/')).toBe(null);
expect(updateOutdatedUrl('http://test.host/?a=b')).toBe(null);
});
it('returns updated url for updating NOT_CONNECTED to NEVER_CONTACTED', () => {
expect(updateOutdatedUrl('http://test.host/admin/runners?status[]=NOT_CONNECTED')).toBe(
'http://test.host/admin/runners?status[]=NEVER_CONTACTED',
);
expect(updateOutdatedUrl('http://test.host/admin/runners?status[]=NOT_CONNECTED&a=b')).toBe(
'http://test.host/admin/runners?status[]=NEVER_CONTACTED&a=b',
);
});
});
describe('fromUrlQueryToSearch', () => { describe('fromUrlQueryToSearch', () => {
examples.forEach(({ name, urlQuery, search }) => { examples.forEach(({ name, urlQuery, search }) => {
it(`Converts ${name} to a search object`, () => { it(`Converts ${name} to a search object`, () => {
......
...@@ -12,7 +12,7 @@ RSpec.describe Ci::RunnersHelper do ...@@ -12,7 +12,7 @@ RSpec.describe Ci::RunnersHelper do
describe '#runner_status_icon', :clean_gitlab_redis_cache do describe '#runner_status_icon', :clean_gitlab_redis_cache do
it "returns - not contacted yet" do it "returns - not contacted yet" do
runner = create(:ci_runner) runner = create(:ci_runner)
expect(helper.runner_status_icon(runner)).to include("not connected yet") expect(helper.runner_status_icon(runner)).to include("not contacted yet")
end end
it "returns offline text" do it "returns offline text" do
......
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