Stations.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. <script setup lang="ts">
  2. import { ref } from "vue";
  3. import { useStore } from "vuex";
  4. import Toast from "toasters";
  5. import AdvancedTable from "@/components/AdvancedTable.vue";
  6. import RunJobDropdown from "@/components/RunJobDropdown.vue";
  7. const store = useStore();
  8. const { socket } = store.state.websockets;
  9. const columnDefault = ref({
  10. sortable: true,
  11. hidable: true,
  12. defaultVisibility: "shown",
  13. draggable: true,
  14. resizable: true,
  15. minWidth: 150,
  16. maxWidth: 600
  17. });
  18. const columns = ref([
  19. {
  20. name: "options",
  21. displayName: "Options",
  22. properties: ["_id", "name"],
  23. sortable: false,
  24. hidable: false,
  25. resizable: false,
  26. minWidth: 129,
  27. defaultWidth: 129
  28. },
  29. {
  30. name: "_id",
  31. displayName: "Station ID",
  32. properties: ["_id"],
  33. sortProperty: "_id",
  34. minWidth: 230,
  35. defaultWidth: 230
  36. },
  37. {
  38. name: "name",
  39. displayName: "Name",
  40. properties: ["name"],
  41. sortProperty: "name"
  42. },
  43. {
  44. name: "displayName",
  45. displayName: "Display Name",
  46. properties: ["displayName"],
  47. sortProperty: "displayName"
  48. },
  49. {
  50. name: "description",
  51. displayName: "Description",
  52. properties: ["description"],
  53. sortProperty: "description",
  54. defaultVisibility: "hidden"
  55. },
  56. {
  57. name: "type",
  58. displayName: "Type",
  59. properties: ["type"],
  60. sortProperty: "type"
  61. },
  62. {
  63. name: "privacy",
  64. displayName: "Privacy",
  65. properties: ["privacy"],
  66. sortProperty: "privacy"
  67. },
  68. {
  69. name: "owner",
  70. displayName: "Owner",
  71. properties: ["owner", "type"],
  72. sortProperty: "owner",
  73. defaultWidth: 150
  74. },
  75. {
  76. name: "theme",
  77. displayName: "Theme",
  78. properties: ["theme"],
  79. sortProperty: "theme",
  80. defaultVisibility: "hidden"
  81. },
  82. {
  83. name: "requestsEnabled",
  84. displayName: "Requests Enabled",
  85. properties: ["requests.enabled"],
  86. sortProperty: "requests.enabled",
  87. minWidth: 180,
  88. defaultWidth: 180,
  89. defaultVisibility: "hidden"
  90. },
  91. {
  92. name: "requestsAccess",
  93. displayName: "Requests Access",
  94. properties: ["requests.access"],
  95. sortProperty: "requests.access",
  96. minWidth: 180,
  97. defaultWidth: 180,
  98. defaultVisibility: "hidden"
  99. },
  100. {
  101. name: "requestsLimit",
  102. displayName: "Requests Limit",
  103. properties: ["requests.limit"],
  104. sortProperty: "requests.limit",
  105. minWidth: 180,
  106. defaultWidth: 180,
  107. defaultVisibility: "hidden"
  108. },
  109. {
  110. name: "autofillEnabled",
  111. displayName: "Autofill Enabled",
  112. properties: ["autofill.enabled"],
  113. sortProperty: "autofill.enabled",
  114. minWidth: 180,
  115. defaultWidth: 180,
  116. defaultVisibility: "hidden"
  117. },
  118. {
  119. name: "autofillLimit",
  120. displayName: "Autofill Limit",
  121. properties: ["autofill.limit"],
  122. sortProperty: "autofill.limit",
  123. minWidth: 180,
  124. defaultWidth: 180,
  125. defaultVisibility: "hidden"
  126. },
  127. {
  128. name: "autofillMode",
  129. displayName: "Autofill Mode",
  130. properties: ["autofill.mode"],
  131. sortProperty: "autofill.mode",
  132. minWidth: 180,
  133. defaultWidth: 180,
  134. defaultVisibility: "hidden"
  135. }
  136. ]);
  137. const filters = ref([
  138. {
  139. name: "_id",
  140. displayName: "Station ID",
  141. property: "_id",
  142. filterTypes: ["exact"],
  143. defaultFilterType: "exact"
  144. },
  145. {
  146. name: "name",
  147. displayName: "Name",
  148. property: "name",
  149. filterTypes: ["contains", "exact", "regex"],
  150. defaultFilterType: "contains"
  151. },
  152. {
  153. name: "displayName",
  154. displayName: "Display Name",
  155. property: "displayName",
  156. filterTypes: ["contains", "exact", "regex"],
  157. defaultFilterType: "contains"
  158. },
  159. {
  160. name: "description",
  161. displayName: "Description",
  162. property: "description",
  163. filterTypes: ["contains", "exact", "regex"],
  164. defaultFilterType: "contains"
  165. },
  166. {
  167. name: "type",
  168. displayName: "Type",
  169. property: "type",
  170. filterTypes: ["exact"],
  171. defaultFilterType: "exact",
  172. dropdown: [
  173. ["official", "Official"],
  174. ["community", "Community"]
  175. ]
  176. },
  177. {
  178. name: "privacy",
  179. displayName: "Privacy",
  180. property: "privacy",
  181. filterTypes: ["exact"],
  182. defaultFilterType: "exact",
  183. dropdown: [
  184. ["public", "Public"],
  185. ["unlisted", "Unlisted"],
  186. ["private", "Private"]
  187. ]
  188. },
  189. {
  190. name: "owner",
  191. displayName: "Owner",
  192. property: "owner",
  193. filterTypes: ["contains", "exact", "regex"],
  194. defaultFilterType: "contains"
  195. },
  196. {
  197. name: "theme",
  198. displayName: "Theme",
  199. property: "theme",
  200. filterTypes: ["exact"],
  201. defaultFilterType: "exact",
  202. dropdown: [
  203. ["blue", "Blue"],
  204. ["purple", "Purple"],
  205. ["teal", "Teal"],
  206. ["orange", "Orange"],
  207. ["red", "Red"]
  208. ]
  209. },
  210. {
  211. name: "requestsEnabled",
  212. displayName: "Requests Enabled",
  213. property: "requests.enabled",
  214. filterTypes: ["boolean"],
  215. defaultFilterType: "boolean"
  216. },
  217. {
  218. name: "requestsAccess",
  219. displayName: "Requests Access",
  220. property: "requests.access",
  221. filterTypes: ["exact"],
  222. defaultFilterType: "exact",
  223. dropdown: [
  224. ["owner", "Owner"],
  225. ["user", "User"]
  226. ]
  227. },
  228. {
  229. name: "requestsLimit",
  230. displayName: "Requests Limit",
  231. property: "requests.limit",
  232. filterTypes: [
  233. "numberLesserEqual",
  234. "numberLesser",
  235. "numberGreater",
  236. "numberGreaterEqual",
  237. "numberEquals"
  238. ],
  239. defaultFilterType: "numberLesser"
  240. },
  241. {
  242. name: "autofillEnabled",
  243. displayName: "Autofill Enabled",
  244. property: "autofill.enabled",
  245. filterTypes: ["boolean"],
  246. defaultFilterType: "boolean"
  247. },
  248. {
  249. name: "autofillLimit",
  250. displayName: "Autofill Limit",
  251. property: "autofill.limit",
  252. filterTypes: [
  253. "numberLesserEqual",
  254. "numberLesser",
  255. "numberGreater",
  256. "numberGreaterEqual",
  257. "numberEquals"
  258. ],
  259. defaultFilterType: "numberLesser"
  260. },
  261. {
  262. name: "autofillMode",
  263. displayName: "Autofill Mode",
  264. property: "autofill.mode",
  265. filterTypes: ["exact"],
  266. defaultFilterType: "exact",
  267. dropdown: [
  268. ["random", "Random"],
  269. ["sequential", "Sequential"]
  270. ]
  271. }
  272. ]);
  273. const events = ref({
  274. adminRoom: "stations",
  275. updated: {
  276. event: "station.updated",
  277. id: "station._id",
  278. item: "station"
  279. },
  280. removed: {
  281. event: "admin.station.deleted",
  282. id: "stationId"
  283. }
  284. });
  285. const jobs = ref([
  286. {
  287. name: "Clear every station queue",
  288. socket: "stations.clearEveryStationQueue"
  289. }
  290. ]);
  291. const openModal = payload =>
  292. store.dispatch("modalVisibility/openModal", payload);
  293. const remove = stationId => {
  294. socket.dispatch(
  295. "stations.remove",
  296. stationId,
  297. res => new Toast(res.message)
  298. );
  299. };
  300. </script>
  301. <template>
  302. <div class="admin-tab">
  303. <page-metadata title="Admin | Stations" />
  304. <div class="card tab-info">
  305. <div class="info-row">
  306. <h1>Stations</h1>
  307. <p>Manage stations or create an official station</p>
  308. </div>
  309. <div class="button-row">
  310. <button
  311. class="button is-primary"
  312. @click="
  313. openModal({
  314. modal: 'createStation',
  315. data: { official: true }
  316. })
  317. "
  318. >
  319. Create Station
  320. </button>
  321. <run-job-dropdown :jobs="jobs" />
  322. </div>
  323. </div>
  324. <advanced-table
  325. :column-default="columnDefault"
  326. :columns="columns"
  327. :filters="filters"
  328. data-action="stations.getData"
  329. name="admin-stations"
  330. :events="events"
  331. >
  332. <template #column-options="slotProps">
  333. <div class="row-options">
  334. <button
  335. class="button is-primary icon-with-button material-icons"
  336. @click="
  337. openModal({
  338. modal: 'manageStation',
  339. data: {
  340. stationId: slotProps.item._id,
  341. sector: 'admin'
  342. }
  343. })
  344. "
  345. :disabled="slotProps.item.removed"
  346. content="Manage Station"
  347. v-tippy
  348. >
  349. settings
  350. </button>
  351. <quick-confirm
  352. @confirm="remove(slotProps.item._id)"
  353. :disabled="slotProps.item.removed"
  354. >
  355. <button
  356. class="button is-danger icon-with-button material-icons"
  357. content="Remove Station"
  358. v-tippy
  359. >
  360. delete_forever
  361. </button>
  362. </quick-confirm>
  363. <router-link
  364. :to="{ path: `/${slotProps.item.name}` }"
  365. target="_blank"
  366. class="button is-primary icon-with-button material-icons"
  367. :disabled="slotProps.item.removed"
  368. content="View Station"
  369. v-tippy
  370. >
  371. radio
  372. </router-link>
  373. </div>
  374. </template>
  375. <template #column-_id="slotProps">
  376. <span :title="slotProps.item._id">{{
  377. slotProps.item._id
  378. }}</span>
  379. </template>
  380. <template #column-name="slotProps">
  381. <span :title="slotProps.item.name">{{
  382. slotProps.item.name
  383. }}</span>
  384. </template>
  385. <template #column-displayName="slotProps">
  386. <span :title="slotProps.item.displayName">{{
  387. slotProps.item.displayName
  388. }}</span>
  389. </template>
  390. <template #column-type="slotProps">
  391. <span :title="slotProps.item.type">{{
  392. slotProps.item.type
  393. }}</span>
  394. </template>
  395. <template #column-description="slotProps">
  396. <span :title="slotProps.item.description">{{
  397. slotProps.item.description
  398. }}</span>
  399. </template>
  400. <template #column-privacy="slotProps">
  401. <span :title="slotProps.item.privacy">{{
  402. slotProps.item.privacy
  403. }}</span>
  404. </template>
  405. <template #column-owner="slotProps">
  406. <span v-if="slotProps.item.type === 'official'">Musare</span>
  407. <user-link v-else :user-id="slotProps.item.owner" />
  408. </template>
  409. <template #column-theme="slotProps">
  410. <span :title="slotProps.item.theme">{{
  411. slotProps.item.theme
  412. }}</span>
  413. </template>
  414. <template #column-requestsEnabled="slotProps">
  415. <span :title="slotProps.item.requests.enabled">{{
  416. slotProps.item.requests.enabled
  417. }}</span>
  418. </template>
  419. <template #column-requestsAccess="slotProps">
  420. <span :title="slotProps.item.requests.access">{{
  421. slotProps.item.requests.access
  422. }}</span>
  423. </template>
  424. <template #column-requestsLimit="slotProps">
  425. <span :title="slotProps.item.requests.limit">{{
  426. slotProps.item.requests.limit
  427. }}</span>
  428. </template>
  429. <template #column-autofillEnabled="slotProps">
  430. <span :title="slotProps.item.autofill.enabled">{{
  431. slotProps.item.autofill.enabled
  432. }}</span>
  433. </template>
  434. <template #column-autofillLimit="slotProps">
  435. <span :title="slotProps.item.autofill.limit">{{
  436. slotProps.item.autofill.limit
  437. }}</span>
  438. </template>
  439. <template #column-autofillMode="slotProps">
  440. <span :title="slotProps.item.autofill.mode">{{
  441. slotProps.item.autofill.mode
  442. }}</span>
  443. </template>
  444. </advanced-table>
  445. </div>
  446. </template>