News.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <script setup lang="ts">
  2. import { defineAsyncComponent, ref } from "vue";
  3. import Toast from "toasters";
  4. import { useModalsStore } from "@/stores/modals";
  5. import { TableColumn, TableFilter } from "@/types/advancedTable";
  6. import { useModelStore } from "@/stores/model";
  7. const AdvancedTable = defineAsyncComponent(
  8. () => import("@/components/AdvancedTable.vue")
  9. );
  10. const QuickConfirm = defineAsyncComponent(
  11. () => import("@/components/QuickConfirm.vue")
  12. );
  13. const UserLink = defineAsyncComponent(
  14. () => import("@/components/UserLink.vue")
  15. );
  16. const columnDefault = ref<TableColumn>({
  17. sortable: true,
  18. hidable: true,
  19. defaultVisibility: "shown",
  20. draggable: true,
  21. resizable: true,
  22. minWidth: 150,
  23. maxWidth: 600
  24. });
  25. const columns = ref<TableColumn[]>([
  26. {
  27. name: "options",
  28. displayName: "Options",
  29. properties: ["_id"],
  30. sortable: false,
  31. hidable: false,
  32. resizable: false,
  33. minWidth: 85,
  34. defaultWidth: 85
  35. },
  36. {
  37. name: "status",
  38. displayName: "Status",
  39. properties: ["status"],
  40. sortProperty: "status",
  41. defaultWidth: 150
  42. },
  43. {
  44. name: "showToNewUsers",
  45. displayName: "Show to new users",
  46. properties: ["showToNewUsers"],
  47. sortProperty: "showToNewUsers",
  48. defaultWidth: 180
  49. },
  50. {
  51. name: "title",
  52. displayName: "Title",
  53. properties: ["title"],
  54. sortProperty: "title"
  55. },
  56. {
  57. name: "createdBy",
  58. displayName: "Created By",
  59. properties: ["createdBy"],
  60. sortProperty: "createdBy",
  61. defaultWidth: 150
  62. },
  63. {
  64. name: "markdown",
  65. displayName: "Markdown",
  66. properties: ["markdown"],
  67. sortProperty: "markdown"
  68. }
  69. ]);
  70. const filters = ref<TableFilter[]>([
  71. {
  72. name: "status",
  73. displayName: "Status",
  74. property: "status",
  75. filterTypes: ["contains", "exact", "regex"],
  76. defaultFilterType: "contains"
  77. },
  78. {
  79. name: "showToNewUsers",
  80. displayName: "Show to new users",
  81. property: "showToNewUsers",
  82. filterTypes: ["boolean"],
  83. defaultFilterType: "boolean"
  84. },
  85. {
  86. name: "title",
  87. displayName: "Title",
  88. property: "title",
  89. filterTypes: ["contains", "exact", "regex"],
  90. defaultFilterType: "contains"
  91. },
  92. {
  93. name: "createdBy",
  94. displayName: "Created By",
  95. property: "createdBy",
  96. filterTypes: ["contains", "exact", "regex"],
  97. defaultFilterType: "contains"
  98. },
  99. {
  100. name: "markdown",
  101. displayName: "Markdown",
  102. property: "markdown",
  103. filterTypes: ["contains", "exact", "regex"],
  104. defaultFilterType: "contains"
  105. }
  106. ]);
  107. const { openModal } = useModalsStore();
  108. const { hasPermission } = useModelStore();
  109. const remove = async item => {
  110. const res = await item.delete();
  111. new Toast(res.message);
  112. };
  113. </script>
  114. <template>
  115. <div class="admin-tab container">
  116. <page-metadata title="Admin | News" />
  117. <div class="card tab-info">
  118. <div class="info-row">
  119. <h1>News</h1>
  120. <p>Create and update news items</p>
  121. </div>
  122. <div class="button-row">
  123. <button
  124. v-if="hasPermission('news', 'data.news.create')"
  125. class="is-primary button"
  126. @click="
  127. openModal({
  128. modal: 'editNews',
  129. props: { createNews: true }
  130. })
  131. "
  132. >
  133. Create News Item
  134. </button>
  135. </div>
  136. </div>
  137. <advanced-table
  138. :column-default="columnDefault"
  139. :columns="columns"
  140. :filters="filters"
  141. model="news"
  142. :max-width="1200"
  143. >
  144. <template #column-options="slotProps">
  145. <div class="row-options">
  146. <button
  147. v-if="
  148. slotProps.item.hasPermission('data.news.updateById')
  149. "
  150. class="button is-primary icon-with-button material-icons"
  151. @click="
  152. openModal({
  153. modal: 'editNews',
  154. props: { newsId: slotProps.item._id }
  155. })
  156. "
  157. content="Edit News"
  158. v-tippy
  159. >
  160. edit
  161. </button>
  162. <quick-confirm
  163. v-if="
  164. slotProps.item.hasPermission('data.news.deleteById')
  165. "
  166. @confirm="remove(slotProps.item)"
  167. :disabled="slotProps.item.removed"
  168. >
  169. <button
  170. class="button is-danger icon-with-button material-icons"
  171. content="Remove News"
  172. v-tippy
  173. >
  174. delete_forever
  175. </button>
  176. </quick-confirm>
  177. </div>
  178. </template>
  179. <template #column-status="slotProps">
  180. <span :title="slotProps.item.status">{{
  181. slotProps.item.status
  182. }}</span>
  183. </template>
  184. <template #column-showToNewUsers="slotProps">
  185. <span :title="slotProps.item.showToNewUsers">{{
  186. slotProps.item.showToNewUsers
  187. }}</span>
  188. </template>
  189. <template #column-title="slotProps">
  190. <span :title="slotProps.item.title">{{
  191. slotProps.item.title
  192. }}</span>
  193. </template>
  194. <template #column-createdBy="slotProps">
  195. <user-link
  196. :user-id="slotProps.item.createdBy._id"
  197. :alt="slotProps.item.createdBy._id"
  198. />
  199. </template>
  200. <template #column-markdown="slotProps">
  201. <span :title="slotProps.item.markdown">{{
  202. slotProps.item.markdown
  203. }}</span>
  204. </template>
  205. </advanced-table>
  206. </div>
  207. </template>