diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-20 21:10:33 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-20 21:10:33 +0300 |
commit | 1cb90c3b4f04d42fa30f7903b10b32721c5fadac (patch) | |
tree | 7fcc5031b249c936a73dfbd4fe2594b1e0a2943d /app/assets/javascripts/releases | |
parent | e45c8a7e74d4c1a1f7e12504df3611f797620166 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/releases')
3 files changed, 219 insertions, 2 deletions
diff --git a/app/assets/javascripts/releases/components/app_index_apollo_client.vue b/app/assets/javascripts/releases/components/app_index_apollo_client.vue new file mode 100644 index 00000000000..be4d7d8543c --- /dev/null +++ b/app/assets/javascripts/releases/components/app_index_apollo_client.vue @@ -0,0 +1,155 @@ +<script> +import { GlButton } from '@gitlab/ui'; +import createFlash from '~/flash'; +import { getParameterByName } from '~/lib/utils/common_utils'; +import { __ } from '~/locale'; +import { PAGE_SIZE } from '~/releases/constants'; +import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql'; +import { convertAllReleasesGraphQLResponse } from '~/releases/util'; +import ReleaseBlock from './release_block.vue'; +import ReleaseSkeletonLoader from './release_skeleton_loader.vue'; +import ReleasesEmptyState from './releases_empty_state.vue'; + +export default { + name: 'ReleasesIndexApolloClientApp', + components: { + GlButton, + ReleaseBlock, + ReleaseSkeletonLoader, + ReleasesEmptyState, + }, + inject: { + projectPath: { + default: '', + }, + newReleasePath: { + default: '', + }, + }, + apollo: { + graphqlResponse: { + query: allReleasesQuery, + variables() { + return this.queryVariables; + }, + update(data) { + return { data }; + }, + error(error) { + this.hasError = true; + + createFlash({ + message: this.$options.i18n.errorMessage, + captureError: true, + error, + }); + }, + }, + }, + data() { + return { + hasError: false, + cursors: { + before: getParameterByName('before'), + after: getParameterByName('after'), + }, + }; + }, + computed: { + queryVariables() { + let paginationParams = { first: PAGE_SIZE }; + if (this.cursors.after) { + paginationParams = { + after: this.cursors.after, + first: PAGE_SIZE, + }; + } else if (this.cursors.before) { + paginationParams = { + before: this.cursors.before, + last: PAGE_SIZE, + }; + } + + return { + fullPath: this.projectPath, + ...paginationParams, + }; + }, + isLoading() { + return this.$apollo.queries.graphqlResponse.loading; + }, + releases() { + if (!this.graphqlResponse || this.hasError) { + return []; + } + + return convertAllReleasesGraphQLResponse(this.graphqlResponse).data; + }, + shouldRenderEmptyState() { + return !this.releases.length && !this.hasError && !this.isLoading; + }, + shouldRenderSuccessState() { + return this.releases.length && !this.isLoading && !this.hasError; + }, + shouldRenderLoadingIndicator() { + return this.isLoading && !this.hasError; + }, + }, + created() { + this.updateQueryParamsFromUrl(); + + window.addEventListener('popstate', this.updateQueryParamsFromUrl); + }, + destroyed() { + window.removeEventListener('popstate', this.updateQueryParamsFromUrl); + }, + methods: { + updateQueryParamsFromUrl() { + this.cursors.before = getParameterByName('before'); + this.cursors.after = getParameterByName('after'); + }, + }, + i18n: { + newRelease: __('New release'), + errorMessage: __('An error occurred while fetching the releases. Please try again.'), + }, +}; +</script> +<template> + <div class="flex flex-column mt-2"> + <div class="gl-align-self-end gl-mb-3"> + <gl-button + v-if="newReleasePath" + :href="newReleasePath" + :aria-describedby="shouldRenderEmptyState && 'releases-description'" + category="primary" + variant="success" + >{{ $options.i18n.newRelease }}</gl-button + > + </div> + + <release-skeleton-loader v-if="shouldRenderLoadingIndicator" /> + + <releases-empty-state v-else-if="shouldRenderEmptyState" /> + + <div v-else-if="shouldRenderSuccessState"> + <release-block + v-for="(release, index) in releases" + :key="index" + :release="release" + :class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }" + /> + </div> + </div> +</template> +<style> +.linked-card::after { + width: 1px; + content: ' '; + border: 1px solid #e5e5e5; + height: 17px; + top: 100%; + position: absolute; + left: 32px; +} +</style> diff --git a/app/assets/javascripts/releases/components/releases_empty_state.vue b/app/assets/javascripts/releases/components/releases_empty_state.vue new file mode 100644 index 00000000000..800497c186a --- /dev/null +++ b/app/assets/javascripts/releases/components/releases_empty_state.vue @@ -0,0 +1,44 @@ +<script> +import { GlEmptyState, GlLink } from '@gitlab/ui'; +import { __ } from '~/locale'; + +export default { + name: 'ReleasesEmptyState', + components: { + GlEmptyState, + GlLink, + }, + inject: { + documentationPath: { + default: '', + }, + illustrationPath: { + default: '', + }, + }, + i18n: { + emptyStateTitle: __('Getting started with releases'), + emptyStateText: __( + "Releases are based on Git tags and mark specific points in a project's development history. They can contain information about the type of changes and can also deliver binaries, like compiled versions of your software.", + ), + releasesDocumentation: __('Releases documentation'), + moreInformation: __('More information'), + }, +}; +</script> +<template> + <gl-empty-state :title="$options.i18n.emptyStateTitle" :svg-path="illustrationPath"> + <template #description> + <span id="releases-description"> + {{ $options.i18n.emptyStateText }} + <gl-link + :href="documentationPath" + :aria-label="$options.i18n.releasesDocumentation" + target="_blank" + > + {{ $options.i18n.moreInformation }} + </gl-link> + </span> + </template> + </gl-empty-state> +</template> diff --git a/app/assets/javascripts/releases/mount_index.js b/app/assets/javascripts/releases/mount_index.js index bb21ec7c43f..57f9f968423 100644 --- a/app/assets/javascripts/releases/mount_index.js +++ b/app/assets/javascripts/releases/mount_index.js @@ -1,14 +1,32 @@ import Vue from 'vue'; +import VueApollo from 'vue-apollo'; import Vuex from 'vuex'; +import createDefaultClient from '~/lib/graphql'; import ReleaseIndexApp from './components/app_index.vue'; +import ReleaseIndexApollopClientApp from './components/app_index_apollo_client.vue'; import createStore from './stores'; import createIndexModule from './stores/modules/index'; -Vue.use(Vuex); - export default () => { const el = document.getElementById('js-releases-page'); + if (window.gon?.features?.releasesIndexApolloClient) { + Vue.use(VueApollo); + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), + }); + + return new Vue({ + el, + apolloProvider, + provide: { ...el.dataset }, + render: (h) => h(ReleaseIndexApollopClientApp), + }); + } + + Vue.use(Vuex); + return new Vue({ el, store: createStore({ |