@necrolab/dashboard 0.4.61 → 0.4.208
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.
- package/.prettierrc +1 -27
- package/.vscode/extensions.json +1 -1
- package/README.md +79 -43
- package/backend/api.js +48 -40
- package/backend/auth.js +3 -3
- package/backend/batching.js +1 -1
- package/backend/endpoints.js +77 -13
- package/backend/index.js +2 -2
- package/backend/mock-data.js +38 -29
- package/backend/mock-src/classes/logger.js +8 -8
- package/backend/mock-src/classes/utils.js +3 -7
- package/backend/mock-src/database.js +0 -0
- package/backend/mock-src/ticketmaster.js +79 -79
- package/backend/validator.js +2 -2
- package/config/configs.json +3 -2
- package/config/filter.json +3 -2
- package/index.html +10 -81
- package/index.js +1 -1
- package/package.json +25 -40
- package/postcss.config.js +1 -1
- package/postinstall.js +17 -98
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/manifest.json +7 -12
- package/public/sw.js +2 -0
- package/public/workbox-49fdaf31.js +2 -0
- package/public/workbox-49fdaf31.js.map +1 -0
- package/public/workbox-88575b92.js +2 -0
- package/public/workbox-88575b92.js.map +1 -0
- package/public/workbox-a67a7b11.js +2 -0
- package/public/workbox-a67a7b11.js.map +1 -0
- package/public/workbox-d4314735.js +2 -0
- package/public/workbox-d4314735.js.map +1 -0
- package/public/workbox-e0f89ef3.js +2 -0
- package/public/workbox-e0f89ef3.js.map +1 -0
- package/run +9 -176
- package/src/App.vue +85 -498
- package/src/assets/css/_input.scss +99 -144
- package/src/assets/css/main.scss +99 -450
- package/src/assets/img/background.svg +2 -2
- package/src/assets/img/logo_icon.png +0 -0
- package/src/components/Auth/LoginForm.vue +11 -62
- package/src/components/Editors/Account/Account.vue +40 -116
- package/src/components/Editors/Account/AccountCreator.vue +39 -88
- package/src/components/Editors/Account/AccountView.vue +34 -102
- package/src/components/Editors/Account/CreateAccount.vue +32 -80
- package/src/components/Editors/Profile/CreateProfile.vue +83 -269
- package/src/components/Editors/Profile/Profile.vue +47 -132
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +20 -82
- package/src/components/Editors/Profile/ProfileView.vue +34 -91
- package/src/components/Editors/TagLabel.vue +6 -67
- package/src/components/Filter/Filter.vue +72 -289
- package/src/components/Filter/FilterPreview.vue +30 -171
- package/src/components/Filter/PriceSortToggle.vue +4 -74
- package/src/components/Table/Header.vue +1 -1
- package/src/components/Table/Row.vue +1 -1
- package/src/components/Table/Table.vue +2 -19
- package/src/components/Tasks/CheckStock.vue +13 -28
- package/src/components/Tasks/Controls/DesktopControls.vue +17 -17
- package/src/components/Tasks/Controls/MobileControls.vue +45 -8
- package/src/components/Tasks/CreateTaskAXS.vue +73 -79
- package/src/components/Tasks/CreateTaskTM.vue +142 -94
- package/src/components/Tasks/MassEdit.vue +7 -9
- package/src/components/Tasks/QuickSettings.vue +55 -169
- package/src/components/Tasks/ScrapeVenue.vue +4 -7
- package/src/components/Tasks/Stats.vue +23 -52
- package/src/components/Tasks/Task.vue +136 -378
- package/src/components/Tasks/TaskView.vue +47 -107
- package/src/components/Tasks/Utilities.vue +6 -5
- package/src/components/icons/Bag.vue +1 -1
- package/src/components/icons/Loyalty.vue +1 -1
- package/src/components/icons/Mail.vue +2 -2
- package/src/components/icons/Play.vue +2 -2
- package/src/components/icons/Reload.vue +5 -4
- package/src/components/icons/Sandclock.vue +2 -2
- package/src/components/icons/Stadium.vue +1 -1
- package/src/components/icons/index.js +1 -24
- package/src/components/ui/Modal.vue +13 -105
- package/src/components/ui/Navbar.vue +38 -171
- package/src/components/ui/ReconnectIndicator.vue +55 -351
- package/src/components/ui/Splash.vue +35 -5
- package/src/components/ui/controls/CountryChooser.vue +62 -200
- package/src/components/ui/controls/atomic/Checkbox.vue +10 -119
- package/src/components/ui/controls/atomic/Dropdown.vue +39 -208
- package/src/components/ui/controls/atomic/MultiDropdown.vue +37 -300
- package/src/libs/Filter.js +170 -200
- package/src/registerServiceWorker.js +1 -1
- package/src/stores/connection.js +53 -51
- package/src/stores/logger.js +3 -11
- package/src/stores/sampleData.js +235 -207
- package/src/stores/ui.js +44 -112
- package/src/stores/utils.js +6 -90
- package/src/views/Accounts.vue +35 -44
- package/src/views/Console.vue +90 -341
- package/src/views/Editor.vue +123 -1176
- package/src/views/FilterBuilder.vue +251 -607
- package/src/views/Login.vue +14 -76
- package/src/views/Profiles.vue +25 -44
- package/src/views/Tasks.vue +100 -187
- package/static/offline.html +50 -192
- package/tailwind.config.js +26 -104
- package/vite.config.js +16 -73
- package/vue.config.js +32 -0
- package/workbox-config.js +11 -0
- package/artwork/image.png +0 -0
- package/dev-server.js +0 -136
- package/exit +0 -209
- package/jsconfig.json +0 -16
- package/src/assets/css/_utilities.scss +0 -388
- package/src/assets/img/background.svg.backup +0 -11
- package/src/components/icons/Check.vue +0 -5
- package/src/components/icons/Close.vue +0 -21
- package/src/components/icons/CloseX.vue +0 -5
- package/src/components/icons/Key.vue +0 -21
- package/src/components/icons/Pencil.vue +0 -21
- package/src/components/icons/Profile.vue +0 -18
- package/src/components/icons/Sell.vue +0 -21
- package/src/components/icons/Spinner.vue +0 -42
- package/src/components/icons/SquareCheck.vue +0 -18
- package/src/components/icons/SquareUncheck.vue +0 -18
- package/src/components/icons/Wildcard.vue +0 -18
- package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
- package/src/composables/useClickOutside.js +0 -21
- package/src/composables/useDropdownPosition.js +0 -174
- package/src/types/index.js +0 -41
- package/src/utils/debug.js +0 -1
- package/switch-branch.sh +0 -41
- package/workbox-config.cjs +0 -63
- /package/src/assets/img/{logo_icon-old.png → logo_icon_2.png} +0 -0
package/src/views/Console.vue
CHANGED
|
@@ -1,105 +1,74 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<h4 class="
|
|
4
|
-
Console
|
|
5
|
-
<ConsoleIcon />
|
|
6
|
-
</h4>
|
|
3
|
+
<h4 class="text-white font-bold mb-5 pt-5 flex gap-2 text-xl items-center">Console <ConsoleIcon /></h4>
|
|
7
4
|
|
|
8
5
|
<div>
|
|
9
|
-
<div class="
|
|
10
|
-
<div class="w-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Object.entries(taskLogMapping)
|
|
20
|
-
|
|
21
|
-
.sort((a, b) => a.localeCompare(b))
|
|
22
|
-
" />
|
|
23
|
-
</div>
|
|
24
|
-
<div class="flex items-center gap-3">
|
|
25
|
-
<!-- Hide Monitors and Auto buttons only on desktop -->
|
|
26
|
-
<div class="hidden items-center gap-3 md:flex">
|
|
27
|
-
<button class="card-dark flex-center flex h-10 gap-3 rounded px-2">
|
|
28
|
-
<h3 class="text-sm text-white">Hide Monitors</h3>
|
|
29
|
-
<Switch class="scale-75" v-model="filteredLogs" />
|
|
30
|
-
</button>
|
|
31
|
-
<button class="card-dark flex-center relative flex h-10 gap-3 rounded px-2">
|
|
32
|
-
<h3 class="text-sm text-white">Auto</h3>
|
|
33
|
-
<Switch class="scale-75" v-model="autoscrollToggled" @change="onAutoscrollToggle" />
|
|
34
|
-
<div
|
|
35
|
-
v-if="userScrolledUp && autoscrollToggled"
|
|
36
|
-
class="absolute -right-1 -top-1 h-2 w-2 animate-pulse rounded-full bg-yellow-500"
|
|
37
|
-
title="Autoscroll paused - scroll to bottom to resume"></div>
|
|
38
|
-
</button>
|
|
6
|
+
<div class="flex items-center mb-3">
|
|
7
|
+
<div class="flex w-full justify-start text-exl items-center">
|
|
8
|
+
<div class="w-40 flex rounded input-default">
|
|
9
|
+
<Dropdown
|
|
10
|
+
class="w-40"
|
|
11
|
+
rightAmount="right-2"
|
|
12
|
+
default="All logs"
|
|
13
|
+
:allowDefault="true"
|
|
14
|
+
:value="currentTaskLog"
|
|
15
|
+
:onClick="(f) => (currentTaskLog = f.split(' ')[0])"
|
|
16
|
+
:options="Object.entries(taskLogMapping).map(([k, v]) => `${k} (${v.length})`).sort((a, b) => a.localeCompare(b))"
|
|
17
|
+
/>
|
|
39
18
|
</div>
|
|
40
|
-
|
|
19
|
+
</div>
|
|
20
|
+
<div class="flex justify-right justify-end text-2xl items-center gap-3">
|
|
21
|
+
<button
|
|
22
|
+
class="hidden ipadlg:flex rounded gap-3 bg-dark-500 border-2 border-dark-550 shadow-lg px-2 h-10 justify-center items-center"
|
|
23
|
+
>
|
|
24
|
+
<h3 class="text-sm text-white">Filtered</h3>
|
|
25
|
+
<Switch class="scale-75" v-model="filteredLogs" />
|
|
26
|
+
</button>
|
|
27
|
+
<button
|
|
28
|
+
class="hidden ipadlg:flex rounded gap-3 bg-dark-500 border-2 border-dark-550 shadow-lg px-2 h-10 justify-center items-center"
|
|
29
|
+
>
|
|
30
|
+
<h3 class="text-sm text-white">Auto</h3>
|
|
31
|
+
<Switch class="scale-75" v-model="autoscrollToggled" />
|
|
32
|
+
</button>
|
|
41
33
|
<button
|
|
42
|
-
class="
|
|
43
|
-
|
|
44
|
-
@
|
|
45
|
-
@mouseleave="stopScrolling"
|
|
46
|
-
@touchstart="startScrolling('up')"
|
|
47
|
-
@touchend="stopScrolling">
|
|
48
|
-
<UpIcon class="pointer-events-none h-5 w-5" />
|
|
34
|
+
class="rounded bg-dark-500 border-2 border-dark-550 shadow-lg w-10 h-10 flex justify-center items-center"
|
|
35
|
+
>
|
|
36
|
+
<UpIcon class="cursor-pointer mx-1 lg:w-4 w-5 h-5" @click="scrollTo('up')" />
|
|
49
37
|
</button>
|
|
50
38
|
<button
|
|
51
|
-
class="
|
|
52
|
-
|
|
53
|
-
@
|
|
54
|
-
@mouseleave="stopScrolling"
|
|
55
|
-
@touchstart="startScrolling('down')"
|
|
56
|
-
@touchend="stopScrolling">
|
|
57
|
-
<DownIcon class="pointer-events-none h-5 w-5" />
|
|
39
|
+
class="rounded bg-dark-500 border-2 border-dark-550 shadow-lg w-10 h-10 flex justify-center items-center"
|
|
40
|
+
>
|
|
41
|
+
<DownIcon class="cursor-pointer ml-1 lg:w-4 w-5 h-5" @click="scrollTo('down')" />
|
|
58
42
|
</button>
|
|
59
43
|
</div>
|
|
60
44
|
</div>
|
|
61
45
|
|
|
62
46
|
<Smoothie
|
|
63
|
-
:weight="0.
|
|
64
|
-
class="console
|
|
65
|
-
style="min-height:
|
|
47
|
+
:weight="0.1"
|
|
48
|
+
class="hidden-scrollbars console overflow-y-auto overflow-x-hidden font-mono text-white"
|
|
49
|
+
style="min-height: 14rem !important"
|
|
66
50
|
ref="$autoscroll"
|
|
67
|
-
|
|
68
|
-
@touchmove.stop
|
|
69
|
-
@scroll="handleScroll">
|
|
70
|
-
<div
|
|
71
|
-
v-if="
|
|
72
|
-
(currentTaskLog && currentTaskLog !== ''
|
|
73
|
-
? taskLogMapping[currentTaskLog]
|
|
74
|
-
: logLines.filter((l) => (filteredLogs ? !['-DISCORD'].some((s) => l.includes(s)) : true))
|
|
75
|
-
).length === 0
|
|
76
|
-
"
|
|
77
|
-
class="empty-state flex h-full flex-col items-center justify-center text-center">
|
|
78
|
-
<ConsoleIcon class="mb-3 h-12 w-12 text-dark-400 opacity-50" />
|
|
79
|
-
<p class="text-sm text-light-400">No logs yet</p>
|
|
80
|
-
<p class="mt-1 text-xs text-light-500">Logs will appear here in real time</p>
|
|
81
|
-
</div>
|
|
51
|
+
>
|
|
82
52
|
<pre
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
v-for="(line, index) in currentTaskLog && currentTaskLog !== ''
|
|
53
|
+
class="hidden-scrollbars"
|
|
54
|
+
v-for="line in currentTaskLog
|
|
86
55
|
? taskLogMapping[currentTaskLog]
|
|
87
|
-
: logLines.filter((l) => (filteredLogs ? !['-
|
|
88
|
-
v-bind:key="
|
|
89
|
-
|
|
56
|
+
: logLines.filter((l) => (filteredLogs ? !['-discord'].some((s) => l.includes(s)) : true))"
|
|
57
|
+
v-bind:key="line"
|
|
58
|
+
><code class="md:text-sm lg:text-base" v-html="line"></code></pre>
|
|
90
59
|
</Smoothie>
|
|
91
|
-
<div class="
|
|
92
|
-
<button
|
|
93
|
-
|
|
60
|
+
<div class="flex ipadlg:hidden justify-between mt-3">
|
|
61
|
+
<button
|
|
62
|
+
class="flex rounded gap-3 bg-dark-500 border-2 border-dark-550 shadow-lg px-2 h-10 justify-center items-center"
|
|
63
|
+
>
|
|
64
|
+
<h3 class="text-sm text-white">Filtered</h3>
|
|
94
65
|
<Switch class="scale-75" v-model="filteredLogs" />
|
|
95
66
|
</button>
|
|
96
|
-
<button
|
|
67
|
+
<button
|
|
68
|
+
class="flex rounded gap-3 bg-dark-500 border-2 border-dark-550 shadow-lg px-2 h-10 justify-center items-center"
|
|
69
|
+
>
|
|
97
70
|
<h3 class="text-sm text-white">Auto</h3>
|
|
98
|
-
<Switch class="scale-75" v-model="autoscrollToggled"
|
|
99
|
-
<div
|
|
100
|
-
v-if="userScrolledUp && autoscrollToggled"
|
|
101
|
-
class="absolute -right-1 -top-1 h-2 w-2 animate-pulse rounded-full bg-yellow-500"
|
|
102
|
-
title="Autoscroll paused - scroll to bottom to resume"></div>
|
|
71
|
+
<Switch class="scale-75" v-model="autoscrollToggled" />
|
|
103
72
|
</button>
|
|
104
73
|
</div>
|
|
105
74
|
</div>
|
|
@@ -107,107 +76,23 @@
|
|
|
107
76
|
</template>
|
|
108
77
|
<style lang="scss" scoped>
|
|
109
78
|
.console {
|
|
110
|
-
@apply
|
|
111
|
-
height: calc(100vh -
|
|
112
|
-
|
|
113
|
-
// Enable scrollbars for console
|
|
114
|
-
scrollbar-width: thin;
|
|
115
|
-
scrollbar-color: #555 #2e2f34;
|
|
116
|
-
|
|
117
|
-
&::-webkit-scrollbar {
|
|
118
|
-
width: 8px;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
&::-webkit-scrollbar-track {
|
|
122
|
-
background: #2e2f34;
|
|
123
|
-
border-radius: 4px;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
&::-webkit-scrollbar-thumb {
|
|
127
|
-
background: #555;
|
|
128
|
-
border-radius: 4px;
|
|
129
|
-
transition: background-color 0.2s ease;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
&::-webkit-scrollbar-thumb:hover {
|
|
133
|
-
background: #777;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Smooth scrolling behavior with momentum
|
|
137
|
-
&.smooth-scroll {
|
|
138
|
-
scroll-behavior: smooth;
|
|
139
|
-
scroll-padding: 0.5rem;
|
|
140
|
-
-webkit-overflow-scrolling: touch;
|
|
141
|
-
overscroll-behavior: contain;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Improved log entry animations
|
|
145
|
-
.log-entry {
|
|
146
|
-
opacity: 0;
|
|
147
|
-
transform: translateY(4px);
|
|
148
|
-
animation: slideInLog 0.2s ease-out forwards;
|
|
149
|
-
transition: all 0.15s ease;
|
|
150
|
-
|
|
151
|
-
&:hover {
|
|
152
|
-
background-color: rgba(255, 255, 255, 0.02);
|
|
153
|
-
transform: translateX(2px);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Stagger animation for new logs
|
|
158
|
-
.log-entry:last-child {
|
|
159
|
-
animation-delay: 0.05s;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
@keyframes slideInLog {
|
|
163
|
-
to {
|
|
164
|
-
opacity: 1;
|
|
165
|
-
transform: translateY(0);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Empty state styling
|
|
170
|
-
.empty-state {
|
|
171
|
-
min-height: 14rem;
|
|
172
|
-
font-family:
|
|
173
|
-
"Inter",
|
|
174
|
-
-apple-system,
|
|
175
|
-
BlinkMacSystemFont,
|
|
176
|
-
"Segoe UI",
|
|
177
|
-
Helvetica,
|
|
178
|
-
Arial,
|
|
179
|
-
sans-serif;
|
|
180
|
-
}
|
|
181
|
-
|
|
79
|
+
@apply bg-dark-400 lg:p-5 p-2 rounded relative border-dark-550 border-2;
|
|
80
|
+
height: calc(100vh - 16.5rem);
|
|
182
81
|
textarea {
|
|
183
82
|
background: transparent;
|
|
184
83
|
resize: none;
|
|
185
|
-
@apply w-full text-white focus:outline-none;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/* Mobile portrait console optimizations */
|
|
190
|
-
@screen mobile-portrait {
|
|
191
|
-
.console {
|
|
192
|
-
height: calc(100vh - 19.5rem);
|
|
193
|
-
@apply p-1 text-xs;
|
|
194
|
-
overflow: hidden;
|
|
195
84
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
@media (max-width: 1024px) and (orientation: landscape) {
|
|
208
|
-
.console {
|
|
209
|
-
height: calc(100vh - 10.5rem);
|
|
210
|
-
}
|
|
85
|
+
@apply w-full focus:outline-none text-white;
|
|
86
|
+
}
|
|
87
|
+
// $border: 1px;
|
|
88
|
+
// &:before {
|
|
89
|
+
// content: "";
|
|
90
|
+
// @apply absolute top-0 left-0 right-0 bottom-0 opacity-60;
|
|
91
|
+
// z-index: -2;
|
|
92
|
+
// margin: -$border;
|
|
93
|
+
// border-radius: inherit;
|
|
94
|
+
// background: radial-gradient(rgba(96, 66, 255, 0.6), rgba(255, 255, 255, 0));
|
|
95
|
+
// }
|
|
211
96
|
}
|
|
212
97
|
|
|
213
98
|
.text-xxs {
|
|
@@ -221,167 +106,50 @@
|
|
|
221
106
|
height: 30px;
|
|
222
107
|
}
|
|
223
108
|
}
|
|
224
|
-
|
|
109
|
+
.max-h-big-con {
|
|
110
|
+
max-height: calc(100vh - 12rem);
|
|
111
|
+
overflow: hidden;
|
|
112
|
+
}
|
|
225
113
|
</style>
|
|
226
114
|
<script setup>
|
|
227
115
|
import { Smoothie } from "vue-smoothie";
|
|
228
|
-
|
|
116
|
+
|
|
117
|
+
const DEBUG = window.location.href.startsWith("http://localhost:5173");
|
|
229
118
|
|
|
230
119
|
import Filter from "@/libs/ansii.js";
|
|
231
120
|
import { ConsoleIcon, DownIcon, UpIcon } from "@/components/icons";
|
|
232
121
|
import Switch from "@/components/ui/controls/atomic/Switch.vue";
|
|
233
122
|
import WebsocketHeartbeatJs from "websocket-heartbeat-js";
|
|
234
|
-
import { onMounted,
|
|
123
|
+
import { onMounted, ref, nextTick } from "vue";
|
|
235
124
|
import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
|
|
236
|
-
import { sortAlphaNum } from "@/stores/utils";
|
|
237
|
-
|
|
238
|
-
import { useUIStore } from "@/stores/ui";
|
|
239
|
-
|
|
240
|
-
const ui = useUIStore();
|
|
241
125
|
|
|
242
126
|
const $autoscroll = ref(null);
|
|
243
127
|
const logLines = ref([]);
|
|
244
128
|
const ansii = new Filter();
|
|
245
129
|
const autoscrollToggled = ref(true);
|
|
246
130
|
const taskLogMapping = ref({});
|
|
247
|
-
const currentTaskLog = ref(
|
|
248
|
-
const filteredLogs = ref(
|
|
249
|
-
const userScrolledUp = ref(false);
|
|
250
|
-
const lastScrollTime = ref(0);
|
|
251
|
-
const scrollInterval = ref(null);
|
|
252
|
-
const isScrolling = ref(false);
|
|
131
|
+
const currentTaskLog = ref(false);
|
|
132
|
+
const filteredLogs = ref(false);
|
|
253
133
|
|
|
254
134
|
const path = "/api/updates?type=console";
|
|
255
135
|
const url = (window.location.protocol === "http:" ? "ws://" : "wss://") + window.location.host + path;
|
|
256
|
-
// Handle manual scroll detection
|
|
257
|
-
const handleScroll = (event) => {
|
|
258
|
-
if (!autoscrollToggled.value) return;
|
|
259
136
|
|
|
260
|
-
|
|
261
|
-
if (!element) return;
|
|
262
|
-
|
|
263
|
-
// Check if user is near bottom (within 50px)
|
|
264
|
-
const threshold = 50;
|
|
265
|
-
const isNearBottom = element.scrollTop + element.clientHeight >= element.scrollHeight - threshold;
|
|
266
|
-
|
|
267
|
-
// Only update if there's an actual change
|
|
268
|
-
if (userScrolledUp.value === isNearBottom) {
|
|
269
|
-
userScrolledUp.value = !isNearBottom;
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
// Bulletproof scroll function with multiple fallbacks
|
|
274
|
-
const performScroll = (direction, smooth = true) => {
|
|
137
|
+
const scrollTo = (dir) => {
|
|
275
138
|
try {
|
|
276
|
-
if (
|
|
277
|
-
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const element = $autoscroll.value.el;
|
|
282
|
-
|
|
283
|
-
if (direction === "up") {
|
|
284
|
-
if (smooth && element.scrollTo) {
|
|
285
|
-
element.scrollTo({ top: 0, behavior: "smooth" });
|
|
286
|
-
} else {
|
|
287
|
-
element.scrollTop = 0;
|
|
288
|
-
}
|
|
289
|
-
} else {
|
|
290
|
-
const targetTop = element.scrollHeight - element.clientHeight;
|
|
291
|
-
if (smooth && element.scrollTo) {
|
|
292
|
-
element.scrollTo({ top: targetTop, behavior: "smooth" });
|
|
293
|
-
} else {
|
|
294
|
-
element.scrollTop = targetTop;
|
|
295
|
-
}
|
|
296
|
-
userScrolledUp.value = false;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return true;
|
|
139
|
+
if (dir === "up") $autoscroll.value.el.scrollTop = 0;
|
|
140
|
+
else $autoscroll.value.el.scrollTop = parseInt($autoscroll.value.el.children[1].style.height);
|
|
300
141
|
} catch (e) {
|
|
301
|
-
|
|
302
|
-
return false;
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
// Continuous scrolling for held buttons
|
|
307
|
-
const startScrolling = (direction) => {
|
|
308
|
-
if (isScrolling.value) return;
|
|
309
|
-
|
|
310
|
-
isScrolling.value = true;
|
|
311
|
-
|
|
312
|
-
// Immediate scroll
|
|
313
|
-
performScroll(direction, true);
|
|
314
|
-
|
|
315
|
-
// Continue scrolling while held (for long content)
|
|
316
|
-
scrollInterval.value = setInterval(() => {
|
|
317
|
-
if (!isScrolling.value) return;
|
|
318
|
-
|
|
319
|
-
const element = $autoscroll.value?.el;
|
|
320
|
-
if (!element) return;
|
|
321
|
-
|
|
322
|
-
const scrollAmount = 100;
|
|
323
|
-
if (direction === "up") {
|
|
324
|
-
element.scrollTop = Math.max(0, element.scrollTop - scrollAmount);
|
|
325
|
-
} else {
|
|
326
|
-
element.scrollTop = Math.min(element.scrollHeight - element.clientHeight, element.scrollTop + scrollAmount);
|
|
327
|
-
}
|
|
328
|
-
}, 50);
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
const stopScrolling = () => {
|
|
332
|
-
isScrolling.value = false;
|
|
333
|
-
if (scrollInterval.value) {
|
|
334
|
-
clearInterval(scrollInterval.value);
|
|
335
|
-
scrollInterval.value = null;
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
// Legacy function for compatibility
|
|
340
|
-
const scrollTo = (dir) => {
|
|
341
|
-
performScroll(dir, true);
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
// Simple autoscroll to bottom
|
|
345
|
-
const autoScrollToBottom = () => {
|
|
346
|
-
if (!$autoscroll.value?.el || !autoscrollToggled.value) return;
|
|
347
|
-
|
|
348
|
-
// Only scroll if user hasn't manually scrolled up
|
|
349
|
-
if (!userScrolledUp.value) {
|
|
350
|
-
const element = $autoscroll.value.el;
|
|
351
|
-
|
|
352
|
-
// Calculate the target scroll position to show the last log
|
|
353
|
-
const targetScrollTop = element.scrollHeight - element.clientHeight;
|
|
354
|
-
|
|
355
|
-
// Use smooth scrolling to ensure new logs are visible
|
|
356
|
-
if (element.scrollTo && Math.abs(element.scrollTop - targetScrollTop) > 5) {
|
|
357
|
-
element.scrollTo({
|
|
358
|
-
top: targetScrollTop,
|
|
359
|
-
behavior: "smooth"
|
|
360
|
-
});
|
|
361
|
-
} else {
|
|
362
|
-
// For small differences or fallback, use instant scroll
|
|
363
|
-
element.scrollTop = targetScrollTop;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
// Handle autoscroll toggle
|
|
369
|
-
const onAutoscrollToggle = () => {
|
|
370
|
-
if (autoscrollToggled.value) {
|
|
371
|
-
userScrolledUp.value = false;
|
|
372
|
-
nextTick().then(autoScrollToBottom);
|
|
142
|
+
console.log("Error scrolling", e);
|
|
373
143
|
}
|
|
374
144
|
};
|
|
375
145
|
|
|
376
146
|
const addAnsiToOutput = (a) => {
|
|
377
|
-
const html = ansii.toHtml(a
|
|
147
|
+
const html = ansii.toHtml(a.log);
|
|
378
148
|
logLines.value.push(html);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
setTimeout(autoScrollToBottom, 10);
|
|
384
|
-
});
|
|
149
|
+
if (autoscrollToggled.value)
|
|
150
|
+
nextTick().then(() => {
|
|
151
|
+
scrollTo("down");
|
|
152
|
+
});
|
|
385
153
|
};
|
|
386
154
|
|
|
387
155
|
const handleWebsocketMessages = (msg) => {
|
|
@@ -404,7 +172,7 @@ const handleWebsocketMessages = (msg) => {
|
|
|
404
172
|
const makeTaskLogMapping = (lines) => {
|
|
405
173
|
lines.forEach((l) => {
|
|
406
174
|
if (!l.metadata) {
|
|
407
|
-
|
|
175
|
+
console.log("Error getting metadata", l);
|
|
408
176
|
return;
|
|
409
177
|
}
|
|
410
178
|
const region = l.metadata.siteId?.split("_")?.[1];
|
|
@@ -416,45 +184,26 @@ const makeTaskLogMapping = (lines) => {
|
|
|
416
184
|
|
|
417
185
|
window.startDebugConsoleMessages = () => {
|
|
418
186
|
setInterval(() => {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
global: false
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
addAnsiToOutput(log);
|
|
429
|
-
makeTaskLogMapping([log]);
|
|
430
|
-
}, 100);
|
|
187
|
+
const line = `\u001b[96m[12:16:02.273]\u001b[00m \u001b[96m[TASK-${Math.round(
|
|
188
|
+
Math.random() * 10
|
|
189
|
+
)}]\u001b[00m AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Needs To Queue: false - Queue up: false`;
|
|
190
|
+
addAnsiToOutput(line);
|
|
191
|
+
makeTaskLogMapping([line]);
|
|
192
|
+
}, 500);
|
|
431
193
|
};
|
|
432
194
|
|
|
433
195
|
if (DEBUG) window.startDebugConsoleMessages();
|
|
434
196
|
|
|
435
|
-
// Watch for log filter changes and reset scroll state
|
|
436
|
-
watch([currentTaskLog, filteredLogs], () => {
|
|
437
|
-
userScrolledUp.value = false;
|
|
438
|
-
nextTick().then(() => {
|
|
439
|
-
setTimeout(autoScrollToBottom, 10);
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
|
|
443
197
|
// Listen for messages
|
|
444
198
|
onMounted(() => {
|
|
445
199
|
const socket = new WebsocketHeartbeatJs({ url, pingMsg: "ping" });
|
|
446
200
|
|
|
447
201
|
socket.onmessage = (event) => {
|
|
448
202
|
const msg = JSON.parse(event.data);
|
|
449
|
-
|
|
203
|
+
console.log("Received message", msg);
|
|
450
204
|
msg.forEach((e) => {
|
|
451
205
|
handleWebsocketMessages(e);
|
|
452
206
|
});
|
|
453
207
|
};
|
|
454
208
|
});
|
|
455
|
-
|
|
456
|
-
// Cleanup on unmount
|
|
457
|
-
onUnmounted(() => {
|
|
458
|
-
stopScrolling();
|
|
459
|
-
});
|
|
460
209
|
</script>
|