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_stacked_summary_cell.vue112
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_status_cell.vue3
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_summary_cell.vue71
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_summary_field.vue33
-rw-r--r--app/assets/javascripts/runner/components/runner_detail.vue9
-rw-r--r--app/assets/javascripts/runner/components/runner_details.vue46
-rw-r--r--app/assets/javascripts/runner/components/runner_header.vue46
-rw-r--r--app/assets/javascripts/runner/components/runner_list.vue49
-rw-r--r--app/assets/javascripts/runner/components/runner_name.vue4
-rw-r--r--app/assets/javascripts/runner/components/runner_paused_badge.vue12
-rw-r--r--app/assets/javascripts/runner/components/runner_projects.vue41
-rw-r--r--app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue58
-rw-r--r--app/assets/javascripts/runner/components/runner_status_badge.vue26
-rw-r--r--app/assets/javascripts/runner/components/runner_tags.vue2
-rw-r--r--app/assets/javascripts/runner/components/runner_type_badge.vue21
-rw-r--r--app/assets/javascripts/runner/components/search_tokens/paused_token_config.js6
-rw-r--r--app/assets/javascripts/runner/components/search_tokens/status_token_config.js14
-rw-r--r--app/assets/javascripts/runner/components/stat/runner_stats.vue22
18 files changed, 397 insertions, 178 deletions
diff --git a/app/assets/javascripts/runner/components/cells/runner_stacked_summary_cell.vue b/app/assets/javascripts/runner/components/cells/runner_stacked_summary_cell.vue
new file mode 100644
index 00000000000..e5d49eb7c8e
--- /dev/null
+++ b/app/assets/javascripts/runner/components/cells/runner_stacked_summary_cell.vue
@@ -0,0 +1,112 @@
+<script>
+import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
+
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import RunnerName from '../runner_name.vue';
+import RunnerTags from '../runner_tags.vue';
+import RunnerTypeBadge from '../runner_type_badge.vue';
+
+import { formatJobCount } from '../../utils';
+import {
+ I18N_LOCKED_RUNNER_DESCRIPTION,
+ I18N_VERSION_LABEL,
+ I18N_LAST_CONTACT_LABEL,
+ I18N_CREATED_AT_LABEL,
+} from '../../constants';
+import RunnerSummaryField from './runner_summary_field.vue';
+
+export default {
+ components: {
+ GlIcon,
+ GlSprintf,
+ TimeAgo,
+ RunnerSummaryField,
+ RunnerName,
+ RunnerTags,
+ RunnerTypeBadge,
+ RunnerUpgradeStatusIcon: () =>
+ import('ee_component/runner/components/runner_upgrade_status_icon.vue'),
+ TooltipOnTruncate,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ jobCount() {
+ return formatJobCount(this.runner.jobCount);
+ },
+ },
+ i18n: {
+ I18N_LOCKED_RUNNER_DESCRIPTION,
+ I18N_VERSION_LABEL,
+ I18N_LAST_CONTACT_LABEL,
+ I18N_CREATED_AT_LABEL,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div>
+ <slot :runner="runner" name="runner-name">
+ <runner-name :runner="runner" />
+ </slot>
+ <gl-icon
+ v-if="runner.locked"
+ v-gl-tooltip
+ :title="$options.i18n.I18N_LOCKED_RUNNER_DESCRIPTION"
+ name="lock"
+ />
+ <runner-type-badge :type="runner.runnerType" size="sm" class="gl-vertical-align-middle" />
+ </div>
+
+ <div class="gl-ml-auto gl-display-inline-flex gl-max-w-full gl-py-2">
+ <div class="gl-flex-shrink-0">
+ <runner-upgrade-status-icon :runner="runner" />
+ <gl-sprintf v-if="runner.version" :message="$options.i18n.I18N_VERSION_LABEL">
+ <template #version>{{ runner.version }}</template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-text-secondary gl-mx-2" aria-hidden="true">ยท</div>
+ <tooltip-on-truncate class="gl-text-truncate gl-display-block" :title="runner.description">
+ {{ runner.description }}
+ </tooltip-on-truncate>
+ </div>
+
+ <div>
+ <runner-summary-field icon="clock">
+ <gl-sprintf :message="$options.i18n.I18N_LAST_CONTACT_LABEL">
+ <template #timeAgo>
+ <time-ago v-if="runner.contactedAt" :time="runner.contactedAt" />
+ <template v-else>{{ __('Never') }}</template>
+ </template>
+ </gl-sprintf>
+ </runner-summary-field>
+
+ <runner-summary-field v-if="runner.ipAddress" icon="disk" :tooltip="__('IP Address')">
+ {{ runner.ipAddress }}
+ </runner-summary-field>
+
+ <runner-summary-field icon="pipeline" data-testid="job-count" :tooltip="__('Jobs')">
+ {{ jobCount }}
+ </runner-summary-field>
+
+ <runner-summary-field icon="calendar">
+ <gl-sprintf :message="$options.i18n.I18N_CREATED_AT_LABEL">
+ <template #timeAgo>
+ <time-ago v-if="runner.createdAt" :time="runner.createdAt" />
+ </template>
+ </gl-sprintf>
+ </runner-summary-field>
+ </div>
+
+ <runner-tags class="gl-display-block gl-pt-2" :tag-list="runner.tagList" size="sm" />
+ </div>
+</template>
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 a48db9f8ac8..eb98d4ae2fb 100644
--- a/app/assets/javascripts/runner/components/cells/runner_status_cell.vue
+++ b/app/assets/javascripts/runner/components/cells/runner_status_cell.vue
@@ -32,17 +32,14 @@ export default {
<div>
<runner-status-badge
:runner="runner"
- 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"
class="gl-display-inline-block gl-max-w-full gl-text-truncate"
/>
</div>
diff --git a/app/assets/javascripts/runner/components/cells/runner_summary_cell.vue b/app/assets/javascripts/runner/components/cells/runner_summary_cell.vue
deleted file mode 100644
index 1cd098d6713..00000000000
--- a/app/assets/javascripts/runner/components/cells/runner_summary_cell.vue
+++ /dev/null
@@ -1,71 +0,0 @@
-<script>
-import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import RunnerName from '../runner_name.vue';
-import RunnerTypeBadge from '../runner_type_badge.vue';
-
-import { I18N_LOCKED_RUNNER_DESCRIPTION } from '../../constants';
-
-export default {
- components: {
- GlIcon,
- TooltipOnTruncate,
- RunnerName,
- RunnerTypeBadge,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- runner: {
- type: Object,
- required: true,
- },
- },
- computed: {
- runnerType() {
- return this.runner.runnerType;
- },
- locked() {
- return this.runner.locked;
- },
- description() {
- return this.runner.description;
- },
- ipAddress() {
- return this.runner.ipAddress;
- },
- },
- i18n: {
- I18N_LOCKED_RUNNER_DESCRIPTION,
- },
-};
-</script>
-
-<template>
- <div>
- <slot :runner="runner" name="runner-name">
- <runner-name :runner="runner" />
- </slot>
-
- <runner-type-badge :type="runnerType" size="sm" />
- <gl-icon
- v-if="locked"
- v-gl-tooltip
- :title="$options.i18n.I18N_LOCKED_RUNNER_DESCRIPTION"
- name="lock"
- />
- <tooltip-on-truncate class="gl-display-block gl-text-truncate" :title="description">
- {{ description }}
- </tooltip-on-truncate>
- <tooltip-on-truncate
- v-if="ipAddress"
- class="gl-display-block gl-text-truncate"
- :title="ipAddress"
- >
- <span class="gl-md-display-none gl-lg-display-inline">{{ __('IP Address') }}</span>
- <strong>{{ ipAddress }}</strong>
- </tooltip-on-truncate>
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/components/cells/runner_summary_field.vue b/app/assets/javascripts/runner/components/cells/runner_summary_field.vue
new file mode 100644
index 00000000000..1bbbd55089a
--- /dev/null
+++ b/app/assets/javascripts/runner/components/cells/runner_summary_field.vue
@@ -0,0 +1,33 @@
+<script>
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlIcon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ icon: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ tooltip: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+};
+</script>
+
+<template>
+ <div v-gl-tooltip="tooltip" class="gl-display-inline-block gl-text-secondary gl-my-2 gl-mr-2">
+ <gl-icon v-if="icon" :name="icon" />
+ <!-- display tooltip as a label for screen readers -->
+ <span class="gl-sr-only">{{ tooltip }}</span>
+ <slot></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_detail.vue b/app/assets/javascripts/runner/components/runner_detail.vue
index 584f77b7648..c260670b517 100644
--- a/app/assets/javascripts/runner/components/runner_detail.vue
+++ b/app/assets/javascripts/runner/components/runner_detail.vue
@@ -21,7 +21,8 @@ export default {
props: {
label: {
type: String,
- required: true,
+ default: null,
+ required: false,
},
value: {
type: String,
@@ -39,7 +40,11 @@ export default {
<template>
<div class="gl-display-contents">
- <dt class="gl-mb-5 gl-mr-6 gl-max-w-26">{{ label }}</dt>
+ <dt class="gl-mb-5 gl-mr-6 gl-max-w-26">
+ <template v-if="label || $scopedSlots.label">
+ <slot name="label">{{ label }}</slot>
+ </template>
+ </dt>
<dd class="gl-mb-5">
<template v-if="value || $scopedSlots.value">
<slot name="value">{{ value }}</slot>
diff --git a/app/assets/javascripts/runner/components/runner_details.vue b/app/assets/javascripts/runner/components/runner_details.vue
index d5222f39b81..79f934764c6 100644
--- a/app/assets/javascripts/runner/components/runner_details.vue
+++ b/app/assets/javascripts/runner/components/runner_details.vue
@@ -1,7 +1,10 @@
<script>
-import { GlIntersperse } from '@gitlab/ui';
+import { GlIntersperse, GlLink } from '@gitlab/ui';
+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';
@@ -12,6 +15,8 @@ import RunnerTags from './runner_tags.vue';
export default {
components: {
GlIntersperse,
+ GlLink,
+ HelpPopover,
RunnerDetail,
RunnerMaintenanceNoteDetail: () =>
import('ee_component/runner/components/runner_maintenance_note_detail.vue'),
@@ -24,6 +29,7 @@ export default {
RunnerTags,
TimeAgo,
},
+ mixins: [glFeatureFlagMixin()],
props: {
runner: {
type: Object,
@@ -60,6 +66,16 @@ export default {
isProjectRunner() {
return this.runner?.runnerType === PROJECT_TYPE;
},
+ tokenExpirationHelpPopoverOptions() {
+ return {
+ title: s__('Runners|Runner authentication token expiration'),
+ };
+ },
+ tokenExpirationHelpUrl() {
+ return helpPagePath('ci/runners/configure_runners', {
+ anchor: 'authentication-token-security',
+ });
+ },
},
ACCESS_LEVEL_REF_PROTECTED,
};
@@ -101,6 +117,34 @@ 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')"
+ >
+ <template #label>
+ {{ s__('Runners|Token expiry') }}
+ <help-popover :options="tokenExpirationHelpPopoverOptions">
+ <p>
+ {{
+ s__(
+ 'Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired.',
+ )
+ }}
+ </p>
+ <p class="gl-mb-0">
+ <gl-link
+ :href="tokenExpirationHelpUrl"
+ target="_blank"
+ class="gl-reset-font-size"
+ >{{ __('Learn more') }}</gl-link
+ >
+ </p>
+ </help-popover>
+ </template>
+ <template v-if="runner.tokenExpiresAt" #value>
+ <time-ago :time="runner.tokenExpiresAt" />
+ </template>
+ </runner-detail>
<runner-detail :label="s__('Runners|Tags')">
<template v-if="tagList.length" #value>
<runner-tags class="gl-vertical-align-middle" :tag-list="tagList" size="sm" />
diff --git a/app/assets/javascripts/runner/components/runner_header.vue b/app/assets/javascripts/runner/components/runner_header.vue
index abc07cec1ad..874c234ca4c 100644
--- a/app/assets/javascripts/runner/components/runner_header.vue
+++ b/app/assets/javascripts/runner/components/runner_header.vue
@@ -38,31 +38,33 @@ export default {
</script>
<template>
<div
- class="gl-display-flex gl-align-items-center gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-gap-3 gl-flex-wrap gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
>
- <div>
+ <div class="gl-display-flex gl-align-items-flex-start gl-gap-3 gl-flex-wrap">
<runner-status-badge :runner="runner" />
<runner-type-badge v-if="runner" :type="runner.runnerType" />
- <template v-if="runner.createdAt">
- <gl-sprintf :message="__('%{runner} created %{timeago}')">
- <template #runner>
- <strong>{{ heading }}</strong>
- <gl-icon
- v-if="runner.locked"
- v-gl-tooltip="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
- name="lock"
- :aria-label="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
- />
- </template>
- <template #timeago>
- <time-ago :time="runner.createdAt" />
- </template>
- </gl-sprintf>
- </template>
- <template v-else>
- <strong>{{ heading }}</strong>
- </template>
+ <span>
+ <template v-if="runner.createdAt">
+ <gl-sprintf :message="__('%{runner} created %{timeago}')">
+ <template #runner>
+ <strong>{{ heading }}</strong>
+ <gl-icon
+ v-if="runner.locked"
+ v-gl-tooltip="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
+ name="lock"
+ :aria-label="$options.I18N_LOCKED_RUNNER_DESCRIPTION"
+ />
+ </template>
+ <template #timeago>
+ <time-ago :time="runner.createdAt" />
+ </template>
+ </gl-sprintf>
+ </template>
+ <template v-else>
+ <strong>{{ heading }}</strong>
+ </template>
+ </span>
</div>
- <div class="gl-ml-auto gl-flex-shrink-0"><slot name="actions"></slot></div>
+ <div class="gl-display-flex gl-gap-3 gl-flex-wrap"><slot name="actions"></slot></div>
</div>
</template>
diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue
index 2e406f71792..26f1f3ce08c 100644
--- a/app/assets/javascripts/runner/components/runner_list.vue
+++ b/app/assets/javascripts/runner/components/runner_list.vue
@@ -1,24 +1,17 @@
<script>
import { GlFormCheckbox, GlTableLite, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { __, s__ } from '~/locale';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import { s__ } from '~/locale';
import checkedRunnerIdsQuery from '../graphql/list/checked_runner_ids.query.graphql';
import { formatJobCount, tableField } from '../utils';
-import RunnerSummaryCell from './cells/runner_summary_cell.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 RunnerTags from './runner_tags.vue';
const defaultFields = [
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') }),
- tableField({ key: 'tagList', label: __('Tags'), thClasses: ['gl-lg-w-25p'] }),
- tableField({ key: 'contactedAt', label: __('Last contact') }),
- tableField({ key: 'actions', label: '' }),
+ tableField({ key: 'summary', label: s__('Runners|Runner') }),
+ tableField({ key: 'actions', label: '', thClasses: ['gl-w-15p'] }),
];
export default {
@@ -26,11 +19,8 @@ export default {
GlFormCheckbox,
GlTableLite,
GlSkeletonLoader,
- TooltipOnTruncate,
- TimeAgo,
RunnerStatusPopover,
- RunnerSummaryCell,
- RunnerTags,
+ RunnerStackedSummaryCell,
RunnerStatusCell,
},
directives: {
@@ -74,6 +64,8 @@ export default {
};
},
fields() {
+ const fields = defaultFields;
+
if (this.checkable) {
const checkboxField = tableField({
key: 'checkbox',
@@ -81,9 +73,9 @@ export default {
thClasses: ['gl-w-9'],
tdClass: ['gl-text-center'],
});
- return [checkboxField, ...defaultFields];
+ return [checkboxField, ...fields];
}
- return defaultFields;
+ return fields;
},
},
methods: {
@@ -141,30 +133,11 @@ export default {
</template>
<template #cell(summary)="{ item, index }">
- <runner-summary-cell :runner="item">
+ <runner-stacked-summary-cell :runner="item">
<template #runner-name="{ runner }">
<slot name="runner-name" :runner="runner" :index="index"></slot>
</template>
- </runner-summary-cell>
- </template>
-
- <template #cell(version)="{ item: { version } }">
- <tooltip-on-truncate class="gl-display-block gl-text-truncate" :title="version">
- {{ version }}
- </tooltip-on-truncate>
- </template>
-
- <template #cell(jobCount)="{ item: { jobCount } }">
- {{ formatJobCount(jobCount) }}
- </template>
-
- <template #cell(tagList)="{ item: { tagList } }">
- <runner-tags :tag-list="tagList" size="sm" />
- </template>
-
- <template #cell(contactedAt)="{ item: { contactedAt } }">
- <time-ago v-if="contactedAt" :time="contactedAt" />
- <template v-else>{{ __('Never') }}</template>
+ </runner-stacked-summary-cell>
</template>
<template #cell(actions)="{ item }">
diff --git a/app/assets/javascripts/runner/components/runner_name.vue b/app/assets/javascripts/runner/components/runner_name.vue
index 8e495125e03..d4ecfd2d776 100644
--- a/app/assets/javascripts/runner/components/runner_name.vue
+++ b/app/assets/javascripts/runner/components/runner_name.vue
@@ -14,5 +14,7 @@ export default {
};
</script>
<template>
- <span>#{{ getIdFromGraphQLId(runner.id) }} ({{ runner.shortSha }})</span>
+ <span class="gl-font-weight-bold gl-vertical-align-middle"
+ >#{{ getIdFromGraphQLId(runner.id) }} ({{ runner.shortSha }})</span
+ >
</template>
diff --git a/app/assets/javascripts/runner/components/runner_paused_badge.vue b/app/assets/javascripts/runner/components/runner_paused_badge.vue
index 27618290ce6..00fd84a48d8 100644
--- a/app/assets/javascripts/runner/components/runner_paused_badge.vue
+++ b/app/assets/javascripts/runner/components/runner_paused_badge.vue
@@ -1,6 +1,6 @@
<script>
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
-import { I18N_PAUSED_DESCRIPTION } from '../constants';
+import { I18N_PAUSED, I18N_PAUSED_DESCRIPTION } from '../constants';
export default {
components: {
@@ -9,11 +9,17 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
+ I18N_PAUSED,
I18N_PAUSED_DESCRIPTION,
};
</script>
<template>
- <gl-badge v-gl-tooltip="$options.I18N_PAUSED_DESCRIPTION" variant="danger" v-bind="$attrs">
- {{ s__('Runners|paused') }}
+ <gl-badge
+ v-gl-tooltip="$options.I18N_PAUSED_DESCRIPTION"
+ variant="warning"
+ icon="status-paused"
+ v-bind="$attrs"
+ >
+ {{ $options.I18N_PAUSED }}
</gl-badge>
</template>
diff --git a/app/assets/javascripts/runner/components/runner_projects.vue b/app/assets/javascripts/runner/components/runner_projects.vue
index 2c1d2fc2b10..84008e8eee8 100644
--- a/app/assets/javascripts/runner/components/runner_projects.vue
+++ b/app/assets/javascripts/runner/components/runner_projects.vue
@@ -1,11 +1,13 @@
<script>
-import { GlSkeletonLoader } from '@gitlab/ui';
+import { GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
import { sprintf, formatNumber } from '~/locale';
import { createAlert } from '~/flash';
import runnerProjectsQuery from '../graphql/show/runner_projects.query.graphql';
import {
I18N_ASSIGNED_PROJECTS,
- I18N_NONE,
+ I18N_CLEAR_FILTER_PROJECTS,
+ I18N_FILTER_PROJECTS,
+ I18N_NO_PROJECTS_FOUND,
I18N_FETCH_ERROR,
RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
} from '../constants';
@@ -14,9 +16,12 @@ import { captureException } from '../sentry_utils';
import RunnerAssignedItem from './runner_assigned_item.vue';
import RunnerPagination from './runner_pagination.vue';
+const SHORT_SEARCH_LENGTH = 3;
+
export default {
name: 'RunnerProjects',
components: {
+ GlSearchBoxByType,
GlSkeletonLoader,
RunnerAssignedItem,
RunnerPagination,
@@ -35,6 +40,7 @@ export default {
pageInfo: {},
count: 0,
},
+ search: '',
pagination: {},
};
},
@@ -61,9 +67,10 @@ export default {
},
computed: {
variables() {
- const { id } = this.runner;
+ const { search, runner } = this;
return {
- id,
+ id: runner.id,
+ search: search.length >= SHORT_SEARCH_LENGTH ? search : '',
...getPaginationVariables(this.pagination, RUNNER_DETAILS_PROJECTS_PAGE_SIZE),
};
},
@@ -80,22 +87,38 @@ export default {
isOwner(projectId) {
return projectId === this.projects.ownerProjectId;
},
+ onSearchInput(search) {
+ this.search = search;
+ this.pagination = {};
+ },
onPaginationInput(value) {
this.pagination = value;
},
},
- I18N_NONE,
+ RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
+ I18N_CLEAR_FILTER_PROJECTS,
+ I18N_FILTER_PROJECTS,
+ I18N_NO_PROJECTS_FOUND,
};
</script>
<template>
<div class="gl-border-t-gray-100 gl-border-t-1 gl-border-t-solid">
- <h3 class="gl-font-lg gl-mt-5 gl-mb-0">
+ <h3 class="gl-font-lg gl-mt-5">
{{ heading }}
</h3>
+ <gl-search-box-by-type
+ :is-loading="loading"
+ :clear-button-title="$options.I18N_CLEAR_FILTER_PROJECTS"
+ :placeholder="$options.I18N_FILTER_PROJECTS"
+ debounce="500"
+ class="gl-w-28"
+ :value="search"
+ @input="onSearchInput"
+ />
- <div v-if="loading" class="gl-py-5">
- <gl-skeleton-loader />
+ <div v-if="!projects.items.length && loading" class="gl-py-5">
+ <gl-skeleton-loader v-for="i in $options.RUNNER_DETAILS_PROJECTS_PAGE_SIZE" :key="i" />
</div>
<template v-else-if="projects.items.length">
<runner-assigned-item
@@ -110,7 +133,7 @@ export default {
:is-owner="isOwner(project.id)"
/>
</template>
- <span v-else class="gl-text-gray-500">{{ $options.I18N_NONE }}</span>
+ <div v-else class="gl-py-5 gl-text-gray-500">{{ $options.I18N_NO_PROJECTS_FOUND }}</div>
<runner-pagination
:disabled="loading"
diff --git a/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue b/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue
new file mode 100644
index 00000000000..e3a9a9fd8a4
--- /dev/null
+++ b/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue
@@ -0,0 +1,58 @@
+<script>
+import allChangesCommittedSvg from '@gitlab/svgs/dist/illustrations/multi-editor_all_changes_committed_empty.svg';
+import { GlBanner } from '@gitlab/ui';
+
+import { s__ } from '~/locale';
+import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
+
+const I18N_TITLE = s__("Runners|We've made some changes and want your feedback");
+const I18N_DESCRIPTION = s__(
+ "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!",
+);
+const I18N_LINK = s__('Runners|Add your feedback in the issue');
+
+// use a data url instead getting it from via HTML data-* attributes to simplify removal of this feature flag
+const ILLUSTRATION_URL = `data:image/svg+xml;utf8,${encodeURIComponent(allChangesCommittedSvg)}`;
+const ISSUE_URL = 'https://gitlab.com/gitlab-org/gitlab/-/issues/371621';
+const STORAGE_KEY = 'runner_list_stacked_layout_feedback_dismissed';
+
+export default {
+ components: {
+ GlBanner,
+ LocalStorageSync,
+ },
+ data() {
+ return {
+ isDismissed: false,
+ };
+ },
+ methods: {
+ onClose() {
+ this.isDismissed = true;
+ },
+ },
+ I18N_TITLE,
+ I18N_DESCRIPTION,
+ I18N_LINK,
+ ILLUSTRATION_URL,
+ ISSUE_URL,
+ STORAGE_KEY,
+};
+</script>
+
+<template>
+ <div>
+ <local-storage-sync v-model="isDismissed" :storage-key="$options.STORAGE_KEY" />
+ <gl-banner
+ v-if="!isDismissed"
+ :svg-path="$options.ILLUSTRATION_URL"
+ :title="$options.I18N_TITLE"
+ :button-text="$options.I18N_LINK"
+ :button-link="$options.ISSUE_URL"
+ class="gl-my-5"
+ @close="onClose"
+ >
+ <p>{{ $options.I18N_DESCRIPTION }}</p>
+ </gl-banner>
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_status_badge.vue b/app/assets/javascripts/runner/components/runner_status_badge.vue
index 073d0a49f59..d084408781e 100644
--- a/app/assets/javascripts/runner/components/runner_status_badge.vue
+++ b/app/assets/javascripts/runner/components/runner_status_badge.vue
@@ -1,8 +1,12 @@
<script>
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
-import { __, s__, sprintf } from '~/locale';
+import { __, sprintf } from '~/locale';
import { getTimeago } from '~/lib/utils/datetime_utility';
import {
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_NEVER_CONTACTED,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
I18N_ONLINE_TIMEAGO_TOOLTIP,
I18N_NEVER_CONTACTED_TOOLTIP,
I18N_OFFLINE_TIMEAGO_TOOLTIP,
@@ -39,26 +43,30 @@ export default {
switch (this.runner?.status) {
case STATUS_ONLINE:
return {
+ icon: 'status-active',
variant: 'success',
- label: s__('Runners|online'),
+ label: I18N_STATUS_ONLINE,
tooltip: this.timeAgoTooltip(I18N_ONLINE_TIMEAGO_TOOLTIP),
};
case STATUS_NEVER_CONTACTED:
return {
+ icon: 'time-out',
variant: 'muted',
- label: s__('Runners|never contacted'),
+ label: I18N_STATUS_NEVER_CONTACTED,
tooltip: I18N_NEVER_CONTACTED_TOOLTIP,
};
case STATUS_OFFLINE:
return {
+ icon: 'time-out',
variant: 'muted',
- label: s__('Runners|offline'),
+ label: I18N_STATUS_OFFLINE,
tooltip: this.timeAgoTooltip(I18N_OFFLINE_TIMEAGO_TOOLTIP),
};
case STATUS_STALE:
return {
+ icon: 'time-out',
variant: 'warning',
- label: s__('Runners|stale'),
+ label: I18N_STATUS_STALE,
// runner may have contacted (or not) and be stale: consider both cases.
tooltip: this.runner.contactedAt
? this.timeAgoTooltip(I18N_STALE_TIMEAGO_TOOLTIP)
@@ -77,7 +85,13 @@ export default {
};
</script>
<template>
- <gl-badge v-if="badge" v-gl-tooltip="badge.tooltip" :variant="badge.variant" v-bind="$attrs">
+ <gl-badge
+ v-if="badge"
+ v-gl-tooltip="badge.tooltip"
+ :variant="badge.variant"
+ :icon="badge.icon"
+ v-bind="$attrs"
+ >
{{ badge.label }}
</gl-badge>
</template>
diff --git a/app/assets/javascripts/runner/components/runner_tags.vue b/app/assets/javascripts/runner/components/runner_tags.vue
index 797d2a35b2c..38e566f9f53 100644
--- a/app/assets/javascripts/runner/components/runner_tags.vue
+++ b/app/assets/javascripts/runner/components/runner_tags.vue
@@ -20,7 +20,7 @@ export default {
};
</script>
<template>
- <span>
+ <span v-if="tagList && tagList.length">
<runner-tag
v-for="tag in tagList"
:key="tag"
diff --git a/app/assets/javascripts/runner/components/runner_type_badge.vue b/app/assets/javascripts/runner/components/runner_type_badge.vue
index b885dcefdcb..f568f914004 100644
--- a/app/assets/javascripts/runner/components/runner_type_badge.vue
+++ b/app/assets/javascripts/runner/components/runner_type_badge.vue
@@ -1,26 +1,31 @@
<script>
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
-import { s__ } from '~/locale';
import {
INSTANCE_TYPE,
GROUP_TYPE,
PROJECT_TYPE,
+ I18N_INSTANCE_TYPE,
I18N_INSTANCE_RUNNER_DESCRIPTION,
+ I18N_GROUP_TYPE,
I18N_GROUP_RUNNER_DESCRIPTION,
+ I18N_PROJECT_TYPE,
I18N_PROJECT_RUNNER_DESCRIPTION,
} from '../constants';
const BADGE_DATA = {
[INSTANCE_TYPE]: {
- text: s__('Runners|shared'),
+ icon: 'users',
+ text: I18N_INSTANCE_TYPE,
tooltip: I18N_INSTANCE_RUNNER_DESCRIPTION,
},
[GROUP_TYPE]: {
- text: s__('Runners|group'),
+ icon: 'group',
+ text: I18N_GROUP_TYPE,
tooltip: I18N_GROUP_RUNNER_DESCRIPTION,
},
[PROJECT_TYPE]: {
- text: s__('Runners|specific'),
+ icon: 'project',
+ text: I18N_PROJECT_TYPE,
tooltip: I18N_PROJECT_RUNNER_DESCRIPTION,
},
};
@@ -50,7 +55,13 @@ export default {
};
</script>
<template>
- <gl-badge v-if="badge" v-gl-tooltip="badge.tooltip" variant="info" v-bind="$attrs">
+ <gl-badge
+ v-if="badge"
+ v-gl-tooltip="badge.tooltip"
+ variant="muted"
+ :icon="badge.icon"
+ v-bind="$attrs"
+ >
{{ badge.text }}
</gl-badge>
</template>
diff --git a/app/assets/javascripts/runner/components/search_tokens/paused_token_config.js b/app/assets/javascripts/runner/components/search_tokens/paused_token_config.js
index c1ad5da3ab9..97ee8ec3eef 100644
--- a/app/assets/javascripts/runner/components/search_tokens/paused_token_config.js
+++ b/app/assets/javascripts/runner/components/search_tokens/paused_token_config.js
@@ -1,7 +1,7 @@
-import { __, s__ } from '~/locale';
+import { __ } 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';
+import { PARAM_KEY_PAUSED, I18N_PAUSED } from '../../constants';
const options = [
{ value: 'true', title: __('Yes') },
@@ -10,7 +10,7 @@ const options = [
export const pausedTokenConfig = {
icon: 'pause',
- title: s__('Runners|Paused'),
+ title: I18N_PAUSED,
type: PARAM_KEY_PAUSED,
token: BaseToken,
unique: true,
diff --git a/app/assets/javascripts/runner/components/search_tokens/status_token_config.js b/app/assets/javascripts/runner/components/search_tokens/status_token_config.js
index 9e6f63d3f7c..f5c42d120fb 100644
--- a/app/assets/javascripts/runner/components/search_tokens/status_token_config.js
+++ b/app/assets/javascripts/runner/components/search_tokens/status_token_config.js
@@ -1,7 +1,11 @@
-import { __, s__ } from '~/locale';
+import { __ } 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 {
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_NEVER_CONTACTED,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
STATUS_ONLINE,
STATUS_OFFLINE,
STATUS_NEVER_CONTACTED,
@@ -10,10 +14,10 @@ import {
} from '../../constants';
const options = [
- { value: STATUS_ONLINE, title: s__('Runners|Online') },
- { value: STATUS_OFFLINE, title: s__('Runners|Offline') },
- { value: STATUS_NEVER_CONTACTED, title: s__('Runners|Never contacted') },
- { value: STATUS_STALE, title: s__('Runners|Stale') },
+ { value: STATUS_ONLINE, title: I18N_STATUS_ONLINE },
+ { value: STATUS_OFFLINE, title: I18N_STATUS_OFFLINE },
+ { value: STATUS_NEVER_CONTACTED, title: I18N_STATUS_NEVER_CONTACTED },
+ { value: STATUS_STALE, title: I18N_STATUS_STALE },
];
export const statusTokenConfig = {
diff --git a/app/assets/javascripts/runner/components/stat/runner_stats.vue b/app/assets/javascripts/runner/components/stat/runner_stats.vue
index 93e54ebe7f4..4df59f5a0c9 100644
--- a/app/assets/javascripts/runner/components/stat/runner_stats.vue
+++ b/app/assets/javascripts/runner/components/stat/runner_stats.vue
@@ -1,7 +1,13 @@
<script>
-import { s__ } from '~/locale';
import RunnerSingleStat from '~/runner/components/stat/runner_single_stat.vue';
-import { STATUS_ONLINE, STATUS_OFFLINE, STATUS_STALE } from '../../constants';
+import {
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
+ STATUS_ONLINE,
+ STATUS_OFFLINE,
+ STATUS_STALE,
+} from '../../constants';
export default {
components: {
@@ -29,8 +35,8 @@ export default {
skip: this.statusCountSkip(STATUS_ONLINE),
variables: { ...this.variables, status: STATUS_ONLINE },
variant: 'success',
- title: s__('Runners|Online runners'),
- metaText: s__('Runners|online'),
+ title: I18N_STATUS_ONLINE,
+ metaIcon: 'status-active',
},
},
{
@@ -39,8 +45,8 @@ export default {
skip: this.statusCountSkip(STATUS_OFFLINE),
variables: { ...this.variables, status: STATUS_OFFLINE },
variant: 'muted',
- title: s__('Runners|Offline runners'),
- metaText: s__('Runners|offline'),
+ title: I18N_STATUS_OFFLINE,
+ metaIcon: 'status-waiting',
},
},
{
@@ -49,8 +55,8 @@ export default {
skip: this.statusCountSkip(STATUS_STALE),
variables: { ...this.variables, status: STATUS_STALE },
variant: 'warning',
- title: s__('Runners|Stale runners'),
- metaText: s__('Runners|stale'),
+ title: I18N_STATUS_STALE,
+ metaIcon: 'time-out',
},
},
];