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>2022-10-18 21:09:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-18 21:09:22 +0300
commite4220eeccaf1d53444fdd9102a4061336f91784e (patch)
tree541d4f0b9fb1273c722973633051795308c46dee /app/assets/javascripts/admin
parentb556d0fab74a7ef460d868e508ea5ca72d0e5eed (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/admin')
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/base.vue93
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/messages_table.vue102
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/messages_table_row.vue16
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/index.js6
4 files changed, 193 insertions, 24 deletions
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/base.vue b/app/assets/javascripts/admin/broadcast_messages/components/base.vue
index bc395a83625..b7bafe46327 100644
--- a/app/assets/javascripts/admin/broadcast_messages/components/base.vue
+++ b/app/assets/javascripts/admin/broadcast_messages/components/base.vue
@@ -1,21 +1,112 @@
<script>
+import { GlPagination } from '@gitlab/ui';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { buildUrlWithCurrentLocation } from '~/lib/utils/common_utils';
+import { createAlert, VARIANT_DANGER } from '~/flash';
+import { s__ } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
import MessagesTable from './messages_table.vue';
+const PER_PAGE = 20;
+
export default {
name: 'BroadcastMessagesBase',
components: {
+ GlPagination,
MessagesTable,
},
+
props: {
+ page: {
+ type: Number,
+ required: true,
+ },
+ messagesCount: {
+ type: Number,
+ required: true,
+ },
messages: {
type: Array,
required: true,
},
},
+
+ i18n: {
+ deleteError: s__(
+ 'BroadcastMessages|There was an issue deleting this message, please try again later.',
+ ),
+ },
+
+ data() {
+ return {
+ currentPage: this.page,
+ totalMessages: this.messagesCount,
+ visibleMessages: this.messages.map((message) => ({
+ ...message,
+ disable_delete: false,
+ })),
+ };
+ },
+
+ computed: {
+ hasVisibleMessages() {
+ return this.visibleMessages.length > 0;
+ },
+ },
+
+ watch: {
+ totalMessages(newVal, oldVal) {
+ // Pagination controls disappear when there is only
+ // one page worth of messages. Since we're relying on static data,
+ // this could hide messages on the next page, or leave the user
+ // stranded on page 2 when deleting the last message.
+ // Force a page reload to avoid this edge case.
+ if (newVal === PER_PAGE && oldVal === PER_PAGE + 1) {
+ redirectTo(this.buildPageUrl(1));
+ }
+ },
+ },
+
+ methods: {
+ buildPageUrl(newPage) {
+ return buildUrlWithCurrentLocation(`?page=${newPage}`);
+ },
+
+ async deleteMessage(messageId) {
+ const index = this.visibleMessages.findIndex((m) => m.id === messageId);
+ if (!index === -1) return;
+
+ const message = this.visibleMessages[index];
+ this.$set(this.visibleMessages, index, { ...message, disable_delete: true });
+
+ try {
+ await axios.delete(message.delete_path);
+ } catch (e) {
+ this.$set(this.visibleMessages, index, { ...message, disable_delete: false });
+ createAlert({ message: this.$options.i18n.deleteError, variant: VARIANT_DANGER });
+ return;
+ }
+
+ // Remove the message from the table
+ this.visibleMessages = this.visibleMessages.filter((m) => m.id !== messageId);
+ this.totalMessages -= 1;
+ },
+ },
};
</script>
+
<template>
<div>
- <messages-table v-if="messages.length > 0" :messages="messages" />
+ <messages-table
+ v-if="hasVisibleMessages"
+ :messages="visibleMessages"
+ @delete-message="deleteMessage"
+ />
+ <gl-pagination
+ v-model="currentPage"
+ :total-items="totalMessages"
+ :link-gen="buildPageUrl"
+ align="center"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/messages_table.vue b/app/assets/javascripts/admin/broadcast_messages/components/messages_table.vue
index 7b531b850c6..1408312d3e4 100644
--- a/app/assets/javascripts/admin/broadcast_messages/components/messages_table.vue
+++ b/app/assets/javascripts/admin/broadcast_messages/components/messages_table.vue
@@ -1,10 +1,23 @@
<script>
-import MessagesTableRow from './messages_table_row.vue';
+import { GlButton, GlTableLite, GlSafeHtmlDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+
+const DEFAULT_TD_CLASSES = 'gl-vertical-align-middle!';
export default {
name: 'MessagesTable',
components: {
- MessagesTableRow,
+ GlButton,
+ GlTableLite,
+ },
+ directives: {
+ SafeHtml: GlSafeHtmlDirective,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ i18n: {
+ edit: __('Edit'),
+ delete: __('Delete'),
},
props: {
messages: {
@@ -12,10 +25,89 @@ export default {
required: true,
},
},
+ computed: {
+ fields() {
+ if (this.glFeatures.roleTargetedBroadcastMessages) return this.$options.allFields;
+ return this.$options.allFields.filter((f) => f.key !== 'target_roles');
+ },
+ },
+ allFields: [
+ {
+ key: 'status',
+ label: __('Status'),
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'preview',
+ label: __('Preview'),
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'starts_at',
+ label: __('Starts'),
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'ends_at',
+ label: __('Ends'),
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'target_roles',
+ label: __('Target roles'),
+ tdClass: DEFAULT_TD_CLASSES,
+ thAttr: { 'data-testid': 'target-roles-th' },
+ },
+ {
+ key: 'target_path',
+ label: __('Target Path'),
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'type',
+ label: __('Type'),
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'buttons',
+ label: '',
+ tdClass: `${DEFAULT_TD_CLASSES} gl-white-space-nowrap`,
+ },
+ ],
+ safeHtmlConfig: {
+ ADD_TAGS: ['use'],
+ },
};
</script>
<template>
- <div>
- <messages-table-row v-for="message in messages" :key="message.id" :message="message" />
- </div>
+ <gl-table-lite
+ :items="messages"
+ :fields="fields"
+ :tbody-tr-attr="{ 'data-testid': 'message-row' }"
+ stacked="md"
+ >
+ <template #cell(preview)="{ item: { preview } }">
+ <div v-safe-html:[$options.safeHtmlConfig]="preview"></div>
+ </template>
+
+ <template #cell(buttons)="{ item: { id, edit_path, disable_delete } }">
+ <gl-button
+ icon="pencil"
+ :aria-label="$options.i18n.edit"
+ :href="edit_path"
+ data-testid="edit-message"
+ />
+
+ <gl-button
+ class="gl-ml-3"
+ icon="remove"
+ variant="danger"
+ :aria-label="$options.i18n.delete"
+ rel="nofollow"
+ :disabled="disable_delete"
+ :data-testid="`delete-message-${id}`"
+ @click="$emit('delete-message', id)"
+ />
+ </template>
+ </gl-table-lite>
</template>
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/messages_table_row.vue b/app/assets/javascripts/admin/broadcast_messages/components/messages_table_row.vue
deleted file mode 100644
index bd45bcc4fc4..00000000000
--- a/app/assets/javascripts/admin/broadcast_messages/components/messages_table_row.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-<script>
-export default {
- name: 'MessagesTableRow',
- props: {
- message: {
- type: Object,
- required: true,
- },
- },
-};
-</script>
-<template>
- <div>
- {{ message.id }}
- </div>
-</template>
diff --git a/app/assets/javascripts/admin/broadcast_messages/index.js b/app/assets/javascripts/admin/broadcast_messages/index.js
index e71495804ee..81952d2033e 100644
--- a/app/assets/javascripts/admin/broadcast_messages/index.js
+++ b/app/assets/javascripts/admin/broadcast_messages/index.js
@@ -3,14 +3,16 @@ import BroadcastMessagesBase from './components/base.vue';
export default () => {
const el = document.querySelector('#js-broadcast-messages');
- const { messages } = el.dataset;
+ const { page, messagesCount, messages } = el.dataset;
return new Vue({
el,
- name: 'BroadcastMessagesBase',
+ name: 'BroadcastMessages',
render(createElement) {
return createElement(BroadcastMessagesBase, {
props: {
+ page: Number(page),
+ messagesCount: Number(messagesCount),
messages: JSON.parse(messages),
},
});