News.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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 { useNewsModelStore } from "@/stores/models/news";
  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 { deleteById, hasPermission } = useNewsModelStore();
  109. const remove = async (_id: string) => {
  110. const res = await deleteById(_id);
  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('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. hasPermission(
  149. 'data.news.updateById',
  150. slotProps.item._id
  151. )
  152. "
  153. class="button is-primary icon-with-button material-icons"
  154. @click="
  155. openModal({
  156. modal: 'editNews',
  157. props: { newsId: slotProps.item._id }
  158. })
  159. "
  160. content="Edit News"
  161. v-tippy
  162. >
  163. edit
  164. </button>
  165. <quick-confirm
  166. v-if="
  167. hasPermission(
  168. 'data.news.deleteById',
  169. slotProps.item._id
  170. )
  171. "
  172. @confirm="remove(slotProps.item._id)"
  173. :disabled="slotProps.item.removed"
  174. >
  175. <button
  176. class="button is-danger icon-with-button material-icons"
  177. content="Remove News"
  178. v-tippy
  179. >
  180. delete_forever
  181. </button>
  182. </quick-confirm>
  183. </div>
  184. </template>
  185. <template #column-status="slotProps">
  186. <span :title="slotProps.item.status">{{
  187. slotProps.item.status
  188. }}</span>
  189. </template>
  190. <template #column-showToNewUsers="slotProps">
  191. <span :title="slotProps.item.showToNewUsers">{{
  192. slotProps.item.showToNewUsers
  193. }}</span>
  194. </template>
  195. <template #column-title="slotProps">
  196. <span :title="slotProps.item.title">{{
  197. slotProps.item.title
  198. }}</span>
  199. </template>
  200. <template #column-createdBy="slotProps">
  201. <user-link
  202. :user-id="slotProps.item.createdBy"
  203. :alt="slotProps.item.createdBy"
  204. />
  205. </template>
  206. <template #column-markdown="slotProps">
  207. <span :title="slotProps.item.markdown">{{
  208. slotProps.item.markdown
  209. }}</span>
  210. </template>
  211. </advanced-table>
  212. </div>
  213. </template>