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>2022-06-10 18:09:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-10 18:09:22 +0300
commit37140013714814d8ffe662a372697c56eea2fde0 (patch)
treeb25c0bfc62da359f97b8b3742007c07723242f93 /app/assets/javascripts/runner
parent948023c9c900344aa1e2f334bcaae5a194873b0d (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/runner')
-rw-r--r--app/assets/javascripts/runner/admin_runners/admin_runners_app.vue18
-rw-r--r--app/assets/javascripts/runner/admin_runners/index.js4
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_status_cell.vue7
-rw-r--r--app/assets/javascripts/runner/components/runner_list.vue2
-rw-r--r--app/assets/javascripts/runner/components/runner_list_empty_state.vue68
-rw-r--r--app/assets/javascripts/runner/graphql/list/admin_runners.query.graphql2
-rw-r--r--app/assets/javascripts/runner/graphql/list/group_runners.query.graphql2
-rw-r--r--app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql21
-rw-r--r--app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql20
-rw-r--r--app/assets/javascripts/runner/group_runner_show/group_runner_show_app.vue114
-rw-r--r--app/assets/javascripts/runner/group_runner_show/index.js36
-rw-r--r--app/assets/javascripts/runner/group_runners/group_runners_app.vue17
-rw-r--r--app/assets/javascripts/runner/group_runners/index.js4
-rw-r--r--app/assets/javascripts/runner/runner_search_utils.js14
14 files changed, 301 insertions, 28 deletions
diff --git a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
index c2bb635e056..a90ef2d3530 100644
--- a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
+++ b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
@@ -10,6 +10,7 @@ import RegistrationDropdown from '../components/registration/registration_dropdo
import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
import RunnerBulkDelete from '../components/runner_bulk_delete.vue';
import RunnerList from '../components/runner_list.vue';
+import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
import RunnerName from '../components/runner_name.vue';
import RunnerStats from '../components/stat/runner_stats.vue';
import RunnerPagination from '../components/runner_pagination.vue';
@@ -35,6 +36,7 @@ import {
fromUrlQueryToSearch,
fromSearchToUrl,
fromSearchToVariables,
+ isSearchFiltered,
} from '../runner_search_utils';
import { captureException } from '../sentry_utils';
@@ -91,6 +93,7 @@ export default {
RunnerFilteredSearchBar,
RunnerBulkDelete,
RunnerList,
+ RunnerListEmptyState,
RunnerName,
RunnerStats,
RunnerPagination,
@@ -98,7 +101,7 @@ export default {
RunnerActionsCell,
},
mixins: [glFeatureFlagMixin()],
- inject: ['localMutations'],
+ inject: ['emptyStateSvgPath', 'emptyStateFilteredSvgPath', 'localMutations'],
props: {
registrationToken: {
type: String,
@@ -190,6 +193,9 @@ export default {
// Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/353981
return this.glFeatures.adminRunnersBulkDelete;
},
+ isSearchFiltered() {
+ return isSearchFiltered(this.search);
+ },
},
watch: {
search: {
@@ -298,9 +304,13 @@ export default {
:stale-runners-count="staleRunnersTotal"
/>
- <div v-if="noRunnersFound" class="gl-text-center gl-p-5">
- {{ __('No runners found') }}
- </div>
+ <runner-list-empty-state
+ v-if="noRunnersFound"
+ :registration-token="registrationToken"
+ :is-search-filtered="isSearchFiltered"
+ :svg-path="emptyStateSvgPath"
+ :filtered-svg-path="emptyStateFilteredSvgPath"
+ />
<template v-else>
<runner-bulk-delete v-if="isBulkDeleteEnabled" />
<runner-list
diff --git a/app/assets/javascripts/runner/admin_runners/index.js b/app/assets/javascripts/runner/admin_runners/index.js
index b1d8442bb32..7bb6cd5689e 100644
--- a/app/assets/javascripts/runner/admin_runners/index.js
+++ b/app/assets/javascripts/runner/admin_runners/index.js
@@ -34,6 +34,8 @@ export const initAdminRunners = (selector = '#js-admin-runners') => {
registrationToken,
onlineContactTimeoutSecs,
staleTimeoutSecs,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
} = el.dataset;
const { cacheConfig, typeDefs, localMutations } = createLocalState();
@@ -50,6 +52,8 @@ export const initAdminRunners = (selector = '#js-admin-runners') => {
localMutations,
onlineContactTimeoutSecs,
staleTimeoutSecs,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
},
render(h) {
return h(AdminRunnersApp, {
diff --git a/app/assets/javascripts/runner/components/cells/runner_status_cell.vue b/app/assets/javascripts/runner/components/cells/runner_status_cell.vue
index 93f86ae2a2c..a48db9f8ac8 100644
--- a/app/assets/javascripts/runner/components/cells/runner_status_cell.vue
+++ b/app/assets/javascripts/runner/components/cells/runner_status_cell.vue
@@ -7,6 +7,8 @@ import RunnerPausedBadge from '../runner_paused_badge.vue';
export default {
components: {
RunnerStatusBadge,
+ RunnerUpgradeStatusBadge: () =>
+ import('ee_component/runner/components/runner_upgrade_status_badge.vue'),
RunnerPausedBadge,
},
directives: {
@@ -33,6 +35,11 @@ export default {
size="sm"
class="gl-display-inline-block gl-max-w-full gl-text-truncate"
/>
+ <runner-upgrade-status-badge
+ :runner="runner"
+ size="sm"
+ class="gl-display-inline-block gl-max-w-full gl-text-truncate"
+ />
<runner-paused-badge
v-if="paused"
size="sm"
diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue
index dcfd4b84dd2..f1f99c728c5 100644
--- a/app/assets/javascripts/runner/components/runner_list.vue
+++ b/app/assets/javascripts/runner/components/runner_list.vue
@@ -12,7 +12,7 @@ import RunnerStatusCell from './cells/runner_status_cell.vue';
import RunnerTags from './runner_tags.vue';
const defaultFields = [
- tableField({ key: 'status', label: s__('Runners|Status') }),
+ tableField({ key: 'status', label: s__('Runners|Status'), thClasses: ['gl-w-15p'] }),
tableField({ key: 'summary', label: s__('Runners|Runner'), thClasses: ['gl-lg-w-25p'] }),
tableField({ key: 'version', label: __('Version') }),
tableField({ key: 'jobCount', label: __('Jobs') }),
diff --git a/app/assets/javascripts/runner/components/runner_list_empty_state.vue b/app/assets/javascripts/runner/components/runner_list_empty_state.vue
new file mode 100644
index 00000000000..cddd51a351c
--- /dev/null
+++ b/app/assets/javascripts/runner/components/runner_list_empty_state.vue
@@ -0,0 +1,68 @@
+<script>
+import { GlEmptyState, GlLink, GlSprintf, GlModalDirective } from '@gitlab/ui';
+import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
+
+export default {
+ components: {
+ GlEmptyState,
+ GlLink,
+ GlSprintf,
+ RunnerInstructionsModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ props: {
+ isSearchFiltered: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ svgPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ filteredSvgPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ registrationToken: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ modalId: 'runners-empty-state-instructions-modal',
+};
+</script>
+
+<template>
+ <gl-empty-state
+ v-if="isSearchFiltered"
+ :title="s__('Runners|No results found')"
+ :svg-path="filteredSvgPath"
+ :description="s__('Runners|Edit your search and try again')"
+ />
+ <gl-empty-state v-else :title="s__('Runners|Get started with runners')" :svg-path="svgPath">
+ <template #description>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link v-gl-modal="$options.modalId">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+
+ <runner-instructions-modal
+ :modal-id="$options.modalId"
+ :registration-token="registrationToken"
+ />
+ </template>
+ </gl-empty-state>
+</template>
diff --git a/app/assets/javascripts/runner/graphql/list/admin_runners.query.graphql b/app/assets/javascripts/runner/graphql/list/admin_runners.query.graphql
index 5d0450e7418..61bfe03bf6e 100644
--- a/app/assets/javascripts/runner/graphql/list/admin_runners.query.graphql
+++ b/app/assets/javascripts/runner/graphql/list/admin_runners.query.graphql
@@ -1,4 +1,4 @@
-#import "~/runner/graphql/list/list_item.fragment.graphql"
+#import "ee_else_ce/runner/graphql/list/list_item.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getRunners(
diff --git a/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql b/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql
index b4f2b5cd8c8..8755636a7ad 100644
--- a/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql
+++ b/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql
@@ -1,4 +1,4 @@
-#import "~/runner/graphql/list/list_item.fragment.graphql"
+#import "ee_else_ce/runner/graphql/list/list_item.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getGroupRunners(
diff --git a/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql b/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql
index 620c18c5bc0..19a5a48ea75 100644
--- a/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql
+++ b/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql
@@ -1,20 +1,5 @@
+#import "./list_item_shared.fragment.graphql"
+
fragment ListItem on CiRunner {
- __typename
- id
- description
- runnerType
- shortSha
- version
- revision
- ipAddress
- active
- locked
- jobCount
- tagList
- contactedAt
- status(legacyMode: null)
- userPermissions {
- updateRunner
- deleteRunner
- }
+ ...ListItemShared
}
diff --git a/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql b/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql
new file mode 100644
index 00000000000..cf925359ffb
--- /dev/null
+++ b/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql
@@ -0,0 +1,20 @@
+fragment ListItemShared on CiRunner {
+ __typename
+ id
+ description
+ runnerType
+ shortSha
+ version
+ revision
+ ipAddress
+ active
+ locked
+ jobCount
+ tagList
+ contactedAt
+ status(legacyMode: null)
+ userPermissions {
+ updateRunner
+ deleteRunner
+ }
+}
diff --git a/app/assets/javascripts/runner/group_runner_show/group_runner_show_app.vue b/app/assets/javascripts/runner/group_runner_show/group_runner_show_app.vue
new file mode 100644
index 00000000000..c336e091fdf
--- /dev/null
+++ b/app/assets/javascripts/runner/group_runner_show/group_runner_show_app.vue
@@ -0,0 +1,114 @@
+<script>
+import { GlBadge, GlTab, GlTooltipDirective } from '@gitlab/ui';
+import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { TYPE_CI_RUNNER } from '~/graphql_shared/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { formatJobCount } from '../utils';
+import RunnerDeleteButton from '../components/runner_delete_button.vue';
+import RunnerEditButton from '../components/runner_edit_button.vue';
+import RunnerPauseButton from '../components/runner_pause_button.vue';
+import RunnerHeader from '../components/runner_header.vue';
+import RunnerDetails from '../components/runner_details.vue';
+import RunnerJobs from '../components/runner_jobs.vue';
+import { I18N_FETCH_ERROR } from '../constants';
+import runnerQuery from '../graphql/show/runner.query.graphql';
+import { captureException } from '../sentry_utils';
+import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_local_storage';
+
+export default {
+ name: 'GroupRunnerShowApp',
+ components: {
+ GlBadge,
+ GlTab,
+ RunnerDeleteButton,
+ RunnerEditButton,
+ RunnerPauseButton,
+ RunnerHeader,
+ RunnerDetails,
+ RunnerJobs,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runnerId: {
+ type: String,
+ required: true,
+ },
+ runnersPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ runner: null,
+ };
+ },
+ apollo: {
+ runner: {
+ query: runnerQuery,
+ variables() {
+ return {
+ id: convertToGraphQLId(TYPE_CI_RUNNER, this.runnerId),
+ };
+ },
+ error(error) {
+ createAlert({ message: I18N_FETCH_ERROR });
+
+ this.reportToSentry(error);
+ },
+ },
+ },
+ computed: {
+ canUpdate() {
+ return this.runner.userPermissions?.updateRunner;
+ },
+ canDelete() {
+ return this.runner.userPermissions?.deleteRunner;
+ },
+ jobCount() {
+ return formatJobCount(this.runner?.jobCount);
+ },
+ },
+ errorCaptured(error) {
+ this.reportToSentry(error);
+ },
+ methods: {
+ reportToSentry(error) {
+ captureException({ error, component: this.$options.name });
+ },
+ onDeleted({ message }) {
+ saveAlertToLocalStorage({ message, variant: VARIANT_SUCCESS });
+ redirectTo(this.runnersPath);
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <runner-header v-if="runner" :runner="runner">
+ <template #actions>
+ <runner-edit-button v-if="canUpdate && runner.editAdminUrl" :href="runner.editAdminUrl" />
+ <runner-pause-button v-if="canUpdate" :runner="runner" />
+ <runner-delete-button v-if="canDelete" :runner="runner" @deleted="onDeleted" />
+ </template>
+ </runner-header>
+
+ <runner-details :runner="runner">
+ <template #jobs-tab>
+ <gl-tab>
+ <template #title>
+ {{ s__('Runners|Jobs') }}
+ <gl-badge v-if="jobCount" data-testid="job-count-badge" class="gl-ml-1" size="sm">
+ {{ jobCount }}
+ </gl-badge>
+ </template>
+
+ <runner-jobs v-if="runner" :runner="runner" />
+ </gl-tab>
+ </template>
+ </runner-details>
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/group_runner_show/index.js b/app/assets/javascripts/runner/group_runner_show/index.js
new file mode 100644
index 00000000000..d1b87c8e427
--- /dev/null
+++ b/app/assets/javascripts/runner/group_runner_show/index.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
+import GroupRunnerShowApp from './group_runner_show_app.vue';
+
+Vue.use(VueApollo);
+
+export const initAdminRunnerShow = (selector = '#js-group-runner-show') => {
+ showAlertFromLocalStorage();
+
+ const el = document.querySelector(selector);
+
+ if (!el) {
+ return null;
+ }
+
+ const { runnerId, runnersPath } = el.dataset;
+
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
+ return new Vue({
+ el,
+ apolloProvider,
+ render(h) {
+ return h(GroupRunnerShowApp, {
+ props: {
+ runnerId,
+ runnersPath,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/runner/group_runners/group_runners_app.vue b/app/assets/javascripts/runner/group_runners/group_runners_app.vue
index b5bd4b111fd..641b3a8f560 100644
--- a/app/assets/javascripts/runner/group_runners/group_runners_app.vue
+++ b/app/assets/javascripts/runner/group_runners/group_runners_app.vue
@@ -8,6 +8,7 @@ import { fetchPolicies } from '~/lib/graphql';
import RegistrationDropdown from '../components/registration/registration_dropdown.vue';
import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
import RunnerList from '../components/runner_list.vue';
+import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
import RunnerName from '../components/runner_name.vue';
import RunnerStats from '../components/stat/runner_stats.vue';
import RunnerPagination from '../components/runner_pagination.vue';
@@ -31,6 +32,7 @@ import {
fromUrlQueryToSearch,
fromSearchToUrl,
fromSearchToVariables,
+ isSearchFiltered,
} from '../runner_search_utils';
import { captureException } from '../sentry_utils';
@@ -86,12 +88,14 @@ export default {
RegistrationDropdown,
RunnerFilteredSearchBar,
RunnerList,
+ RunnerListEmptyState,
RunnerName,
RunnerStats,
RunnerPagination,
RunnerTypeTabs,
RunnerActionsCell,
},
+ inject: ['emptyStateSvgPath', 'emptyStateFilteredSvgPath'],
props: {
registrationToken: {
type: String,
@@ -196,6 +200,9 @@ export default {
filteredSearchNamespace() {
return `${GROUP_FILTERED_SEARCH_NAMESPACE}/${this.groupFullPath}`;
},
+ isSearchFiltered() {
+ return isSearchFiltered(this.search);
+ },
},
watch: {
search: {
@@ -299,9 +306,13 @@ export default {
:stale-runners-count="staleRunnersTotal"
/>
- <div v-if="noRunnersFound" class="gl-text-center gl-p-5">
- {{ __('No runners found') }}
- </div>
+ <runner-list-empty-state
+ v-if="noRunnersFound"
+ :registration-token="registrationToken"
+ :is-search-filtered="isSearchFiltered"
+ :svg-path="emptyStateSvgPath"
+ :filtered-svg-path="emptyStateFilteredSvgPath"
+ />
<template v-else>
<runner-list :runners="runners.items" :loading="runnersLoading">
<template #runner-name="{ runner }">
diff --git a/app/assets/javascripts/runner/group_runners/index.js b/app/assets/javascripts/runner/group_runners/index.js
index 0dade30f820..feed6b0ceb7 100644
--- a/app/assets/javascripts/runner/group_runners/index.js
+++ b/app/assets/javascripts/runner/group_runners/index.js
@@ -22,6 +22,8 @@ export const initGroupRunners = (selector = '#js-group-runners') => {
groupRunnersLimitedCount,
onlineContactTimeoutSecs,
staleTimeoutSecs,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
} = el.dataset;
const apolloProvider = new VueApollo({
@@ -36,6 +38,8 @@ export const initGroupRunners = (selector = '#js-group-runners') => {
groupId,
onlineContactTimeoutSecs: parseInt(onlineContactTimeoutSecs, 10),
staleTimeoutSecs: parseInt(staleTimeoutSecs, 10),
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
},
render(h) {
return h(GroupRunnersApp, {
diff --git a/app/assets/javascripts/runner/runner_search_utils.js b/app/assets/javascripts/runner/runner_search_utils.js
index 0d688ed65ef..e01878f355a 100644
--- a/app/assets/javascripts/runner/runner_search_utils.js
+++ b/app/assets/javascripts/runner/runner_search_utils.js
@@ -236,3 +236,17 @@ export const fromSearchToVariables = ({
...paginationVariables,
};
};
+
+/**
+ * Decides whether or not a search object is the "default" or empty.
+ *
+ * A search is filtered if the user has entered filtering criteria.
+ *
+ * @param {Object} search
+ * @returns true if this search is filtered, false otherwise
+ */
+export const isSearchFiltered = ({ runnerType = null, filters = [], pagination = {} } = {}) => {
+ return Boolean(
+ runnerType !== null || filters?.length !== 0 || (pagination && pagination?.page !== 1),
+ );
+};