diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /app/assets/javascripts/releases | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'app/assets/javascripts/releases')
11 files changed, 252 insertions, 61 deletions
diff --git a/app/assets/javascripts/releases/components/asset_links_form.vue b/app/assets/javascripts/releases/components/asset_links_form.vue index 0698ca5e31f..d0d1485d8e7 100644 --- a/app/assets/javascripts/releases/components/asset_links_form.vue +++ b/app/assets/javascripts/releases/components/asset_links_form.vue @@ -8,12 +8,25 @@ import { GlIcon, GlTooltipDirective, GlFormInput, + GlFormSelect, } from '@gitlab/ui'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { DEFAULT_ASSET_LINK_TYPE, ASSET_LINK_TYPE } from '../constants'; +import { s__ } from '~/locale'; export default { name: 'AssetLinksForm', - components: { GlSprintf, GlLink, GlFormGroup, GlButton, GlIcon, GlFormInput }, + components: { + GlSprintf, + GlLink, + GlFormGroup, + GlButton, + GlIcon, + GlFormInput, + GlFormSelect, + }, directives: { GlTooltip: GlTooltipDirective }, + mixins: [glFeatureFlagsMixin()], computed: { ...mapState('detail', ['release', 'releaseAssetsDocsPath']), ...mapGetters('detail', ['validationErrors']), @@ -26,6 +39,7 @@ export default { 'addEmptyAssetLink', 'updateAssetLinkUrl', 'updateAssetLinkName', + 'updateAssetLinkType', 'removeAssetLink', ]), onAddAnotherClicked() { @@ -35,12 +49,6 @@ export default { this.removeAssetLink(linkId); this.ensureAtLeastOneLink(); }, - onUrlInput(linkIdToUpdate, newUrl) { - this.updateAssetLinkUrl({ linkIdToUpdate, newUrl }); - }, - onLinkTitleInput(linkIdToUpdate, newName) { - this.updateAssetLinkName({ linkIdToUpdate, newName }); - }, hasDuplicateUrl(link) { return Boolean(this.getLinkErrors(link).isDuplicate); }, @@ -73,6 +81,13 @@ export default { } }, }, + typeOptions: [ + { value: ASSET_LINK_TYPE.IMAGE, text: s__('ReleaseAssetLinkType|Image') }, + { value: ASSET_LINK_TYPE.PACKAGE, text: s__('ReleaseAssetLinkType|Package') }, + { value: ASSET_LINK_TYPE.RUNBOOK, text: s__('ReleaseAssetLinkType|Runbook') }, + { value: ASSET_LINK_TYPE.OTHER, text: s__('ReleaseAssetLinkType|Other') }, + ], + defaultTypeOptionValue: DEFAULT_ASSET_LINK_TYPE, }; </script> @@ -109,10 +124,10 @@ export default { <div v-for="(link, index) in release.assets.links" :key="link.id" - class="row flex-column flex-sm-row align-items-stretch align-items-sm-start" + class="row flex-column flex-sm-row align-items-stretch align-items-sm-start no-gutters" > <gl-form-group - class="url-field form-group col" + class="url-field form-group col pr-sm-2" :label="__('URL')" :label-for="`asset-url-${index}`" > @@ -123,7 +138,7 @@ export default { type="text" class="form-control" :state="isUrlValid(link)" - @change="onUrlInput(link.id, $event)" + @change="updateAssetLinkUrl({ linkIdToUpdate: link.id, newUrl: $event })" /> <template #invalid-feedback> <span v-if="hasEmptyUrl(link)" class="invalid-feedback d-inline"> @@ -149,7 +164,7 @@ export default { </gl-form-group> <gl-form-group - class="link-title-field col" + class="link-title-field col px-sm-2" :label="__('Link title')" :label-for="`asset-link-name-${index}`" > @@ -160,7 +175,7 @@ export default { type="text" class="form-control" :state="isNameValid(link)" - @change="onLinkTitleInput(link.id, $event)" + @change="updateAssetLinkName({ linkIdToUpdate: link.id, newName: $event })" /> <template #invalid-feedback> <span v-if="hasEmptyName(link)" class="invalid-feedback d-inline"> @@ -169,16 +184,34 @@ export default { </template> </gl-form-group> - <div class="mb-5 mb-sm-3 mt-sm-4 col col-sm-auto"> + <gl-form-group + v-if="glFeatures.releaseAssetLinkType" + class="link-type-field col-auto px-sm-2" + :label="__('Type')" + :label-for="`asset-type-${index}`" + > + <gl-form-select + :id="`asset-type-${index}`" + ref="typeSelect" + :value="link.linkType || $options.defaultTypeOptionValue" + class="form-control pr-4" + :options="$options.typeOptions" + @change="updateAssetLinkType({ linkIdToUpdate: link.id, newType: $event })" + /> + </gl-form-group> + + <div class="mb-5 mb-sm-3 mt-sm-4 col col-sm-auto pl-sm-2"> <gl-button v-gl-tooltip - class="remove-button w-100" + class="remove-button w-100 form-control" :aria-label="__('Remove asset link')" :title="__('Remove asset link')" @click="onRemoveClicked(link.id)" > - <gl-icon class="mr-1 mr-sm-0 mb-1" :size="16" name="remove" /> - <span class="d-inline d-sm-none">{{ __('Remove asset link') }}</span> + <div class="d-flex"> + <gl-icon class="mr-1 mr-sm-0" :size="16" name="remove" /> + <span class="d-inline d-sm-none">{{ __('Remove asset link') }}</span> + </div> </gl-button> </div> </div> diff --git a/app/assets/javascripts/releases/components/evidence_block.vue b/app/assets/javascripts/releases/components/evidence_block.vue index acae6fda533..2cc15777343 100644 --- a/app/assets/javascripts/releases/components/evidence_block.vue +++ b/app/assets/javascripts/releases/components/evidence_block.vue @@ -71,7 +71,7 @@ export default { :download="evidenceTitle(index)" :href="evidenceUrl(index)" > - <gl-icon name="review-list" class="align-middle append-right-8" /> + <gl-icon name="review-list" class="align-middle gl-mr-3" /> <span>{{ evidenceTitle(index) }}</span> </gl-link> @@ -96,7 +96,7 @@ export default { <gl-icon v-gl-tooltip name="clock" - class="align-middle append-right-8" + class="align-middle gl-mr-3" :title="collectedAt(index)" /> <span>{{ timeSummary(index) }}</span> diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue index 58045b57d80..adb0e69b786 100644 --- a/app/assets/javascripts/releases/components/release_block.vue +++ b/app/assets/javascripts/releases/components/release_block.vue @@ -109,7 +109,7 @@ export default { <evidence-block v-if="hasEvidence && shouldShowEvidence" :release="release" /> <div ref="gfm-content" class="card-text prepend-top-default"> - <div v-html="release.descriptionHtml"></div> + <div class="md" v-html="release.descriptionHtml"></div> </div> </div> diff --git a/app/assets/javascripts/releases/components/release_block_assets.vue b/app/assets/javascripts/releases/components/release_block_assets.vue index f4b92416e47..e07646e9a9f 100644 --- a/app/assets/javascripts/releases/components/release_block_assets.vue +++ b/app/assets/javascripts/releases/components/release_block_assets.vue @@ -1,65 +1,190 @@ <script> -import { GlTooltipDirective, GlLink } from '@gitlab/ui'; +import { GlTooltipDirective, GlLink, GlButton, GlCollapse, GlIcon, GlBadge } from '@gitlab/ui'; import Icon from '~/vue_shared/components/icon.vue'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { ASSET_LINK_TYPE } from '../constants'; +import { __, s__, sprintf } from '~/locale'; +import { difference } from 'lodash'; export default { name: 'ReleaseBlockAssets', components: { GlLink, + GlButton, + GlCollapse, + GlIcon, Icon, + GlBadge, }, directives: { GlTooltip: GlTooltipDirective, }, + mixins: [glFeatureFlagsMixin()], props: { assets: { type: Object, required: true, }, }, + data() { + return { + isAssetsExpanded: true, + }; + }, computed: { hasAssets() { return Boolean(this.assets.count); }, + imageLinks() { + return this.linksForType(ASSET_LINK_TYPE.IMAGE); + }, + packageLinks() { + return this.linksForType(ASSET_LINK_TYPE.PACKAGE); + }, + runbookLinks() { + return this.linksForType(ASSET_LINK_TYPE.RUNBOOK); + }, + otherLinks() { + return difference(this.assets.links, [ + ...this.imageLinks, + ...this.packageLinks, + ...this.runbookLinks, + ]); + }, + sections() { + return [ + { + links: this.assets.sources.map(s => ({ + url: s.url, + name: sprintf(__('Source code (%{fileExtension})'), { fileExtension: s.format }), + })), + iconName: 'doc-code', + }, + { + title: s__('ReleaseAssetLinkType|Images'), + links: this.imageLinks, + iconName: 'container-image', + }, + { + title: s__('ReleaseAssetLinkType|Packages'), + links: this.packageLinks, + iconName: 'package', + }, + { + title: s__('ReleaseAssetLinkType|Runbooks'), + links: this.runbookLinks, + iconName: 'book', + }, + { + title: s__('ReleaseAssetLinkType|Other'), + links: this.otherLinks, + iconName: 'link', + }, + ].filter(section => section.links.length > 0); + }, + }, + methods: { + toggleAssetsExpansion() { + this.isAssetsExpanded = !this.isAssetsExpanded; + }, + linksForType(type) { + return this.assets.links.filter(l => l.linkType === type); + }, }, + externalLinkTooltipText: __('This link points to external content'), }; </script> <template> <div class="card-text prepend-top-default"> - <b> - {{ __('Assets') }} - <span class="js-assets-count badge badge-pill">{{ assets.count }}</span> - </b> - - <ul v-if="assets.links.length" class="pl-0 mb-0 prepend-top-8 list-unstyled js-assets-list"> - <li v-for="link in assets.links" :key="link.name" class="append-bottom-8"> - <gl-link v-gl-tooltip.bottom :title="__('Download asset')" :href="link.directAssetUrl"> - <icon name="package" class="align-middle append-right-4 align-text-bottom" /> - {{ link.name }} - <span v-if="link.external">{{ __('(external source)') }}</span> - </gl-link> - </li> - </ul> - - <div v-if="hasAssets" class="dropdown"> - <button - type="button" - class="btn btn-link" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false" + <template v-if="glFeatures.releaseAssetLinkType"> + <gl-button + data-testid="accordion-button" + variant="link" + class="gl-font-weight-bold" + @click="toggleAssetsExpansion" > - <icon name="doc-code" class="align-top append-right-4" /> - {{ __('Source code') }} - <icon name="chevron-down" /> - </button> + <gl-icon + name="chevron-right" + class="gl-transition-medium" + :class="{ 'gl-rotate-90': isAssetsExpanded }" + /> + {{ __('Assets') }} + <gl-badge size="sm" variant="neutral" class="gl-display-inline-block">{{ + assets.count + }}</gl-badge> + </gl-button> + <gl-collapse v-model="isAssetsExpanded"> + <div class="gl-pl-6 gl-pt-3 js-assets-list"> + <template v-for="(section, index) in sections"> + <h5 v-if="section.title" :key="`section-header-${index}`" class="gl-mb-2"> + {{ section.title }} + </h5> + <ul :key="`section-body-${index}`" class="list-unstyled gl-m-0"> + <li v-for="link in section.links" :key="link.url"> + <gl-link + :href="link.directAssetUrl || link.url" + class="gl-display-flex gl-align-items-center gl-line-height-24" + > + <gl-icon + :name="section.iconName" + class="gl-mr-2 gl-flex-shrink-0 gl-flex-grow-0" + /> + {{ link.name }} + <gl-icon + v-if="link.external" + v-gl-tooltip + name="external-link" + :aria-label="$options.externalLinkTooltipText" + :title="$options.externalLinkTooltipText" + data-testid="external-link-indicator" + class="gl-ml-2 gl-flex-shrink-0 gl-flex-grow-0 gl-text-gray-600" + /> + </gl-link> + </li> + </ul> + </template> + </div> + </gl-collapse> + </template> - <div class="js-sources-dropdown dropdown-menu"> - <li v-for="asset in assets.sources" :key="asset.url"> - <gl-link :href="asset.url">{{ __('Download') }} {{ asset.format }}</gl-link> + <template v-else> + <b> + {{ __('Assets') }} + <span class="js-assets-count badge badge-pill">{{ assets.count }}</span> + </b> + + <ul v-if="assets.links.length" class="pl-0 mb-0 gl-mt-3 list-unstyled js-assets-list"> + <li v-for="link in assets.links" :key="link.name" class="gl-mb-3"> + <gl-link v-gl-tooltip.bottom :title="__('Download asset')" :href="link.directAssetUrl"> + <icon name="package" class="align-middle append-right-4 align-text-bottom" /> + {{ link.name }} + <span v-if="link.external" data-testid="external-link-indicator">{{ + __('(external source)') + }}</span> + </gl-link> </li> + </ul> + + <div v-if="hasAssets" class="dropdown"> + <button + type="button" + class="btn btn-link" + data-toggle="dropdown" + aria-haspopup="true" + aria-expanded="false" + > + <icon name="doc-code" class="align-top append-right-4" /> + {{ __('Source code') }} + <icon name="chevron-down" /> + </button> + + <div class="js-sources-dropdown dropdown-menu"> + <li v-for="asset in assets.sources" :key="asset.url"> + <gl-link :href="asset.url">{{ __('Download') }} {{ asset.format }}</gl-link> + </li> + </div> </div> - </div> + </template> </div> </template> diff --git a/app/assets/javascripts/releases/components/release_block_author.vue b/app/assets/javascripts/releases/components/release_block_author.vue index 0432d45b2dc..94f2b1795f0 100644 --- a/app/assets/javascripts/releases/components/release_block_author.vue +++ b/app/assets/javascripts/releases/components/release_block_author.vue @@ -30,7 +30,7 @@ export default { <gl-sprintf :message="__('by %{user}')"> <template #user> <user-avatar-link - class="prepend-left-4" + class="gl-ml-2" :link-href="author.webUrl" :img-src="author.avatarUrl" :img-alt="userImageAltDescription" diff --git a/app/assets/javascripts/releases/components/release_block_metadata.vue b/app/assets/javascripts/releases/components/release_block_metadata.vue index 40133941011..a3377ce044a 100644 --- a/app/assets/javascripts/releases/components/release_block_metadata.vue +++ b/app/assets/javascripts/releases/components/release_block_metadata.vue @@ -57,7 +57,7 @@ export default { <template> <div class="card-subtitle d-flex flex-wrap text-secondary"> - <div class="append-right-8"> + <div class="gl-mr-3"> <icon name="commit" class="align-middle" /> <gl-link v-if="commitUrl" v-gl-tooltip.bottom :title="commit.title" :href="commitUrl"> {{ commit.shortId }} @@ -65,7 +65,7 @@ export default { <span v-else v-gl-tooltip.bottom :title="commit.title">{{ commit.shortId }}</span> </div> - <div class="append-right-8"> + <div class="gl-mr-3"> <icon name="tag" class="align-middle" /> <gl-link v-if="tagUrl" v-gl-tooltip.bottom :title="__('Tag')" :href="tagUrl"> {{ release.tagName }} diff --git a/app/assets/javascripts/releases/components/release_block_milestone_info.vue b/app/assets/javascripts/releases/components/release_block_milestone_info.vue index d9fbd2884b7..4f75e15a149 100644 --- a/app/assets/javascripts/releases/components/release_block_milestone_info.vue +++ b/app/assets/javascripts/releases/components/release_block_milestone_info.vue @@ -144,7 +144,7 @@ export default { <div class="d-flex flex-column align-items-start flex-shrink-0 mr-4 mb-3 js-issues-container"> <span class="mb-1"> {{ __('Issues') }} - <gl-badge pill variant="light" class="font-weight-bold">{{ totalIssuesCount }}</gl-badge> + <gl-badge variant="muted" size="sm">{{ totalIssuesCount }}</gl-badge> </span> <div class="d-flex"> <gl-link v-if="openIssuesPath" ref="openIssuesLink" :href="openIssuesPath"> diff --git a/app/assets/javascripts/releases/constants.js b/app/assets/javascripts/releases/constants.js index 1db93323a87..361cee70747 100644 --- a/app/assets/javascripts/releases/constants.js +++ b/app/assets/javascripts/releases/constants.js @@ -1,3 +1,12 @@ export const MAX_MILESTONES_TO_DISPLAY = 5; export const BACK_URL_PARAM = 'back_url'; + +export const ASSET_LINK_TYPE = Object.freeze({ + OTHER: 'other', + IMAGE: 'image', + PACKAGE: 'package', + RUNBOOK: 'runbook', +}); + +export const DEFAULT_ASSET_LINK_TYPE = ASSET_LINK_TYPE.OTHER; diff --git a/app/assets/javascripts/releases/stores/modules/detail/actions.js b/app/assets/javascripts/releases/stores/modules/detail/actions.js index 3bc427dfa16..2026eeba880 100644 --- a/app/assets/javascripts/releases/stores/modules/detail/actions.js +++ b/app/assets/javascripts/releases/stores/modules/detail/actions.js @@ -3,7 +3,10 @@ import api from '~/api'; import createFlash from '~/flash'; import { s__ } from '~/locale'; import { redirectTo } from '~/lib/utils/url_utility'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { + convertObjectPropsToCamelCase, + convertObjectPropsToSnakeCase, +} from '~/lib/utils/common_utils'; export const requestRelease = ({ commit }) => commit(types.REQUEST_RELEASE); export const receiveReleaseSuccess = ({ commit }, data) => @@ -54,13 +57,18 @@ export const updateRelease = ({ dispatch, state, getters }) => { const { release } = state; const milestones = release.milestones ? release.milestones.map(milestone => milestone.title) : []; + const updatedRelease = convertObjectPropsToSnakeCase( + { + name: release.name, + description: release.description, + milestones, + }, + { deep: true }, + ); + return ( api - .updateRelease(state.projectId, state.tagName, { - name: release.name, - description: release.description, - milestones, - }) + .updateRelease(state.projectId, state.tagName, updatedRelease) /** * Currently, we delete all existing links and then @@ -91,7 +99,11 @@ export const updateRelease = ({ dispatch, state, getters }) => { // Create a new link for each link in the form return Promise.all( getters.releaseLinksToCreate.map(l => - api.createReleaseLink(state.projectId, release.tagName, l), + api.createReleaseLink( + state.projectId, + release.tagName, + convertObjectPropsToSnakeCase(l, { deep: true }), + ), ), ); }) @@ -118,6 +130,10 @@ export const updateAssetLinkName = ({ commit }, { linkIdToUpdate, newName }) => commit(types.UPDATE_ASSET_LINK_NAME, { linkIdToUpdate, newName }); }; +export const updateAssetLinkType = ({ commit }, { linkIdToUpdate, newType }) => { + commit(types.UPDATE_ASSET_LINK_TYPE, { linkIdToUpdate, newType }); +}; + export const removeAssetLink = ({ commit }, linkIdToRemove) => { commit(types.REMOVE_ASSET_LINK, linkIdToRemove); }; diff --git a/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js b/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js index 1d6356990ce..7b694120126 100644 --- a/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js +++ b/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js @@ -13,4 +13,5 @@ export const RECEIVE_UPDATE_RELEASE_ERROR = 'RECEIVE_UPDATE_RELEASE_ERROR'; export const ADD_EMPTY_ASSET_LINK = 'ADD_EMPTY_ASSET_LINK'; export const UPDATE_ASSET_LINK_URL = 'UPDATE_ASSET_LINK_URL'; export const UPDATE_ASSET_LINK_NAME = 'UPDATE_ASSET_LINK_NAME'; +export const UPDATE_ASSET_LINK_TYPE = 'UPDATE_ASSET_LINK_TYPE'; export const REMOVE_ASSET_LINK = 'REMOVE_ASSET_LINK'; diff --git a/app/assets/javascripts/releases/stores/modules/detail/mutations.js b/app/assets/javascripts/releases/stores/modules/detail/mutations.js index 5c29b402cba..ca544151323 100644 --- a/app/assets/javascripts/releases/stores/modules/detail/mutations.js +++ b/app/assets/javascripts/releases/stores/modules/detail/mutations.js @@ -1,5 +1,6 @@ import * as types from './mutation_types'; import { uniqueId, cloneDeep } from 'lodash'; +import { DEFAULT_ASSET_LINK_TYPE } from '../../../constants'; const findReleaseLink = (release, id) => { return release.assets.links.find(l => l.id === id); @@ -49,6 +50,7 @@ export default { id: uniqueId('new-link-'), url: '', name: '', + linkType: DEFAULT_ASSET_LINK_TYPE, }); }, @@ -62,6 +64,11 @@ export default { linkToUpdate.name = newName; }, + [types.UPDATE_ASSET_LINK_TYPE](state, { linkIdToUpdate, newType }) { + const linkToUpdate = findReleaseLink(state.release, linkIdToUpdate); + linkToUpdate.linkType = newType; + }, + [types.REMOVE_ASSET_LINK](state, linkIdToRemove) { state.release.assets.links = state.release.assets.links.filter(l => l.id !== linkIdToRemove); }, |