debian-mirror-gitlab/app/assets/javascripts/clusters_list/components/agents.vue
2022-04-04 11:22:00 +05:30

221 lines
5.9 KiB
Vue

<script>
import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlBanner } from '@gitlab/ui';
import { s__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import {
MAX_LIST_COUNT,
ACTIVE_CONNECTION_TIME,
AGENT_FEEDBACK_ISSUE,
AGENT_FEEDBACK_KEY,
} from '../constants';
import getAgentsQuery from '../graphql/queries/get_agents.query.graphql';
import AgentEmptyState from './agent_empty_state.vue';
import AgentTable from './agent_table.vue';
export default {
i18n: {
feedbackBannerTitle: s__('ClusterAgents|Tell us what you think'),
feedbackBannerText: s__(
'ClusterAgents|We would love to learn more about your experience with the GitLab Agent.',
),
feedbackBannerButton: s__('ClusterAgents|Give feedback'),
error: s__('ClusterAgents|An error occurred while loading your Agents'),
},
AGENT_FEEDBACK_ISSUE,
AGENT_FEEDBACK_KEY,
apollo: {
agents: {
query: getAgentsQuery,
variables() {
return {
defaultBranchName: this.defaultBranchName,
projectPath: this.projectPath,
...this.cursor,
};
},
update(data) {
this.updateTreeList(data);
return data;
},
result() {
this.emitAgentsLoaded();
},
},
},
components: {
AgentEmptyState,
AgentTable,
GlAlert,
GlKeysetPagination,
GlLoadingIcon,
GlBanner,
LocalStorageSync,
},
mixins: [glFeatureFlagMixin()],
inject: ['projectPath'],
props: {
defaultBranchName: {
default: '.noBranch',
required: false,
type: String,
},
isChildComponent: {
default: false,
required: false,
type: Boolean,
},
limit: {
default: null,
required: false,
type: Number,
},
},
data() {
return {
cursor: {
first: this.limit ? this.limit : MAX_LIST_COUNT,
last: null,
},
folderList: {},
feedbackBannerDismissed: false,
};
},
computed: {
agentList() {
let list = this.agents?.project?.clusterAgents?.nodes;
if (list) {
list = list.map((agent) => {
const configFolder = this.folderList[agent.name];
const lastContact = this.getLastContact(agent);
const status = this.getStatus(lastContact);
return { ...agent, configFolder, lastContact, status };
});
}
return list;
},
agentPageInfo() {
return this.agents?.project?.clusterAgents?.pageInfo || {};
},
isLoading() {
return this.$apollo.queries.agents.loading;
},
showPagination() {
return !this.limit && (this.agentPageInfo.hasPreviousPage || this.agentPageInfo.hasNextPage);
},
treePageInfo() {
return this.agents?.project?.repository?.tree?.trees?.pageInfo || {};
},
feedbackBannerEnabled() {
return this.glFeatures.showGitlabAgentFeedback;
},
feedbackBannerClasses() {
return this.isChildComponent ? 'gl-my-2' : 'gl-mb-4';
},
},
methods: {
reloadAgents() {
this.$apollo.queries.agents.refetch();
},
nextPage() {
this.cursor = {
first: MAX_LIST_COUNT,
last: null,
afterAgent: this.agentPageInfo.endCursor,
afterTree: this.treePageInfo.endCursor,
};
},
prevPage() {
this.cursor = {
first: null,
last: MAX_LIST_COUNT,
beforeAgent: this.agentPageInfo.startCursor,
beforeTree: this.treePageInfo.endCursor,
};
},
updateTreeList(data) {
const configFolders = data?.project?.repository?.tree?.trees?.nodes;
if (configFolders) {
configFolders.forEach((folder) => {
this.folderList[folder.name] = folder;
});
}
},
getLastContact(agent) {
const tokens = agent?.tokens?.nodes;
let lastContact = null;
if (tokens?.length) {
tokens.forEach((token) => {
const lastContactToDate = new Date(token.lastUsedAt).getTime();
if (lastContactToDate > lastContact) {
lastContact = lastContactToDate;
}
});
}
return lastContact;
},
getStatus(lastContact) {
if (lastContact) {
const now = new Date().getTime();
const diff = now - lastContact;
return diff > ACTIVE_CONNECTION_TIME ? 'inactive' : 'active';
}
return 'unused';
},
emitAgentsLoaded() {
const count = this.agents?.project?.clusterAgents?.count;
this.$emit('onAgentsLoad', count);
},
handleBannerClose() {
this.feedbackBannerDismissed = true;
},
},
};
</script>
<template>
<gl-loading-icon v-if="isLoading" size="md" />
<section v-else-if="agentList">
<div v-if="agentList.length">
<local-storage-sync
v-if="feedbackBannerEnabled"
v-model="feedbackBannerDismissed"
:storage-key="$options.AGENT_FEEDBACK_KEY"
>
<gl-banner
v-if="!feedbackBannerDismissed"
variant="introduction"
:class="feedbackBannerClasses"
:title="$options.i18n.feedbackBannerTitle"
:button-text="$options.i18n.feedbackBannerButton"
:button-link="$options.AGENT_FEEDBACK_ISSUE"
@close="handleBannerClose"
>
<p>{{ $options.i18n.feedbackBannerText }}</p>
</gl-banner>
</local-storage-sync>
<agent-table
:agents="agentList"
:default-branch-name="defaultBranchName"
:max-agents="cursor.first"
/>
<div v-if="showPagination" class="gl-display-flex gl-justify-content-center gl-mt-5">
<gl-keyset-pagination v-bind="agentPageInfo" @prev="prevPage" @next="nextPage" />
</div>
</div>
<agent-empty-state v-else :is-child-component="isChildComponent" />
</section>
<gl-alert v-else variant="danger" :dismissible="false">
{{ $options.i18n.error }}
</gl-alert>
</template>