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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-08-04 03:09:26 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-04 03:09:26 +0300
commit65b1882ddddca5f86397f60dfbd28deb94ec7249 (patch)
treef6333826cf39f6c5064c22b6b17b938bb41f1523 /app/assets/javascripts/badges
parent01fa7c10d9c301ca09e40ce2b2e70514cd3f1053 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/badges')
-rw-r--r--app/assets/javascripts/badges/components/badge_form.vue66
-rw-r--r--app/assets/javascripts/badges/components/badge_list.vue168
-rw-r--r--app/assets/javascripts/badges/components/badge_list_row.vue81
-rw-r--r--app/assets/javascripts/badges/components/badge_settings.vue89
-rw-r--r--app/assets/javascripts/badges/constants.js2
5 files changed, 270 insertions, 136 deletions
diff --git a/app/assets/javascripts/badges/components/badge_form.vue b/app/assets/javascripts/badges/components/badge_form.vue
index 1a80030c7e6..23873922618 100644
--- a/app/assets/javascripts/badges/components/badge_form.vue
+++ b/app/assets/javascripts/badges/components/badge_form.vue
@@ -28,6 +28,11 @@ export default {
type: Boolean,
required: true,
},
+ inModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -119,16 +124,28 @@ export default {
exampleUrl,
});
},
+ cancelButtonType() {
+ return this.isEditing ? 'button' : 'reset';
+ },
+ saveText() {
+ return this.isEditing ? s__('Badges|Save changes') : s__('Badges|Add badge');
+ },
+ },
+ mounted() {
+ // declared here to make it cancel-able
+ this.debouncedPreview = debounce(function search() {
+ this.renderBadge();
+ }, badgePreviewDelayInMilliseconds);
},
methods: {
...mapActions(['addBadge', 'renderBadge', 'saveBadge', 'stopEditing', 'updateBadgeInForm']),
- debouncedPreview: debounce(function preview() {
- this.renderBadge();
- }, badgePreviewDelayInMilliseconds),
- onCancel() {
- this.stopEditing();
+ updatePreview() {
+ this.debouncedPreview();
},
onSubmit() {
+ this.debouncedPreview.cancel();
+ this.renderBadge();
+
const form = this.$el;
if (!form.checkValidity()) {
this.wasValidated = true;
@@ -161,6 +178,7 @@ export default {
variant: VARIANT_INFO,
});
this.wasValidated = false;
+ this.$emit('close-add-form');
})
.catch((error) => {
createAlert({
@@ -171,6 +189,17 @@ export default {
throw error;
});
},
+ closeForm() {
+ this.$refs.form.reset();
+ this.$emit('close-add-form');
+ },
+ handleCancel() {
+ if (this.isEditing) {
+ this.stopEditing();
+ } else {
+ this.closeForm();
+ }
+ },
},
safeHtmlConfig: { ALLOW_TAGS: ['a', 'code'] },
};
@@ -178,6 +207,7 @@ export default {
<template>
<form
+ ref="form"
:class="{ 'was-validated': wasValidated }"
class="gl-mt-3 gl-mb-3 needs-validation"
novalidate
@@ -197,7 +227,7 @@ export default {
type="URL"
class="form-control gl-form-input"
required
- @input="debouncedPreview"
+ @input="updatePreview"
/>
<div class="invalid-feedback">{{ s__('Badges|Enter a valid URL') }}</div>
<span class="form-text text-muted">{{ badgeLinkUrlExample }}</span>
@@ -213,7 +243,7 @@ export default {
type="URL"
class="form-control gl-form-input"
required
- @input="debouncedPreview"
+ @input="updatePreview"
/>
<div class="invalid-feedback">{{ s__('Badges|Enter a valid URL') }}</div>
<span class="form-text text-muted">{{ badgeImageUrlExample }}</span>
@@ -235,29 +265,23 @@ export default {
</p>
</div>
- <div v-if="isEditing" class="row-content-block">
- <gl-button class="btn-cancel gl-mr-4" data-testid="cancelEditing" @click="onCancel">
- {{ __('Cancel') }}
- </gl-button>
+ <div v-if="!inModal" class="form-group" data-testid="action-buttons">
<gl-button
:loading="isSaving"
type="submit"
variant="confirm"
category="primary"
- data-testid="saveEditing"
+ data-qa-selector="add_badge_button"
+ class="gl-mr-3"
>
- {{ s__('Badges|Save changes') }}
+ {{ saveText }}
</gl-button>
- </div>
- <div v-else class="form-group">
<gl-button
- :loading="isSaving"
- type="submit"
- variant="confirm"
- category="primary"
- data-qa-selector="add_badge_button"
+ :type="cancelButtonType"
+ data-qa-selector="cancel_badge_button"
+ @click="handleCancel"
>
- {{ s__('Badges|Add badge') }}
+ {{ __('Cancel') }}
</gl-button>
</div>
</form>
diff --git a/app/assets/javascripts/badges/components/badge_list.vue b/app/assets/javascripts/badges/components/badge_list.vue
index 76625fe9a60..dbb692a389e 100644
--- a/app/assets/javascripts/badges/components/badge_list.vue
+++ b/app/assets/javascripts/badges/components/badge_list.vue
@@ -1,15 +1,42 @@
<script>
-import { GlLoadingIcon, GlBadge } from '@gitlab/ui';
-import { mapState } from 'vuex';
-import { GROUP_BADGE } from '../constants';
-import BadgeListRow from './badge_list_row.vue';
+import {
+ GlBadge,
+ GlLoadingIcon,
+ GlTable,
+ GlPagination,
+ GlButton,
+ GlModalDirective,
+} from '@gitlab/ui';
+import { mapActions, mapState } from 'vuex';
+import { __, s__ } from '~/locale';
+import { GROUP_BADGE, PROJECT_BADGE, INITIAL_PAGE, PAGE_SIZE } from '../constants';
+import Badge from './badge.vue';
export default {
+ PAGE_SIZE,
+ INITIAL_PAGE,
name: 'BadgeList',
components: {
- BadgeListRow,
- GlLoadingIcon,
+ Badge,
GlBadge,
+ GlLoadingIcon,
+ GlTable,
+ GlPagination,
+ GlButton,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ i18n: {
+ emptyGroupMessage: s__('Badges|This group has no badges, start by creating a new one above.'),
+ emptyProjectMessage: s__(
+ 'Badges|This project has no badges, start by creating a new one above.',
+ ),
+ },
+ data() {
+ return {
+ currentPage: INITIAL_PAGE,
+ };
},
computed: {
...mapState(['badges', 'isLoading', 'kind']),
@@ -19,28 +46,123 @@ export default {
isGroupBadge() {
return this.kind === GROUP_BADGE;
},
+ showPagination() {
+ return this.badges.length > PAGE_SIZE;
+ },
+ emptyMessage() {
+ return this.isGroupBadge
+ ? this.$options.i18n.emptyGroupMessage
+ : this.$options.i18n.emptyProjectMessage;
+ },
+ fields() {
+ return [
+ {
+ key: 'name',
+ label: __('Name'),
+ tdClass: 'gl-vertical-align-middle!',
+ },
+ {
+ key: 'badge',
+ label: __('Badge'),
+ tdClass: 'gl-vertical-align-middle!',
+ },
+ {
+ key: 'url',
+ label: __('URL'),
+ tdClass: 'gl-vertical-align-middle!',
+ },
+ {
+ key: 'actions',
+ label: __('Actions'),
+ thClass: 'gl-text-right',
+ tdClass: 'gl-text-right',
+ },
+ ];
+ },
+ },
+ methods: {
+ ...mapActions(['editBadge', 'updateBadgeInModal']),
+ badgeKindText(item) {
+ if (item.kind === PROJECT_BADGE) {
+ return s__('Badges|Project Badge');
+ }
+
+ return s__('Badges|Group Badge');
+ },
+ canEditBadge(item) {
+ return item.kind === this.kind;
+ },
},
};
</script>
<template>
- <div class="card">
- <div class="card-header">
- {{ s__('Badges|Your badges') }}
- <gl-badge v-show="!isLoading" size="sm">{{ badges.length }}</gl-badge>
- </div>
- <gl-loading-icon v-show="isLoading" size="lg" class="card-body" />
- <div v-if="hasNoBadges" class="card-body">
- <span v-if="isGroupBadge">{{ s__('Badges|This group has no badges') }}</span>
- <span v-else>{{ s__('Badges|This project has no badges') }}</span>
- </div>
- <div v-else class="card-body" data-qa-selector="badge_list_content">
- <badge-list-row
- v-for="badge in badges"
- :key="badge.id"
- :badge="badge"
- data-qa-selector="badge_list_row"
- :data-qa-badge-name="badge.name"
+ <div>
+ <gl-loading-icon v-show="isLoading" size="md" />
+ <div data-qa-selector="badge_list_content">
+ <gl-table
+ :empty-text="emptyMessage"
+ :fields="fields"
+ :items="badges"
+ :per-page="$options.PAGE_SIZE"
+ :current-page="currentPage"
+ stacked="md"
+ show-empty
+ data-qa-selector="badge_list"
+ >
+ <template #cell(name)="{ item }">
+ <label class="label-bold str-truncated mb-0">{{ item.name }}</label>
+ <gl-badge size="sm">{{ badgeKindText(item) }}</gl-badge>
+ </template>
+
+ <template #cell(badge)="{ item }">
+ <badge :image-url="item.renderedImageUrl" :link-url="item.renderedLinkUrl" />
+ </template>
+
+ <template #cell(url)="{ item }">
+ {{ item.linkUrl }}
+ </template>
+
+ <template #cell(actions)="{ item }">
+ <div v-if="canEditBadge(item)" class="table-action-buttons" data-testid="badge-actions">
+ <gl-button
+ v-gl-modal.edit-badge-modal
+ :disabled="item.isDeleting"
+ class="gl-mr-3"
+ variant="default"
+ icon="pencil"
+ size="medium"
+ :aria-label="__('Edit')"
+ data-testid="edit-badge-button"
+ @click="editBadge(item)"
+ />
+ <gl-button
+ v-gl-modal.delete-badge-modal
+ :disabled="item.isDeleting"
+ category="secondary"
+ variant="danger"
+ icon="remove"
+ size="medium"
+ :aria-label="__('Delete')"
+ data-testid="delete-badge"
+ @click="updateBadgeInModal(item)"
+ />
+ <gl-loading-icon v-show="item.isDeleting" size="sm" :inline="true" />
+ </div>
+ </template>
+ </gl-table>
+
+ <gl-pagination
+ v-if="showPagination"
+ v-model="currentPage"
+ :per-page="$options.PAGE_SIZE"
+ :total-items="badges.length"
+ :prev-text="__('Prev')"
+ :next-text="__('Next')"
+ :label-next-page="__('Go to next page')"
+ :label-prev-page="__('Go to previous page')"
+ align="center"
+ class="gl-mt-5"
/>
</div>
</div>
diff --git a/app/assets/javascripts/badges/components/badge_list_row.vue b/app/assets/javascripts/badges/components/badge_list_row.vue
deleted file mode 100644
index 4c2b700c7ff..00000000000
--- a/app/assets/javascripts/badges/components/badge_list_row.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<script>
-import { GlLoadingIcon, GlButton, GlModalDirective, GlBadge } from '@gitlab/ui';
-import { mapActions, mapState } from 'vuex';
-import { s__ } from '~/locale';
-import { PROJECT_BADGE } from '../constants';
-import Badge from './badge.vue';
-
-export default {
- name: 'BadgeListRow',
- components: {
- Badge,
- GlLoadingIcon,
- GlButton,
- GlBadge,
- },
- directives: {
- GlModal: GlModalDirective,
- },
- props: {
- badge: {
- type: Object,
- required: true,
- },
- },
- computed: {
- ...mapState(['kind']),
- badgeKindText() {
- if (this.badge.kind === PROJECT_BADGE) {
- return s__('Badges|Project Badge');
- }
-
- return s__('Badges|Group Badge');
- },
- canEditBadge() {
- return this.badge.kind === this.kind;
- },
- },
- methods: {
- ...mapActions(['editBadge', 'updateBadgeInModal']),
- },
-};
-</script>
-
-<template>
- <div class="gl-responsive-table-row-layout gl-responsive-table-row">
- <badge
- :image-url="badge.renderedImageUrl"
- :link-url="badge.renderedLinkUrl"
- class="table-section section-30"
- />
- <div class="table-section section-30">
- <label class="label-bold str-truncated mb-0">{{ badge.name }}</label>
- <gl-badge size="sm">{{ badgeKindText }}</gl-badge>
- </div>
- <span class="table-section section-30 str-truncated">{{ badge.linkUrl }}</span>
- <div class="table-section section-10 table-button-footer">
- <div v-if="canEditBadge" class="table-action-buttons">
- <gl-button
- :disabled="badge.isDeleting"
- class="gl-mr-3"
- variant="default"
- icon="pencil"
- size="medium"
- :aria-label="__('Edit')"
- @click="editBadge(badge)"
- />
- <gl-button
- v-gl-modal.delete-badge-modal
- :disabled="badge.isDeleting"
- variant="danger"
- icon="remove"
- size="medium"
- :aria-label="__('Delete')"
- data-testid="delete-badge"
- @click="updateBadgeInModal(badge)"
- />
- <gl-loading-icon v-show="badge.isDeleting" size="sm" :inline="true" />
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/badges/components/badge_settings.vue b/app/assets/javascripts/badges/components/badge_settings.vue
index 09f997d73aa..6fe772e717c 100644
--- a/app/assets/javascripts/badges/components/badge_settings.vue
+++ b/app/assets/javascripts/badges/components/badge_settings.vue
@@ -1,5 +1,5 @@
<script>
-import { GlSprintf, GlModal } from '@gitlab/ui';
+import { GlButton, GlCard, GlModal, GlIcon, GlSprintf } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { createAlert, VARIANT_INFO } from '~/alert';
import { __, s__ } from '~/locale';
@@ -13,17 +13,34 @@ export default {
Badge,
BadgeForm,
BadgeList,
+ GlButton,
+ GlCard,
GlModal,
+ GlIcon,
GlSprintf,
},
i18n: {
+ title: s__('Badges|Your badges'),
+ addButton: s__('Badges|Add badge'),
+ addFormTitle: s__('Badges|Add new badge'),
deleteModalText: s__(
'Badges|You are going to delete this badge. Deleted badges %{strongStart}cannot%{strongEnd} be restored.',
),
},
+ data() {
+ return {
+ addFormVisible: false,
+ };
+ },
computed: {
- ...mapState(['badgeInModal', 'isEditing']),
- primaryProps() {
+ ...mapState(['badges', 'badgeInModal', 'isEditing']),
+ saveProps() {
+ return {
+ text: __('Save changes'),
+ attributes: { category: 'primary', variant: 'confirm' },
+ };
+ },
+ deleteProps() {
return {
text: __('Delete badge'),
attributes: { category: 'primary', variant: 'danger' },
@@ -37,7 +54,16 @@ export default {
},
methods: {
...mapActions(['deleteBadge']),
- onSubmitModal() {
+ showAddForm() {
+ this.addFormVisible = !this.addFormVisible;
+ },
+ closeAddForm() {
+ this.addFormVisible = false;
+ },
+ onSubmitEditModal() {
+ this.$refs.editForm.onSubmit();
+ },
+ onSubmitDeleteModal() {
this.deleteBadge(this.badgeInModal)
.then(() => {
createAlert({
@@ -58,12 +84,58 @@ export default {
<template>
<div class="badge-settings">
+ <gl-card
+ class="gl-new-card"
+ header-class="gl-new-card-header"
+ body-class="gl-new-card-body gl-overflow-hidden gl-px-0"
+ >
+ <template #header>
+ <div class="gl-new-card-title-wrapper">
+ <h3 class="gl-new-card-title">{{ $options.i18n.title }}</h3>
+ <span class="gl-new-card-count">
+ <gl-icon name="labels" class="gl-mr-2" />
+ {{ badges.length }}
+ </span>
+ </div>
+ <div class="gl-new-card-actions">
+ <gl-button
+ v-if="!addFormVisible"
+ size="small"
+ data-testid="show-badge-add-form"
+ @click="showAddForm"
+ >{{ $options.i18n.addButton }}</gl-button
+ >
+ </div>
+ </template>
+
+ <div v-if="addFormVisible" class="gl-new-card-add-form gl-m-5">
+ <h4 class="gl-mt-0">{{ $options.i18n.addFormTitle }}</h4>
+ <badge-form
+ :is-editing="false"
+ data-testid="add-new-badge"
+ @close-add-form="closeAddForm"
+ />
+ </div>
+
+ <badge-list />
+ </gl-card>
+
+ <gl-modal
+ modal-id="edit-badge-modal"
+ :title="s__('Badges|Edit badge')"
+ :action-primary="saveProps"
+ :action-cancel="cancelProps"
+ @primary="onSubmitEditModal"
+ >
+ <badge-form ref="editForm" :is-editing="true" :in-modal="true" data-testid="edit-badge" />
+ </gl-modal>
+
<gl-modal
modal-id="delete-badge-modal"
:title="s__('Badges|Delete badge?')"
- :action-primary="primaryProps"
+ :action-primary="deleteProps"
:action-cancel="cancelProps"
- @primary="onSubmitModal"
+ @primary="onSubmitDeleteModal"
>
<div class="well">
<badge
@@ -79,10 +151,5 @@ export default {
</gl-sprintf>
</p>
</gl-modal>
-
- <badge-form v-show="isEditing" :is-editing="true" data-testid="edit-badge" />
-
- <badge-form v-show="!isEditing" :is-editing="false" data-testid="add-new-badge" />
- <badge-list v-show="!isEditing" />
</div>
</template>
diff --git a/app/assets/javascripts/badges/constants.js b/app/assets/javascripts/badges/constants.js
index 709436abca6..56b45abbe6b 100644
--- a/app/assets/javascripts/badges/constants.js
+++ b/app/assets/javascripts/badges/constants.js
@@ -8,3 +8,5 @@ export const PLACEHOLDERS = [
'default_branch',
'commit_sha',
];
+export const INITIAL_PAGE = 1;
+export const PAGE_SIZE = 10;