summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/clusters_list
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-12-20 13:37:47 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-20 13:37:47 +0000
commitaee0a117a889461ce8ced6fcf73207fe017f1d99 (patch)
tree891d9ef189227a8445d83f35c1b0fc99573f4380 /app/assets/javascripts/clusters_list
parent8d46af3258650d305f53b819eabf7ab18d22f59e (diff)
downloadgitlab-ce-aee0a117a889461ce8ced6fcf73207fe017f1d99.tar.gz
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/clusters_list')
-rw-r--r--app/assets/javascripts/clusters_list/components/agent_empty_state.vue67
-rw-r--r--app/assets/javascripts/clusters_list/components/agents.vue9
-rw-r--r--app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue30
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters_empty_state.vue89
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters_main_view.vue19
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters_view_all.vue33
-rw-r--r--app/assets/javascripts/clusters_list/components/install_agent_modal.vue325
-rw-r--r--app/assets/javascripts/clusters_list/constants.js147
-rw-r--r--app/assets/javascripts/clusters_list/graphql/cache_update.js84
-rw-r--r--app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql1
-rw-r--r--app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql2
-rw-r--r--app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql2
12 files changed, 471 insertions, 337 deletions
diff --git a/app/assets/javascripts/clusters_list/components/agent_empty_state.vue b/app/assets/javascripts/clusters_list/components/agent_empty_state.vue
index af44a23b4b3..f54f7b11414 100644
--- a/app/assets/javascripts/clusters_list/components/agent_empty_state.vue
+++ b/app/assets/javascripts/clusters_list/components/agent_empty_state.vue
@@ -1,107 +1,54 @@
<script>
-import { GlButton, GlEmptyState, GlLink, GlSprintf, GlAlert, GlModalDirective } from '@gitlab/ui';
+import { GlButton, GlEmptyState, GlLink, GlSprintf, GlModalDirective } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { INSTALL_AGENT_MODAL_ID, I18N_AGENTS_EMPTY_STATE } from '../constants';
export default {
i18n: I18N_AGENTS_EMPTY_STATE,
modalId: INSTALL_AGENT_MODAL_ID,
- multipleClustersDocsUrl: helpPagePath('user/project/clusters/multiple_kubernetes_clusters'),
- installDocsUrl: helpPagePath('administration/clusters/kas'),
- getStartedDocsUrl: helpPagePath('user/clusters/agent/index', {
- anchor: 'define-a-configuration-repository',
- }),
+ agentDocsUrl: helpPagePath('user/clusters/agent/index'),
components: {
GlButton,
GlEmptyState,
GlLink,
GlSprintf,
- GlAlert,
},
directives: {
GlModalDirective,
},
- inject: ['emptyStateImage', 'projectPath'],
+ inject: ['emptyStateImage'],
props: {
- hasConfigurations: {
- type: Boolean,
- required: true,
- },
isChildComponent: {
default: false,
required: false,
type: Boolean,
},
},
- computed: {
- repositoryPath() {
- return `/${this.projectPath}`;
- },
- },
};
</script>
<template>
<gl-empty-state :svg-path="emptyStateImage" title="" class="agents-empty-state">
<template #description>
- <p class="mw-460 gl-mx-auto gl-text-left">
- {{ $options.i18n.introText }}
- </p>
- <p class="mw-460 gl-mx-auto gl-text-left">
- <gl-sprintf :message="$options.i18n.multipleClustersText">
+ <p class="gl-text-left">
+ <gl-sprintf :message="$options.i18n.introText">
<template #link="{ content }">
- <gl-link
- :href="$options.multipleClustersDocsUrl"
- target="_blank"
- data-testid="multiple-clusters-docs-link"
- >
+ <gl-link :href="$options.agentDocsUrl">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</p>
-
- <p class="mw-460 gl-mx-auto">
- <gl-link :href="$options.installDocsUrl" target="_blank" data-testid="install-docs-link">
- {{ $options.i18n.learnMoreText }}
- </gl-link>
- </p>
-
- <gl-alert
- v-if="!hasConfigurations"
- variant="warning"
- class="gl-mb-5 text-left"
- :dismissible="false"
- >
- {{ $options.i18n.warningText }}
-
- <template #actions>
- <gl-button
- category="primary"
- variant="info"
- :href="$options.getStartedDocsUrl"
- target="_blank"
- class="gl-ml-0!"
- >
- {{ $options.i18n.readMoreText }}
- </gl-button>
- <gl-button category="secondary" variant="info" :href="repositoryPath">
- {{ $options.i18n.repositoryButtonText }}
- </gl-button>
- </template>
- </gl-alert>
</template>
<template #actions>
<gl-button
v-if="!isChildComponent"
v-gl-modal-directive="$options.modalId"
- :disabled="!hasConfigurations"
- data-testid="integration-primary-button"
category="primary"
variant="confirm"
>
- {{ $options.i18n.primaryButtonText }}
+ {{ $options.i18n.buttonText }}
</gl-button>
</template>
</gl-empty-state>
diff --git a/app/assets/javascripts/clusters_list/components/agents.vue b/app/assets/javascripts/clusters_list/components/agents.vue
index fb5cf7d1206..45108a28e37 100644
--- a/app/assets/javascripts/clusters_list/components/agents.vue
+++ b/app/assets/javascripts/clusters_list/components/agents.vue
@@ -86,9 +86,6 @@ export default {
treePageInfo() {
return this.agents?.project?.repository?.tree?.trees?.pageInfo || {};
},
- hasConfigurations() {
- return Boolean(this.agents?.project?.repository?.tree?.trees?.nodes?.length);
- },
},
methods: {
reloadAgents() {
@@ -161,11 +158,7 @@ export default {
</div>
</div>
- <agent-empty-state
- v-else
- :has-configurations="hasConfigurations"
- :is-child-component="isChildComponent"
- />
+ <agent-empty-state v-else :is-child-component="isChildComponent" />
</section>
<gl-alert v-else variant="danger" :dismissible="false">
diff --git a/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue b/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue
index 9fb020d2f4f..1630d0d5c92 100644
--- a/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue
+++ b/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue
@@ -1,7 +1,6 @@
<script>
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { I18N_AVAILABLE_AGENTS_DROPDOWN } from '../constants';
-import agentConfigurations from '../graphql/queries/agent_configurations.query.graphql';
export default {
name: 'AvailableAgentsDropdown',
@@ -10,36 +9,22 @@ export default {
GlDropdown,
GlDropdownItem,
},
- inject: ['projectPath'],
props: {
isRegistering: {
required: true,
type: Boolean,
},
- },
- apollo: {
- agents: {
- query: agentConfigurations,
- variables() {
- return {
- projectPath: this.projectPath,
- };
- },
- update(data) {
- this.populateAvailableAgents(data);
- },
+ availableAgents: {
+ required: true,
+ type: Array,
},
},
data() {
return {
- availableAgents: [],
selectedAgent: null,
};
},
computed: {
- isLoading() {
- return this.$apollo.queries.agents.loading;
- },
dropdownText() {
if (this.isRegistering) {
return this.$options.i18n.registeringAgent;
@@ -58,18 +43,11 @@ export default {
isSelected(agent) {
return this.selectedAgent === agent;
},
- populateAvailableAgents(data) {
- const installedAgents = data?.project?.clusterAgents?.nodes.map((agent) => agent.name) ?? [];
- const configuredAgents =
- data?.project?.agentConfigurations?.nodes.map((config) => config.agentName) ?? [];
-
- this.availableAgents = configuredAgents.filter((agent) => !installedAgents.includes(agent));
- },
},
};
</script>
<template>
- <gl-dropdown :text="dropdownText" :loading="isLoading || isRegistering">
+ <gl-dropdown :text="dropdownText" :loading="isRegistering">
<gl-dropdown-item
v-for="agent in availableAgents"
:key="agent"
diff --git a/app/assets/javascripts/clusters_list/components/clusters_empty_state.vue b/app/assets/javascripts/clusters_list/components/clusters_empty_state.vue
index 3879af6e9cb..ce601de57bd 100644
--- a/app/assets/javascripts/clusters_list/components/clusters_empty_state.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters_empty_state.vue
@@ -1,5 +1,5 @@
<script>
-import { GlEmptyState, GlButton, GlLink, GlSprintf } from '@gitlab/ui';
+import { GlEmptyState, GlButton, GlLink, GlSprintf, GlAlert } from '@gitlab/ui';
import { mapState } from 'vuex';
import { helpPagePath } from '~/helpers/help_page_helper';
import { I18N_CLUSTERS_EMPTY_STATE } from '../constants';
@@ -11,6 +11,7 @@ export default {
GlButton,
GlLink,
GlSprintf,
+ GlAlert,
},
inject: ['emptyStateHelpText', 'clustersEmptyStateImage', 'newClusterPath'],
props: {
@@ -20,8 +21,11 @@ export default {
type: Boolean,
},
},
- learnMoreHelpUrl: helpPagePath('user/project/clusters/index'),
- multipleClustersHelpUrl: helpPagePath('user/project/clusters/multiple_kubernetes_clusters'),
+ clustersHelpUrl: helpPagePath('user/infrastructure/clusters/index', {
+ anchor: 'certificate-based-kubernetes-integration-deprecated',
+ }),
+ blogPostUrl:
+ 'https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/',
computed: {
...mapState(['canAddCluster']),
},
@@ -29,48 +33,45 @@ export default {
</script>
<template>
- <gl-empty-state :svg-path="clustersEmptyStateImage" title="">
- <template #description>
- <p class="gl-text-left">
- {{ $options.i18n.description }}
- </p>
- <p class="gl-text-left">
- <gl-sprintf :message="$options.i18n.multipleClustersText">
- <template #link="{ content }">
- <gl-link
- :href="$options.multipleClustersHelpUrl"
- target="_blank"
- data-testid="multiple-clusters-docs-link"
- >
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </p>
+ <div>
+ <gl-empty-state :svg-path="clustersEmptyStateImage" title="">
+ <template #description>
+ <p class="gl-text-left">
+ <gl-sprintf :message="$options.i18n.introText">
+ <template #link="{ content }">
+ <gl-link :href="$options.clustersHelpUrl">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
- <p v-if="emptyStateHelpText" data-testid="clusters-empty-state-text">
- {{ emptyStateHelpText }}
- </p>
+ <p v-if="emptyStateHelpText" data-testid="clusters-empty-state-text">
+ {{ emptyStateHelpText }}
+ </p>
+ </template>
- <p>
- <gl-link :href="$options.learnMoreHelpUrl" target="_blank" data-testid="clusters-docs-link">
- {{ $options.i18n.learnMoreLinkText }}
- </gl-link>
- </p>
- </template>
+ <template #actions>
+ <gl-button
+ v-if="!isChildComponent"
+ data-testid="integration-primary-button"
+ data-qa-selector="add_kubernetes_cluster_link"
+ category="primary"
+ variant="confirm"
+ :disabled="!canAddCluster"
+ :href="newClusterPath"
+ >
+ {{ $options.i18n.buttonText }}
+ </gl-button>
+ </template>
+ </gl-empty-state>
- <template #actions>
- <gl-button
- v-if="!isChildComponent"
- data-testid="integration-primary-button"
- data-qa-selector="add_kubernetes_cluster_link"
- category="primary"
- variant="confirm"
- :disabled="!canAddCluster"
- :href="newClusterPath"
- >
- {{ $options.i18n.buttonText }}
- </gl-button>
- </template>
- </gl-empty-state>
+ <gl-alert variant="warning" :dismissible="false">
+ <gl-sprintf :message="$options.i18n.alertText">
+ <template #link="{ content }">
+ <gl-link :href="$options.blogPostUrl" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
+ </div>
</template>
diff --git a/app/assets/javascripts/clusters_list/components/clusters_main_view.vue b/app/assets/javascripts/clusters_list/components/clusters_main_view.vue
index 9e03093aa67..7dd5ece9b8e 100644
--- a/app/assets/javascripts/clusters_list/components/clusters_main_view.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters_main_view.vue
@@ -1,12 +1,22 @@
<script>
import { GlTabs, GlTab } from '@gitlab/ui';
-import { CLUSTERS_TABS, MAX_CLUSTERS_LIST, MAX_LIST_COUNT, AGENT } from '../constants';
+import Tracking from '~/tracking';
+import {
+ CLUSTERS_TABS,
+ MAX_CLUSTERS_LIST,
+ MAX_LIST_COUNT,
+ AGENT,
+ EVENT_LABEL_TABS,
+ EVENT_ACTIONS_CHANGE,
+} from '../constants';
import Agents from './agents.vue';
import InstallAgentModal from './install_agent_modal.vue';
import ClustersActions from './clusters_actions.vue';
import Clusters from './clusters.vue';
import ClustersViewAll from './clusters_view_all.vue';
+const trackingMixin = Tracking.mixin({ label: EVENT_LABEL_TABS });
+
export default {
components: {
GlTabs,
@@ -18,6 +28,7 @@ export default {
InstallAgentModal,
},
CLUSTERS_TABS,
+ mixins: [trackingMixin],
props: {
defaultBranchName: {
default: '.noBranch',
@@ -34,9 +45,12 @@ export default {
methods: {
onTabChange(tabName) {
this.selectedTabIndex = CLUSTERS_TABS.findIndex((tab) => tab.queryParamValue === tabName);
-
this.maxAgents = tabName === AGENT ? MAX_LIST_COUNT : MAX_CLUSTERS_LIST;
},
+ trackTabChange(tab) {
+ const tabName = CLUSTERS_TABS[tab].queryParamValue;
+ this.track(EVENT_ACTIONS_CHANGE, { property: tabName });
+ },
},
};
</script>
@@ -47,6 +61,7 @@ export default {
sync-active-tab-with-query-params
nav-class="gl-flex-grow-1 gl-align-items-center"
lazy
+ @input="trackTabChange"
>
<gl-tab
v-for="(tab, idx) in $options.CLUSTERS_TABS"
diff --git a/app/assets/javascripts/clusters_list/components/clusters_view_all.vue b/app/assets/javascripts/clusters_list/components/clusters_view_all.vue
index 285876e57d8..0e312d21e4e 100644
--- a/app/assets/javascripts/clusters_list/components/clusters_view_all.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters_view_all.vue
@@ -34,10 +34,12 @@ export default {
directives: {
GlModalDirective,
},
- AGENT_CARD_INFO,
- CERTIFICATE_BASED_CARD_INFO,
MAX_CLUSTERS_LIST,
INSTALL_AGENT_MODAL_ID,
+ i18n: {
+ agent: AGENT_CARD_INFO,
+ certificate: CERTIFICATE_BASED_CARD_INFO,
+ },
inject: ['addClusterPath'],
props: {
defaultBranchName: {
@@ -122,21 +124,21 @@ export default {
</gl-sprintf>
</h3>
- <gl-badge id="clusters-recommended-badge" size="md" variant="info">{{
- $options.AGENT_CARD_INFO.tooltip.label
+ <gl-badge id="clusters-recommended-badge" variant="info">{{
+ $options.i18n.agent.tooltip.label
}}</gl-badge>
<gl-popover
target="clusters-recommended-badge"
container="viewport"
placement="bottom"
- :title="$options.AGENT_CARD_INFO.tooltip.title"
+ :title="$options.i18n.agent.tooltip.title"
>
<p class="gl-mb-0">
- <gl-sprintf :message="$options.AGENT_CARD_INFO.tooltip.text">
+ <gl-sprintf :message="$options.i18n.agent.tooltip.text">
<template #link="{ content }">
<gl-link
- :href="$options.AGENT_CARD_INFO.tooltip.link"
+ :href="$options.i18n.agent.tooltip.link"
target="_blank"
class="gl-font-sm"
>
@@ -159,9 +161,9 @@ export default {
<gl-link
v-if="totalAgents"
data-testid="agents-tab-footer-link"
- :href="`?tab=${$options.AGENT_CARD_INFO.tabName}`"
- @click="changeTab($event, $options.AGENT_CARD_INFO.tabName)"
- ><gl-sprintf :message="$options.AGENT_CARD_INFO.footerText"
+ :href="`?tab=${$options.i18n.agent.tabName}`"
+ @click="changeTab($event, $options.i18n.agent.tabName)"
+ ><gl-sprintf :message="$options.i18n.agent.footerText"
><template #number>{{ cardFooterNumber(totalAgents) }}</template></gl-sprintf
></gl-link
><gl-button
@@ -169,7 +171,7 @@ export default {
class="gl-ml-4"
category="secondary"
variant="confirm"
- >{{ $options.AGENT_CARD_INFO.actionText }}</gl-button
+ >{{ $options.i18n.agent.actionText }}</gl-button
>
</template>
</gl-card>
@@ -190,6 +192,7 @@ export default {
<template #total>{{ clustersCardTitle.total }}</template>
</gl-sprintf>
</h3>
+ <gl-badge variant="warning">{{ $options.i18n.certificate.badgeText }}</gl-badge>
</template>
<clusters :limit="$options.MAX_CLUSTERS_LIST" :is-child-component="true" />
@@ -198,9 +201,9 @@ export default {
<gl-link
v-if="totalClusters"
data-testid="clusters-tab-footer-link"
- :href="`?tab=${$options.CERTIFICATE_BASED_CARD_INFO.tabName}`"
- @click="changeTab($event, $options.CERTIFICATE_BASED_CARD_INFO.tabName)"
- ><gl-sprintf :message="$options.CERTIFICATE_BASED_CARD_INFO.footerText"
+ :href="`?tab=${$options.i18n.certificate.tabName}`"
+ @click="changeTab($event, $options.i18n.certificate.tabName)"
+ ><gl-sprintf :message="$options.i18n.certificate.footerText"
><template #number>{{ cardFooterNumber(totalClusters) }}</template></gl-sprintf
></gl-link
><gl-button
@@ -209,7 +212,7 @@ export default {
variant="confirm"
class="gl-ml-4"
:href="addClusterPath"
- >{{ $options.CERTIFICATE_BASED_CARD_INFO.actionText }}</gl-button
+ >{{ $options.i18n.certificate.actionText }}</gl-button
>
</template>
</gl-card>
diff --git a/app/assets/javascripts/clusters_list/components/install_agent_modal.vue b/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
index 6eb2e85ecea..5eef76252bd 100644
--- a/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
+++ b/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
@@ -9,22 +9,48 @@ import {
GlSprintf,
} from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
import CodeBlock from '~/vue_shared/components/code_block.vue';
+import Tracking from '~/tracking';
import { generateAgentRegistrationCommand } from '../clusters_util';
-import { INSTALL_AGENT_MODAL_ID, I18N_INSTALL_AGENT_MODAL } from '../constants';
-import { addAgentToStore } from '../graphql/cache_update';
+import {
+ INSTALL_AGENT_MODAL_ID,
+ I18N_AGENT_MODAL,
+ KAS_DISABLED_ERROR,
+ EVENT_LABEL_MODAL,
+ EVENT_ACTIONS_OPEN,
+ EVENT_ACTIONS_SELECT,
+ EVENT_ACTIONS_CLICK,
+ MODAL_TYPE_EMPTY,
+ MODAL_TYPE_REGISTER,
+} from '../constants';
+import { addAgentToStore, addAgentConfigToStore } from '../graphql/cache_update';
import createAgent from '../graphql/mutations/create_agent.mutation.graphql';
import createAgentToken from '../graphql/mutations/create_agent_token.mutation.graphql';
import getAgentsQuery from '../graphql/queries/get_agents.query.graphql';
+import agentConfigurations from '../graphql/queries/agent_configurations.query.graphql';
import AvailableAgentsDropdown from './available_agents_dropdown.vue';
+const trackingMixin = Tracking.mixin({ label: EVENT_LABEL_MODAL });
+
export default {
modalId: INSTALL_AGENT_MODAL_ID,
- i18n: I18N_INSTALL_AGENT_MODAL,
+ EVENT_ACTIONS_OPEN,
+ EVENT_ACTIONS_CLICK,
+ EVENT_LABEL_MODAL,
+ basicInstallPath: helpPagePath('user/clusters/agent/install/index', {
+ anchor: 'install-the-agent-into-the-cluster',
+ }),
+ advancedInstallPath: helpPagePath('user/clusters/agent/install/index', {
+ anchor: 'advanced-installation',
+ }),
+ enableKasPath: helpPagePath('administration/clusters/kas'),
+ installAgentPath: helpPagePath('user/clusters/agent/install/index'),
+ registerAgentPath: helpPagePath('user/clusters/agent/install/index', {
+ anchor: 'register-an-agent-with-gitlab',
+ }),
components: {
AvailableAgentsDropdown,
- ClipboardButton,
CodeBlock,
GlAlert,
GlButton,
@@ -33,8 +59,10 @@ export default {
GlLink,
GlModal,
GlSprintf,
+ ModalCopyButton,
},
- inject: ['projectPath', 'kasAddress'],
+ mixins: [trackingMixin],
+ inject: ['projectPath', 'kasAddress', 'emptyStateImage'],
props: {
defaultBranchName: {
default: '.noBranch',
@@ -46,6 +74,22 @@ export default {
type: Number,
},
},
+ apollo: {
+ agents: {
+ query: agentConfigurations,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ };
+ },
+ update(data) {
+ this.populateAvailableAgents(data);
+ },
+ error(error) {
+ this.kasDisabled = error?.message?.indexOf(KAS_DISABLED_ERROR) >= 0;
+ },
+ },
+ },
data() {
return {
registering: false,
@@ -53,6 +97,8 @@ export default {
agentToken: null,
error: null,
clusterAgent: null,
+ availableAgents: [],
+ kasDisabled: false,
};
},
computed: {
@@ -63,19 +109,11 @@ export default {
return !this.registering && this.agentName !== null;
},
canCancel() {
- return !this.registered && !this.registering;
+ return !this.registered && !this.registering && this.isAgentRegistrationModal;
},
agentRegistrationCommand() {
return generateAgentRegistrationCommand(this.agentToken, this.kasAddress);
},
- basicInstallPath() {
- return helpPagePath('user/clusters/agent/install/index', {
- anchor: 'install-the-agent-into-the-cluster',
- });
- },
- advancedInstallPath() {
- return helpPagePath('user/clusters/agent/install/index', { anchor: 'advanced-installation' });
- },
getAgentsQueryVariables() {
return {
defaultBranchName: this.defaultBranchName,
@@ -84,10 +122,31 @@ export default {
projectPath: this.projectPath,
};
},
+ i18n() {
+ return I18N_AGENT_MODAL[this.modalType];
+ },
+ repositoryPath() {
+ return `/${this.projectPath}`;
+ },
+ modalType() {
+ return !this.availableAgents?.length && !this.registered
+ ? MODAL_TYPE_EMPTY
+ : MODAL_TYPE_REGISTER;
+ },
+ modalSize() {
+ return this.isEmptyStateModal ? 'sm' : 'md';
+ },
+ isEmptyStateModal() {
+ return this.modalType === MODAL_TYPE_EMPTY;
+ },
+ isAgentRegistrationModal() {
+ return this.modalType === MODAL_TYPE_REGISTER;
+ },
},
methods: {
setAgentName(name) {
this.agentName = name;
+ this.track(EVENT_ACTIONS_SELECT);
},
closeModal() {
this.$refs.modal.hide();
@@ -96,8 +155,16 @@ export default {
this.registering = false;
this.agentName = null;
this.agentToken = null;
+ this.clusterAgent = null;
this.error = null;
},
+ populateAvailableAgents(data) {
+ const installedAgents = data?.project?.clusterAgents?.nodes.map((agent) => agent.name) ?? [];
+ const configuredAgents =
+ data?.project?.agentConfigurations?.nodes.map((config) => config.agentName) ?? [];
+
+ this.availableAgents = configuredAgents.filter((agent) => !installedAgents.includes(agent));
+ },
createAgentMutation() {
return this.$apollo
.mutate({
@@ -117,7 +184,9 @@ export default {
);
},
})
- .then(({ data: { createClusterAgent } }) => createClusterAgent);
+ .then(({ data: { createClusterAgent } }) => {
+ return createClusterAgent;
+ });
},
createAgentTokenMutation(agendId) {
return this.$apollo
@@ -129,6 +198,17 @@ export default {
name: this.agentName,
},
},
+ update: (store, { data: { clusterAgentTokenCreate } }) => {
+ addAgentConfigToStore(
+ store,
+ clusterAgentTokenCreate,
+ this.clusterAgent,
+ agentConfigurations,
+ {
+ projectPath: this.projectPath,
+ },
+ );
+ },
})
.then(({ data: { clusterAgentTokenCreate } }) => clusterAgentTokenCreate);
},
@@ -158,7 +238,7 @@ export default {
if (error) {
this.error = error.message;
} else {
- this.error = this.$options.i18n.unknownError;
+ this.error = this.i18n.unknownError;
}
} finally {
this.registering = false;
@@ -172,115 +252,172 @@ export default {
<gl-modal
ref="modal"
:modal-id="$options.modalId"
- :title="$options.i18n.modalTitle"
+ :title="i18n.modalTitle"
+ :size="modalSize"
static
lazy
@hidden="resetModal"
+ @show="track($options.EVENT_ACTIONS_OPEN, { property: modalType })"
>
- <template v-if="!registered">
- <p>
- <strong>{{ $options.i18n.selectAgentTitle }}</strong>
- </p>
+ <template v-if="isAgentRegistrationModal">
+ <template v-if="!registered">
+ <p>
+ <strong>{{ i18n.selectAgentTitle }}</strong>
+ </p>
- <p>
- <gl-sprintf :message="$options.i18n.selectAgentBody">
- <template #link="{ content }">
- <gl-link :href="basicInstallPath" target="_blank"> {{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
+ <p class="gl-mb-0">{{ i18n.selectAgentBody }}</p>
+ <p>
+ <gl-link :href="$options.registerAgentPath"> {{ i18n.learnMoreLink }}</gl-link>
+ </p>
- <form>
- <gl-form-group label-for="agent-name">
- <available-agents-dropdown
- class="gl-w-70p"
- :is-registering="registering"
- @agentSelected="setAgentName"
- />
- </gl-form-group>
- </form>
+ <form>
+ <gl-form-group label-for="agent-name">
+ <available-agents-dropdown
+ class="gl-w-70p"
+ :is-registering="registering"
+ :available-agents="availableAgents"
+ @agentSelected="setAgentName"
+ />
+ </gl-form-group>
+ </form>
- <p v-if="error">
- <gl-alert
- :title="$options.i18n.registrationErrorTitle"
- variant="danger"
- :dismissible="false"
- >
- {{ error }}
- </gl-alert>
- </p>
- </template>
+ <p v-if="error">
+ <gl-alert :title="i18n.registrationErrorTitle" variant="danger" :dismissible="false">
+ {{ error }}
+ </gl-alert>
+ </p>
+ </template>
- <template v-else>
- <p>
- <strong>{{ $options.i18n.tokenTitle }}</strong>
- </p>
+ <template v-else>
+ <p>
+ <strong>{{ i18n.tokenTitle }}</strong>
+ </p>
- <p>
- <gl-sprintf :message="$options.i18n.tokenBody">
- <template #link="{ content }">
- <gl-link :href="basicInstallPath" target="_blank"> {{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
+ <p>
+ <gl-sprintf :message="i18n.tokenBody">
+ <template #link="{ content }">
+ <gl-link :href="$options.basicInstallPath" target="_blank"> {{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
- <p>
- <gl-alert
- :title="$options.i18n.tokenSingleUseWarningTitle"
- variant="warning"
- :dismissible="false"
- >
- {{ $options.i18n.tokenSingleUseWarningBody }}
- </gl-alert>
- </p>
+ <p>
+ <gl-alert :title="i18n.tokenSingleUseWarningTitle" variant="warning" :dismissible="false">
+ {{ i18n.tokenSingleUseWarningBody }}
+ </gl-alert>
+ </p>
- <p>
- <gl-form-input-group readonly :value="agentToken" :select-on-click="true">
- <template #append>
- <clipboard-button :text="agentToken" :title="$options.i18n.copyToken" />
- </template>
- </gl-form-input-group>
- </p>
+ <p>
+ <gl-form-input-group readonly :value="agentToken" :select-on-click="true">
+ <template #append>
+ <modal-copy-button
+ :text="agentToken"
+ :title="i18n.copyToken"
+ :modal-id="$options.modalId"
+ />
+ </template>
+ </gl-form-input-group>
+ </p>
- <p>
- <strong>{{ $options.i18n.basicInstallTitle }}</strong>
- </p>
+ <p>
+ <strong>{{ i18n.basicInstallTitle }}</strong>
+ </p>
- <p>
- {{ $options.i18n.basicInstallBody }}
- </p>
+ <p>
+ {{ i18n.basicInstallBody }}
+ </p>
- <p>
- <code-block :code="agentRegistrationCommand" />
- </p>
+ <p>
+ <code-block :code="agentRegistrationCommand" />
+ </p>
+
+ <p>
+ <strong>{{ i18n.advancedInstallTitle }}</strong>
+ </p>
+
+ <p>
+ <gl-sprintf :message="i18n.advancedInstallBody">
+ <template #link="{ content }">
+ <gl-link :href="$options.advancedInstallPath" target="_blank"> {{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </template>
+ </template>
+
+ <template v-else>
+ <div class="gl-text-center gl-mb-5">
+ <img :alt="i18n.altText" :src="emptyStateImage" height="100" />
+ </div>
<p>
- <strong>{{ $options.i18n.advancedInstallTitle }}</strong>
+ <gl-sprintf :message="i18n.modalBody">
+ <template #link="{ content }">
+ <gl-link :href="$options.installAgentPath"> {{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
</p>
- <p>
- <gl-sprintf :message="$options.i18n.advancedInstallBody">
+ <p v-if="kasDisabled">
+ <gl-sprintf :message="i18n.enableKasText">
<template #link="{ content }">
- <gl-link :href="advancedInstallPath" target="_blank"> {{ content }}</gl-link>
+ <gl-link :href="$options.enableKasPath"> {{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
</template>
<template #modal-footer>
- <gl-button v-if="canCancel" @click="closeModal">{{ $options.i18n.cancel }} </gl-button>
-
- <gl-button v-if="registered" variant="confirm" category="primary" @click="closeModal"
- >{{ $options.i18n.close }}
+ <gl-button
+ v-if="registered"
+ variant="confirm"
+ category="primary"
+ :data-track-action="$options.EVENT_ACTIONS_CLICK"
+ :data-track-label="$options.EVENT_LABEL_MODAL"
+ data-track-property="close"
+ @click="closeModal"
+ >{{ i18n.close }}
</gl-button>
<gl-button
- v-else
+ v-else-if="isAgentRegistrationModal"
:disabled="!nextButtonDisabled"
variant="confirm"
category="primary"
+ :data-track-action="$options.EVENT_ACTIONS_CLICK"
+ :data-track-label="$options.EVENT_LABEL_MODAL"
+ data-track-property="register"
@click="registerAgent"
- >{{ $options.i18n.registerAgentButton }}
+ >{{ i18n.registerAgentButton }}
+ </gl-button>
+
+ <gl-button
+ v-if="canCancel"
+ :data-track-action="$options.EVENT_ACTIONS_CLICK"
+ :data-track-label="$options.EVENT_LABEL_MODAL"
+ data-track-property="cancel"
+ @click="closeModal"
+ >{{ i18n.cancel }}
+ </gl-button>
+
+ <gl-button
+ v-if="isEmptyStateModal"
+ :href="repositoryPath"
+ variant="confirm"
+ category="secondary"
+ data-testid="agent-secondary-button"
+ >{{ i18n.secondaryButton }}
+ </gl-button>
+
+ <gl-button
+ v-if="isEmptyStateModal"
+ variant="confirm"
+ category="primary"
+ :data-track-action="$options.EVENT_ACTIONS_CLICK"
+ :data-track-label="$options.EVENT_LABEL_MODAL"
+ data-track-property="done"
+ @click="closeModal"
+ >{{ i18n.done }}
</gl-button>
</template>
</gl-modal>
diff --git a/app/assets/javascripts/clusters_list/constants.js b/app/assets/javascripts/clusters_list/constants.js
index 9fefdf450c4..9b52df74fc5 100644
--- a/app/assets/javascripts/clusters_list/constants.js
+++ b/app/assets/javascripts/clusters_list/constants.js
@@ -64,47 +64,63 @@ export const STATUSES = {
creating: { title: __('Creating') },
};
-export const I18N_INSTALL_AGENT_MODAL = {
- registerAgentButton: s__('ClusterAgents|Register Agent'),
- close: __('Close'),
- cancel: __('Cancel'),
-
- modalTitle: s__('ClusterAgents|Install new Agent'),
-
- selectAgentTitle: s__('ClusterAgents|Select which Agent you want to install'),
- selectAgentBody: s__(
- `ClusterAgents|Select the Agent you want to register with GitLab and install on your cluster. To learn more about the Kubernetes Agent registration process %{linkStart}go to the documentation%{linkEnd}.`,
- ),
+export const I18N_AGENT_MODAL = {
+ agent_registration: {
+ registerAgentButton: s__('ClusterAgents|Register'),
+ close: __('Close'),
+ cancel: __('Cancel'),
+
+ modalTitle: s__('ClusterAgents|Connect a cluster through the Agent'),
+ selectAgentTitle: s__('ClusterAgents|Select an agent to register with GitLab'),
+ selectAgentBody: s__(
+ 'ClusterAgents|Register an agent to generate a token that will be used to install the agent on your cluster in the next step.',
+ ),
+ learnMoreLink: s__('ClusterAgents|How to register an agent?'),
- copyToken: s__('ClusterAgents|Copy token'),
- tokenTitle: s__('ClusterAgents|Registration token'),
- tokenBody: s__(
- `ClusterAgents|The registration token will be used to connect the Agent on your cluster to GitLab. To learn more about the registration tokens and how they are used %{linkStart}go to the documentation%{linkEnd}.`,
- ),
+ copyToken: s__('ClusterAgents|Copy token'),
+ tokenTitle: s__('ClusterAgents|Registration token'),
+ tokenBody: s__(
+ `ClusterAgents|The registration token will be used to connect the agent on your cluster to GitLab. %{linkStart}What are registration tokens?%{linkEnd}`,
+ ),
- tokenSingleUseWarningTitle: s__(
- 'ClusterAgents|The token value will not be shown again after you close this window.',
- ),
- tokenSingleUseWarningBody: s__(
- `ClusterAgents|The recommended installation method provided below includes the token. If you want to follow the alternative installation method provided in the docs make sure you save the token value before you close the window.`,
- ),
+ tokenSingleUseWarningTitle: s__(
+ 'ClusterAgents|You cannot see this token again after you close this window.',
+ ),
+ tokenSingleUseWarningBody: s__(
+ `ClusterAgents|The recommended installation method includes the token. If you want to follow the advanced installation method provided in the docs, make sure you save the token value before you close this window.`,
+ ),
- basicInstallTitle: s__('ClusterAgents|Recommended installation method'),
- basicInstallBody: __(
- `Open a CLI and connect to the cluster you want to install the Agent in. Use this installation method to minimize any manual steps. The token is already included in the command.`,
- ),
+ basicInstallTitle: s__('ClusterAgents|Recommended installation method'),
+ basicInstallBody: __(
+ `Open a CLI and connect to the cluster you want to install the agent in. Use this installation method to minimize any manual steps. The token is already included in the command.`,
+ ),
- advancedInstallTitle: s__('ClusterAgents|Alternative installation methods'),
- advancedInstallBody: s__(
- 'ClusterAgents|For alternative installation methods %{linkStart}go to the documentation%{linkEnd}.',
- ),
+ advancedInstallTitle: s__('ClusterAgents|Advanced installation methods'),
+ advancedInstallBody: s__(
+ 'ClusterAgents|For the advanced installation method %{linkStart}see the documentation%{linkEnd}.',
+ ),
- registrationErrorTitle: __('Failed to register Agent'),
- unknownError: s__('ClusterAgents|An unknown error occurred. Please try again.'),
+ registrationErrorTitle: s__('ClusterAgents|Failed to register an agent'),
+ unknownError: s__('ClusterAgents|An unknown error occurred. Please try again.'),
+ },
+ empty_state: {
+ modalTitle: s__('ClusterAgents|Connect your cluster through the Agent'),
+ modalBody: s__(
+ "ClusterAgents|To install a new agent, first add the agent's configuration file to this repository. %{linkStart}What's the agent's configuration file?%{linkEnd}",
+ ),
+ enableKasText: s__(
+ "ClusterAgents|Your instance doesn't have the %{linkStart}GitLab Agent Server (KAS)%{linkEnd} set up. Ask a GitLab Administrator to install it.",
+ ),
+ altText: s__('ClusterAgents|GitLab Agent for Kubernetes'),
+ secondaryButton: s__('ClusterAgents|Go to the repository files'),
+ done: __('Cancel'),
+ },
};
+export const KAS_DISABLED_ERROR = 'Gitlab::Kas::Client::ConfigurationError';
+
export const I18N_AVAILABLE_AGENTS_DROPDOWN = {
- selectAgent: s__('ClusterAgents|Select an Agent'),
+ selectAgent: s__('ClusterAgents|Select an agent'),
registeringAgent: s__('ClusterAgents|Registering Agent'),
};
@@ -125,7 +141,7 @@ export const AGENT_STATUSES = {
title: s__('ClusterAgents|Agent might not be connected to GitLab'),
body: sprintf(
s__(
- 'ClusterAgents|The Agent has not been connected in a long time. There might be a connectivity issue. Last contact was %{timeAgo}.',
+ 'ClusterAgents|The agent has not been connected in a long time. There might be a connectivity issue. Last contact was %{timeAgo}.',
),
),
},
@@ -143,55 +159,48 @@ export const AGENT_STATUSES = {
export const I18N_AGENTS_EMPTY_STATE = {
introText: s__(
- 'ClusterAgents|Use GitLab Agents to more securely integrate with your clusters to deploy your applications, run your pipelines, use review apps and much more.',
- ),
- multipleClustersText: s__(
- 'ClusterAgents|If you are setting up multiple clusters and are using Auto DevOps, %{linkStart}read about using multiple Kubernetes clusters first.%{linkEnd}',
- ),
- learnMoreText: s__('ClusterAgents|Learn more about the GitLab Kubernetes Agent.'),
- warningText: s__(
- 'ClusterAgents|To install an Agent you should create an agent directory in the Repository first. We recommend that you add the Agent configuration to the directory before you start the installation process.',
+ 'ClusterIntegration|Use the %{linkStart}GitLab Agent%{linkEnd} to safely connect your Kubernetes clusters to GitLab. You can deploy your applications, run your pipelines, use Review Apps, and much more.',
),
- readMoreText: s__('ClusterAgents|Read more about getting started'),
- repositoryButtonText: s__('ClusterAgents|Go to the repository'),
- primaryButtonText: s__('ClusterAgents|Connect with a GitLab Agent'),
+ buttonText: s__('ClusterAgents|Connect with the GitLab Agent'),
};
export const I18N_CLUSTERS_EMPTY_STATE = {
- description: s__(
- 'ClusterIntegration|Use certificates to integrate with your clusters to deploy your applications, run your pipelines, use review apps and much more in an easy way.',
- ),
- multipleClustersText: s__(
- 'ClusterIntegration|If you are setting up multiple clusters and are using Auto DevOps, %{linkStart}read about using multiple Kubernetes clusters first.%{linkEnd}',
+ introText: s__(
+ 'ClusterIntegration|Connect your cluster to GitLab through %{linkStart}cluster certificates%{linkEnd}.',
),
- learnMoreLinkText: s__('ClusterIntegration|Learn more about the GitLab managed clusters'),
buttonText: s__('ClusterIntegration|Connect with a certificate'),
+ alertText: s__(
+ 'ClusterIntegration|The certificate-based method to connect clusters to GitLab was %{linkStart}deprecated%{linkEnd} in GitLab 14.5.',
+ ),
};
export const AGENT_CARD_INFO = {
tabName: 'agent',
- title: sprintf(s__('ClusterAgents|%{number} of %{total} Agent based integrations')),
- emptyTitle: s__('ClusterAgents|No Agent based integrations'),
+ title: sprintf(s__('ClusterAgents|%{number} of %{total} agents')),
+ emptyTitle: s__('ClusterAgents|No agents'),
tooltip: {
label: s__('ClusterAgents|Recommended'),
- title: s__('ClusterAgents|GitLab Agents'),
+ title: s__('ClusterAgents|GitLab Agent'),
text: sprintf(
s__(
- 'ClusterAgents|GitLab Agents provide an increased level of security when integrating with clusters. %{linkStart}Learn more about the GitLab Kubernetes Agent.%{linkEnd}',
+ 'ClusterAgents|The GitLab Agent provides an increased level of security when connecting Kubernetes clusters to GitLab. %{linkStart}Learn more about the GitLab Agent.%{linkEnd}',
),
),
link: helpPagePath('user/clusters/agent/index'),
},
- actionText: s__('ClusterAgents|Install new Agent'),
- footerText: sprintf(s__('ClusterAgents|View all %{number} Agent based integrations')),
+ actionText: s__('ClusterAgents|Install a new agent'),
+ footerText: sprintf(s__('ClusterAgents|View all %{number} agents')),
};
export const CERTIFICATE_BASED_CARD_INFO = {
tabName: 'certificate_based',
- title: sprintf(s__('ClusterAgents|%{number} of %{total} Certificate based integrations')),
- emptyTitle: s__('ClusterAgents|No Certificate based integrations'),
+ title: sprintf(
+ s__('ClusterAgents|%{number} of %{total} clusters connected through cluster certificates'),
+ ),
+ emptyTitle: s__('ClusterAgents|No clusters connected through cluster certificates'),
actionText: s__('ClusterAgents|Connect existing cluster'),
- footerText: sprintf(s__('ClusterAgents|View all %{number} Certificate based integrations')),
+ footerText: sprintf(s__('ClusterAgents|View all %{number} clusters')),
+ badgeText: s__('ClusterAgents|Deprecated'),
};
export const MAX_CLUSTERS_LIST = 6;
@@ -208,7 +217,7 @@ export const CLUSTERS_TABS = [
queryParamValue: 'agent',
},
{
- title: s__('ClusterAgents|Certificate based'),
+ title: s__('ClusterAgents|Certificate'),
component: 'clusters',
queryParamValue: 'certificate_based',
},
@@ -216,10 +225,20 @@ export const CLUSTERS_TABS = [
export const CLUSTERS_ACTIONS = {
actionsButton: s__('ClusterAgents|Actions'),
- createNewCluster: s__('ClusterAgents|Create new cluster'),
- connectWithAgent: s__('ClusterAgents|Connect with Agent'),
- connectExistingCluster: s__('ClusterAgents|Connect with certificate'),
+ createNewCluster: s__('ClusterAgents|Create a new cluster'),
+ connectWithAgent: s__('ClusterAgents|Connect with the Agent'),
+ connectExistingCluster: s__('ClusterAgents|Connect with a certificate'),
};
export const AGENT = 'agent';
export const CERTIFICATE_BASED = 'certificate_based';
+
+export const EVENT_LABEL_MODAL = 'agent_registration_modal';
+export const EVENT_LABEL_TABS = 'kubernetes_section_tabs';
+export const EVENT_ACTIONS_OPEN = 'open_modal';
+export const EVENT_ACTIONS_SELECT = 'select_agent';
+export const EVENT_ACTIONS_CLICK = 'click_button';
+export const EVENT_ACTIONS_CHANGE = 'change_tab';
+
+export const MODAL_TYPE_EMPTY = 'empty_state';
+export const MODAL_TYPE_REGISTER = 'agent_registration';
diff --git a/app/assets/javascripts/clusters_list/graphql/cache_update.js b/app/assets/javascripts/clusters_list/graphql/cache_update.js
index dd633820952..4d12bc8151c 100644
--- a/app/assets/javascripts/clusters_list/graphql/cache_update.js
+++ b/app/assets/javascripts/clusters_list/graphql/cache_update.js
@@ -1,29 +1,65 @@
import produce from 'immer';
import { getAgentConfigPath } from '../clusters_util';
+export const hasErrors = ({ errors = [] }) => errors?.length;
+
export function addAgentToStore(store, createClusterAgent, query, variables) {
- const { clusterAgent } = createClusterAgent;
- const sourceData = store.readQuery({
- query,
- variables,
- });
-
- const data = produce(sourceData, (draftData) => {
- const configuration = {
- name: clusterAgent.name,
- path: getAgentConfigPath(clusterAgent.name),
- webPath: clusterAgent.webPath,
- __typename: 'TreeEntry',
- };
-
- draftData.project.clusterAgents.nodes.push(clusterAgent);
- draftData.project.clusterAgents.count += 1;
- draftData.project.repository.tree.trees.nodes.push(configuration);
- });
-
- store.writeQuery({
- query,
- variables,
- data,
- });
+ if (!hasErrors(createClusterAgent)) {
+ const { clusterAgent } = createClusterAgent;
+ const sourceData = store.readQuery({
+ query,
+ variables,
+ });
+
+ const data = produce(sourceData, (draftData) => {
+ const configuration = {
+ id: clusterAgent.id,
+ name: clusterAgent.name,
+ path: getAgentConfigPath(clusterAgent.name),
+ webPath: clusterAgent.webPath,
+ __typename: 'TreeEntry',
+ };
+
+ draftData.project.clusterAgents.nodes.push(clusterAgent);
+ draftData.project.clusterAgents.count += 1;
+ draftData.project.repository.tree.trees.nodes.push(configuration);
+ });
+
+ store.writeQuery({
+ query,
+ variables,
+ data,
+ });
+ }
+}
+
+export function addAgentConfigToStore(
+ store,
+ clusterAgentTokenCreate,
+ clusterAgent,
+ query,
+ variables,
+) {
+ if (!hasErrors(clusterAgentTokenCreate)) {
+ const sourceData = store.readQuery({
+ query,
+ variables,
+ });
+
+ const data = produce(sourceData, (draftData) => {
+ const configuration = {
+ agentName: clusterAgent.name,
+ __typename: 'AgentConfiguration',
+ };
+
+ draftData.project.clusterAgents.nodes.push(clusterAgent);
+ draftData.project.agentConfigurations.nodes.push(configuration);
+ });
+
+ store.writeQuery({
+ query,
+ variables,
+ data,
+ });
+ }
}
diff --git a/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql b/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql
index 9b40260471c..cd46dfee170 100644
--- a/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql
+++ b/app/assets/javascripts/clusters_list/graphql/fragments/cluster_agent.fragment.graphql
@@ -4,6 +4,7 @@ fragment ClusterAgentFragment on ClusterAgent {
webPath
tokens {
nodes {
+ id
lastUsedAt
}
}
diff --git a/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql b/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql
index 40b61337024..9a24cec5a9c 100644
--- a/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql
+++ b/app/assets/javascripts/clusters_list/graphql/queries/agent_configurations.query.graphql
@@ -1,5 +1,6 @@
query agentConfigurations($projectPath: ID!) {
project(fullPath: $projectPath) {
+ id
agentConfigurations {
nodes {
agentName
@@ -8,6 +9,7 @@ query agentConfigurations($projectPath: ID!) {
clusterAgents {
nodes {
+ id
name
}
}
diff --git a/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql b/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql
index 47b25988877..f8efb6683f6 100644
--- a/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql
+++ b/app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql
@@ -12,6 +12,7 @@ query getAgents(
$beforeTree: String
) {
project(fullPath: $projectPath) {
+ id
clusterAgents(first: $first, last: $last, before: $beforeAgent, after: $afterAgent) {
nodes {
...ClusterAgentFragment
@@ -28,6 +29,7 @@ query getAgents(
tree(path: ".gitlab/agents", ref: $defaultBranchName) {
trees(first: $first, last: $last, after: $afterTree, before: $beforeTree) {
nodes {
+ id
name
path
webPath