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:
Diffstat (limited to 'app/assets/javascripts/runner/components')
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_actions_cell.vue7
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_owner_cell.vue63
-rw-r--r--app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue16
-rw-r--r--app/assets/javascripts/runner/components/runner_delete_button.vue32
-rw-r--r--app/assets/javascripts/runner/components/runner_details.vue7
-rw-r--r--app/assets/javascripts/runner/components/runner_filtered_search_bar.vue1
-rw-r--r--app/assets/javascripts/runner/components/runner_list.vue44
-rw-r--r--app/assets/javascripts/runner/components/runner_list_empty_state.vue9
-rw-r--r--app/assets/javascripts/runner/components/runner_membership_toggle.vue42
-rw-r--r--app/assets/javascripts/runner/components/search_tokens/tag_token.vue18
10 files changed, 182 insertions, 57 deletions
diff --git a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue
index 7a4760f81ee..13f520c4edb 100644
--- a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue
+++ b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue
@@ -52,11 +52,6 @@ export default {
:compact="true"
@toggledPaused="onToggledPaused"
/>
- <runner-delete-button
- :disabled="!canDelete"
- :runner="runner"
- :compact="true"
- @deleted="onDeleted"
- />
+ <runner-delete-button v-if="canDelete" :runner="runner" :compact="true" @deleted="onDeleted" />
</gl-button-group>
</template>
diff --git a/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue b/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue
new file mode 100644
index 00000000000..cb43760b2d6
--- /dev/null
+++ b/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue
@@ -0,0 +1,63 @@
+<script>
+import { GlLink, GlTooltipDirective } from '@gitlab/ui';
+import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE, I18N_ADMIN } from '../../constants';
+
+export default {
+ components: {
+ GlLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ cell() {
+ switch (this.runner?.runnerType) {
+ case INSTANCE_TYPE:
+ return {
+ text: I18N_ADMIN,
+ };
+ case GROUP_TYPE: {
+ const { name, fullName, webUrl } = this.runner?.groups?.nodes[0] || {};
+
+ return {
+ text: name,
+ href: webUrl,
+ tooltip: fullName !== name ? fullName : '',
+ };
+ }
+ case PROJECT_TYPE: {
+ const { name, nameWithNamespace, webUrl } = this.runner?.ownerProject || {};
+
+ return {
+ text: name,
+ href: webUrl,
+ tooltip: nameWithNamespace !== name ? nameWithNamespace : '',
+ };
+ }
+ default:
+ return {};
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-link
+ v-if="cell.href"
+ v-gl-tooltip="cell.tooltip"
+ :href="cell.href"
+ class="gl-text-body gl-text-decoration-underline"
+ >
+ {{ cell.text }}
+ </gl-link>
+ <span v-else>{{ cell.text }}</span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue b/app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue
index dde5a5a4a05..75afb7a00bc 100644
--- a/app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue
+++ b/app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue
@@ -1,5 +1,6 @@
<script>
import { GlFormCheckbox } from '@gitlab/ui';
+import { s__ } from '~/locale';
import checkedRunnerIdsQuery from '../graphql/list/checked_runner_ids.query.graphql';
export default {
@@ -25,14 +26,20 @@ export default {
},
},
computed: {
+ deletableRunners() {
+ return this.runners.filter((runner) => runner.userPermissions?.deleteRunner);
+ },
disabled() {
- return !this.runners.length;
+ return !this.deletableRunners.length;
},
checked() {
- return Boolean(this.runners.length) && this.runners.every(this.isChecked);
+ return Boolean(this.deletableRunners.length) && this.deletableRunners.every(this.isChecked);
},
indeterminate() {
- return !this.checked && this.runners.some(this.isChecked);
+ return !this.checked && this.deletableRunners.some(this.isChecked);
+ },
+ label() {
+ return this.checked ? s__('Runners|Unselect all') : s__('Runners|Select all');
},
},
methods: {
@@ -41,7 +48,7 @@ export default {
},
onChange($event) {
this.localMutations.setRunnersChecked({
- runners: this.runners,
+ runners: this.deletableRunners,
isChecked: $event,
});
},
@@ -51,6 +58,7 @@ export default {
<template>
<gl-form-checkbox
+ :aria-label="label"
:indeterminate="indeterminate"
:checked="checked"
:disabled="disabled"
diff --git a/app/assets/javascripts/runner/components/runner_delete_button.vue b/app/assets/javascripts/runner/components/runner_delete_button.vue
index 62382891df0..b4f022a7d14 100644
--- a/app/assets/javascripts/runner/components/runner_delete_button.vue
+++ b/app/assets/javascripts/runner/components/runner_delete_button.vue
@@ -5,12 +5,7 @@ import { createAlert } from '~/flash';
import { sprintf } from '~/locale';
import { captureException } from '~/runner/sentry_utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import {
- I18N_DELETE_DISABLED_MANY_PROJECTS,
- I18N_DELETE_DISABLED_UNKNOWN_REASON,
- I18N_DELETE_RUNNER,
- I18N_DELETED_TOAST,
-} from '../constants';
+import { I18N_DELETE_RUNNER, I18N_DELETED_TOAST } from '../constants';
import RunnerDeleteModal from './runner_delete_modal.vue';
export default {
@@ -31,11 +26,6 @@ export default {
return runner?.id && runner?.shortSha;
},
},
- disabled: {
- type: Boolean,
- required: false,
- default: false,
- },
compact: {
type: Boolean,
required: false,
@@ -85,29 +75,14 @@ export default {
return null;
},
tooltip() {
- if (this.disabled && this.runner.projectCount > 1) {
- return I18N_DELETE_DISABLED_MANY_PROJECTS;
- }
- if (this.disabled) {
- return I18N_DELETE_DISABLED_UNKNOWN_REASON;
- }
-
// Only show basic "delete" tooltip when compact.
// Also prevent a "sticky" tooltip: If this button is
- // disabled, mouseout listeners don't run leaving the tooltip stuck
+ // loading, mouseout listeners don't run leaving the tooltip stuck
if (this.compact && !this.deleting) {
return I18N_DELETE_RUNNER;
}
return '';
},
- wrapperTabindex() {
- if (this.disabled) {
- // Trigger tooltip on keyboard-focusable wrapper
- // See https://bootstrap-vue.org/docs/directives/tooltip
- return '0';
- }
- return null;
- },
},
methods: {
async onDelete() {
@@ -156,14 +131,13 @@ export default {
</script>
<template>
- <div v-gl-tooltip="tooltip" class="btn-group" :tabindex="wrapperTabindex">
+ <div v-gl-tooltip="tooltip" class="btn-group">
<gl-button
v-gl-modal="runnerDeleteModalId"
:aria-label="ariaLabel"
:icon="icon"
:class="buttonClass"
:loading="deleting"
- :disabled="disabled"
variant="danger"
category="secondary"
v-bind="$attrs"
diff --git a/app/assets/javascripts/runner/components/runner_details.vue b/app/assets/javascripts/runner/components/runner_details.vue
index 79f934764c6..3d72abcd393 100644
--- a/app/assets/javascripts/runner/components/runner_details.vue
+++ b/app/assets/javascripts/runner/components/runner_details.vue
@@ -4,7 +4,6 @@ import { helpPagePath } from '~/helpers/help_page_helper';
import { s__ } from '~/locale';
import HelpPopover from '~/vue_shared/components/help_popover.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import { ACCESS_LEVEL_REF_PROTECTED, GROUP_TYPE, PROJECT_TYPE } from '../constants';
import RunnerDetail from './runner_detail.vue';
@@ -29,7 +28,6 @@ export default {
RunnerTags,
TimeAgo,
},
- mixins: [glFeatureFlagMixin()],
props: {
runner: {
type: Object,
@@ -117,10 +115,7 @@ export default {
</template>
</runner-detail>
<runner-detail :label="s__('Runners|Maximum job timeout')" :value="maximumTimeout" />
- <runner-detail
- v-if="glFeatures.enforceRunnerTokenExpiresAt"
- :empty-value="s__('Runners|Never expires')"
- >
+ <runner-detail :empty-value="s__('Runners|Never expires')">
<template #label>
{{ s__('Runners|Token expiry') }}
<help-popover :options="tokenExpirationHelpPopoverOptions">
diff --git a/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue b/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue
index 5a9ab21a457..da59de9a9eb 100644
--- a/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue
+++ b/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue
@@ -85,7 +85,6 @@ export default {
</script>
<template>
<filtered-search
- class="gl-bg-gray-10 gl-p-5 gl-border-solid gl-border-gray-100 gl-border-0 gl-border-t-1 gl-border-b-1"
v-bind="$attrs"
:namespace="namespace"
recent-searches-storage-key="runners-search"
diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue
index 26f1f3ce08c..e895537dcdc 100644
--- a/app/assets/javascripts/runner/components/runner_list.vue
+++ b/app/assets/javascripts/runner/components/runner_list.vue
@@ -2,15 +2,20 @@
import { GlFormCheckbox, GlTableLite, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { s__ } from '~/locale';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
import checkedRunnerIdsQuery from '../graphql/list/checked_runner_ids.query.graphql';
import { formatJobCount, tableField } from '../utils';
+import RunnerBulkDelete from './runner_bulk_delete.vue';
+import RunnerBulkDeleteCheckbox from './runner_bulk_delete_checkbox.vue';
import RunnerStackedSummaryCell from './cells/runner_stacked_summary_cell.vue';
import RunnerStatusPopover from './runner_status_popover.vue';
import RunnerStatusCell from './cells/runner_status_cell.vue';
+import RunnerOwnerCell from './cells/runner_owner_cell.vue';
const defaultFields = [
tableField({ key: 'status', label: s__('Runners|Status'), thClasses: ['gl-w-15p'] }),
tableField({ key: 'summary', label: s__('Runners|Runner') }),
+ tableField({ key: 'owner', label: s__('Runners|Owner'), thClasses: ['gl-w-20p'] }),
tableField({ key: 'actions', label: '', thClasses: ['gl-w-15p'] }),
];
@@ -19,9 +24,13 @@ export default {
GlFormCheckbox,
GlTableLite,
GlSkeletonLoader,
+ HelpPopover,
+ RunnerBulkDelete,
+ RunnerBulkDeleteCheckbox,
RunnerStatusPopover,
RunnerStackedSummaryCell,
RunnerStatusCell,
+ RunnerOwnerCell,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -34,6 +43,7 @@ export default {
},
},
},
+ inject: ['localMutations'],
props: {
checkable: {
type: Boolean,
@@ -50,7 +60,7 @@ export default {
required: true,
},
},
- emits: ['checked'],
+ emits: ['deleted'],
data() {
return { checkedRunnerIds: [] };
},
@@ -79,6 +89,12 @@ export default {
},
},
methods: {
+ canDelete(runner) {
+ return runner.userPermissions?.deleteRunner;
+ },
+ onDeleted(event) {
+ this.$emit('deleted', event);
+ },
formatJobCount(jobCount) {
return formatJobCount(jobCount);
},
@@ -91,7 +107,7 @@ export default {
return {};
},
onCheckboxChange(runner, isChecked) {
- this.$emit('checked', {
+ this.localMutations.setRunnerChecked({
runner,
isChecked,
});
@@ -104,6 +120,7 @@ export default {
</script>
<template>
<div>
+ <runner-bulk-delete v-if="checkable" :runners="runners" @deleted="onDeleted" />
<gl-table-lite
:aria-busy="loading"
:class="tableClass"
@@ -116,11 +133,15 @@ export default {
fixed
>
<template #head(checkbox)>
- <slot name="head-checkbox"></slot>
+ <runner-bulk-delete-checkbox :runners="runners" />
</template>
<template #cell(checkbox)="{ item }">
- <gl-form-checkbox :checked="isChecked(item)" @change="onCheckboxChange(item, $event)" />
+ <gl-form-checkbox
+ v-if="canDelete(item)"
+ :checked="isChecked(item)"
+ @change="onCheckboxChange(item, $event)"
+ />
</template>
<template #head(status)="{ label }">
@@ -140,6 +161,21 @@ export default {
</runner-stacked-summary-cell>
</template>
+ <template #head(owner)="{ label }">
+ {{ label }}
+ <help-popover>
+ {{
+ s__(
+ 'Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator.',
+ )
+ }}
+ </help-popover>
+ </template>
+
+ <template #cell(owner)="{ item }">
+ <runner-owner-cell :runner="item" />
+ </template>
+
<template #cell(actions)="{ item }">
<slot name="runner-actions-cell" :runner="item"></slot>
</template>
diff --git a/app/assets/javascripts/runner/components/runner_list_empty_state.vue b/app/assets/javascripts/runner/components/runner_list_empty_state.vue
index ab9cde6a401..e6576c83e69 100644
--- a/app/assets/javascripts/runner/components/runner_list_empty_state.vue
+++ b/app/assets/javascripts/runner/components/runner_list_empty_state.vue
@@ -53,7 +53,7 @@ export default {
:svg-path="svgPath"
:svg-height="$options.svgHeight"
>
- <template #description>
+ <template v-if="registrationToken" #description>
<gl-sprintf
:message="
s__(
@@ -71,5 +71,12 @@ export default {
:registration-token="registrationToken"
/>
</template>
+ <template v-else #description>
+ {{
+ s__(
+ 'Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator.',
+ )
+ }}
+ </template>
</gl-empty-state>
</template>
diff --git a/app/assets/javascripts/runner/components/runner_membership_toggle.vue b/app/assets/javascripts/runner/components/runner_membership_toggle.vue
new file mode 100644
index 00000000000..2b37b1cc797
--- /dev/null
+++ b/app/assets/javascripts/runner/components/runner_membership_toggle.vue
@@ -0,0 +1,42 @@
+<script>
+import { GlToggle } from '@gitlab/ui';
+import {
+ I18N_SHOW_ONLY_INHERITED,
+ MEMBERSHIP_DESCENDANTS,
+ MEMBERSHIP_ALL_AVAILABLE,
+} from '../constants';
+
+export default {
+ components: {
+ GlToggle,
+ },
+ props: {
+ value: {
+ type: String,
+ default: MEMBERSHIP_DESCENDANTS,
+ required: false,
+ },
+ },
+ computed: {
+ toggle() {
+ return this.value === MEMBERSHIP_DESCENDANTS;
+ },
+ },
+ methods: {
+ onChange(value) {
+ this.$emit('input', value ? MEMBERSHIP_DESCENDANTS : MEMBERSHIP_ALL_AVAILABLE);
+ },
+ },
+ I18N_SHOW_ONLY_INHERITED,
+};
+</script>
+
+<template>
+ <gl-toggle
+ data-testid="runner-membership-toggle"
+ :value="toggle"
+ :label="$options.I18N_SHOW_ONLY_INHERITED"
+ label-position="left"
+ @change="onChange"
+ />
+</template>
diff --git a/app/assets/javascripts/runner/components/search_tokens/tag_token.vue b/app/assets/javascripts/runner/components/search_tokens/tag_token.vue
index 59230bb809e..6e7c41885f8 100644
--- a/app/assets/javascripts/runner/components/search_tokens/tag_token.vue
+++ b/app/assets/javascripts/runner/components/search_tokens/tag_token.vue
@@ -7,6 +7,12 @@ import { s__ } from '~/locale';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { RUNNER_TAG_BG_CLASS } from '../../constants';
+// TODO This should be implemented via a GraphQL API
+// The API should
+// 1) scope to the rights of the user
+// 2) stay up to date to the removal of old tags
+// 3) consider the scope of search, like searching within the tags of a group
+// See: https://gitlab.com/gitlab-org/gitlab/-/issues/333796
export const TAG_SUGGESTIONS_PATH = '/admin/runners/tag_list.json';
export default {
@@ -29,12 +35,6 @@ export default {
},
methods: {
getTagsOptions(search) {
- // TODO This should be implemented via a GraphQL API
- // The API should
- // 1) scope to the rights of the user
- // 2) stay up to date to the removal of old tags
- // 3) consider the scope of search, like searching within the tags of a group
- // See: https://gitlab.com/gitlab-org/gitlab/-/issues/333796
return axios
.get(TAG_SUGGESTIONS_PATH, {
params: {
@@ -46,6 +46,12 @@ export default {
});
},
async fetchTags(searchTerm) {
+ // Note: Suggestions should only be enabled for admin users
+ if (this.config.suggestionsDisabled) {
+ this.tags = [];
+ return;
+ }
+
this.loading = true;
try {
this.tags = await this.getTagsOptions(searchTerm);