@necrolab/dashboard 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/.claude/settings.local.json +45 -0
  2. package/.eslintrc.js +24 -0
  3. package/.prettierignore +1 -0
  4. package/.prettierrc +10 -0
  5. package/.vscode/extensions.json +3 -0
  6. package/ICONS.md +21 -0
  7. package/README.md +65 -0
  8. package/backend/api.js +430 -0
  9. package/backend/auth.js +62 -0
  10. package/backend/batching.js +43 -0
  11. package/backend/endpoints.js +343 -0
  12. package/backend/index.js +23 -0
  13. package/backend/mock-data.js +66 -0
  14. package/backend/mock-src/classes/logger.js +112 -0
  15. package/backend/mock-src/classes/utils.js +42 -0
  16. package/backend/mock-src/ticketmaster.js +92 -0
  17. package/backend/validator.js +62 -0
  18. package/config/configs.json +20 -0
  19. package/config/filter.json +3 -0
  20. package/config/presale.csv +3 -0
  21. package/config/proxies.txt +6 -0
  22. package/config/used-codes.json +4 -0
  23. package/index.html +114 -0
  24. package/index.js +2 -0
  25. package/jsconfig.json +16 -0
  26. package/package.json +48 -0
  27. package/postcss.config.js +6 -0
  28. package/postinstall.js +9 -0
  29. package/public/android-chrome-192x192.png +0 -0
  30. package/public/android-chrome-512x512.png +0 -0
  31. package/public/apple-touch-icon.png +0 -0
  32. package/public/favicon-16x16.png +0 -0
  33. package/public/favicon-32x32.png +0 -0
  34. package/public/favicon.ico +0 -0
  35. package/public/flags/ae.svg +1 -0
  36. package/public/flags/at.svg +1 -0
  37. package/public/flags/au.svg +1 -0
  38. package/public/flags/be.svg +1 -0
  39. package/public/flags/ch.svg +1 -0
  40. package/public/flags/cz.svg +1 -0
  41. package/public/flags/de.svg +1 -0
  42. package/public/flags/dk.svg +1 -0
  43. package/public/flags/es.svg +1 -0
  44. package/public/flags/nl.svg +1 -0
  45. package/public/flags/no.svg +1 -0
  46. package/public/flags/nz.svg +1 -0
  47. package/public/flags/pl.svg +1 -0
  48. package/public/flags/se.svg +1 -0
  49. package/public/flags/uk.svg +1 -0
  50. package/public/flags/us.svg +1 -0
  51. package/public/img/award.svg +3 -0
  52. package/public/img/background.svg +14 -0
  53. package/public/img/bag_w.svg +12 -0
  54. package/public/img/banks/amex.svg +4 -0
  55. package/public/img/banks/mastercard.svg +4 -0
  56. package/public/img/banks/visa.svg +4 -0
  57. package/public/img/camera.svg +3 -0
  58. package/public/img/close.svg +3 -0
  59. package/public/img/controls/disable.svg +5 -0
  60. package/public/img/controls/enable.svg +5 -0
  61. package/public/img/groups.svg +3 -0
  62. package/public/img/hand.svg +3 -0
  63. package/public/img/key.svg +3 -0
  64. package/public/img/logo.png +0 -0
  65. package/public/img/logo_icon.png +0 -0
  66. package/public/img/logo_icon_2.png +0 -0
  67. package/public/img/logo_trans.png +0 -0
  68. package/public/img/loyalty.svg +3 -0
  69. package/public/img/mail.svg +3 -0
  70. package/public/img/pencil.svg +3 -0
  71. package/public/img/profile.svg +4 -0
  72. package/public/img/reload.svg +3 -0
  73. package/public/img/sandclock.svg +25 -0
  74. package/public/img/save.svg +5 -0
  75. package/public/img/savings.svg +3 -0
  76. package/public/img/scanner.svg +3 -0
  77. package/public/img/sell.svg +3 -0
  78. package/public/img/shield.svg +3 -0
  79. package/public/img/ski.svg +3 -0
  80. package/public/img/stadium.svg +8 -0
  81. package/public/img/stadium_w.svg +8 -0
  82. package/public/img/timer.svg +3 -0
  83. package/public/manifest.json +27 -0
  84. package/public/robots.txt +2 -0
  85. package/run +10 -0
  86. package/src/App.vue +307 -0
  87. package/src/assets/css/_input.scss +197 -0
  88. package/src/assets/css/main.scss +269 -0
  89. package/src/assets/css/tailwind.css +3 -0
  90. package/src/assets/img/award.svg +3 -0
  91. package/src/assets/img/background.svg +11 -0
  92. package/src/assets/img/camera.svg +3 -0
  93. package/src/assets/img/close.svg +3 -0
  94. package/src/assets/img/eyes/closed.svg +13 -0
  95. package/src/assets/img/eyes/open.svg +12 -0
  96. package/src/assets/img/groups.svg +3 -0
  97. package/src/assets/img/hand.svg +3 -0
  98. package/src/assets/img/key.svg +3 -0
  99. package/src/assets/img/logo.png +0 -0
  100. package/src/assets/img/logo_icon.png +0 -0
  101. package/src/assets/img/logo_icon_2.png +0 -0
  102. package/src/assets/img/logo_trans.png +0 -0
  103. package/src/assets/img/loyalty.svg +3 -0
  104. package/src/assets/img/mail.svg +3 -0
  105. package/src/assets/img/pencil.svg +3 -0
  106. package/src/assets/img/reload.svg +3 -0
  107. package/src/assets/img/savings.svg +3 -0
  108. package/src/assets/img/scanner.svg +3 -0
  109. package/src/assets/img/sell.svg +3 -0
  110. package/src/assets/img/shield.svg +3 -0
  111. package/src/assets/img/ski.svg +3 -0
  112. package/src/assets/img/square_check.svg +5 -0
  113. package/src/assets/img/square_uncheck.svg +5 -0
  114. package/src/assets/img/stadium.svg +8 -0
  115. package/src/assets/img/timer.svg +3 -0
  116. package/src/assets/img/wildcard.svg +7 -0
  117. package/src/components/Auth/LoginForm.vue +48 -0
  118. package/src/components/Editors/Account/Account.vue +119 -0
  119. package/src/components/Editors/Account/AccountCreator.vue +147 -0
  120. package/src/components/Editors/Account/AccountView.vue +87 -0
  121. package/src/components/Editors/Account/CreateAccount.vue +106 -0
  122. package/src/components/Editors/Profile/CreateProfile.vue +321 -0
  123. package/src/components/Editors/Profile/Profile.vue +142 -0
  124. package/src/components/Editors/Profile/ProfileCountryChooser.vue +75 -0
  125. package/src/components/Editors/Profile/ProfileView.vue +96 -0
  126. package/src/components/Editors/TagLabel.vue +16 -0
  127. package/src/components/Editors/TagToggle.vue +41 -0
  128. package/src/components/Filter/Filter.vue +409 -0
  129. package/src/components/Filter/FilterPreview.vue +236 -0
  130. package/src/components/Filter/PriceSortToggle.vue +105 -0
  131. package/src/components/Table/Header.vue +5 -0
  132. package/src/components/Table/Row.vue +5 -0
  133. package/src/components/Table/Table.vue +14 -0
  134. package/src/components/Table/index.js +4 -0
  135. package/src/components/Tasks/CheckStock.vue +62 -0
  136. package/src/components/Tasks/Controls/DesktopControls.vue +73 -0
  137. package/src/components/Tasks/Controls/MobileControls.vue +32 -0
  138. package/src/components/Tasks/Controls/index.js +3 -0
  139. package/src/components/Tasks/CreateTaskAXS.vue +339 -0
  140. package/src/components/Tasks/CreateTaskTM.vue +459 -0
  141. package/src/components/Tasks/MassEdit.vue +50 -0
  142. package/src/components/Tasks/QuickSettings.vue +167 -0
  143. package/src/components/Tasks/ScrapeVenue.vue +42 -0
  144. package/src/components/Tasks/Stats.vue +66 -0
  145. package/src/components/Tasks/Task.vue +296 -0
  146. package/src/components/Tasks/TaskLabel.vue +20 -0
  147. package/src/components/Tasks/TaskView.vue +126 -0
  148. package/src/components/Tasks/Utilities.vue +33 -0
  149. package/src/components/icons/Award.vue +8 -0
  150. package/src/components/icons/Bag.vue +8 -0
  151. package/src/components/icons/BagWhite.vue +8 -0
  152. package/src/components/icons/Box.vue +8 -0
  153. package/src/components/icons/Camera.vue +8 -0
  154. package/src/components/icons/Cart.vue +8 -0
  155. package/src/components/icons/Check.vue +5 -0
  156. package/src/components/icons/Checkmark.vue +11 -0
  157. package/src/components/icons/Click.vue +8 -0
  158. package/src/components/icons/Close.vue +21 -0
  159. package/src/components/icons/CloseX.vue +5 -0
  160. package/src/components/icons/Console.vue +13 -0
  161. package/src/components/icons/Down.vue +8 -0
  162. package/src/components/icons/Edit.vue +13 -0
  163. package/src/components/icons/Event.vue +8 -0
  164. package/src/components/icons/Expand.vue +8 -0
  165. package/src/components/icons/Filter.vue +13 -0
  166. package/src/components/icons/Gear.vue +8 -0
  167. package/src/components/icons/Group.vue +8 -0
  168. package/src/components/icons/Hand.vue +8 -0
  169. package/src/components/icons/Key.vue +21 -0
  170. package/src/components/icons/Logout.vue +13 -0
  171. package/src/components/icons/Loyalty.vue +8 -0
  172. package/src/components/icons/Mail.vue +8 -0
  173. package/src/components/icons/Menu.vue +8 -0
  174. package/src/components/icons/Pause.vue +5 -0
  175. package/src/components/icons/Pencil.vue +21 -0
  176. package/src/components/icons/Play.vue +8 -0
  177. package/src/components/icons/Plus.vue +8 -0
  178. package/src/components/icons/Profile.vue +18 -0
  179. package/src/components/icons/Reload.vue +7 -0
  180. package/src/components/icons/Sandclock.vue +33 -0
  181. package/src/components/icons/Savings.vue +8 -0
  182. package/src/components/icons/Scanner.vue +8 -0
  183. package/src/components/icons/Scrape.vue +8 -0
  184. package/src/components/icons/Sell.vue +21 -0
  185. package/src/components/icons/Shield.vue +8 -0
  186. package/src/components/icons/Shrink.vue +8 -0
  187. package/src/components/icons/Ski.vue +8 -0
  188. package/src/components/icons/Spinner.vue +42 -0
  189. package/src/components/icons/SquareCheck.vue +18 -0
  190. package/src/components/icons/SquareUncheck.vue +18 -0
  191. package/src/components/icons/Stadium.vue +13 -0
  192. package/src/components/icons/StadiumWhite.vue +13 -0
  193. package/src/components/icons/Status.vue +8 -0
  194. package/src/components/icons/Tag.vue +8 -0
  195. package/src/components/icons/Tasks.vue +13 -0
  196. package/src/components/icons/Ticket.vue +8 -0
  197. package/src/components/icons/Timer.vue +8 -0
  198. package/src/components/icons/Trash.vue +8 -0
  199. package/src/components/icons/Up.vue +10 -0
  200. package/src/components/icons/Wildcard.vue +18 -0
  201. package/src/components/icons/index.js +111 -0
  202. package/src/components/ui/Modal.vue +61 -0
  203. package/src/components/ui/Navbar.vue +207 -0
  204. package/src/components/ui/ReconnectIndicator.vue +90 -0
  205. package/src/components/ui/Splash.vue +24 -0
  206. package/src/components/ui/controls/CountryChooser.vue +87 -0
  207. package/src/components/ui/controls/EyeToggle.vue +11 -0
  208. package/src/components/ui/controls/atomic/Checkbox.vue +28 -0
  209. package/src/components/ui/controls/atomic/Dropdown.vue +138 -0
  210. package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
  211. package/src/components/ui/controls/atomic/MultiDropdown.vue +262 -0
  212. package/src/components/ui/controls/atomic/Switch.vue +84 -0
  213. package/src/libs/Filter.js +593 -0
  214. package/src/libs/ansii.js +565 -0
  215. package/src/libs/panzoom.js +1413 -0
  216. package/src/main.js +23 -0
  217. package/src/registerServiceWorker.js +32 -0
  218. package/src/router/index.js +65 -0
  219. package/src/stores/cities.json +1 -0
  220. package/src/stores/connection.js +399 -0
  221. package/src/stores/countries.js +88 -0
  222. package/src/stores/logger.js +103 -0
  223. package/src/stores/requests.js +88 -0
  224. package/src/stores/sampleData.js +1034 -0
  225. package/src/stores/ui.js +584 -0
  226. package/src/stores/utils.js +554 -0
  227. package/src/types/index.js +42 -0
  228. package/src/utils/debug.js +1 -0
  229. package/src/views/Accounts.vue +191 -0
  230. package/src/views/Console.vue +224 -0
  231. package/src/views/Editor.vue +785 -0
  232. package/src/views/FilterBuilder.vue +785 -0
  233. package/src/views/Login.vue +27 -0
  234. package/src/views/Profiles.vue +209 -0
  235. package/src/views/Tasks.vue +157 -0
  236. package/static/offline.html +184 -0
  237. package/tailwind.config.js +57 -0
  238. package/vite.config.js +63 -0
  239. package/vue.config.js +32 -0
  240. package/workbox-config.js +66 -0
@@ -0,0 +1,191 @@
1
+ <template>
2
+ <div>
3
+ <div class="flex-between pt-5 pb-2">
4
+ <!-- Heading -->
5
+ <div class="flex-center gap-4">
6
+ <MailIcon class="cursor-pointer smooth-hover text-white" />
7
+ <h4 class="text-heading">
8
+ Accounts
9
+ <span class="text-subheading pl-1">{{ ui.getSelectedAccounts().length }}</span>
10
+ </h4>
11
+ </div>
12
+ <ul class="mobile-icons">
13
+ <li>
14
+ <EyeToggle v-model="privacy" />
15
+ </li>
16
+ <li>
17
+ <button
18
+ :disabled="ui.disabledButtons['create-accounts']"
19
+ @click="ui.toggleModal('account-creator', true)"
20
+ class="smooth-hover"
21
+ >
22
+ <PlayIcon class="w-4 h-4" />
23
+ </button>
24
+ </li>
25
+ <li>
26
+ <button
27
+ :disabled="ui.disabledButtons['add-accounts']"
28
+ @click="ui.toggleModal('create-account', true)"
29
+ class="smooth-hover"
30
+ >
31
+ <PlusIcon class="w-4 h-4" />
32
+ </button>
33
+ </li>
34
+ </ul>
35
+ </div>
36
+
37
+ <div class="flex items-center mb-3">
38
+ <div class="flex sm:w-auto w-full justify-start items-center gap-1">
39
+ <TagToggle
40
+ class="smooth-hover rounded-l min-w-9"
41
+ :options="['All', 'Enabled', 'Disabled']"
42
+ @change="(f) => (ui.search.accounts.show = f)"
43
+ />
44
+ <input
45
+ class="h-10 w-44 text-white text-sm p-2 bg-dark-500 flex items-center relative border-2 border-dark-550"
46
+ placeholder="Search Email"
47
+ v-model="ui.search.accounts.query"
48
+ />
49
+
50
+ <!-- <Dropdown
51
+ class="min-w-16 text-sm lg:w-24 bg-dark-550 rounded-none"
52
+ :onClick="(f) => (ui.search.accounts.show = f)"
53
+ default="All"
54
+ :chosen="ui.search.accounts.show"
55
+ :options="['All', 'Enabled', 'Disabled']"
56
+ rightAmount="right-2"
57
+ /> -->
58
+ <!-- <TagToggle
59
+ class="smooth-hover rounded-r w-32"
60
+ :options="allTags"
61
+ @change="(f) => (ui.search.accounts.tag = f)"
62
+ /> -->
63
+
64
+ <Dropdown
65
+ class="rounded-r-lg min-w-32 bg-dark-500 relative z-50 border-2 border-dark-550 search-dropdown"
66
+ style="margin-left: 0 !important; border-width: 2px !important"
67
+ rightAmount="right-1"
68
+ default="Any"
69
+ :value="ui.search.accounts.tag"
70
+ :onClick="(f) => (ui.search.accounts.tag = f)"
71
+ :options="allTags"
72
+ :capitalize="true"
73
+ />
74
+ </div>
75
+
76
+ <div class="ml-auto gap-2 hidden lg:flex">
77
+ <div
78
+ class="bg-dark-400 border border-light-300 justify-between px-4 w-44 flex text-white text-xs font-medium items-center rounded-md ml-auto h-10"
79
+ >
80
+ <p>Privacy</p>
81
+ <Switch class="scale-75" v-model="privacy" />
82
+ </div>
83
+ <button
84
+ :disabled="ui.disabledButtons['create-accounts']"
85
+ class="bg-dark-400 disabled:opacity-70 smooth-hover border border-light-300 hover:border-light-400 w-44 flex text-white text-xs font-medium justify-center items-center rounded-md ml-auto h-10"
86
+ @click="ui.toggleModal('account-creator')"
87
+ >
88
+ Create Accounts <PlayIcon class="ml-2" />
89
+ </button>
90
+
91
+ <button
92
+ :disabled="ui.disabledButtons['add-accounts']"
93
+ class="bg-dark-400 disabled:opacity-70 smooth-hover border border-light-300 hover:border-light-400 w-44 flex text-white text-xs font-medium justify-center items-center rounded-md ml-auto h-10"
94
+ @click="ui.toggleModal('create-account')"
95
+ >
96
+ Add Account
97
+ <PlusIcon class="ml-2" />
98
+ </button>
99
+ </div>
100
+ </div>
101
+
102
+ <!-- Tasks (Table) -->
103
+ <AccountView :tasks="processedTasks" class="max-h-big-acc" />
104
+
105
+ <!-- Modal -->
106
+ <transition-group name="fade" mode="out-in">
107
+ <CreateAccount v-if="activeModal === 'create-account'" />
108
+ <AccountCreator v-if="activeModal === 'account-creator'" />
109
+ </transition-group>
110
+ </div>
111
+ </template>
112
+ <style lang="scss" scoped>
113
+ .custom-dropdown-content {
114
+ top: 2.6rem !important;
115
+ left: -13px;
116
+ @apply border border-light-300;
117
+ }
118
+
119
+ /* Search dropdown should always be h-10 and have no left corners */
120
+ .search-dropdown {
121
+ height: 2.5rem !important; /* Always 40px regardless of screen size */
122
+ border-top-left-radius: 0 !important;
123
+ border-bottom-left-radius: 0 !important;
124
+ }
125
+ .max-h-big-acc {
126
+ max-height: calc(100vh - 14rem);
127
+ overflow: hidden;
128
+ }
129
+ </style>
130
+ <script setup>
131
+ import { computed, watch, ref } from "vue";
132
+ import AccountView from "@/components/Editors/Account/AccountView.vue";
133
+ import AccountCreator from "@/components/Editors/Account/AccountCreator.vue";
134
+ import CreateAccount from "@/components/Editors/Account/CreateAccount.vue";
135
+ import { useUIStore } from "@/stores/ui";
136
+ import { PlusIcon, PlayIcon, MailIcon } from "@/components/icons";
137
+ import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
138
+ import TagToggle from "@/components/Editors/TagToggle.vue";
139
+ import Switch from "@/components/ui/controls/atomic/Switch.vue";
140
+ import EyeToggle from "@/components/ui/controls/EyeToggle.vue";
141
+
142
+ const ui = useUIStore();
143
+ const activeModal = computed(() => ui.activeModal);
144
+ const allTags = ref([]);
145
+ const privacy = ref(true);
146
+
147
+ const filterAccounts = () => {
148
+ const { query, show, tag } = ui.search.accounts;
149
+ let accs = ui.accounts;
150
+ if (show === "Enabled") accs = accs.filter((p) => p.enabled);
151
+ if (show === "Disabled") accs = accs.filter((p) => !p.enabled);
152
+ ui.logger.Info(`Filtered accounts for ${ui.currentModule}`);
153
+
154
+ accs = accs.filter((acc) => acc.module === ui.currentModule);
155
+
156
+ if (tag !== "Any") accs = accs.filter((p) => p.tags.includes(ui.search.accounts.tag));
157
+ if (!query) return (ui.search.accounts.results = accs);
158
+ let searchRegex = new RegExp(query, "i");
159
+ accs = accs.filter((a) => searchRegex.test(a.email));
160
+ return accs;
161
+ };
162
+
163
+ ui.search.accounts.results = filterAccounts();
164
+
165
+ const processedTasks = computed(() => {
166
+ return ui.search.accounts.results.map((e) => ({ ...e, privacy: privacy.value }));
167
+ });
168
+
169
+ watch(
170
+ () =>
171
+ ui.search.accounts.query +
172
+ ui.search.accounts.show +
173
+ ui.accounts.length +
174
+ ui.search.accounts.tag +
175
+ ui.currentModule,
176
+ () => {
177
+ ui.search.accounts.results = filterAccounts();
178
+ }
179
+ );
180
+ const getAllTags = () => {
181
+ let tags = ["Any"];
182
+ ui.search.accounts.results.forEach((p) =>
183
+ p.tags.forEach((tag) => {
184
+ if (!tags.includes(tag)) tags.push(tag);
185
+ })
186
+ );
187
+ return tags;
188
+ };
189
+
190
+ allTags.value = getAllTags();
191
+ </script>
@@ -0,0 +1,224 @@
1
+ <template>
2
+ <div>
3
+ <h4 class="text-white font-bold mb-5 pt-5 flex gap-2 text-xl items-center">Console <ConsoleIcon /></h4>
4
+
5
+ <div>
6
+ <div class="flex items-center justify-between mb-3">
7
+ <div class="w-64">
8
+ <Dropdown
9
+ class="console-dropdown input-default w-64 bg-dark-500 border-2 border-dark-550"
10
+ rightAmount="right-2"
11
+ default="All logs"
12
+ :allowDefault="true"
13
+ :value="currentTaskLog"
14
+ :onClick="(f) => (currentTaskLog = f.split(' ')[0])"
15
+ :options="
16
+ Object.entries(taskLogMapping)
17
+ .map(([k, v]) => `${k} (${v.length})`)
18
+ .sort((a, b) => a.localeCompare(b))
19
+ "
20
+ />
21
+ </div>
22
+ <div class="flex items-center gap-3">
23
+ <!-- Hide Monitors and Auto buttons only on desktop -->
24
+ <div class="hidden ipadlg:flex items-center gap-3">
25
+ <button
26
+ class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
27
+ >
28
+ <h3 class="text-sm text-white">Hide Monitors</h3>
29
+ <Switch class="scale-75" v-model="filteredLogs" />
30
+ </button>
31
+ <button
32
+ class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
33
+ >
34
+ <h3 class="text-sm text-white">Auto</h3>
35
+ <Switch class="scale-75" v-model="autoscrollToggled" />
36
+ </button>
37
+ </div>
38
+ <!-- Scroll buttons always visible -->
39
+ <button
40
+ class="rounded card-dark w-10 h-10 flex-center"
41
+ >
42
+ <UpIcon class="cursor-pointer mx-1 lg:w-4 w-5 h-5" @click="scrollTo('up')" />
43
+ </button>
44
+ <button
45
+ class="rounded card-dark w-10 h-10 flex-center"
46
+ >
47
+ <DownIcon class="cursor-pointer ml-1 lg:w-4 w-5 h-5" @click="scrollTo('down')" />
48
+ </button>
49
+ </div>
50
+ </div>
51
+
52
+ <Smoothie
53
+ :weight="0.1"
54
+ class="hidden-scrollbars console overflow-y-auto overflow-x-hidden font-mono text-white"
55
+ style="min-height: 14rem !important"
56
+ ref="$autoscroll"
57
+ >
58
+ <pre
59
+ class="hidden-scrollbars"
60
+ v-for="line in currentTaskLog
61
+ ? taskLogMapping[currentTaskLog]
62
+ : logLines.filter((l) => (filteredLogs ? !['-DISCORD'].some((s) => l.includes(s)) : true))"
63
+ v-bind:key="line"
64
+ ><code class="md:text-sm lg:text-base" v-html="line"></code></pre>
65
+ </Smoothie>
66
+ <div class="flex ipadlg:hidden justify-between mt-3">
67
+ <button
68
+ class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
69
+ >
70
+ <h3 class="text-sm text-white">Hide Monitors</h3>
71
+ <Switch class="scale-75" v-model="filteredLogs" />
72
+ </button>
73
+ <button
74
+ class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
75
+ >
76
+ <h3 class="text-sm text-white">Auto</h3>
77
+ <Switch class="scale-75" v-model="autoscrollToggled" />
78
+ </button>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ </template>
83
+ <style lang="scss" scoped>
84
+ .console {
85
+ @apply bg-dark-400 lg:p-5 p-2 rounded relative border-dark-550 border-2;
86
+ height: calc(100vh - 16.5rem);
87
+ textarea {
88
+ background: transparent;
89
+ resize: none;
90
+
91
+ @apply w-full focus:outline-none text-white;
92
+ }
93
+ // $border: 1px;
94
+ // &:before {
95
+ // content: "";
96
+ // @apply absolute top-0 left-0 right-0 bottom-0 opacity-60;
97
+ // z-index: -2;
98
+ // margin: -$border;
99
+ // border-radius: inherit;
100
+ // background: radial-gradient(rgba(96, 66, 255, 0.6), rgba(255, 255, 255, 0));
101
+ // }
102
+ }
103
+
104
+ .text-xxs {
105
+ font-size: 0.5rem;
106
+ line-height: 0.8rem;
107
+ }
108
+
109
+ .header-wrapper {
110
+ svg {
111
+ width: 30px;
112
+ height: 30px;
113
+ }
114
+ }
115
+ .max-h-big-con {
116
+ max-height: calc(100vh - 12rem);
117
+ overflow: hidden;
118
+ }
119
+
120
+ /* Console dropdown styling - simplified to match input-default pattern */
121
+ .console-dropdown {
122
+ font-size: 0.875rem !important; /* text-sm */
123
+ font-weight: 500 !important; /* medium font weight */
124
+ }
125
+ </style>
126
+ <script setup>
127
+ import { Smoothie } from "vue-smoothie";
128
+ import { DEBUG } from "@/utils/debug";
129
+
130
+ import Filter from "@/libs/ansii.js";
131
+ import { ConsoleIcon, DownIcon, UpIcon } from "@/components/icons";
132
+ import Switch from "@/components/ui/controls/atomic/Switch.vue";
133
+ import WebsocketHeartbeatJs from "websocket-heartbeat-js";
134
+ import { onMounted, ref, nextTick } from "vue";
135
+ import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
136
+ import { sortAlphaNum } from "@/stores/utils";
137
+
138
+ import { useUIStore } from "@/stores/ui";
139
+
140
+ const ui = useUIStore();
141
+
142
+ const $autoscroll = ref(null);
143
+ const logLines = ref([]);
144
+ const ansii = new Filter();
145
+ const autoscrollToggled = ref(true);
146
+ const taskLogMapping = ref({});
147
+ const currentTaskLog = ref(false);
148
+ const filteredLogs = ref(true);
149
+
150
+ const path = "/api/updates?type=console";
151
+ const url = (window.location.protocol === "http:" ? "ws://" : "wss://") + window.location.host + path;
152
+ const scrollTo = (dir) => {
153
+ try {
154
+ if (dir === "up") $autoscroll.value.el.scrollTop = 0;
155
+ else $autoscroll.value.el.scrollTop = parseInt($autoscroll.value.el.children[1].style.height);
156
+ } catch (e) {
157
+ if (DEBUG) console.log("Error scrolling", e);
158
+ }
159
+ };
160
+
161
+ const addAnsiToOutput = (a) => {
162
+ const html = ansii.toHtml(a.log);
163
+ logLines.value.push(html);
164
+ if (autoscrollToggled.value)
165
+ nextTick().then(() => {
166
+ scrollTo("down");
167
+ });
168
+ };
169
+
170
+ const handleWebsocketMessages = (msg) => {
171
+ const data = msg.log;
172
+ if (msg.type === "console-init") {
173
+ logLines.value = [];
174
+ taskLogMapping.value = {};
175
+ makeTaskLogMapping(data);
176
+
177
+ data.forEach((l) => {
178
+ addAnsiToOutput(l);
179
+ });
180
+ } else if (msg.type === "console") {
181
+ makeTaskLogMapping([msg]);
182
+ if (data.includes("Cleared logs")) logLines.value = [];
183
+ addAnsiToOutput(msg);
184
+ }
185
+ };
186
+
187
+ const makeTaskLogMapping = (lines) => {
188
+ lines.forEach((l) => {
189
+ if (!l.metadata) {
190
+ if (DEBUG) console.log("Error getting metadata", l);
191
+ return;
192
+ }
193
+ const region = l.metadata.siteId?.split("_")?.[1];
194
+ const n = l.metadata.global ? "Global" : `${region}-${l.metadata.taskId}`;
195
+ if (!taskLogMapping.value[n]) taskLogMapping.value[n] = [];
196
+ taskLogMapping.value[n].push(ansii.toHtml(l.log));
197
+ });
198
+ };
199
+
200
+ window.startDebugConsoleMessages = () => {
201
+ setInterval(() => {
202
+ const line = `\u001b[96m[12:16:02.273]\u001b[00m \u001b[96m[TASK-${Math.round(
203
+ Math.random() * 10
204
+ )}]\u001b[00m AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Needs To Queue: false - Queue up: false`;
205
+ addAnsiToOutput(line);
206
+ makeTaskLogMapping([line]);
207
+ }, 500);
208
+ };
209
+
210
+ if (DEBUG) window.startDebugConsoleMessages();
211
+
212
+ // Listen for messages
213
+ onMounted(() => {
214
+ const socket = new WebsocketHeartbeatJs({ url, pingMsg: "ping" });
215
+
216
+ socket.onmessage = (event) => {
217
+ const msg = JSON.parse(event.data);
218
+ if (DEBUG) console.log("Received message", msg);
219
+ msg.forEach((e) => {
220
+ handleWebsocketMessages(e);
221
+ });
222
+ };
223
+ });
224
+ </script>