Playlists.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <template>
  2. <div>
  3. <page-metadata title="Admin | Playlists" />
  4. <div class="admin-tab">
  5. <div class="button-row">
  6. <run-job-dropdown :jobs="jobs" />
  7. </div>
  8. <advanced-table
  9. :column-default="columnDefault"
  10. :columns="columns"
  11. :filters="filters"
  12. data-action="playlists.getData"
  13. name="admin-playlists"
  14. :events="events"
  15. >
  16. <template #column-options="slotProps">
  17. <div class="row-options">
  18. <button
  19. class="button is-primary icon-with-button material-icons"
  20. @click="edit(slotProps.item._id)"
  21. :disabled="slotProps.item.removed"
  22. content="Edit Playlist"
  23. v-tippy
  24. >
  25. edit
  26. </button>
  27. </div>
  28. </template>
  29. <template #column-displayName="slotProps">
  30. <span :title="slotProps.item.displayName">{{
  31. slotProps.item.displayName
  32. }}</span>
  33. </template>
  34. <template #column-type="slotProps">
  35. <span :title="slotProps.item.type">{{
  36. slotProps.item.type
  37. }}</span>
  38. </template>
  39. <template #column-privacy="slotProps">
  40. <span :title="slotProps.item.privacy">{{
  41. slotProps.item.privacy
  42. }}</span>
  43. </template>
  44. <template #column-songsCount="slotProps">
  45. <span :title="slotProps.item.songsCount">{{
  46. slotProps.item.songsCount
  47. }}</span>
  48. </template>
  49. <template #column-totalLength="slotProps">
  50. <span :title="formatTimeLong(slotProps.item.totalLength)">{{
  51. formatTimeLong(slotProps.item.totalLength)
  52. }}</span>
  53. </template>
  54. <template #column-createdBy="slotProps">
  55. <span v-if="slotProps.item.createdBy === 'Musare'"
  56. >Musare</span
  57. >
  58. <user-id-to-username
  59. v-else
  60. :user-id="slotProps.item.createdBy"
  61. :link="true"
  62. />
  63. </template>
  64. <template #column-createdAt="slotProps">
  65. <span :title="new Date(slotProps.item.createdAt)">{{
  66. getDateFormatted(slotProps.item.createdAt)
  67. }}</span>
  68. </template>
  69. <template #column-createdFor="slotProps">
  70. <span :title="slotProps.item.createdFor">{{
  71. slotProps.item.createdFor
  72. }}</span>
  73. </template>
  74. <template #column-_id="slotProps">
  75. <span :title="slotProps.item._id">{{
  76. slotProps.item._id
  77. }}</span>
  78. </template>
  79. </advanced-table>
  80. </div>
  81. <edit-playlist v-if="modals.editPlaylist" sector="admin" />
  82. <edit-song v-if="modals.editSong" song-type="songs" />
  83. <report v-if="modals.report" />
  84. </div>
  85. </template>
  86. <script>
  87. import { mapState, mapActions } from "vuex";
  88. import { defineAsyncComponent } from "vue";
  89. import AdvancedTable from "@/components/AdvancedTable.vue";
  90. import RunJobDropdown from "@/components/RunJobDropdown.vue";
  91. import utils from "../../../js/utils";
  92. export default {
  93. components: {
  94. EditPlaylist: defineAsyncComponent(() =>
  95. import("@/components/modals/EditPlaylist")
  96. ),
  97. Report: defineAsyncComponent(() =>
  98. import("@/components/modals/Report.vue")
  99. ),
  100. EditSong: defineAsyncComponent(() =>
  101. import("@/components/modals/EditSong")
  102. ),
  103. AdvancedTable,
  104. RunJobDropdown
  105. },
  106. data() {
  107. return {
  108. utils,
  109. columnDefault: {
  110. sortable: true,
  111. hidable: true,
  112. defaultVisibility: "shown",
  113. draggable: true,
  114. resizable: true,
  115. minWidth: 150,
  116. maxWidth: 600
  117. },
  118. columns: [
  119. {
  120. name: "options",
  121. displayName: "Options",
  122. properties: ["_id"],
  123. sortable: false,
  124. hidable: false,
  125. resizable: false,
  126. minWidth: 76,
  127. defaultWidth: 76
  128. },
  129. {
  130. name: "displayName",
  131. displayName: "Display Name",
  132. properties: ["displayName"],
  133. sortProperty: "displayName"
  134. },
  135. {
  136. name: "type",
  137. displayName: "Type",
  138. properties: ["type"],
  139. sortProperty: "type"
  140. },
  141. {
  142. name: "privacy",
  143. displayName: "Privacy",
  144. properties: ["privacy"],
  145. sortProperty: "privacy"
  146. },
  147. {
  148. name: "songsCount",
  149. displayName: "Songs #",
  150. properties: ["songsCount"],
  151. sortProperty: "songsCount",
  152. minWidth: 100,
  153. defaultWidth: 100
  154. },
  155. {
  156. name: "totalLength",
  157. displayName: "Total Length",
  158. properties: ["totalLength"],
  159. sortProperty: "totalLength",
  160. minWidth: 250,
  161. defaultWidth: 250
  162. },
  163. {
  164. name: "createdBy",
  165. displayName: "Created By",
  166. properties: ["createdBy"],
  167. sortProperty: "createdBy",
  168. defaultWidth: 150
  169. },
  170. {
  171. name: "createdAt",
  172. displayName: "Created At",
  173. properties: ["createdAt"],
  174. sortProperty: "createdAt",
  175. defaultWidth: 150
  176. },
  177. {
  178. name: "createdFor",
  179. displayName: "Created For",
  180. properties: ["createdFor"],
  181. sortProperty: "createdFor",
  182. minWidth: 230,
  183. defaultWidth: 230
  184. },
  185. {
  186. name: "_id",
  187. displayName: "Playlist ID",
  188. properties: ["_id"],
  189. sortProperty: "_id",
  190. minWidth: 230,
  191. defaultWidth: 230
  192. }
  193. ],
  194. filters: [
  195. {
  196. name: "_id",
  197. displayName: "Playlist ID",
  198. property: "_id",
  199. filterTypes: ["exact"],
  200. defaultFilterType: "exact"
  201. },
  202. {
  203. name: "displayName",
  204. displayName: "Display Name",
  205. property: "displayName",
  206. filterTypes: ["contains", "exact", "regex"],
  207. defaultFilterType: "contains"
  208. },
  209. {
  210. name: "type",
  211. displayName: "Type",
  212. property: "type",
  213. filterTypes: ["exact"],
  214. defaultFilterType: "exact",
  215. dropdown: [
  216. ["genre", "Genre"],
  217. ["station", "Station"],
  218. ["user", "User"],
  219. ["user-disliked", "User Disliked"],
  220. ["user-liked", "User Liked"]
  221. ]
  222. },
  223. {
  224. name: "privacy",
  225. displayName: "Privacy",
  226. property: "privacy",
  227. filterTypes: ["exact"],
  228. defaultFilterType: "exact",
  229. dropdown: [
  230. ["public", "Public"],
  231. ["private", "Private"]
  232. ]
  233. },
  234. {
  235. name: "songsCount",
  236. displayName: "Songs Count",
  237. property: "songsCount",
  238. filterTypes: [
  239. "numberLesserEqual",
  240. "numberLesser",
  241. "numberGreater",
  242. "numberGreaterEqual",
  243. "numberEquals"
  244. ],
  245. defaultFilterType: "numberLesser"
  246. },
  247. {
  248. name: "totalLength",
  249. displayName: "Total Length",
  250. property: "totalLength",
  251. filterTypes: [
  252. "numberLesserEqual",
  253. "numberLesser",
  254. "numberGreater",
  255. "numberGreaterEqual",
  256. "numberEquals"
  257. ],
  258. defaultFilterType: "numberLesser"
  259. },
  260. {
  261. name: "createdBy",
  262. displayName: "Created By",
  263. property: "createdBy",
  264. filterTypes: ["contains", "exact", "regex"],
  265. defaultFilterType: "contains"
  266. },
  267. {
  268. name: "createdAt",
  269. displayName: "Created At",
  270. property: "createdAt",
  271. filterTypes: ["datetimeBefore", "datetimeAfter"],
  272. defaultFilterType: "datetimeBefore"
  273. },
  274. {
  275. name: "createdFor",
  276. displayName: "Created For",
  277. property: "createdFor",
  278. filterTypes: ["contains", "exact", "regex"],
  279. defaultFilterType: "contains"
  280. }
  281. ],
  282. events: {
  283. adminRoom: "playlists",
  284. updated: {
  285. event: "admin.playlist.updated",
  286. id: "playlist._id",
  287. item: "playlist"
  288. },
  289. removed: {
  290. event: "admin.playlist.deleted",
  291. id: "playlistId"
  292. }
  293. },
  294. jobs: [
  295. {
  296. name: "Delete orphaned station playlists",
  297. socket: "playlists.deleteOrphanedStationPlaylists"
  298. },
  299. {
  300. name: "Delete orphaned genre playlists",
  301. socket: "playlists.deleteOrphanedGenrePlaylists"
  302. },
  303. {
  304. name: "Request orphaned playlist songs",
  305. socket: "playlists.requestOrphanedPlaylistSongs"
  306. },
  307. {
  308. name: "Clear and refill all station playlists",
  309. socket: "playlists.clearAndRefillAllStationPlaylists"
  310. },
  311. {
  312. name: "Clear and refill all genre playlists",
  313. socket: "playlists.clearAndRefillAllGenrePlaylists"
  314. },
  315. {
  316. name: "Create missing genre playlists",
  317. socket: "playlists.createMissingGenrePlaylists"
  318. }
  319. ]
  320. };
  321. },
  322. computed: {
  323. ...mapState("modalVisibility", {
  324. modals: state => state.modals
  325. })
  326. },
  327. methods: {
  328. edit(playlistId) {
  329. this.editPlaylist(playlistId);
  330. this.openModal("editPlaylist");
  331. },
  332. getDateFormatted(createdAt) {
  333. const date = new Date(createdAt);
  334. const year = date.getFullYear();
  335. const month = `${date.getMonth() + 1}`.padStart(2, 0);
  336. const day = `${date.getDate()}`.padStart(2, 0);
  337. const hour = `${date.getHours()}`.padStart(2, 0);
  338. const minute = `${date.getMinutes()}`.padStart(2, 0);
  339. return `${year}-${month}-${day} ${hour}:${minute}`;
  340. },
  341. formatTimeLong(length) {
  342. return this.utils.formatTimeLong(length);
  343. },
  344. ...mapActions("modalVisibility", ["openModal"]),
  345. ...mapActions("user/playlists", ["editPlaylist"])
  346. }
  347. };
  348. </script>