Users.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. <template>
  2. <div>
  3. <page-metadata title="Admin | Users" />
  4. <div class="container">
  5. <h2>Data Requests</h2>
  6. <advanced-table
  7. :column-default="dataRequests.columnDefault"
  8. :columns="dataRequests.columns"
  9. :filters="dataRequests.filters"
  10. data-action="dataRequests.getData"
  11. name="admin-data-requests"
  12. max-width="1200"
  13. :query="false"
  14. :events="dataRequests.events"
  15. >
  16. <template #column-options="slotProps">
  17. <div class="row-options">
  18. <quick-confirm
  19. placement="right"
  20. @confirm="resolveDataRequest(slotProps.item._id)"
  21. :disabled="slotProps.item.removed"
  22. >
  23. <button
  24. class="
  25. button
  26. is-success
  27. icon-with-button
  28. material-icons
  29. "
  30. content="Resolve Data Request"
  31. v-tippy
  32. >
  33. done_all
  34. </button>
  35. </quick-confirm>
  36. </div>
  37. </template>
  38. <template #column-type="slotProps">
  39. <span
  40. :title="
  41. slotProps.item.type
  42. ? 'Remove all associated data'
  43. : slotProps.item.type
  44. "
  45. >{{
  46. slotProps.item.type
  47. ? "Remove all associated data"
  48. : slotProps.item.type
  49. }}</span
  50. >
  51. </template>
  52. <template #column-userId="slotProps">
  53. <span :title="slotProps.item.userId">{{
  54. slotProps.item.userId
  55. }}</span>
  56. </template>
  57. <template #column-_id="slotProps">
  58. <span :title="slotProps.item._id">{{
  59. slotProps.item._id
  60. }}</span>
  61. </template>
  62. </advanced-table>
  63. <h1 id="page-title">Users</h1>
  64. <advanced-table
  65. :column-default="users.columnDefault"
  66. :columns="users.columns"
  67. :filters="users.filters"
  68. data-action="users.getData"
  69. name="admin-users"
  70. max-width="1200"
  71. :events="users.events"
  72. >
  73. <template #column-options="slotProps">
  74. <div class="row-options">
  75. <button
  76. class="
  77. button
  78. is-primary
  79. icon-with-button
  80. material-icons
  81. "
  82. @click="edit(slotProps.item._id)"
  83. :disabled="slotProps.item.removed"
  84. content="Edit User"
  85. v-tippy
  86. >
  87. edit
  88. </button>
  89. </div>
  90. </template>
  91. <template #column-profilePicture="slotProps">
  92. <profile-picture
  93. :avatar="slotProps.item.avatar"
  94. :name="
  95. slotProps.item.name
  96. ? slotProps.item.name
  97. : slotProps.item.username
  98. "
  99. />
  100. </template>
  101. <template #column-name="slotProps">
  102. <span :title="slotProps.item.name">{{
  103. slotProps.item.name
  104. }}</span>
  105. </template>
  106. <template #column-username="slotProps">
  107. <span :title="slotProps.item.username">{{
  108. slotProps.item.username
  109. }}</span>
  110. </template>
  111. <template #column-_id="slotProps">
  112. <span :title="slotProps.item._id">{{
  113. slotProps.item._id
  114. }}</span>
  115. </template>
  116. <template #column-githubId="slotProps">
  117. <span
  118. v-if="slotProps.item.services.github"
  119. :title="slotProps.item.services.github.id"
  120. >{{ slotProps.item.services.github.id }}</span
  121. >
  122. </template>
  123. <template #column-hasPassword="slotProps">
  124. <span :title="slotProps.item.hasPassword">{{
  125. slotProps.item.hasPassword
  126. }}</span>
  127. </template>
  128. <template #column-role="slotProps">
  129. <span :title="slotProps.item.role">{{
  130. slotProps.item.role
  131. }}</span>
  132. </template>
  133. <template #column-emailAddress="slotProps">
  134. <span :title="slotProps.item.email.address">{{
  135. slotProps.item.email.address
  136. }}</span>
  137. </template>
  138. <template #column-emailVerified="slotProps">
  139. <span :title="slotProps.item.email.verified">{{
  140. slotProps.item.email.verified
  141. }}</span>
  142. </template>
  143. <template #column-songsRequested="slotProps">
  144. <span :title="slotProps.item.statistics.songsRequested">{{
  145. slotProps.item.statistics.songsRequested
  146. }}</span>
  147. </template>
  148. </advanced-table>
  149. </div>
  150. <edit-user
  151. v-if="modals.editUser"
  152. :user-id="editingUserId"
  153. sector="admin"
  154. />
  155. </div>
  156. </template>
  157. <script>
  158. import { mapState, mapActions, mapGetters } from "vuex";
  159. import { defineAsyncComponent } from "vue";
  160. import Toast from "toasters";
  161. import AdvancedTable from "@/components/AdvancedTable.vue";
  162. import ProfilePicture from "@/components/ProfilePicture.vue";
  163. import QuickConfirm from "@/components/QuickConfirm.vue";
  164. // import ws from "@/ws";
  165. export default {
  166. components: {
  167. EditUser: defineAsyncComponent(() =>
  168. import("@/components/modals/EditUser.vue")
  169. ),
  170. AdvancedTable,
  171. ProfilePicture,
  172. QuickConfirm
  173. },
  174. data() {
  175. return {
  176. editingUserId: "",
  177. dataRequests: {
  178. columnDefault: {
  179. sortable: true,
  180. hidable: true,
  181. defaultVisibility: "shown",
  182. draggable: true,
  183. resizable: true,
  184. minWidth: 150,
  185. maxWidth: 600
  186. },
  187. columns: [
  188. {
  189. name: "options",
  190. displayName: "Edit",
  191. properties: ["_id"],
  192. sortable: false,
  193. hidable: false,
  194. resizable: false,
  195. minWidth: 51,
  196. defaultWidth: 51
  197. },
  198. {
  199. name: "type",
  200. displayName: "Type",
  201. properties: ["type"],
  202. sortProperty: "type"
  203. },
  204. {
  205. name: "userId",
  206. displayName: "User ID",
  207. properties: ["userId"],
  208. sortProperty: "userId"
  209. },
  210. {
  211. name: "_id",
  212. displayName: "Request ID",
  213. properties: ["_id"],
  214. sortProperty: "_id"
  215. }
  216. ],
  217. filters: [
  218. {
  219. name: "_id",
  220. displayName: "Request ID",
  221. property: "_id",
  222. filterTypes: ["exact"],
  223. defaultFilterType: "exact"
  224. },
  225. {
  226. name: "userId",
  227. displayName: "User ID",
  228. property: "userId",
  229. filterTypes: ["contains", "exact", "regex"],
  230. defaultFilterType: "contains"
  231. },
  232. {
  233. name: "type",
  234. displayName: "Type",
  235. property: "type",
  236. filterTypes: ["contains", "exact", "regex"],
  237. defaultFilterType: "contains"
  238. }
  239. ],
  240. events: {
  241. adminRoom: "users",
  242. removed: {
  243. event: "admin.dataRequests.resolved",
  244. id: "dataRequestId"
  245. }
  246. }
  247. },
  248. users: {
  249. columnDefault: {
  250. sortable: true,
  251. hidable: true,
  252. defaultVisibility: "shown",
  253. draggable: true,
  254. resizable: true,
  255. minWidth: 150,
  256. maxWidth: 600
  257. },
  258. columns: [
  259. {
  260. name: "options",
  261. displayName: "Edit",
  262. properties: ["_id"],
  263. sortable: false,
  264. hidable: false,
  265. resizable: false,
  266. minWidth: 51,
  267. defaultWidth: 51
  268. },
  269. {
  270. name: "profilePicture",
  271. displayName: "Image",
  272. properties: ["avatar", "name", "username"],
  273. sortable: false,
  274. resizable: false,
  275. minWidth: 71,
  276. defaultWidth: 71
  277. },
  278. {
  279. name: "name",
  280. displayName: "Display Name",
  281. properties: ["name"],
  282. sortProperty: "name"
  283. },
  284. {
  285. name: "username",
  286. displayName: "Username",
  287. properties: ["username"],
  288. sortProperty: "username"
  289. },
  290. {
  291. name: "_id",
  292. displayName: "User ID",
  293. properties: ["_id"],
  294. sortProperty: "_id",
  295. minWidth: 230,
  296. defaultWidth: 230
  297. },
  298. {
  299. name: "githubId",
  300. displayName: "GitHub ID",
  301. properties: ["services.github.id"],
  302. sortProperty: "services.github.id",
  303. minWidth: 115,
  304. defaultWidth: 115
  305. },
  306. {
  307. name: "hasPassword",
  308. displayName: "Has Password",
  309. properties: ["hasPassword"],
  310. sortProperty: "hasPassword"
  311. },
  312. {
  313. name: "role",
  314. displayName: "Role",
  315. properties: ["role"],
  316. sortProperty: "role",
  317. minWidth: 90,
  318. defaultWidth: 90
  319. },
  320. {
  321. name: "emailAddress",
  322. displayName: "Email Address",
  323. properties: ["email.address"],
  324. sortProperty: "email.address",
  325. defaultVisibility: "hidden"
  326. },
  327. {
  328. name: "emailVerified",
  329. displayName: "Email Verified",
  330. properties: ["email.verified"],
  331. sortProperty: "email.verified",
  332. defaultVisibility: "hidden",
  333. minWidth: 140,
  334. defaultWidth: 140
  335. },
  336. {
  337. name: "songsRequested",
  338. displayName: "Songs Requested",
  339. properties: ["statistics.songsRequested"],
  340. sortProperty: "statistics.songsRequested",
  341. minWidth: 170,
  342. defaultWidth: 170
  343. }
  344. ],
  345. filters: [
  346. {
  347. name: "_id",
  348. displayName: "User ID",
  349. property: "_id",
  350. filterTypes: ["exact"],
  351. defaultFilterType: "exact"
  352. },
  353. {
  354. name: "name",
  355. displayName: "Display Name",
  356. property: "name",
  357. filterTypes: ["contains", "exact", "regex"],
  358. defaultFilterType: "contains"
  359. },
  360. {
  361. name: "username",
  362. displayName: "Username",
  363. property: "username",
  364. filterTypes: ["contains", "exact", "regex"],
  365. defaultFilterType: "contains"
  366. },
  367. {
  368. name: "githubId",
  369. displayName: "GitHub ID",
  370. property: "services.github.id",
  371. filterTypes: ["contains", "exact", "regex"],
  372. defaultFilterType: "contains"
  373. },
  374. {
  375. name: "hasPassword",
  376. displayName: "Has Password",
  377. property: "hasPassword",
  378. filterTypes: ["boolean"],
  379. defaultFilterType: "boolean"
  380. },
  381. {
  382. name: "role",
  383. displayName: "Role",
  384. property: "role",
  385. filterTypes: ["exact", "regex"],
  386. defaultFilterType: "exact",
  387. filterValues: ["admin", "default"]
  388. },
  389. {
  390. name: "emailAddress",
  391. displayName: "Email Address",
  392. property: "email.address",
  393. filterTypes: ["contains", "exact", "regex"],
  394. defaultFilterType: "contains"
  395. },
  396. {
  397. name: "emailVerified",
  398. displayName: "Email Verified",
  399. property: "email.verified",
  400. filterTypes: ["boolean"],
  401. defaultFilterType: "boolean"
  402. },
  403. {
  404. name: "songsRequested",
  405. displayName: "Songs Requested",
  406. property: "statistics.songsRequested",
  407. filterTypes: [
  408. "numberLesserEqual",
  409. "numberLesser",
  410. "numberGreater",
  411. "numberGreaterEqual",
  412. "numberEquals",
  413. "exact",
  414. "regex"
  415. ],
  416. defaultFilterType: "numberLesser"
  417. }
  418. ],
  419. events: {
  420. adminRoom: "users",
  421. removed: {
  422. event: "user.removed",
  423. id: "userId"
  424. }
  425. }
  426. }
  427. };
  428. },
  429. computed: {
  430. ...mapState("modalVisibility", {
  431. modals: state => state.modals
  432. }),
  433. ...mapGetters({
  434. socket: "websockets/getSocket"
  435. })
  436. },
  437. mounted() {
  438. if (this.$route.query.userId) this.edit(this.$route.query.userId);
  439. },
  440. methods: {
  441. edit(userId) {
  442. this.editingUserId = userId;
  443. this.openModal("editUser");
  444. },
  445. resolveDataRequest(id) {
  446. this.socket.dispatch("dataRequests.resolve", id, res => {
  447. if (res.status === "success") new Toast(res.message);
  448. });
  449. },
  450. ...mapActions("modalVisibility", ["openModal"])
  451. }
  452. };
  453. </script>
  454. <style lang="scss" scoped>
  455. #page-title {
  456. margin: 30px 0;
  457. }
  458. h2 {
  459. font-size: 30px;
  460. text-align: center;
  461. @media only screen and (min-width: 700px) {
  462. font-size: 35px;
  463. }
  464. }
  465. .profile-picture {
  466. max-width: 50px !important;
  467. max-height: 50px !important;
  468. }
  469. /deep/ .profile-picture.using-initials span {
  470. font-size: 20px; // 2/5th of .profile-picture height/width
  471. }
  472. </style>