diff options
Diffstat (limited to 'app/assets/javascripts/clusters')
5 files changed, 208 insertions, 4 deletions
diff --git a/app/assets/javascripts/clusters/agents/components/agent_integration_status_row.vue b/app/assets/javascripts/clusters/agents/components/agent_integration_status_row.vue new file mode 100644 index 00000000000..59de6df1e49 --- /dev/null +++ b/app/assets/javascripts/clusters/agents/components/agent_integration_status_row.vue @@ -0,0 +1,66 @@ +<script> +import { GlLink, GlIcon, GlBadge } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; + +export default { + components: { + GlLink, + GlIcon, + GlBadge, + }, + mixins: [glFeatureFlagMixin()], + i18n: { + premiumTitle: s__('ClusterAgents|Premium'), + }, + props: { + text: { + required: true, + type: String, + }, + icon: { + required: false, + type: String, + default: 'information', + }, + iconClass: { + required: false, + type: String, + default: 'text-info', + }, + helpUrl: { + required: false, + type: String, + default: null, + }, + featureName: { + required: false, + type: String, + default: null, + }, + }, + computed: { + showPremiumBadge() { + return this.featureName && !this.glFeatures[this.featureName]; + }, + }, +}; +</script> + +<template> + <li class="gl-mb-3"> + <gl-icon :name="icon" :size="16" :class="iconClass" class="gl-mr-2" /> + + <gl-link v-if="helpUrl" :href="helpUrl">{{ text }}</gl-link> + <span v-else>{{ text }}</span> + + <gl-badge + v-if="showPremiumBadge" + size="md" + class="gl-ml-2 gl-vertical-align-middle" + icon="license" + variant="tier" + >{{ $options.i18n.premiumTitle }}</gl-badge + > + </li> +</template> diff --git a/app/assets/javascripts/clusters/agents/components/integration_status.vue b/app/assets/javascripts/clusters/agents/components/integration_status.vue new file mode 100644 index 00000000000..68a77dfbc8e --- /dev/null +++ b/app/assets/javascripts/clusters/agents/components/integration_status.vue @@ -0,0 +1,98 @@ +<script> +import { GlCollapse, GlButton, GlIcon } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { AGENT_STATUSES } from '~/clusters_list/constants'; +import { getAgentLastContact, getAgentStatus } from '~/clusters_list/clusters_util'; +import { + INTEGRATION_STATUS_VALID_TOKEN, + INTEGRATION_STATUS_NO_TOKEN, + INTEGRATION_STATUS_RESTRICTED_CI_CD, +} from '../constants'; +import AgentIntegrationStatusRow from './agent_integration_status_row.vue'; + +export default { + components: { + GlCollapse, + GlButton, + GlIcon, + AgentIntegrationStatusRow, + }, + i18n: { + title: s__('ClusterAgents|Integration Status'), + }, + AGENT_STATUSES, + props: { + tokens: { + required: true, + type: Array, + }, + }, + data() { + return { + isVisible: false, + }; + }, + computed: { + chevronIcon() { + return this.isVisible ? 'chevron-down' : 'chevron-right'; + }, + agentStatus() { + const lastContact = getAgentLastContact(this.tokens); + return getAgentStatus(lastContact); + }, + integrationStatuses() { + const statuses = []; + + if (this.agentStatus === 'active') { + statuses.push(INTEGRATION_STATUS_VALID_TOKEN); + } + + if (!this.tokens.length) { + statuses.push(INTEGRATION_STATUS_NO_TOKEN); + } + + statuses.push(INTEGRATION_STATUS_RESTRICTED_CI_CD); + + return statuses; + }, + }, + methods: { + toggleCollapse() { + this.isVisible = !this.isVisible; + }, + }, +}; +</script> + +<template> + <div> + <gl-button + :icon="chevronIcon" + variant="link" + size="small" + class="gl-mr-3" + @click="toggleCollapse" + > + {{ $options.i18n.title }} </gl-button + ><span data-testid="agent-status"> + <gl-icon + :name="$options.AGENT_STATUSES[agentStatus].icon" + :class="$options.AGENT_STATUSES[agentStatus].class" + class="gl-mr-2" + />{{ $options.AGENT_STATUSES[agentStatus].name }} + </span> + <gl-collapse v-model="isVisible" class="gl-ml-5 gl-mt-5"> + <ul class="gl-list-style-none gl-pl-2 gl-mb-0"> + <agent-integration-status-row + v-for="(status, index) in integrationStatuses" + :key="index" + :icon="status.icon" + :icon-class="status.iconClass" + :text="status.text" + :help-url="status.helpUrl" + :feature-name="status.featureName" + /> + </ul> + </gl-collapse> + </div> +</template> diff --git a/app/assets/javascripts/clusters/agents/components/show.vue b/app/assets/javascripts/clusters/agents/components/show.vue index e3de8339325..f1bd36b4a63 100644 --- a/app/assets/javascripts/clusters/agents/components/show.vue +++ b/app/assets/javascripts/clusters/agents/components/show.vue @@ -14,6 +14,7 @@ import { MAX_LIST_COUNT, TOKEN_STATUS_ACTIVE } from '../constants'; import getClusterAgentQuery from '../graphql/queries/get_cluster_agent.query.graphql'; import TokenTable from './token_table.vue'; import ActivityEvents from './activity_events_list.vue'; +import IntegrationStatus from './integration_status.vue'; export default { i18n: { @@ -51,6 +52,7 @@ export default { TimeAgoTooltip, TokenTable, ActivityEvents, + IntegrationStatus, }, inject: ['agentName', 'projectPath'], data() { @@ -105,11 +107,11 @@ export default { <template> <section> - <h2>{{ agentName }}</h2> + <h1>{{ agentName }}</h1> <gl-loading-icon v-if="isLoading && clusterAgent == null" size="lg" class="gl-m-3" /> - <div v-else-if="clusterAgent"> + <template v-else-if="clusterAgent"> <p data-testid="cluster-agent-create-info"> <gl-sprintf :message="$options.i18n.installedInfo"> <template #name> @@ -122,7 +124,16 @@ export default { </gl-sprintf> </p> - <gl-tabs sync-active-tab-with-query-params lazy> + <integration-status + :tokens="tokens" + class="gl-py-5 gl-border-t-1 gl-border-t-solid gl-border-t-gray-100" + /> + + <gl-tabs + sync-active-tab-with-query-params + lazy + class="gl-border-t-1 gl-border-t-solid gl-border-t-gray-100" + > <gl-tab :title="$options.i18n.activity" query-param-value="activity"> <activity-events :agent-name="agentName" :project-path="projectPath" /> </gl-tab> @@ -151,7 +162,7 @@ export default { </div> </gl-tab> </gl-tabs> - </div> + </template> <gl-alert v-else variant="danger" :dismissible="false"> {{ $options.i18n.loadingError }} diff --git a/app/assets/javascripts/clusters/agents/components/token_table.vue b/app/assets/javascripts/clusters/agents/components/token_table.vue index f74d66f6b8f..667d10e1753 100644 --- a/app/assets/javascripts/clusters/agents/components/token_table.vue +++ b/app/assets/javascripts/clusters/agents/components/token_table.vue @@ -44,36 +44,43 @@ export default { }, computed: { fields() { + const tdClass = 'gl-vertical-align-middle!'; return [ { key: 'name', label: this.$options.i18n.name, tdAttr: { 'data-testid': 'agent-token-name' }, + tdClass, }, { key: 'lastUsed', label: this.$options.i18n.lastUsed, tdAttr: { 'data-testid': 'agent-token-used' }, + tdClass, }, { key: 'createdAt', label: this.$options.i18n.dateCreated, tdAttr: { 'data-testid': 'agent-token-created-time' }, + tdClass, }, { key: 'createdBy', label: this.$options.i18n.createdBy, tdAttr: { 'data-testid': 'agent-token-created-user' }, + tdClass, }, { key: 'description', label: this.$options.i18n.description, tdAttr: { 'data-testid': 'agent-token-description' }, + tdClass, }, { key: 'actions', label: '', tdAttr: { 'data-testid': 'agent-token-revoke' }, + tdClass, }, ]; }, diff --git a/app/assets/javascripts/clusters/agents/constants.js b/app/assets/javascripts/clusters/agents/constants.js index 962fa243903..76af552181f 100644 --- a/app/assets/javascripts/clusters/agents/constants.js +++ b/app/assets/javascripts/clusters/agents/constants.js @@ -1,4 +1,5 @@ import { s__ } from '~/locale'; +import { helpPagePath } from '~/helpers/help_page_helper'; export const MAX_LIST_COUNT = 25; @@ -46,3 +47,24 @@ export const EVENT_ACTIONS_CLICK = 'click_button'; export const TOKEN_NAME_LIMIT = 255; export const REVOKE_TOKEN_MODAL_ID = 'revoke-token-%{tokenName}'; + +export const INTEGRATION_STATUS_VALID_TOKEN = { + icon: 'status-success', + iconClass: 'text-success-500', + text: s__('ClusterAgents|Valid access token'), +}; +export const INTEGRATION_STATUS_NO_TOKEN = { + icon: 'status-alert', + iconClass: 'text-danger-500', + text: s__('ClusterAgents|No agent access token'), +}; + +export const INTEGRATION_STATUS_RESTRICTED_CI_CD = { + icon: 'information', + iconClass: 'text-info', + text: s__('ClusterAgents|CI/CD workflow with restricted access'), + helpUrl: helpPagePath('user/clusters/agent/ci_cd_workflow', { + anchor: 'restrict-project-and-group-access-by-using-impersonation', + }), + featureName: 'clusterAgentsCiImpersonation', +}; |