Commit de3c64af authored by Brandon Labuschagne's avatar Brandon Labuschagne

Merge branch '298748-token-pagination' into 'master'

Add pagination to agent token table

See merge request gitlab-org/gitlab!55788
parents d0221d03 ed0a62df
<script> <script>
import { GlAlert, GlBadge, GlLoadingIcon, GlSprintf, GlTab, GlTabs } from '@gitlab/ui'; import {
GlAlert,
GlBadge,
GlKeysetPagination,
GlLoadingIcon,
GlSprintf,
GlTab,
GlTabs,
} from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; 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 getClusterAgentQuery from '../graphql/queries/get_cluster_agent.query.graphql';
import TokenTable from './token_table.vue'; import TokenTable from './token_table.vue';
...@@ -19,6 +28,7 @@ export default { ...@@ -19,6 +28,7 @@ export default {
return { return {
agentName: this.agentName, agentName: this.agentName,
projectPath: this.projectPath, projectPath: this.projectPath,
...this.cursor,
}; };
}, },
update: (data) => data?.project?.clusterAgent, update: (data) => data?.project?.clusterAgent,
...@@ -30,6 +40,7 @@ export default { ...@@ -30,6 +40,7 @@ export default {
components: { components: {
GlAlert, GlAlert,
GlBadge, GlBadge,
GlKeysetPagination,
GlLoadingIcon, GlLoadingIcon,
GlSprintf, GlSprintf,
GlTab, GlTab,
...@@ -47,6 +58,14 @@ export default { ...@@ -47,6 +58,14 @@ export default {
type: String, type: String,
}, },
}, },
data() {
return {
cursor: {
first: MAX_LIST_COUNT,
last: null,
},
};
},
computed: { computed: {
createdAt() { createdAt() {
return this.clusterAgent?.createdAt; return this.clusterAgent?.createdAt;
...@@ -57,13 +76,35 @@ export default { ...@@ -57,13 +76,35 @@ export default {
isLoading() { isLoading() {
return this.$apollo.queries.clusterAgent.loading; return this.$apollo.queries.clusterAgent.loading;
}, },
showPagination() {
return this.tokenPageInfo.hasPreviousPage || this.tokenPageInfo.hasNextPage;
},
tokenCount() { tokenCount() {
return this.clusterAgent?.tokens?.count; return this.clusterAgent?.tokens?.count;
}, },
tokenPageInfo() {
return this.clusterAgent?.tokens?.pageInfo || {};
},
tokens() { tokens() {
return this.clusterAgent?.tokens?.nodes || []; 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> </script>
...@@ -71,7 +112,7 @@ export default { ...@@ -71,7 +112,7 @@ export default {
<section> <section>
<h2>{{ agentName }}</h2> <h2>{{ agentName }}</h2>
<gl-loading-icon v-if="isLoading" size="lg" class="gl-m-3" /> <gl-loading-icon v-if="isLoading && clusterAgent == null" size="lg" class="gl-m-3" />
<div v-else-if="clusterAgent"> <div v-else-if="clusterAgent">
<p data-testid="cluster-agent-create-info"> <p data-testid="cluster-agent-create-info">
...@@ -98,7 +139,15 @@ export default { ...@@ -98,7 +139,15 @@ export default {
</span> </span>
</template> </template>
<TokenTable :tokens="tokens" /> <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-tab>
</gl-tabs> </gl-tabs>
</div> </div>
......
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "../fragments/cluster_agent_token.fragment.graphql" #import "../fragments/cluster_agent_token.fragment.graphql"
query getClusterAgent($projectPath: ID!, $agentName: String!) { query getClusterAgent(
$projectPath: ID!
$agentName: String!
$first: Int
$last: Int
$afterToken: String
$beforeToken: String
) {
project(fullPath: $projectPath) { project(fullPath: $projectPath) {
clusterAgent(name: $agentName) { clusterAgent(name: $agentName) {
id id
...@@ -10,12 +18,16 @@ query getClusterAgent($projectPath: ID!, $agentName: String!) { ...@@ -10,12 +18,16 @@ query getClusterAgent($projectPath: ID!, $agentName: String!) {
name name
} }
tokens { tokens(first: $first, last: $last, before: $beforeToken, after: $afterToken) {
count count
nodes { nodes {
...Token ...Token
} }
pageInfo {
...PageInfo
}
} }
} }
} }
......
---
title: Add pagination to agent token table
merge_request: 55788
author:
type: changed
import { GlAlert, GlLoadingIcon, GlSprintf } from '@gitlab/ui'; import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import ClusterAgentShow from 'ee/clusters/agents/components/show.vue'; import ClusterAgentShow from 'ee/clusters/agents/components/show.vue';
...@@ -31,6 +31,7 @@ describe('ClusterAgentShow', () => { ...@@ -31,6 +31,7 @@ describe('ClusterAgentShow', () => {
tokens: { tokens: {
count: 1, count: 1,
nodes: [], nodes: [],
pageInfo: null,
}, },
}; };
...@@ -47,23 +48,50 @@ describe('ClusterAgentShow', () => { ...@@ -47,23 +48,50 @@ describe('ClusterAgentShow', () => {
}); });
}; };
const createWrapperWithoutApollo = ({ clusterAgent, loading = false }) => {
const $apollo = { queries: { clusterAgent: { loading } } };
wrapper = shallowMount(ClusterAgentShow, {
propsData,
mocks: { $apollo, clusterAgent },
});
};
const findCreatedText = () => wrapper.find('[data-testid="cluster-agent-create-info"]').text(); const findCreatedText = () => wrapper.find('[data-testid="cluster-agent-create-info"]').text();
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findPaginationButtons = () => wrapper.find(GlKeysetPagination);
const findTokenCount = () => wrapper.find('[data-testid="cluster-agent-token-count"]').text(); const findTokenCount = () => wrapper.find('[data-testid="cluster-agent-token-count"]').text();
beforeEach(() => {
return createWrapper({ clusterAgent: defaultClusterAgent });
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
it('displays the agent name', () => { describe('default behaviour', () => {
expect(wrapper.text()).toContain(propsData.agentName); beforeEach(() => {
}); return createWrapper({ clusterAgent: defaultClusterAgent });
});
it('displays the agent name', () => {
expect(wrapper.text()).toContain(propsData.agentName);
});
it('displays agent create information', () => {
expect(findCreatedText()).toMatchInterpolatedText('Created by user-1 2 days ago');
});
it('displays agent create information', () => { it('displays token count', () => {
expect(findCreatedText()).toMatchInterpolatedText('Created by user-1 2 days ago'); expect(findTokenCount()).toMatchInterpolatedText(
`${ClusterAgentShow.i18n.tokens} ${defaultClusterAgent.tokens.count}`,
);
});
it('renders token table', () => {
expect(wrapper.find(TokenTable).exists()).toBe(true);
});
it('should not render pagination buttons when there are no additional pages', () => {
expect(findPaginationButtons().exists()).toBe(false);
});
}); });
describe('when create user is unknown', () => { describe('when create user is unknown', () => {
...@@ -81,12 +109,6 @@ describe('ClusterAgentShow', () => { ...@@ -81,12 +109,6 @@ describe('ClusterAgentShow', () => {
}); });
}); });
it('displays token count', () => {
expect(findTokenCount()).toMatchInterpolatedText(
`${ClusterAgentShow.i18n.tokens} ${defaultClusterAgent.tokens.count}`,
);
});
describe('when token count is missing', () => { describe('when token count is missing', () => {
const missingTokens = { const missingTokens = {
...defaultClusterAgent, ...defaultClusterAgent,
...@@ -102,20 +124,59 @@ describe('ClusterAgentShow', () => { ...@@ -102,20 +124,59 @@ describe('ClusterAgentShow', () => {
}); });
}); });
it('renders token table', () => { describe('when the token list has additional pages', () => {
expect(wrapper.find(TokenTable).exists()).toBe(true); const pageInfo = {
hasNextPage: true,
hasPreviousPage: false,
startCursor: 'prev',
endCursor: 'next',
};
const tokenPagination = {
...defaultClusterAgent,
tokens: {
...defaultClusterAgent.tokens,
pageInfo,
},
};
beforeEach(() => {
return createWrapper({ clusterAgent: tokenPagination });
});
it('should render pagination buttons', () => {
expect(findPaginationButtons().exists()).toBe(true);
});
it('should pass pageInfo to the pagination component', () => {
expect(findPaginationButtons().props()).toMatchObject(pageInfo);
});
}); });
describe('when the agent query is loading', () => { describe('when the agent query is loading', () => {
beforeEach(() => { describe('when the clusterAgent is missing', () => {
return createWrapper({ beforeEach(() => {
clusterAgent: null, return createWrapper({
queryResponse: jest.fn().mockReturnValue(new Promise(() => {})), clusterAgent: null,
queryResponse: jest.fn().mockReturnValue(new Promise(() => {})),
});
});
it('displays a loading icon and hides the token tab', () => {
expect(findLoadingIcon().exists()).toBe(true);
expect(wrapper.text()).not.toContain(ClusterAgentShow.i18n.tokens);
}); });
}); });
it('displays a loading icon', () => { describe('when the clusterAgent is present', () => {
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); beforeEach(() => {
createWrapperWithoutApollo({ clusterAgent: defaultClusterAgent, loading: true });
});
it('displays a loading icon and token tab', () => {
expect(findLoadingIcon().exists()).toBe(true);
expect(wrapper.text()).toContain(ClusterAgentShow.i18n.tokens);
});
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment