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
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-11-15 21:12:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-15 21:12:21 +0300
commit4481a56a94c579f52e1cdef1cc1f4995f0ee1412 (patch)
tree9b8d431d53057e6351dd56718d212b2c89b19312 /app
parente5c7d631a84940c66e46f1824ba7ce0c7f1d0ea4 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/clusters_list/components/agent_empty_state.vue9
-rw-r--r--app/assets/javascripts/clusters_list/components/agents.vue27
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters.vue22
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters_empty_state.vue8
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters_main_view.vue9
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters_view_all.vue217
-rw-r--r--app/assets/javascripts/clusters_list/components/install_agent_modal.vue8
-rw-r--r--app/assets/javascripts/clusters_list/constants.js37
-rw-r--r--app/assets/javascripts/clusters_list/graphql/cache_update.js1
-rw-r--r--app/assets/javascripts/clusters_list/graphql/queries/get_agents.query.graphql2
-rw-r--r--app/assets/javascripts/clusters_list/store/actions.js12
-rw-r--r--app/assets/javascripts/clusters_list/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/clusters_list/store/mutations.js3
-rw-r--r--app/assets/javascripts/clusters_list/store/state.js2
-rw-r--r--app/finders/ci/pipelines_finder.rb17
-rw-r--r--app/graphql/resolvers/concerns/resolves_pipelines.rb3
-rw-r--r--app/graphql/types/ci/pipeline_scope_enum.rb21
-rw-r--r--app/graphql/types/ci/pipeline_status_enum.rb22
-rw-r--r--app/models/ci/trigger.rb4
-rw-r--r--app/models/concerns/ci/has_status.rb17
20 files changed, 403 insertions, 39 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 5c6f9de0624..af44a23b4b3 100644
--- a/app/assets/javascripts/clusters_list/components/agent_empty_state.vue
+++ b/app/assets/javascripts/clusters_list/components/agent_empty_state.vue
@@ -11,9 +11,6 @@ export default {
getStartedDocsUrl: helpPagePath('user/clusters/agent/index', {
anchor: 'define-a-configuration-repository',
}),
- integrationsDocsUrl: helpPagePath('user/clusters/agent/index', {
- anchor: 'get-started-with-gitops-and-the-gitlab-agent',
- }),
components: {
GlButton,
GlEmptyState,
@@ -30,6 +27,11 @@ export default {
type: Boolean,
required: true,
},
+ isChildComponent: {
+ default: false,
+ required: false,
+ type: Boolean,
+ },
},
computed: {
repositoryPath() {
@@ -92,6 +94,7 @@ export default {
<template #actions>
<gl-button
+ v-if="!isChildComponent"
v-gl-modal-directive="$options.modalId"
:disabled="!hasConfigurations"
data-testid="integration-primary-button"
diff --git a/app/assets/javascripts/clusters_list/components/agents.vue b/app/assets/javascripts/clusters_list/components/agents.vue
index 4fc79b32b9c..fb5cf7d1206 100644
--- a/app/assets/javascripts/clusters_list/components/agents.vue
+++ b/app/assets/javascripts/clusters_list/components/agents.vue
@@ -20,6 +20,9 @@ export default {
this.updateTreeList(data);
return data;
},
+ result() {
+ this.emitAgentsLoaded();
+ },
},
},
components: {
@@ -36,11 +39,21 @@ export default {
required: false,
type: String,
},
+ isChildComponent: {
+ default: false,
+ required: false,
+ type: Boolean,
+ },
+ limit: {
+ default: null,
+ required: false,
+ type: Number,
+ },
},
data() {
return {
cursor: {
- first: MAX_LIST_COUNT,
+ first: this.limit ? this.limit : MAX_LIST_COUNT,
last: null,
},
folderList: {},
@@ -68,7 +81,7 @@ export default {
return this.$apollo.queries.agents.loading;
},
showPagination() {
- return this.agentPageInfo.hasPreviousPage || this.agentPageInfo.hasNextPage;
+ return !this.limit && (this.agentPageInfo.hasPreviousPage || this.agentPageInfo.hasNextPage);
},
treePageInfo() {
return this.agents?.project?.repository?.tree?.trees?.pageInfo || {};
@@ -128,6 +141,10 @@ export default {
}
return 'unused';
},
+ emitAgentsLoaded() {
+ const count = this.agents?.project?.clusterAgents?.count;
+ this.$emit('onAgentsLoad', count);
+ },
},
};
</script>
@@ -144,7 +161,11 @@ export default {
</div>
</div>
- <agent-empty-state v-else :has-configurations="hasConfigurations" />
+ <agent-empty-state
+ v-else
+ :has-configurations="hasConfigurations"
+ :is-child-component="isChildComponent"
+ />
</section>
<gl-alert v-else variant="danger" :dismissible="false">
diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue
index bc27563b6d5..9c330045596 100644
--- a/app/assets/javascripts/clusters_list/components/clusters.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters.vue
@@ -34,6 +34,18 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
+ props: {
+ isChildComponent: {
+ default: false,
+ required: false,
+ type: Boolean,
+ },
+ limit: {
+ default: null,
+ required: false,
+ type: Number,
+ },
+ },
computed: {
...mapState([
'clusters',
@@ -100,10 +112,14 @@ export default {
},
},
mounted() {
+ if (this.limit) {
+ this.setClustersPerPage(this.limit);
+ }
+
this.fetchClusters();
},
methods: {
- ...mapActions(['fetchClusters', 'reportSentryError', 'setPage']),
+ ...mapActions(['fetchClusters', 'reportSentryError', 'setPage', 'setClustersPerPage']),
k8sQuantityToGb(quantity) {
if (!quantity) {
return 0;
@@ -312,10 +328,10 @@ export default {
</template>
</gl-table>
- <clusters-empty-state v-else />
+ <clusters-empty-state v-else :is-child-component="isChildComponent" />
<gl-pagination
- v-if="hasClustersPerPage"
+ v-if="hasClustersPerPage && !limit"
v-model="currentPage"
:per-page="clustersPerPage"
:total-items="totalClusters"
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 993507b18bf..3879af6e9cb 100644
--- a/app/assets/javascripts/clusters_list/components/clusters_empty_state.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters_empty_state.vue
@@ -13,6 +13,13 @@ export default {
GlSprintf,
},
inject: ['emptyStateHelpText', 'clustersEmptyStateImage', 'newClusterPath'],
+ props: {
+ isChildComponent: {
+ default: false,
+ required: false,
+ type: Boolean,
+ },
+ },
learnMoreHelpUrl: helpPagePath('user/project/clusters/index'),
multipleClustersHelpUrl: helpPagePath('user/project/clusters/multiple_kubernetes_clusters'),
computed: {
@@ -54,6 +61,7 @@ export default {
<template #actions>
<gl-button
+ v-if="!isChildComponent"
data-testid="integration-primary-button"
data-qa-selector="add_kubernetes_cluster_link"
category="primary"
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 c87cf593305..9e03093aa67 100644
--- a/app/assets/javascripts/clusters_list/components/clusters_main_view.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters_main_view.vue
@@ -1,16 +1,18 @@
<script>
import { GlTabs, GlTab } from '@gitlab/ui';
-import { CLUSTERS_TABS } from '../constants';
+import { CLUSTERS_TABS, MAX_CLUSTERS_LIST, MAX_LIST_COUNT, AGENT } 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';
export default {
components: {
GlTabs,
GlTab,
ClustersActions,
+ ClustersViewAll,
Clusters,
Agents,
InstallAgentModal,
@@ -26,11 +28,14 @@ export default {
data() {
return {
selectedTabIndex: 0,
+ maxAgents: MAX_CLUSTERS_LIST,
};
},
methods: {
onTabChange(tabName) {
this.selectedTabIndex = CLUSTERS_TABS.findIndex((tab) => tab.queryParamValue === tabName);
+
+ this.maxAgents = tabName === AGENT ? MAX_LIST_COUNT : MAX_CLUSTERS_LIST;
},
},
};
@@ -63,6 +68,6 @@ export default {
</template>
</gl-tabs>
- <install-agent-modal :default-branch-name="defaultBranchName" />
+ <install-agent-modal :default-branch-name="defaultBranchName" :max-agents="maxAgents" />
</div>
</template>
diff --git a/app/assets/javascripts/clusters_list/components/clusters_view_all.vue b/app/assets/javascripts/clusters_list/components/clusters_view_all.vue
new file mode 100644
index 00000000000..48a1944fde3
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/components/clusters_view_all.vue
@@ -0,0 +1,217 @@
+<script>
+import {
+ GlCard,
+ GlSprintf,
+ GlPopover,
+ GlLink,
+ GlButton,
+ GlBadge,
+ GlLoadingIcon,
+ GlModalDirective,
+} from '@gitlab/ui';
+import { mapState } from 'vuex';
+import {
+ AGENT_CARD_INFO,
+ CERTIFICATE_BASED_CARD_INFO,
+ MAX_CLUSTERS_LIST,
+ INSTALL_AGENT_MODAL_ID,
+} from '../constants';
+import Clusters from './clusters.vue';
+import Agents from './agents.vue';
+
+export default {
+ components: {
+ GlCard,
+ GlSprintf,
+ GlPopover,
+ GlLink,
+ GlButton,
+ GlBadge,
+ GlLoadingIcon,
+ Clusters,
+ Agents,
+ },
+ directives: {
+ GlModalDirective,
+ },
+ AGENT_CARD_INFO,
+ CERTIFICATE_BASED_CARD_INFO,
+ MAX_CLUSTERS_LIST,
+ INSTALL_AGENT_MODAL_ID,
+ inject: ['addClusterPath'],
+ props: {
+ defaultBranchName: {
+ default: '.noBranch',
+ required: false,
+ type: String,
+ },
+ },
+ data() {
+ return {
+ loadingAgents: true,
+ totalAgents: null,
+ };
+ },
+ computed: {
+ ...mapState(['loadingClusters', 'totalClusters']),
+ isLoading() {
+ return this.loadingAgents || this.loadingClusters;
+ },
+ agentsCardTitle() {
+ let cardTitle;
+ if (this.totalAgents > 0) {
+ cardTitle = {
+ message: AGENT_CARD_INFO.title,
+ number: this.totalAgents < MAX_CLUSTERS_LIST ? this.totalAgents : MAX_CLUSTERS_LIST,
+ total: this.totalAgents,
+ };
+ } else {
+ cardTitle = {
+ message: AGENT_CARD_INFO.emptyTitle,
+ };
+ }
+
+ return cardTitle;
+ },
+ clustersCardTitle() {
+ let cardTitle;
+ if (this.totalClusters > 0) {
+ cardTitle = {
+ message: CERTIFICATE_BASED_CARD_INFO.title,
+ number: this.totalClusters < MAX_CLUSTERS_LIST ? this.totalClusters : MAX_CLUSTERS_LIST,
+ total: this.totalClusters,
+ };
+ } else {
+ cardTitle = {
+ message: CERTIFICATE_BASED_CARD_INFO.emptyTitle,
+ };
+ }
+
+ return cardTitle;
+ },
+ },
+ methods: {
+ cardFooterNumber(number) {
+ return number > MAX_CLUSTERS_LIST ? number : '';
+ },
+ onAgentsLoad(number) {
+ this.totalAgents = number;
+ this.loadingAgents = false;
+ },
+ changeTab($event, tab) {
+ $event.preventDefault();
+ this.$emit('changeTab', tab);
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-loading-icon v-if="isLoading" size="md" />
+ <div v-show="!isLoading" data-testid="clusters-cards-container">
+ <gl-card
+ header-class="gl-bg-white gl-display-flex gl-align-items-center gl-justify-content-space-between gl-py-4"
+ body-class="gl-pb-0"
+ footer-class="gl-text-right"
+ >
+ <template #header>
+ <h3 data-testid="agent-card-title" class="gl-my-0 gl-font-weight-normal gl-font-size-h2">
+ <gl-sprintf :message="agentsCardTitle.message"
+ ><template #number>{{ agentsCardTitle.number }}</template>
+ <template #total>{{ agentsCardTitle.total }}</template>
+ </gl-sprintf>
+ </h3>
+
+ <gl-badge id="clusters-recommended-badge" size="md" variant="info">{{
+ $options.AGENT_CARD_INFO.tooltip.label
+ }}</gl-badge>
+
+ <gl-popover
+ target="clusters-recommended-badge"
+ container="viewport"
+ placement="bottom"
+ :title="$options.AGENT_CARD_INFO.tooltip.title"
+ >
+ <p class="gl-mb-0">
+ <gl-sprintf :message="$options.AGENT_CARD_INFO.tooltip.text">
+ <template #link="{ content }">
+ <gl-link
+ :href="$options.AGENT_CARD_INFO.tooltip.link"
+ target="_blank"
+ class="gl-font-sm"
+ >
+ {{ content }}</gl-link
+ >
+ </template>
+ </gl-sprintf>
+ </p>
+ </gl-popover>
+ </template>
+
+ <agents
+ :limit="$options.MAX_CLUSTERS_LIST"
+ :default-branch-name="defaultBranchName"
+ :is-child-component="true"
+ @onAgentsLoad="onAgentsLoad"
+ />
+
+ <template #footer>
+ <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"
+ ><template #number>{{ cardFooterNumber(totalAgents) }}</template></gl-sprintf
+ ></gl-link
+ ><gl-button
+ v-gl-modal-directive="$options.INSTALL_AGENT_MODAL_ID"
+ class="gl-ml-4"
+ category="secondary"
+ variant="confirm"
+ >{{ $options.AGENT_CARD_INFO.actionText }}</gl-button
+ >
+ </template>
+ </gl-card>
+
+ <gl-card
+ class="gl-mt-6"
+ header-class="gl-bg-white gl-display-flex gl-align-items-center gl-justify-content-space-between"
+ body-class="gl-pb-0"
+ footer-class="gl-text-right"
+ >
+ <template #header>
+ <h3
+ class="gl-my-1 gl-font-weight-normal gl-font-size-h2"
+ data-testid="clusters-card-title"
+ >
+ <gl-sprintf :message="clustersCardTitle.message"
+ ><template #number>{{ clustersCardTitle.number }}</template>
+ <template #total>{{ clustersCardTitle.total }}</template>
+ </gl-sprintf>
+ </h3>
+ </template>
+
+ <clusters :limit="$options.MAX_CLUSTERS_LIST" :is-child-component="true" />
+
+ <template #footer>
+ <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"
+ ><template #number>{{ cardFooterNumber(totalClusters) }}</template></gl-sprintf
+ ></gl-link
+ ><gl-button
+ category="secondary"
+ variant="confirm"
+ class="gl-ml-4"
+ :href="addClusterPath"
+ >{{ $options.CERTIFICATE_BASED_CARD_INFO.actionText }}</gl-button
+ >
+ </template>
+ </gl-card>
+ </div>
+ </div>
+</template>
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 0efd3844cc9..6eb2e85ecea 100644
--- a/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
+++ b/app/assets/javascripts/clusters_list/components/install_agent_modal.vue
@@ -12,7 +12,7 @@ import { helpPagePath } from '~/helpers/help_page_helper';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import CodeBlock from '~/vue_shared/components/code_block.vue';
import { generateAgentRegistrationCommand } from '../clusters_util';
-import { INSTALL_AGENT_MODAL_ID, I18N_INSTALL_AGENT_MODAL, MAX_LIST_COUNT } from '../constants';
+import { INSTALL_AGENT_MODAL_ID, I18N_INSTALL_AGENT_MODAL } from '../constants';
import { addAgentToStore } from '../graphql/cache_update';
import createAgent from '../graphql/mutations/create_agent.mutation.graphql';
import createAgentToken from '../graphql/mutations/create_agent_token.mutation.graphql';
@@ -41,6 +41,10 @@ export default {
required: false,
type: String,
},
+ maxAgents: {
+ required: true,
+ type: Number,
+ },
},
data() {
return {
@@ -75,7 +79,7 @@ export default {
getAgentsQueryVariables() {
return {
defaultBranchName: this.defaultBranchName,
- first: MAX_LIST_COUNT,
+ first: this.maxAgents,
last: null,
projectPath: this.projectPath,
};
diff --git a/app/assets/javascripts/clusters_list/constants.js b/app/assets/javascripts/clusters_list/constants.js
index 36e6a065cbf..9fefdf450c4 100644
--- a/app/assets/javascripts/clusters_list/constants.js
+++ b/app/assets/javascripts/clusters_list/constants.js
@@ -1,4 +1,5 @@
import { __, s__, sprintf } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
export const MAX_LIST_COUNT = 25;
export const INSTALL_AGENT_MODAL_ID = 'install-agent';
@@ -167,8 +168,41 @@ export const I18N_CLUSTERS_EMPTY_STATE = {
buttonText: s__('ClusterIntegration|Connect with a certificate'),
};
+export const AGENT_CARD_INFO = {
+ tabName: 'agent',
+ title: sprintf(s__('ClusterAgents|%{number} of %{total} Agent based integrations')),
+ emptyTitle: s__('ClusterAgents|No Agent based integrations'),
+ tooltip: {
+ label: s__('ClusterAgents|Recommended'),
+ title: s__('ClusterAgents|GitLab Agents'),
+ 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}',
+ ),
+ ),
+ link: helpPagePath('user/clusters/agent/index'),
+ },
+ actionText: s__('ClusterAgents|Install new Agent'),
+ footerText: sprintf(s__('ClusterAgents|View all %{number} Agent based integrations')),
+};
+
+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'),
+ actionText: s__('ClusterAgents|Connect existing cluster'),
+ footerText: sprintf(s__('ClusterAgents|View all %{number} Certificate based integrations')),
+};
+
+export const MAX_CLUSTERS_LIST = 6;
+
export const CLUSTERS_TABS = [
{
+ title: s__('ClusterAgents|All'),
+ component: 'ClustersViewAll',
+ queryParamValue: 'all',
+ },
+ {
title: s__('ClusterAgents|Agent'),
component: 'agents',
queryParamValue: 'agent',
@@ -186,3 +220,6 @@ export const CLUSTERS_ACTIONS = {
connectWithAgent: s__('ClusterAgents|Connect with Agent'),
connectExistingCluster: s__('ClusterAgents|Connect with certificate'),
};
+
+export const AGENT = 'agent';
+export const CERTIFICATE_BASED = 'certificate_based';
diff --git a/app/assets/javascripts/clusters_list/graphql/cache_update.js b/app/assets/javascripts/clusters_list/graphql/cache_update.js
index ce6daecc908..dd633820952 100644
--- a/app/assets/javascripts/clusters_list/graphql/cache_update.js
+++ b/app/assets/javascripts/clusters_list/graphql/cache_update.js
@@ -17,6 +17,7 @@ export function addAgentToStore(store, createClusterAgent, query, variables) {
};
draftData.project.clusterAgents.nodes.push(clusterAgent);
+ draftData.project.clusterAgents.count += 1;
draftData.project.repository.tree.trees.nodes.push(configuration);
});
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 397895b7d01..47b25988877 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
@@ -20,6 +20,8 @@ query getAgents(
pageInfo {
...PageInfo
}
+
+ count
}
repository {
diff --git a/app/assets/javascripts/clusters_list/store/actions.js b/app/assets/javascripts/clusters_list/store/actions.js
index f0f96fd7872..d70b36e63bc 100644
--- a/app/assets/javascripts/clusters_list/store/actions.js
+++ b/app/assets/javascripts/clusters_list/store/actions.js
@@ -30,7 +30,13 @@ export const fetchClusters = ({ state, commit, dispatch }) => {
const poll = new Poll({
resource: {
- fetchClusters: (paginatedEndPoint) => axios.get(paginatedEndPoint),
+ fetchClusters: (paginatedEndPoint) =>
+ axios.get(paginatedEndPoint, {
+ params: {
+ page: state.page,
+ per_page: state.clustersPerPage,
+ },
+ }),
},
data: `${state.endpoint}?page=${state.page}`,
method: 'fetchClusters',
@@ -78,3 +84,7 @@ export const fetchClusters = ({ state, commit, dispatch }) => {
export const setPage = ({ commit }, page) => {
commit(types.SET_PAGE, page);
};
+
+export const setClustersPerPage = ({ commit }, limit) => {
+ commit(types.SET_CLUSTERS_PER_PAGE, limit);
+};
diff --git a/app/assets/javascripts/clusters_list/store/mutation_types.js b/app/assets/javascripts/clusters_list/store/mutation_types.js
index beb4388c93e..e88d4c74761 100644
--- a/app/assets/javascripts/clusters_list/store/mutation_types.js
+++ b/app/assets/javascripts/clusters_list/store/mutation_types.js
@@ -2,3 +2,4 @@ export const SET_CLUSTERS_DATA = 'SET_CLUSTERS_DATA';
export const SET_LOADING_CLUSTERS = 'SET_LOADING_CLUSTERS';
export const SET_LOADING_NODES = 'SET_LOADING_NODES';
export const SET_PAGE = 'SET_PAGE';
+export const SET_CLUSTERS_PER_PAGE = 'SET_CLUSTERS_PER_PAGE';
diff --git a/app/assets/javascripts/clusters_list/store/mutations.js b/app/assets/javascripts/clusters_list/store/mutations.js
index e5c15ccbd6e..93156c9200f 100644
--- a/app/assets/javascripts/clusters_list/store/mutations.js
+++ b/app/assets/javascripts/clusters_list/store/mutations.js
@@ -18,4 +18,7 @@ export default {
[types.SET_PAGE](state, value) {
state.page = Number(value) || 1;
},
+ [types.SET_CLUSTERS_PER_PAGE](state, value) {
+ state.clustersPerPage = Number(value) || 1;
+ },
};
diff --git a/app/assets/javascripts/clusters_list/store/state.js b/app/assets/javascripts/clusters_list/store/state.js
index 3dcbf58c8d3..763d7389d0f 100644
--- a/app/assets/javascripts/clusters_list/store/state.js
+++ b/app/assets/javascripts/clusters_list/store/state.js
@@ -5,7 +5,7 @@ export default (initialState = {}) => ({
endpoint: initialState.endpoint,
hasAncestorClusters: false,
clusters: [],
- clustersPerPage: 0,
+ clustersPerPage: 20,
loadingClusters: true,
loadingNodes: true,
page: 1,
diff --git a/app/finders/ci/pipelines_finder.rb b/app/finders/ci/pipelines_finder.rb
index 39355853d88..712d5f8c6fb 100644
--- a/app/finders/ci/pipelines_finder.rb
+++ b/app/finders/ci/pipelines_finder.rb
@@ -5,6 +5,13 @@ module Ci
attr_reader :project, :pipelines, :params, :current_user
ALLOWED_INDEXED_COLUMNS = %w[id status ref updated_at user_id].freeze
+ ALLOWED_SCOPES = {
+ RUNNING: 'running',
+ PENDING: 'pending',
+ FINISHED: 'finished',
+ BRANCHES: 'branches',
+ TAGS: 'tags'
+ }.freeze
def initialize(project, current_user, params = {})
@project = project
@@ -65,15 +72,15 @@ module Ci
def by_scope(items)
case params[:scope]
- when 'running'
+ when ALLOWED_SCOPES[:RUNNING]
items.running
- when 'pending'
+ when ALLOWED_SCOPES[:PENDING]
items.pending
- when 'finished'
+ when ALLOWED_SCOPES[:FINISHED]
items.finished
- when 'branches'
+ when ALLOWED_SCOPES[:BRANCHES]
from_ids(ids_for_ref(branches))
- when 'tags'
+ when ALLOWED_SCOPES[:TAGS]
from_ids(ids_for_ref(tags))
else
items
diff --git a/app/graphql/resolvers/concerns/resolves_pipelines.rb b/app/graphql/resolvers/concerns/resolves_pipelines.rb
index 7fb0852b11e..1c01e5e0250 100644
--- a/app/graphql/resolvers/concerns/resolves_pipelines.rb
+++ b/app/graphql/resolvers/concerns/resolves_pipelines.rb
@@ -9,6 +9,9 @@ module ResolvesPipelines
Types::Ci::PipelineStatusEnum,
required: false,
description: "Filter pipelines by their status."
+ argument :scope, ::Types::Ci::PipelineScopeEnum,
+ required: false,
+ description: 'Filter pipelines by scope.'
argument :ref,
GraphQL::Types::String,
required: false,
diff --git a/app/graphql/types/ci/pipeline_scope_enum.rb b/app/graphql/types/ci/pipeline_scope_enum.rb
new file mode 100644
index 00000000000..3ce81bc7bf3
--- /dev/null
+++ b/app/graphql/types/ci/pipeline_scope_enum.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class PipelineScopeEnum < BaseEnum
+ SCOPES_DESCRIPTION = {
+ running: 'Pipeline is running.',
+ pending: 'Pipeline has not started running yet.',
+ finished: 'Pipeline has completed.',
+ branches: 'Branches.',
+ tags: 'Tags.'
+ }.freeze
+
+ SCOPES_DESCRIPTION.each do |scope, description|
+ value scope.to_s.upcase,
+ description: description,
+ value: scope.to_s
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/ci/pipeline_status_enum.rb b/app/graphql/types/ci/pipeline_status_enum.rb
index 2800454a999..c8e031e18ea 100644
--- a/app/graphql/types/ci/pipeline_status_enum.rb
+++ b/app/graphql/types/ci/pipeline_status_enum.rb
@@ -3,10 +3,24 @@
module Types
module Ci
class PipelineStatusEnum < BaseEnum
- ::Ci::Pipeline.all_state_names.each do |state_symbol|
- value state_symbol.to_s.upcase,
- description: "#{::Ci::Pipeline::STATUSES_DESCRIPTION[state_symbol]}.",
- value: state_symbol.to_s
+ STATUSES_DESCRIPTION = {
+ created: 'Pipeline has been created.',
+ waiting_for_resource: 'A resource (for example, a runner) that the pipeline requires to run is unavailable.',
+ preparing: 'Pipeline is preparing to run.',
+ pending: 'Pipeline has not started running yet.',
+ running: 'Pipeline is running.',
+ failed: 'At least one stage of the pipeline failed.',
+ success: 'Pipeline completed successfully.',
+ canceled: 'Pipeline was canceled before completion.',
+ skipped: 'Pipeline was skipped.',
+ manual: 'Pipeline needs to be manually started.',
+ scheduled: 'Pipeline is scheduled to run.'
+ }.freeze
+
+ STATUSES_DESCRIPTION.each do |state, description|
+ value state.to_s.upcase,
+ description: description,
+ value: state.to_s
end
end
end
diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb
index 595315f14ab..5bf5ae51ec8 100644
--- a/app/models/ci/trigger.rb
+++ b/app/models/ci/trigger.rb
@@ -3,6 +3,10 @@
module Ci
class Trigger < Ci::ApplicationRecord
include Presentable
+ include Limitable
+
+ self.limit_name = 'pipeline_triggers'
+ self.limit_scope = :project
belongs_to :project
belongs_to :owner, class_name: "User"
diff --git a/app/models/concerns/ci/has_status.rb b/app/models/concerns/ci/has_status.rb
index 8d715279da8..ccaccec3b6b 100644
--- a/app/models/concerns/ci/has_status.rb
+++ b/app/models/concerns/ci/has_status.rb
@@ -14,21 +14,8 @@ module Ci
PASSED_WITH_WARNINGS_STATUSES = %w[failed canceled].to_set.freeze
EXCLUDE_IGNORED_STATUSES = %w[manual failed canceled].to_set.freeze
STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3,
- failed: 4, canceled: 5, skipped: 6, manual: 7,
- scheduled: 8, preparing: 9, waiting_for_resource: 10 }.freeze
- STATUSES_DESCRIPTION = {
- created: 'Pipeline has been created',
- waiting_for_resource: 'A resource (for example, a runner) that the pipeline requires to run is unavailable',
- preparing: 'Pipeline is preparing to run',
- pending: 'Pipeline has not started running yet',
- running: 'Pipeline is running',
- failed: 'At least one stage of the pipeline failed',
- success: 'Pipeline completed successfully',
- canceled: 'Pipeline was canceled before completion',
- skipped: 'Pipeline was skipped',
- manual: 'Pipeline needs to be manually started',
- scheduled: 'Pipeline is scheduled to run'
- }.freeze
+ failed: 4, canceled: 5, skipped: 6, manual: 7,
+ scheduled: 8, preparing: 9, waiting_for_resource: 10 }.freeze
UnknownStatusError = Class.new(StandardError)