@necrolab/dashboard 0.4.49 → 0.4.51
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 +12 -1
- package/package.json +1 -1
- package/src/App.vue +178 -195
- package/src/assets/css/_input.scss +2 -4
- package/src/assets/css/_utilities.scss +0 -53
- package/src/assets/css/main.scss +0 -25
- package/src/components/Auth/LoginForm.vue +51 -8
- package/src/components/Editors/Account/AccountView.vue +12 -13
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +4 -6
- package/src/components/Filter/FilterPreview.vue +24 -37
- package/src/components/Tasks/Stats.vue +1 -2
- package/src/components/Tasks/Task.vue +422 -477
- package/src/components/Tasks/TaskView.vue +185 -123
- package/src/components/ui/Modal.vue +21 -17
- package/src/components/ui/controls/atomic/Dropdown.vue +126 -131
- package/src/components/ui/controls/atomic/MultiDropdown.vue +200 -206
- package/src/stores/sampleData.js +4 -2
- package/src/stores/ui.js +4 -3
- package/src/views/Accounts.vue +10 -17
- package/src/views/Console.vue +10 -3
- package/src/views/Editor.vue +952 -1037
- package/src/views/FilterBuilder.vue +1 -1
- package/src/views/Login.vue +26 -86
- package/src/views/Tasks.vue +5 -5
- package/static/offline.html +192 -50
|
@@ -1,459 +1,423 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
>
|
|
20
|
-
{{ props.task.taskId }}
|
|
21
|
-
</h4>
|
|
22
|
-
</div>
|
|
23
|
-
<div class="col-span-1 lg:col-span-2 flex items-center justify-start">
|
|
24
|
-
<Checkbox
|
|
25
|
-
class="ml-2 mr-4 flex-shrink-0"
|
|
26
|
-
:toggled="props.task.selected"
|
|
27
|
-
@valueUpdate="ui.toggleTaskSelected(props.task.taskId)"
|
|
28
|
-
/>
|
|
29
|
-
<h4
|
|
30
|
-
class="task-event-id mx-auto hidden lg:block text-white cursor-pointer hover:text-light-300"
|
|
31
|
-
@click="copy(props.task.eventId)"
|
|
32
|
-
>
|
|
33
|
-
{{ props.task.eventId }}
|
|
34
|
-
</h4>
|
|
35
|
-
</div>
|
|
36
|
-
<div class="col-span-2">
|
|
37
|
-
<h4 class="text-white">
|
|
38
|
-
<span v-if="!props.task.reservedTicketsList">-</span>
|
|
39
|
-
<div v-else>
|
|
40
|
-
<div v-for="l in props.task.reservedTicketsList.split(' | ')" :key="l">
|
|
41
|
-
<span v-if="!!l.trim()">{{ l.trim() }}</span>
|
|
42
|
-
</div>
|
|
2
|
+
<Row class="relative text-white grid-cols-10 gap-2 lg:grid-cols-12" @click="ui.setOpenContextMenu('')">
|
|
3
|
+
<div class="block md:hidden absolute left-1 top-1">
|
|
4
|
+
<h4
|
|
5
|
+
class="text-xs text-white font-bold"
|
|
6
|
+
style="
|
|
7
|
+
background: transparent !important;
|
|
8
|
+
border: none !important;
|
|
9
|
+
padding: 0 !important;
|
|
10
|
+
margin: 0 !important;
|
|
11
|
+
color: #c9cad1 !important;
|
|
12
|
+
font-size: 11px !important;
|
|
13
|
+
font-weight: 600 !important;
|
|
14
|
+
letter-spacing: 0.4px !important;
|
|
15
|
+
">
|
|
16
|
+
{{ props.task.taskId }}
|
|
17
|
+
</h4>
|
|
43
18
|
</div>
|
|
44
|
-
<span
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
<div
|
|
192
|
-
v-if="ui.openContextMenu === task.taskId"
|
|
193
|
-
ref="contextMenuRef"
|
|
194
|
-
class="fixed bg-dark-500 text-white w-42 grid grid-cols-1 p-1 gap-1 rounded-lg shadow-xl border border-dark-650 context-menu z-max"
|
|
195
|
-
:style="contextMenuPosition"
|
|
196
|
-
>
|
|
197
|
-
<button
|
|
198
|
-
class="btn-primary"
|
|
199
|
-
@click="openInNewTab(`${ui.currentCountry.url}/event/${task.eventId}`)"
|
|
200
|
-
>
|
|
201
|
-
Open Event
|
|
202
|
-
</button>
|
|
203
|
-
<button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(false)">
|
|
204
|
-
Open in browser (proxy)
|
|
205
|
-
</button>
|
|
206
|
-
<button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(true)">
|
|
207
|
-
Open in browser (debug)
|
|
208
|
-
</button>
|
|
209
|
-
</div>
|
|
210
|
-
</transition>
|
|
211
|
-
</Row>
|
|
19
|
+
<div class="col-span-1 lg:col-span-2 flex items-center justify-start">
|
|
20
|
+
<Checkbox
|
|
21
|
+
class="ml-2 mr-4 flex-shrink-0"
|
|
22
|
+
:toggled="props.task.selected"
|
|
23
|
+
@valueUpdate="ui.toggleTaskSelected(props.task.taskId)" />
|
|
24
|
+
<h4
|
|
25
|
+
class="task-event-id mx-auto hidden lg:block text-white cursor-pointer hover:text-light-300"
|
|
26
|
+
@click="copy(props.task.eventId)">
|
|
27
|
+
{{ props.task.eventId }}
|
|
28
|
+
</h4>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="col-span-2">
|
|
31
|
+
<h4 class="text-white">
|
|
32
|
+
<span v-if="!props.task.reservedTicketsList">-</span>
|
|
33
|
+
<div v-else>
|
|
34
|
+
<div v-for="l in props.task.reservedTicketsList.split(' | ')" :key="l">
|
|
35
|
+
<span v-if="!!l.trim()">{{ l.trim() }}</span>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<span
|
|
39
|
+
class="ml-1 font-bold"
|
|
40
|
+
:class="{
|
|
41
|
+
'text-red-400':
|
|
42
|
+
props.task._timeLeftString === '00:00' || props.task._timeLeftString === 'No Cartholds'
|
|
43
|
+
}">
|
|
44
|
+
{{ props.task._timeLeftString !== "00:00" ? props.task._timeLeftString : "Expired" }}
|
|
45
|
+
</span>
|
|
46
|
+
</h4>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="col-span-5 md:col-span-4 lg:col-span-5 text-center justify-center">
|
|
49
|
+
<div class="status-container">
|
|
50
|
+
<div
|
|
51
|
+
class="status-indicator"
|
|
52
|
+
:class="
|
|
53
|
+
colorToClass(
|
|
54
|
+
props.task.active || props.task.status.toLowerCase() === 'idle'
|
|
55
|
+
? props.task.statusColor
|
|
56
|
+
: 'red'
|
|
57
|
+
)
|
|
58
|
+
"></div>
|
|
59
|
+
<span class="status-text">{{ props.task.status }}</span>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="col-span-2 lg:col-span-3 flex">
|
|
63
|
+
<ul class="task-buttons">
|
|
64
|
+
<li>
|
|
65
|
+
<button v-if="task.active" @click="ui.stopTask(task.taskId)">
|
|
66
|
+
<PauseIcon />
|
|
67
|
+
</button>
|
|
68
|
+
<button v-else @click="ui.startTask(task.taskId)">
|
|
69
|
+
<PlayIcon />
|
|
70
|
+
</button>
|
|
71
|
+
</li>
|
|
72
|
+
<li v-if="task.status?.toLowerCase() == 'waiting' && props.task._timeLeftString !== '00:00'">
|
|
73
|
+
<button @click="ui.continueTask(task.taskId, 'autocheckout')">
|
|
74
|
+
<BagWhiteIcon />
|
|
75
|
+
</button>
|
|
76
|
+
</li>
|
|
77
|
+
<li v-if="task.status?.toLowerCase() == 'waiting'">
|
|
78
|
+
<button @click="ui.continueTask(task.taskId, 'change_reservation')">
|
|
79
|
+
<EditIcon />
|
|
80
|
+
</button>
|
|
81
|
+
</li>
|
|
82
|
+
<li>
|
|
83
|
+
<button @click="ui.deleteTask(task.taskId)">
|
|
84
|
+
<TrashIcon />
|
|
85
|
+
</button>
|
|
86
|
+
</li>
|
|
87
|
+
<li @contextmenu.prevent="handleRightClick">
|
|
88
|
+
<button @click="props.task.isExpanded = !props.task.isExpanded">
|
|
89
|
+
<span>{{ props.task.isExpanded ? "−" : "+" }}</span>
|
|
90
|
+
</button>
|
|
91
|
+
</li>
|
|
92
|
+
</ul>
|
|
93
|
+
</div>
|
|
94
|
+
<div class="hidden md:block col-span-1 absolute right-5 top-4 lg:flex items-center justify-center">
|
|
95
|
+
<h4 class="text-center text-xs task-id text-white">
|
|
96
|
+
{{ props.task.taskId }}
|
|
97
|
+
</h4>
|
|
98
|
+
</div>
|
|
99
|
+
<transition name="fade">
|
|
100
|
+
<div
|
|
101
|
+
class="col-span-10 lg:col-span-12 flex flex-wrap gap-x-4 gap-y-4 lg:gap-x-10 pt-8 pb-2 xl:justify-around will-change-auto"
|
|
102
|
+
v-if="props.task.isExpanded">
|
|
103
|
+
<!-- Details -->
|
|
104
|
+
<TaskLabel
|
|
105
|
+
class="md:hidden"
|
|
106
|
+
image="stadium_w"
|
|
107
|
+
:text="props.task.eventId"
|
|
108
|
+
@click="copy(props.task.eventId)" />
|
|
109
|
+
|
|
110
|
+
<TaskLabel class="md:hidden" image="bag_w" :text="String(props.task.quantity)" />
|
|
111
|
+
<TaskLabel
|
|
112
|
+
v-if="props.task.email"
|
|
113
|
+
image="mail"
|
|
114
|
+
:text="props.task.email"
|
|
115
|
+
@click="copy(props.task.email)" />
|
|
116
|
+
<TaskLabel
|
|
117
|
+
v-if="props.task.password"
|
|
118
|
+
image="key"
|
|
119
|
+
:text="props.task.password"
|
|
120
|
+
@click="copy(props.task.password)" />
|
|
121
|
+
<TaskLabel v-if="!props.task.email && !props.task.password" image="mail" text="No account chosen yet" />
|
|
122
|
+
<TaskLabel v-if="props.task.profileName" image="profile" :text="props.task.profileName" />
|
|
123
|
+
<TaskLabel image="timer" :text="props.task.smartTimer ? 'On' : 'Off'" />
|
|
124
|
+
<TaskLabel image="groups" :text="props.task.loginAfterCart ? 'On' : 'Off'" />
|
|
125
|
+
<TaskLabel image="hand" :text="props.task.manual ? 'On' : 'Off'" />
|
|
126
|
+
<TaskLabel image="savings" :text="props.task.doNotPay ? 'On' : 'Off'" />
|
|
127
|
+
<TaskLabel image="loyalty" :text="props.task.presaleMode ? 'On' : 'Off'" />
|
|
128
|
+
<TaskLabel image="ski" :text="props.task.quickQueue ? 'On' : 'Off'" />
|
|
129
|
+
<TaskLabel image="scanner" :text="props.task.accountTag" />
|
|
130
|
+
<TaskLabel image="sell" :text="props.task.profileTags.join(', ')" />
|
|
131
|
+
<TaskLabel
|
|
132
|
+
v-if="props.task.presaleCode"
|
|
133
|
+
@click="copy(props.task.presaleCode)"
|
|
134
|
+
image="pencil"
|
|
135
|
+
:text="props.task.presaleCode" />
|
|
136
|
+
|
|
137
|
+
<TaskLabel v-if="props.task.eventName" image="stadium_w" :text="props.task.eventName" />
|
|
138
|
+
<TaskLabel v-if="props.task.eventVenue" image="stadium_w" :text="props.task.eventVenue" />
|
|
139
|
+
<TaskLabel
|
|
140
|
+
v-if="props.task.eventLocalDate"
|
|
141
|
+
image="stadium_w"
|
|
142
|
+
:text="formatDate(props.task.eventLocalDate)" />
|
|
143
|
+
<TaskLabel image="sandclock" :text="props.task.agedAccount ? 'On' : 'Off'" />
|
|
144
|
+
</div>
|
|
145
|
+
</transition>
|
|
146
|
+
|
|
147
|
+
<!-- Context menu -->
|
|
148
|
+
<transition name="fade">
|
|
149
|
+
<div
|
|
150
|
+
v-if="ui.openContextMenu === task.taskId"
|
|
151
|
+
ref="contextMenuRef"
|
|
152
|
+
class="fixed bg-dark-500 text-white w-42 grid grid-cols-1 p-1 gap-1 rounded-lg shadow-xl border border-dark-650 context-menu z-max"
|
|
153
|
+
:style="contextMenuPosition">
|
|
154
|
+
<button class="btn-primary" @click="openInNewTab(`${ui.currentCountry.url}/event/${task.eventId}`)">
|
|
155
|
+
Open Event
|
|
156
|
+
</button>
|
|
157
|
+
<button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(false)">
|
|
158
|
+
Open in browser (proxy)
|
|
159
|
+
</button>
|
|
160
|
+
<button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(true)">
|
|
161
|
+
Open in browser (debug)
|
|
162
|
+
</button>
|
|
163
|
+
</div>
|
|
164
|
+
</transition>
|
|
165
|
+
</Row>
|
|
212
166
|
</template>
|
|
213
167
|
<style lang="scss" scoped>
|
|
214
168
|
h4 {
|
|
215
|
-
|
|
216
|
-
|
|
169
|
+
@apply text-center;
|
|
170
|
+
color: #e2e2e5;
|
|
217
171
|
}
|
|
218
172
|
|
|
219
173
|
.status-container {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
&:hover {
|
|
227
|
-
@apply bg-dark-550 border-dark-700;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
.status-text {
|
|
232
|
-
@apply font-medium text-sm truncate uppercase;
|
|
233
|
-
color: #e2e2e5;
|
|
234
|
-
letter-spacing: 0.025em;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
.task-buttons {
|
|
238
|
-
@apply flex items-center justify-center mx-auto bg-dark-500 border border-dark-650 rounded;
|
|
239
|
-
padding: 2px;
|
|
240
|
-
gap: 1px;
|
|
241
|
-
|
|
242
|
-
button {
|
|
243
|
-
@apply flex items-center justify-center transition-all duration-150 border-0 outline-0 relative rounded;
|
|
244
|
-
background: transparent;
|
|
245
|
-
width: 22px;
|
|
246
|
-
height: 22px;
|
|
247
|
-
color: #cccccc;
|
|
248
|
-
border-radius: 4px;
|
|
174
|
+
@apply flex items-center justify-center mx-auto w-fit bg-dark-500 border border-dark-650 rounded-lg;
|
|
175
|
+
padding: 6px 12px;
|
|
176
|
+
gap: 6px;
|
|
177
|
+
transition: all 0.15s ease;
|
|
178
|
+
max-width: 100%;
|
|
249
179
|
|
|
250
180
|
&:hover {
|
|
251
|
-
|
|
252
|
-
color: #ffffff;
|
|
253
|
-
transform: scale(1.05);
|
|
181
|
+
@apply bg-dark-550 border-dark-700;
|
|
254
182
|
}
|
|
183
|
+
}
|
|
255
184
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
svg,
|
|
263
|
-
img {
|
|
264
|
-
width: 12px;
|
|
265
|
-
height: 12px;
|
|
266
|
-
position: relative;
|
|
267
|
-
z-index: 1;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
svg path {
|
|
271
|
-
fill: currentColor;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
span {
|
|
275
|
-
@apply text-xs font-medium relative z-[1];
|
|
276
|
-
}
|
|
185
|
+
.status-text {
|
|
186
|
+
@apply font-medium text-sm truncate uppercase;
|
|
187
|
+
color: #e2e2e5;
|
|
188
|
+
letter-spacing: 0.025em;
|
|
277
189
|
}
|
|
278
190
|
|
|
279
|
-
|
|
280
|
-
@
|
|
281
|
-
.task-buttons {
|
|
191
|
+
.task-buttons {
|
|
192
|
+
@apply flex items-center justify-center mx-auto bg-dark-500 border border-dark-650 rounded;
|
|
282
193
|
padding: 2px;
|
|
283
194
|
gap: 1px;
|
|
284
|
-
border-radius: 6px;
|
|
285
195
|
|
|
286
196
|
button {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
197
|
+
@apply flex items-center justify-center transition-all duration-150 border-0 outline-0 relative rounded;
|
|
198
|
+
background: transparent;
|
|
199
|
+
width: 22px;
|
|
200
|
+
height: 22px;
|
|
201
|
+
color: #cccccc;
|
|
202
|
+
border-radius: 4px;
|
|
203
|
+
|
|
204
|
+
&:hover {
|
|
205
|
+
background: rgba(255, 255, 255, 0.1);
|
|
206
|
+
color: #ffffff;
|
|
207
|
+
transform: scale(1.05);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
&:active {
|
|
211
|
+
background: rgba(255, 255, 255, 0.2);
|
|
212
|
+
transform: scale(0.95);
|
|
213
|
+
}
|
|
290
214
|
}
|
|
291
215
|
|
|
292
216
|
svg,
|
|
293
217
|
img {
|
|
294
|
-
|
|
295
|
-
|
|
218
|
+
width: 12px;
|
|
219
|
+
height: 12px;
|
|
220
|
+
position: relative;
|
|
221
|
+
z-index: 1;
|
|
296
222
|
}
|
|
297
223
|
|
|
298
|
-
|
|
299
|
-
|
|
224
|
+
svg path {
|
|
225
|
+
fill: currentColor;
|
|
300
226
|
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
227
|
|
|
304
|
-
|
|
305
|
-
@
|
|
306
|
-
.task-buttons {
|
|
307
|
-
padding: 3px;
|
|
308
|
-
gap: 2px;
|
|
309
|
-
border-radius: 8px;
|
|
310
|
-
|
|
311
|
-
button {
|
|
312
|
-
width: 28px;
|
|
313
|
-
height: 28px;
|
|
314
|
-
border-radius: 6px;
|
|
228
|
+
span {
|
|
229
|
+
@apply text-xs font-medium relative z-[1];
|
|
315
230
|
}
|
|
231
|
+
}
|
|
316
232
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
233
|
+
/* Tablet sizing - medium buttons */
|
|
234
|
+
@media (min-width: 768px) and (max-width: 1023px) {
|
|
235
|
+
.task-buttons {
|
|
236
|
+
padding: 2px;
|
|
237
|
+
gap: 1px;
|
|
238
|
+
border-radius: 6px;
|
|
239
|
+
|
|
240
|
+
button {
|
|
241
|
+
width: 26px;
|
|
242
|
+
height: 26px;
|
|
243
|
+
border-radius: 5px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
svg,
|
|
247
|
+
img {
|
|
248
|
+
width: 14px;
|
|
249
|
+
height: 14px;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
span {
|
|
253
|
+
font-size: 0.75rem;
|
|
254
|
+
}
|
|
321
255
|
}
|
|
256
|
+
}
|
|
322
257
|
|
|
323
|
-
|
|
324
|
-
|
|
258
|
+
/* Desktop sizing - large buttons */
|
|
259
|
+
@media (min-width: 1024px) {
|
|
260
|
+
.task-buttons {
|
|
261
|
+
padding: 3px;
|
|
262
|
+
gap: 2px;
|
|
263
|
+
border-radius: 8px;
|
|
264
|
+
|
|
265
|
+
button {
|
|
266
|
+
width: 28px;
|
|
267
|
+
height: 28px;
|
|
268
|
+
border-radius: 6px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
svg,
|
|
272
|
+
img {
|
|
273
|
+
width: 16px;
|
|
274
|
+
height: 16px;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
span {
|
|
278
|
+
font-size: 0.875rem;
|
|
279
|
+
}
|
|
325
280
|
}
|
|
326
|
-
}
|
|
327
281
|
}
|
|
328
282
|
|
|
329
283
|
/* Mobile portrait specific styling */
|
|
330
284
|
@media (max-width: 480px) and (orientation: portrait) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/* Ultra-compact button layout for mobile portrait */
|
|
339
|
-
.task-buttons {
|
|
340
|
-
padding: 1px;
|
|
341
|
-
gap: 0;
|
|
342
|
-
border-radius: 4px;
|
|
343
|
-
border: none !important;
|
|
344
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
|
|
345
|
-
max-width: 100%;
|
|
346
|
-
overflow: visible;
|
|
347
|
-
flex-wrap: wrap;
|
|
348
|
-
justify-content: center;
|
|
349
|
-
min-height: 18px;
|
|
350
|
-
height: auto;
|
|
351
|
-
|
|
352
|
-
button {
|
|
353
|
-
width: 15px;
|
|
354
|
-
height: 15px;
|
|
355
|
-
border-radius: 2px;
|
|
356
|
-
min-width: 15px;
|
|
357
|
-
border: none !important;
|
|
358
|
-
flex-shrink: 0;
|
|
359
|
-
margin: 0.5px;
|
|
360
|
-
|
|
361
|
-
&:hover {
|
|
362
|
-
transform: scale(1.1);
|
|
363
|
-
}
|
|
285
|
+
/* Position adjustment for mobile taskId */
|
|
286
|
+
.block.md\\:hidden {
|
|
287
|
+
left: 4rem !important;
|
|
288
|
+
top: 0.25rem !important;
|
|
289
|
+
z-index: 1 !important;
|
|
364
290
|
}
|
|
365
291
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
292
|
+
/* Improved button layout for mobile portrait */
|
|
293
|
+
.task-buttons {
|
|
294
|
+
padding: 1px;
|
|
295
|
+
gap: 1px;
|
|
296
|
+
border-radius: 4px;
|
|
297
|
+
border: 1px solid #3d3e44 !important;
|
|
298
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
|
|
299
|
+
max-width: 100%;
|
|
300
|
+
min-height: 28px;
|
|
301
|
+
height: auto;
|
|
302
|
+
flex-wrap: wrap;
|
|
303
|
+
justify-content: center;
|
|
304
|
+
align-items: center;
|
|
305
|
+
background: #2e2f34;
|
|
306
|
+
|
|
307
|
+
button {
|
|
308
|
+
width: 20px;
|
|
309
|
+
height: 20px;
|
|
310
|
+
border-radius: 3px;
|
|
311
|
+
min-width: 20px;
|
|
312
|
+
border: none !important;
|
|
313
|
+
flex-shrink: 0;
|
|
314
|
+
margin: 0.5px;
|
|
315
|
+
background: transparent;
|
|
316
|
+
|
|
317
|
+
&:hover {
|
|
318
|
+
background: rgba(255, 255, 255, 0.1);
|
|
319
|
+
transform: scale(1.05);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
&:active {
|
|
323
|
+
background: rgba(255, 255, 255, 0.15);
|
|
324
|
+
transform: scale(0.95);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
svg,
|
|
329
|
+
img {
|
|
330
|
+
width: 10px;
|
|
331
|
+
height: 10px;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
span {
|
|
335
|
+
font-size: 0.7rem;
|
|
336
|
+
line-height: 1;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* Improved list item layout */
|
|
340
|
+
li {
|
|
341
|
+
display: flex;
|
|
342
|
+
margin: 0;
|
|
343
|
+
padding: 0;
|
|
344
|
+
}
|
|
370
345
|
}
|
|
371
346
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
347
|
+
/* Make the actions column more flexible */
|
|
348
|
+
.col-span-2.lg\\:col-span-3 {
|
|
349
|
+
min-width: 0;
|
|
350
|
+
flex-shrink: 0;
|
|
351
|
+
display: flex;
|
|
352
|
+
align-items: center;
|
|
353
|
+
justify-content: center;
|
|
354
|
+
padding: 0 2px;
|
|
375
355
|
}
|
|
376
356
|
|
|
377
|
-
/*
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
357
|
+
/* Compact status container */
|
|
358
|
+
.status-container {
|
|
359
|
+
border: none !important;
|
|
360
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
|
|
361
|
+
padding: 2px 4px;
|
|
362
|
+
font-size: 0.7rem;
|
|
363
|
+
max-width: 100%;
|
|
381
364
|
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/* Make the actions column slightly more flexible */
|
|
385
|
-
.col-span-2.lg\\:col-span-3 {
|
|
386
|
-
min-width: 0;
|
|
387
|
-
flex-shrink: 0;
|
|
388
|
-
display: flex;
|
|
389
|
-
align-items: center;
|
|
390
|
-
justify-content: center;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/* Compact status container */
|
|
394
|
-
.status-container {
|
|
395
|
-
border: none !important;
|
|
396
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
|
|
397
|
-
padding: 3px 6px;
|
|
398
|
-
font-size: 0.75rem;
|
|
399
|
-
max-width: 100%;
|
|
400
|
-
}
|
|
401
365
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
366
|
+
.status-text {
|
|
367
|
+
font-size: 0.65rem;
|
|
368
|
+
letter-spacing: 0;
|
|
369
|
+
}
|
|
406
370
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
371
|
+
/* Reduce row height to accommodate smaller elements */
|
|
372
|
+
.task-row-container {
|
|
373
|
+
min-height: 45px !important;
|
|
374
|
+
}
|
|
411
375
|
}
|
|
412
376
|
|
|
413
377
|
.task-id {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
378
|
+
font-size: 10px;
|
|
379
|
+
font-weight: 600;
|
|
380
|
+
letter-spacing: 0.5px;
|
|
381
|
+
margin: 0;
|
|
382
|
+
color: #a0a0a6;
|
|
383
|
+
background: rgba(46, 47, 52, 0.4);
|
|
384
|
+
padding: 2px 6px;
|
|
385
|
+
border-radius: 4px;
|
|
386
|
+
border: 1px solid #3d3e44;
|
|
423
387
|
}
|
|
424
388
|
|
|
425
389
|
.task-event-id {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
390
|
+
font-size: 11px;
|
|
391
|
+
font-weight: 500;
|
|
392
|
+
text-align: center;
|
|
393
|
+
color: #d0d0d3;
|
|
430
394
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
395
|
+
&:hover {
|
|
396
|
+
color: #ffffff;
|
|
397
|
+
}
|
|
434
398
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
399
|
+
@media (max-width: 1024px) {
|
|
400
|
+
font-size: 10px;
|
|
401
|
+
}
|
|
438
402
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
403
|
+
@media (max-width: 768px) {
|
|
404
|
+
font-size: 9px;
|
|
405
|
+
}
|
|
442
406
|
}
|
|
443
407
|
|
|
444
408
|
/* Responsive task styling */
|
|
445
409
|
@screen lg {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
410
|
+
h4 {
|
|
411
|
+
font-size: 10px;
|
|
412
|
+
}
|
|
449
413
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
414
|
+
.task-id {
|
|
415
|
+
font-size: 8px;
|
|
416
|
+
}
|
|
453
417
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
418
|
+
.task-event-id {
|
|
419
|
+
font-size: 10px;
|
|
420
|
+
}
|
|
457
421
|
}
|
|
458
422
|
</style>
|
|
459
423
|
|
|
@@ -461,13 +425,7 @@ h4 {
|
|
|
461
425
|
/// <reference path="@/types/index.js" />
|
|
462
426
|
|
|
463
427
|
import { Row } from "@/components/Table";
|
|
464
|
-
import {
|
|
465
|
-
PlayIcon,
|
|
466
|
-
TrashIcon,
|
|
467
|
-
BagWhiteIcon,
|
|
468
|
-
PauseIcon,
|
|
469
|
-
EditIcon,
|
|
470
|
-
} from "@/components/icons";
|
|
428
|
+
import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon } from "@/components/icons";
|
|
471
429
|
import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
|
|
472
430
|
import { useUIStore } from "@/stores/ui";
|
|
473
431
|
import TaskLabel from "@/components/Tasks/TaskLabel.vue";
|
|
@@ -477,7 +435,7 @@ const ui = useUIStore();
|
|
|
477
435
|
|
|
478
436
|
/** @type {{ task: Task }} */
|
|
479
437
|
const props = defineProps({
|
|
480
|
-
|
|
438
|
+
task: { type: Object }
|
|
481
439
|
});
|
|
482
440
|
|
|
483
441
|
// Context menu positioning
|
|
@@ -486,51 +444,51 @@ const contextMenuRef = ref(null);
|
|
|
486
444
|
|
|
487
445
|
// Handle right-click to position context menu
|
|
488
446
|
const handleRightClick = (event) => {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
447
|
+
const menuWidth = 168; // w-42 = 10.5rem = 168px
|
|
448
|
+
const menuHeight = 200; // Approximate height
|
|
449
|
+
|
|
450
|
+
let x = event.clientX;
|
|
451
|
+
let y = event.clientY - 55;
|
|
452
|
+
|
|
453
|
+
// Prevent menu from going off screen
|
|
454
|
+
if (x + menuWidth > window.innerWidth) {
|
|
455
|
+
x = event.clientX - menuWidth; // Show to the left instead
|
|
456
|
+
}
|
|
457
|
+
if (y + menuHeight > window.innerHeight) {
|
|
458
|
+
y = event.clientY - menuHeight; // Show above instead
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
contextMenuPosition.value = {
|
|
462
|
+
left: `${x}px`,
|
|
463
|
+
top: `${y}px`
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
// Open the context menu for this task
|
|
467
|
+
ui.setOpenContextMenu(props.task.taskId);
|
|
468
|
+
|
|
469
|
+
// Add click outside listener after menu opens
|
|
470
|
+
nextTick(() => {
|
|
471
|
+
document.addEventListener("click", handleClickOutside);
|
|
472
|
+
});
|
|
515
473
|
};
|
|
516
474
|
|
|
517
475
|
// Handle clicking outside the context menu
|
|
518
476
|
const handleClickOutside = (event) => {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
477
|
+
if (contextMenuRef.value && !contextMenuRef.value.contains(event.target)) {
|
|
478
|
+
ui.setOpenContextMenu("");
|
|
479
|
+
document.removeEventListener("click", handleClickOutside);
|
|
480
|
+
}
|
|
523
481
|
};
|
|
524
482
|
|
|
525
483
|
// Cleanup on unmount
|
|
526
484
|
onUnmounted(() => {
|
|
527
|
-
|
|
485
|
+
document.removeEventListener("click", handleClickOutside);
|
|
528
486
|
});
|
|
529
487
|
|
|
530
488
|
const copy = (txt) => {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
489
|
+
if (!txt) return;
|
|
490
|
+
navigator.clipboard.writeText(txt);
|
|
491
|
+
ui.showSuccess("Copied text");
|
|
534
492
|
};
|
|
535
493
|
|
|
536
494
|
const colorMapping = new Map();
|
|
@@ -539,52 +497,39 @@ colorMapping.set("red", "bg-red-400");
|
|
|
539
497
|
colorMapping.set("error", "bg-red-400");
|
|
540
498
|
colorMapping.set("success", "bg-green-400");
|
|
541
499
|
const colorToClass = (color) => {
|
|
542
|
-
|
|
500
|
+
return colorMapping.get(color) || "bg-white";
|
|
543
501
|
};
|
|
544
502
|
|
|
545
503
|
const openInBrowser = (debug) => {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
504
|
+
if (!props.task.openerLink) return;
|
|
505
|
+
ui.showSuccess(`Opening in browser ${debug ? "(debug)" : ""}`);
|
|
506
|
+
const input = props.task.openerLink;
|
|
507
|
+
const data = JSON.parse(atob(input.split("://")[1]));
|
|
508
|
+
data.config.debug = debug;
|
|
509
|
+
const out = "necro://" + btoa(JSON.stringify(data));
|
|
510
|
+
openInNewTab(out);
|
|
553
511
|
};
|
|
554
512
|
|
|
555
513
|
const formatDate = (date) => {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
"Mar",
|
|
567
|
-
"Apr",
|
|
568
|
-
"May",
|
|
569
|
-
"Jun",
|
|
570
|
-
"Jul",
|
|
571
|
-
"Aug",
|
|
572
|
-
"Sep",
|
|
573
|
-
"Oct",
|
|
574
|
-
"Nov",
|
|
575
|
-
"Dec",
|
|
576
|
-
];
|
|
577
|
-
const monthName = monthNames[parseInt(month) - 1];
|
|
578
|
-
return `${dayName} ${monthName} ${parseInt(day)} ${year} ${time}`;
|
|
514
|
+
if (!date) return "-";
|
|
515
|
+
const d = new Date(date);
|
|
516
|
+
const iso = d.toISOString();
|
|
517
|
+
const [year, month, day] = iso.substring(0, 10).split("-");
|
|
518
|
+
const time = iso.substring(11, 16);
|
|
519
|
+
const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
520
|
+
const dayName = dayNames[d.getUTCDay()];
|
|
521
|
+
const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
522
|
+
const monthName = monthNames[parseInt(month) - 1];
|
|
523
|
+
return `${dayName} ${monthName} ${parseInt(day)} ${year} ${time}`;
|
|
579
524
|
};
|
|
580
525
|
|
|
581
526
|
const openInNewTab = (href) => {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
527
|
+
if (!href) return;
|
|
528
|
+
ui.logger.Info("Opening", href);
|
|
529
|
+
Object.assign(document.createElement("a"), {
|
|
530
|
+
target: "_blank",
|
|
531
|
+
rel: "noopener noreferrer",
|
|
532
|
+
href: href
|
|
533
|
+
}).click();
|
|
589
534
|
};
|
|
590
535
|
</script>
|