PlaylistSrv.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Libraries
  2. import { Location } from 'history';
  3. import { pickBy } from 'lodash';
  4. // Utils
  5. import { locationUtil, urlUtil, rangeUtil } from '@grafana/data';
  6. import { getBackendSrv, locationService } from '@grafana/runtime';
  7. export const queryParamsToPreserve: { [key: string]: boolean } = {
  8. kiosk: true,
  9. autofitpanels: true,
  10. orgId: true,
  11. };
  12. export class PlaylistSrv {
  13. private nextTimeoutId: any;
  14. private declare dashboards: Array<{ url: string }>;
  15. private index = 0;
  16. private declare interval: number;
  17. private declare startUrl: string;
  18. private numberOfLoops = 0;
  19. private declare validPlaylistUrl: string;
  20. private locationListenerUnsub?: () => void;
  21. isPlaying = false;
  22. constructor() {
  23. this.locationUpdated = this.locationUpdated.bind(this);
  24. }
  25. next() {
  26. clearTimeout(this.nextTimeoutId);
  27. const playedAllDashboards = this.index > this.dashboards.length - 1;
  28. if (playedAllDashboards) {
  29. this.numberOfLoops++;
  30. // This does full reload of the playlist to keep memory in check due to existing leaks but at the same time
  31. // we do not want page to flicker after each full loop.
  32. if (this.numberOfLoops >= 3) {
  33. window.location.href = this.startUrl;
  34. return;
  35. }
  36. this.index = 0;
  37. }
  38. const dash = this.dashboards[this.index];
  39. const queryParams = locationService.getSearchObject();
  40. const filteredParams = pickBy(queryParams, (value: any, key: string) => queryParamsToPreserve[key]);
  41. const nextDashboardUrl = locationUtil.stripBaseFromUrl(dash.url);
  42. this.index++;
  43. this.validPlaylistUrl = nextDashboardUrl;
  44. this.nextTimeoutId = setTimeout(() => this.next(), this.interval);
  45. locationService.push(nextDashboardUrl + '?' + urlUtil.toUrlParams(filteredParams));
  46. }
  47. prev() {
  48. this.index = Math.max(this.index - 2, 0);
  49. this.next();
  50. }
  51. // Detect url changes not caused by playlist srv and stop playlist
  52. locationUpdated(location: Location) {
  53. if (location.pathname !== this.validPlaylistUrl) {
  54. this.stop();
  55. }
  56. }
  57. start(playlistUid: string) {
  58. this.stop();
  59. this.startUrl = window.location.href;
  60. this.index = 0;
  61. this.isPlaying = true;
  62. // setup location tracking
  63. this.locationListenerUnsub = locationService.getHistory().listen(this.locationUpdated);
  64. return getBackendSrv()
  65. .get(`/api/playlists/${playlistUid}`)
  66. .then((playlist: any) => {
  67. return getBackendSrv()
  68. .get(`/api/playlists/${playlistUid}/dashboards`)
  69. .then((dashboards: any) => {
  70. this.dashboards = dashboards;
  71. this.interval = rangeUtil.intervalToMs(playlist.interval);
  72. this.next();
  73. });
  74. });
  75. }
  76. stop() {
  77. if (!this.isPlaying) {
  78. return;
  79. }
  80. this.index = 0;
  81. this.isPlaying = false;
  82. if (this.locationListenerUnsub) {
  83. this.locationListenerUnsub();
  84. }
  85. if (this.nextTimeoutId) {
  86. clearTimeout(this.nextTimeoutId);
  87. }
  88. if (locationService.getSearchObject().kiosk) {
  89. locationService.partial({ kiosk: null });
  90. }
  91. }
  92. }
  93. export const playlistSrv = new PlaylistSrv();