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/clusters')
-rw-r--r--app/assets/javascripts/clusters/agents/components/show.vue159
-rw-r--r--app/assets/javascripts/clusters/agents/components/token_table.vue122
-rw-r--r--app/assets/javascripts/clusters/agents/constants.js1
-rw-r--r--app/assets/javascripts/clusters/agents/graphql/fragments/cluster_agent_token.fragment.graphql11
-rw-r--r--app/assets/javascripts/clusters/agents/graphql/queries/get_cluster_agent.query.graphql34
-rw-r--r--app/assets/javascripts/clusters/agents/index.js30
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,
+ },
+ });
+ },
+ });
+};