diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-20 11:43:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-20 11:43:02 +0300 |
commit | d9ab72d6080f594d0b3cae15f14b3ef2c6c638cb (patch) | |
tree | 2341ef426af70ad1e289c38036737e04b0aa5007 /app/assets/javascripts/clusters | |
parent | d6e514dd13db8947884cd58fe2a9c2a063400a9b (diff) |
Add latest changes from gitlab-org/gitlab@14-4-stable-eev14.4.0-rc42
Diffstat (limited to 'app/assets/javascripts/clusters')
6 files changed, 357 insertions, 0 deletions
diff --git a/app/assets/javascripts/clusters/agents/components/show.vue b/app/assets/javascripts/clusters/agents/components/show.vue new file mode 100644 index 00000000000..5c672d288c5 --- /dev/null +++ b/app/assets/javascripts/clusters/agents/components/show.vue @@ -0,0 +1,159 @@ +<script> +import { + GlAlert, + GlBadge, + GlKeysetPagination, + GlLoadingIcon, + GlSprintf, + GlTab, + GlTabs, +} from '@gitlab/ui'; +import { s__ } from '~/locale'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import { MAX_LIST_COUNT } from '../constants'; +import getClusterAgentQuery from '../graphql/queries/get_cluster_agent.query.graphql'; +import TokenTable from './token_table.vue'; + +export default { + i18n: { + installedInfo: s__('ClusterAgents|Created by %{name} %{time}'), + loadingError: s__('ClusterAgents|An error occurred while loading your agent'), + tokens: s__('ClusterAgents|Access tokens'), + unknownUser: s__('ClusterAgents|Unknown user'), + }, + apollo: { + clusterAgent: { + query: getClusterAgentQuery, + variables() { + return { + agentName: this.agentName, + projectPath: this.projectPath, + ...this.cursor, + }; + }, + update: (data) => data?.project?.clusterAgent, + error() { + this.clusterAgent = null; + }, + }, + }, + components: { + GlAlert, + GlBadge, + GlKeysetPagination, + GlLoadingIcon, + GlSprintf, + GlTab, + GlTabs, + TimeAgoTooltip, + TokenTable, + }, + props: { + agentName: { + required: true, + type: String, + }, + projectPath: { + required: true, + type: String, + }, + }, + data() { + return { + cursor: { + first: MAX_LIST_COUNT, + last: null, + }, + }; + }, + computed: { + createdAt() { + return this.clusterAgent?.createdAt; + }, + createdBy() { + return this.clusterAgent?.createdByUser?.name || this.$options.i18n.unknownUser; + }, + isLoading() { + return this.$apollo.queries.clusterAgent.loading; + }, + showPagination() { + return this.tokenPageInfo.hasPreviousPage || this.tokenPageInfo.hasNextPage; + }, + tokenCount() { + return this.clusterAgent?.tokens?.count; + }, + tokenPageInfo() { + return this.clusterAgent?.tokens?.pageInfo || {}; + }, + tokens() { + return this.clusterAgent?.tokens?.nodes || []; + }, + }, + methods: { + nextPage() { + this.cursor = { + first: MAX_LIST_COUNT, + last: null, + afterToken: this.tokenPageInfo.endCursor, + }; + }, + prevPage() { + this.cursor = { + first: null, + last: MAX_LIST_COUNT, + beforeToken: this.tokenPageInfo.startCursor, + }; + }, + }, +}; +</script> + +<template> + <section> + <h2>{{ agentName }}</h2> + + <gl-loading-icon v-if="isLoading && clusterAgent == null" size="lg" class="gl-m-3" /> + + <div v-else-if="clusterAgent"> + <p data-testid="cluster-agent-create-info"> + <gl-sprintf :message="$options.i18n.installedInfo"> + <template #name> + {{ createdBy }} + </template> + + <template #time> + <time-ago-tooltip :time="createdAt" /> + </template> + </gl-sprintf> + </p> + + <gl-tabs> + <gl-tab> + <template #title> + <span data-testid="cluster-agent-token-count"> + {{ $options.i18n.tokens }} + + <gl-badge v-if="tokenCount" size="sm" class="gl-tab-counter-badge">{{ + tokenCount + }}</gl-badge> + </span> + </template> + + <gl-loading-icon v-if="isLoading" size="md" class="gl-m-3" /> + + <div v-else> + <TokenTable :tokens="tokens" /> + + <div v-if="showPagination" class="gl-display-flex gl-justify-content-center gl-mt-5"> + <gl-keyset-pagination v-bind="tokenPageInfo" @prev="prevPage" @next="nextPage" /> + </div> + </div> + </gl-tab> + </gl-tabs> + </div> + + <gl-alert v-else variant="danger" :dismissible="false"> + {{ $options.i18n.loadingError }} + </gl-alert> + </section> +</template> diff --git a/app/assets/javascripts/clusters/agents/components/token_table.vue b/app/assets/javascripts/clusters/agents/components/token_table.vue new file mode 100644 index 00000000000..70ed2566134 --- /dev/null +++ b/app/assets/javascripts/clusters/agents/components/token_table.vue @@ -0,0 +1,122 @@ +<script> +import { GlEmptyState, GlLink, GlTable, GlTooltip, GlTruncate } from '@gitlab/ui'; +import { helpPagePath } from '~/helpers/help_page_helper'; +import { s__ } from '~/locale'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; + +export default { + components: { + GlEmptyState, + GlLink, + GlTable, + GlTooltip, + GlTruncate, + TimeAgoTooltip, + }, + i18n: { + createdBy: s__('ClusterAgents|Created by'), + createToken: s__('ClusterAgents|You will need to create a token to connect to your agent'), + dateCreated: s__('ClusterAgents|Date created'), + description: s__('ClusterAgents|Description'), + lastUsed: s__('ClusterAgents|Last contact'), + learnMore: s__('ClusterAgents|Learn how to create an agent access token'), + name: s__('ClusterAgents|Name'), + neverUsed: s__('ClusterAgents|Never'), + noTokens: s__('ClusterAgents|This agent has no tokens'), + unknownUser: s__('ClusterAgents|Unknown user'), + }, + props: { + tokens: { + required: true, + type: Array, + }, + }, + computed: { + fields() { + return [ + { + key: 'name', + label: this.$options.i18n.name, + tdAttr: { 'data-testid': 'agent-token-name' }, + }, + { + key: 'lastUsed', + label: this.$options.i18n.lastUsed, + tdAttr: { 'data-testid': 'agent-token-used' }, + }, + { + key: 'createdAt', + label: this.$options.i18n.dateCreated, + tdAttr: { 'data-testid': 'agent-token-created-time' }, + }, + { + key: 'createdBy', + label: this.$options.i18n.createdBy, + tdAttr: { 'data-testid': 'agent-token-created-user' }, + }, + { + key: 'description', + label: this.$options.i18n.description, + tdAttr: { 'data-testid': 'agent-token-description' }, + }, + ]; + }, + learnMoreUrl() { + return helpPagePath('user/clusters/agent/index.md', { + anchor: 'create-an-agent-record-in-gitlab', + }); + }, + }, + methods: { + createdByName(token) { + return token?.createdByUser?.name || this.$options.i18n.unknownUser; + }, + }, +}; +</script> + +<template> + <div v-if="tokens.length"> + <div class="gl-text-right gl-my-5"> + <gl-link target="_blank" :href="learnMoreUrl"> + {{ $options.i18n.learnMore }} + </gl-link> + </div> + + <gl-table :items="tokens" :fields="fields" fixed stacked="md"> + <template #cell(lastUsed)="{ item }"> + <time-ago-tooltip v-if="item.lastUsedAt" :time="item.lastUsedAt" /> + <span v-else>{{ $options.i18n.neverUsed }}</span> + </template> + + <template #cell(createdAt)="{ item }"> + <time-ago-tooltip :time="item.createdAt" /> + </template> + + <template #cell(createdBy)="{ item }"> + <span>{{ createdByName(item) }}</span> + </template> + + <template #cell(description)="{ item }"> + <div v-if="item.description" :id="`tooltip-description-container-${item.id}`"> + <gl-truncate :id="`tooltip-description-${item.id}`" :text="item.description" /> + + <gl-tooltip + :container="`tooltip-description-container-${item.id}`" + :target="`tooltip-description-${item.id}`" + placement="top" + > + {{ item.description }} + </gl-tooltip> + </div> + </template> + </gl-table> + </div> + + <gl-empty-state + v-else + :title="$options.i18n.noTokens" + :primary-button-link="learnMoreUrl" + :primary-button-text="$options.i18n.learnMore" + /> +</template> diff --git a/app/assets/javascripts/clusters/agents/constants.js b/app/assets/javascripts/clusters/agents/constants.js new file mode 100644 index 00000000000..bbc4630f83b --- /dev/null +++ b/app/assets/javascripts/clusters/agents/constants.js @@ -0,0 +1 @@ +export const MAX_LIST_COUNT = 25; diff --git a/app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql b/app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql new file mode 100644 index 00000000000..1e9187e8ad1 --- /dev/null +++ b/app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql @@ -0,0 +1,11 @@ +fragment Token on ClusterAgentToken { + id + createdAt + description + lastUsedAt + name + + createdByUser { + name + } +} diff --git a/app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql b/app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql new file mode 100644 index 00000000000..d01db8f0a6a --- /dev/null +++ b/app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql @@ -0,0 +1,34 @@ +#import "~/graphql_shared/fragments/pageInfo.fragment.graphql" +#import "../fragments/cluster_agent_token.fragment.graphql" + +query getClusterAgent( + $projectPath: ID! + $agentName: String! + $first: Int + $last: Int + $afterToken: String + $beforeToken: String +) { + project(fullPath: $projectPath) { + clusterAgent(name: $agentName) { + id + createdAt + + createdByUser { + name + } + + tokens(first: $first, last: $last, before: $beforeToken, after: $afterToken) { + count + + nodes { + ...Token + } + + pageInfo { + ...PageInfo + } + } + } + } +} diff --git a/app/assets/javascripts/clusters/agents/index.js b/app/assets/javascripts/clusters/agents/index.js new file mode 100644 index 00000000000..bcb5b271203 --- /dev/null +++ b/app/assets/javascripts/clusters/agents/index.js @@ -0,0 +1,30 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import AgentShowPage from './components/show.vue'; + +Vue.use(VueApollo); + +export default () => { + const el = document.querySelector('#js-cluster-agent-details'); + + if (!el) { + return null; + } + + const defaultClient = createDefaultClient(); + const { agentName, projectPath } = el.dataset; + + return new Vue({ + el, + apolloProvider: new VueApollo({ defaultClient }), + render(createElement) { + return createElement(AgentShowPage, { + props: { + agentName, + projectPath, + }, + }); + }, + }); +}; |