BulkActions.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <template>
  2. <div>
  3. <modal title="Bulk Actions" class="bulk-actions-modal">
  4. <template #body>
  5. <label class="label">Method</label>
  6. <div class="control is-expanded select">
  7. <select v-model="method">
  8. <option value="add">Add</option>
  9. <option value="remove">Remove</option>
  10. <option value="replace">Replace</option>
  11. </select>
  12. </div>
  13. <label class="label">{{ type.name.slice(0, -1) }}</label>
  14. <div class="control is-grouped input-with-button">
  15. <input
  16. v-model="itemInput"
  17. class="input"
  18. type="text"
  19. :placeholder="`Enter ${type.name} to ${method}`"
  20. autocomplete="off"
  21. @keypress.enter="addItem()"
  22. />
  23. <p class="control">
  24. <button
  25. class="button is-primary material-icons"
  26. @click="addItem()"
  27. >
  28. add
  29. </button>
  30. </p>
  31. </div>
  32. <label class="label"
  33. >{{ type.name }} to be
  34. {{ method === "add" ? `added` : `${method}d` }}</label
  35. >
  36. <div v-if="items.length > 0">
  37. <div
  38. v-for="(item, index) in items"
  39. :key="`item-${item}`"
  40. class="tag"
  41. >
  42. {{ item }}
  43. <span
  44. class="material-icons remove-item"
  45. @click="removeItem(index)"
  46. content="Remove item"
  47. v-tippy
  48. >highlight_off</span
  49. >
  50. </div>
  51. </div>
  52. <p v-else>No {{ type.name }} specified</p>
  53. </template>
  54. <template #footer>
  55. <button
  56. class="button is-primary"
  57. :disabled="items.length === 0"
  58. @click="applyChanges()"
  59. >
  60. Apply Changes
  61. </button>
  62. </template>
  63. </modal>
  64. </div>
  65. </template>
  66. <script>
  67. import { mapGetters, mapActions } from "vuex";
  68. import Toast from "toasters";
  69. import Modal from "../Modal.vue";
  70. export default {
  71. components: { Modal },
  72. props: {
  73. type: {
  74. type: Object,
  75. default: () => {}
  76. }
  77. },
  78. data() {
  79. return {
  80. method: "add",
  81. items: [],
  82. itemInput: null
  83. };
  84. },
  85. computed: {
  86. ...mapGetters({
  87. socket: "websockets/getSocket"
  88. })
  89. },
  90. beforeUnmount() {
  91. this.itemInput = null;
  92. this.items = [];
  93. },
  94. methods: {
  95. addItem() {
  96. if (!this.itemInput) return;
  97. if (!this.items.includes(this.itemInput))
  98. this.items.push(this.itemInput);
  99. this.itemInput = null;
  100. },
  101. removeItem(index) {
  102. this.items.splice(index, 1);
  103. },
  104. applyChanges() {
  105. this.socket.dispatch(
  106. this.type.action,
  107. this.method,
  108. this.items,
  109. this.type.items,
  110. res => {
  111. new Toast(res.message);
  112. this.closeModal("bulkActions");
  113. }
  114. );
  115. },
  116. ...mapActions("modalVisibility", ["closeModal"])
  117. }
  118. };
  119. </script>
  120. <style lang="scss" scoped>
  121. .label {
  122. text-transform: capitalize;
  123. }
  124. .select.is-expanded select {
  125. width: 100%;
  126. }
  127. .tag {
  128. display: inline-flex;
  129. margin: 5px;
  130. padding: 5px 10px;
  131. font-size: 14px;
  132. font-weight: 600;
  133. border-radius: 5px;
  134. background-color: var(--primary-color);
  135. color: var(--white);
  136. transition: all 0.2s ease-in-out;
  137. &:hover,
  138. &:focus {
  139. filter: brightness(90%);
  140. transition: all 0.2s ease-in-out;
  141. }
  142. .remove-item {
  143. font-size: 16px;
  144. margin: auto 2px auto 5px;
  145. cursor: pointer;
  146. }
  147. }
  148. </style>