Playlists.vue 7.8 KB

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