@necrolab/dashboard 0.5.6 → 0.5.7
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/package.json
CHANGED
|
@@ -10,7 +10,25 @@
|
|
|
10
10
|
class="ml-2 mr-4 flex-shrink-0"
|
|
11
11
|
:toggled="props.task.selected"
|
|
12
12
|
@valueUpdate="ui.toggleTaskSelected(props.task.taskId)" />
|
|
13
|
+
<div
|
|
14
|
+
v-if="props.preferEventName && props.task.eventName"
|
|
15
|
+
class="event-details hidden cursor-pointer lg:flex flex-col gap-0.5"
|
|
16
|
+
@click="copy(props.task.eventId)"
|
|
17
|
+
:title="`Event ID: ${props.task.eventId}`">
|
|
18
|
+
<div class="event-name text-white text-xs font-semibold leading-tight">
|
|
19
|
+
{{ props.task.eventName }}
|
|
20
|
+
</div>
|
|
21
|
+
<div v-if="props.task.eventVenue" class="event-venue flex items-center gap-1 text-[10px] text-light-400">
|
|
22
|
+
<StadiumIcon class="w-2.5 h-2.5 flex-shrink-0" />
|
|
23
|
+
<span class="truncate">{{ props.task.eventVenue }}</span>
|
|
24
|
+
</div>
|
|
25
|
+
<div v-if="props.task.eventLocalDate" class="event-date flex items-center gap-1 text-[10px] text-light-400">
|
|
26
|
+
<TimerIcon class="w-2.5 h-2.5 flex-shrink-0" />
|
|
27
|
+
<span>{{ formatEventDate(props.task.eventLocalDate) }}</span>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
13
30
|
<h4
|
|
31
|
+
v-else
|
|
14
32
|
class="task-event-id mx-auto hidden cursor-pointer text-white hover:text-light-300 lg:block"
|
|
15
33
|
@click="copy(props.task.eventId)">
|
|
16
34
|
{{ props.task.eventId }}
|
|
@@ -375,7 +393,7 @@ h4 {
|
|
|
375
393
|
/// <reference path="@/types/index.js" />
|
|
376
394
|
|
|
377
395
|
import { Row } from "@/components/Table";
|
|
378
|
-
import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon, EyeIcon } from "@/components/icons";
|
|
396
|
+
import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon, EyeIcon, StadiumIcon, TimerIcon } from "@/components/icons";
|
|
379
397
|
import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
|
|
380
398
|
import { useUIStore } from "@/stores/ui";
|
|
381
399
|
import TaskLabel from "@/components/Tasks/TaskLabel.vue";
|
|
@@ -386,9 +404,29 @@ const ui = useUIStore();
|
|
|
386
404
|
|
|
387
405
|
/** @type {{ task: Task }} */
|
|
388
406
|
const props = defineProps({
|
|
389
|
-
task: { type: Object }
|
|
407
|
+
task: { type: Object },
|
|
408
|
+
preferEventName: { type: Boolean, default: false }
|
|
390
409
|
});
|
|
391
410
|
|
|
411
|
+
// Format event date for display
|
|
412
|
+
const formatEventDate = (dateString) => {
|
|
413
|
+
if (!dateString) return '';
|
|
414
|
+
try {
|
|
415
|
+
const date = new Date(dateString);
|
|
416
|
+
const options = {
|
|
417
|
+
month: 'short',
|
|
418
|
+
day: 'numeric',
|
|
419
|
+
year: 'numeric',
|
|
420
|
+
hour: 'numeric',
|
|
421
|
+
minute: '2-digit',
|
|
422
|
+
hour12: true
|
|
423
|
+
};
|
|
424
|
+
return date.toLocaleString('en-US', options).replace(',', '');
|
|
425
|
+
} catch {
|
|
426
|
+
return dateString;
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
|
|
392
430
|
// Context menu positioning
|
|
393
431
|
const contextMenuPosition = ref({});
|
|
394
432
|
const contextMenuRef = ref(null);
|
|
@@ -14,31 +14,31 @@
|
|
|
14
14
|
<UpIcon v-if="ui.sortData.sortBy === 'eventId' && ui.sortData.reversed" class="ml-1" />
|
|
15
15
|
</div>
|
|
16
16
|
</div>
|
|
17
|
-
<div class="col-span-2 flex items-center justify-start" v-once>
|
|
17
|
+
<div class="col-span-2 flex items-center justify-start lg:justify-center" v-once>
|
|
18
18
|
<TicketIcon class="mr-0 lg:mr-3" />
|
|
19
19
|
<h4 class="hidden lg:flex">Tickets</h4>
|
|
20
20
|
</div>
|
|
21
|
-
<div
|
|
21
|
+
<div
|
|
22
|
+
class="col-span-5 flex items-center justify-center md:col-span-4 lg:col-span-5"
|
|
23
|
+
@click="ui.toggleSort('status')">
|
|
22
24
|
<StatusIcon class="mr-0 lg:mr-3" />
|
|
23
25
|
<h4 class="hidden lg:flex">Status</h4>
|
|
24
26
|
<DownIcon v-if="ui.sortData.sortBy === 'status' && !ui.sortData.reversed" class="ml-1" />
|
|
25
27
|
<UpIcon v-if="ui.sortData.sortBy === 'status' && ui.sortData.reversed" class="ml-1" />
|
|
26
28
|
</div>
|
|
27
|
-
<div class="col-span-2
|
|
29
|
+
<div class="col-span-2 flex items-center justify-center lg:col-span-3" v-once>
|
|
28
30
|
<ClickIcon class="mr-0 lg:mr-3" />
|
|
29
31
|
<h4 class="hidden lg:flex">Actions</h4>
|
|
30
32
|
</div>
|
|
31
|
-
<div class="absolute right-5 top-3.5 hidden items-center lg:flex"
|
|
33
|
+
<div class="absolute right-5 top-3.5 hidden items-center lg:flex">
|
|
32
34
|
<h4 class="text-center text-xs">ID</h4>
|
|
33
|
-
<DownIcon v-if="ui.sortData.sortBy === 'taskId' && !ui.sortData.reversed" class="ml-1" />
|
|
34
|
-
<UpIcon v-if="ui.sortData.sortBy === 'taskId' && ui.sortData.reversed" class="ml-1" />
|
|
35
35
|
</div>
|
|
36
36
|
</Header>
|
|
37
37
|
<div
|
|
38
38
|
class="hidden-scrollbars stop-pan flex flex-col divide-y divide-dark-650 overflow-y-auto overflow-x-hidden"
|
|
39
39
|
:style="{ maxHeight: dynamicTableHeight }">
|
|
40
40
|
<div v-for="(task, i) in getTasksInOrder()" :key="task.taskId" class="task-row-container">
|
|
41
|
-
<Task :task="task" :class="i % 2 == 1 ? 'table-row-even' : 'table-row-odd'" />
|
|
41
|
+
<Task :task="task" :preferEventName="props.preferEventName" :class="i % 2 == 1 ? 'table-row-even' : 'table-row-odd'" />
|
|
42
42
|
</div>
|
|
43
43
|
<div
|
|
44
44
|
v-if="getTasksInOrder().length === 0"
|
|
@@ -104,12 +104,13 @@ import { useUIStore } from "@/stores/ui";
|
|
|
104
104
|
|
|
105
105
|
const props = defineProps({
|
|
106
106
|
tasks: { type: Object },
|
|
107
|
-
searchQuery: { type: String, default:
|
|
107
|
+
searchQuery: { type: String, default: "" },
|
|
108
|
+
preferEventName: { type: Boolean, default: false }
|
|
108
109
|
});
|
|
109
110
|
|
|
110
111
|
const shouldTaskShow = (task) => {
|
|
111
112
|
if (ui.taskFilter === "All") return true;
|
|
112
|
-
else if (ui.taskFilter === "Checkout") return task.
|
|
113
|
+
else if (ui.taskFilter === "Checkout") return Boolean(task.checkoutUrl);
|
|
113
114
|
else return true;
|
|
114
115
|
};
|
|
115
116
|
|
|
@@ -124,7 +125,7 @@ const siteIdEdgeCases = {
|
|
|
124
125
|
|
|
125
126
|
const getTasksInOrder = () => {
|
|
126
127
|
let out = [];
|
|
127
|
-
const searchLower = props.searchQuery?.toLowerCase().trim() ||
|
|
128
|
+
const searchLower = props.searchQuery?.toLowerCase().trim() || "";
|
|
128
129
|
|
|
129
130
|
ui.taskIdOrder.forEach((id) => {
|
|
130
131
|
if (props.tasks[id] && !props.tasks[id]?.hidden) {
|
|
@@ -150,7 +151,10 @@ const getTasksInOrder = () => {
|
|
|
150
151
|
task.profileName,
|
|
151
152
|
task.presaleCode,
|
|
152
153
|
task.reservedTicketsList
|
|
153
|
-
]
|
|
154
|
+
]
|
|
155
|
+
.filter(Boolean)
|
|
156
|
+
.join(" ")
|
|
157
|
+
.toLowerCase();
|
|
154
158
|
|
|
155
159
|
if (!searchableText.includes(searchLower)) return;
|
|
156
160
|
}
|
|
@@ -185,9 +189,14 @@ const dynamicTableHeight = computed(() => {
|
|
|
185
189
|
const controlsHeight = windowWidth.value >= 650 ? 55 : 0; // Desktop controls
|
|
186
190
|
// On desktop: stats + filters all in one row (45px)
|
|
187
191
|
// On mobile: stats row (40px) + filters stacked (90px) = 130px
|
|
188
|
-
const filtersAndStatsHeight =
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
const filtersAndStatsHeight =
|
|
193
|
+
windowWidth.value >= 768
|
|
194
|
+
? ui.queueStats.show
|
|
195
|
+
? 50
|
|
196
|
+
: 45 // Desktop: single row
|
|
197
|
+
: ui.queueStats.show
|
|
198
|
+
? 130
|
|
199
|
+
: 90; // Mobile: stats row + stacked filters
|
|
191
200
|
const utilitiesHeight = windowWidth.value <= 768 ? 180 : 160; // Increase mobile utilities space to prevent cutoff
|
|
192
201
|
const margins =
|
|
193
202
|
windowWidth.value >= 1024 ? 20 : windowWidth.value <= 480 && windowHeight.value > windowWidth.value ? 8 : 12;
|
package/src/views/Tasks.vue
CHANGED
|
@@ -45,13 +45,19 @@
|
|
|
45
45
|
|
|
46
46
|
<div class="flex md:hidden items-center justify-between gap-2 mb-1">
|
|
47
47
|
<Stats class="stats-component flex-1" />
|
|
48
|
-
<
|
|
49
|
-
class="
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
<div class="flex gap-2 items-center">
|
|
49
|
+
<div class="bg-dark-400 border border-dark-650 justify-between px-2 flex text-white text-xs font-medium items-center rounded-md h-8">
|
|
50
|
+
<p class="text-[10px]">Name</p>
|
|
51
|
+
<Switch class="scale-75" v-model="preferEventName" />
|
|
52
|
+
</div>
|
|
53
|
+
<PriceSortToggle
|
|
54
|
+
class="min-w-20 max-w-28 flex-shrink-0 h-8"
|
|
55
|
+
:options="['All', 'Checkout']"
|
|
56
|
+
:darker="true"
|
|
57
|
+
:current="ui.taskFilter"
|
|
58
|
+
@change="(e) => ui.setTaskFilter(e)"
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
55
61
|
</div>
|
|
56
62
|
|
|
57
63
|
<div class="hidden md:flex items-center gap-2 lg:mb-2 mb-1">
|
|
@@ -80,6 +86,10 @@
|
|
|
80
86
|
<span v-if="taskSearchQuery" class="ml-2 text-xs text-light-500">{{ filteredTaskCount }}</span>
|
|
81
87
|
</div>
|
|
82
88
|
</div>
|
|
89
|
+
<div class="bg-dark-400 border border-dark-650 justify-between px-3 w-32 flex text-white text-xs font-medium items-center rounded-md h-10">
|
|
90
|
+
<p>Name</p>
|
|
91
|
+
<Switch class="scale-75" v-model="preferEventName" />
|
|
92
|
+
</div>
|
|
83
93
|
<PriceSortToggle
|
|
84
94
|
class="min-w-24 max-w-28 flex-shrink-0"
|
|
85
95
|
:options="['All', 'Checkout']"
|
|
@@ -118,7 +128,7 @@
|
|
|
118
128
|
</div>
|
|
119
129
|
</div>
|
|
120
130
|
|
|
121
|
-
<TaskView class="lg:mb-3 mb-2" :tasks="ui.tasks" :searchQuery="taskSearchQuery" />
|
|
131
|
+
<TaskView class="lg:mb-3 mb-2" :tasks="ui.tasks" :searchQuery="taskSearchQuery" :preferEventName="preferEventName" />
|
|
122
132
|
|
|
123
133
|
<Utilities class="utilities-section" />
|
|
124
134
|
</div>
|
|
@@ -230,7 +240,7 @@
|
|
|
230
240
|
}
|
|
231
241
|
</style>
|
|
232
242
|
<script setup>
|
|
233
|
-
import { computed, onMounted, ref } from "vue";
|
|
243
|
+
import { computed, onMounted, ref, watch } from "vue";
|
|
234
244
|
import { DesktopControls } from "@/components/Tasks/Controls";
|
|
235
245
|
import TaskView from "@/components/Tasks/TaskView.vue";
|
|
236
246
|
import ViewTask from "@/components/Tasks/ViewTask.vue";
|
|
@@ -242,6 +252,7 @@ import ScrapeVenue from "@/components/Tasks/ScrapeVenue.vue";
|
|
|
242
252
|
import MassEditPresaleCode from "@/components/Tasks/MassEdit.vue";
|
|
243
253
|
import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
|
|
244
254
|
import Stats from "@/components/Tasks/Stats.vue";
|
|
255
|
+
import Switch from "@/components/ui/controls/atomic/Switch.vue";
|
|
245
256
|
import { useUIStore } from "@/stores/ui";
|
|
246
257
|
import { TrashIcon, GearIcon, PlusIcon, PlayIcon, PauseIcon } from "@/components/icons";
|
|
247
258
|
import QuickSettings from "@/components/Tasks/QuickSettings.vue";
|
|
@@ -253,6 +264,13 @@ const taskCount = computed(() => Object.keys(ui.getSelectedTasks()).length);
|
|
|
253
264
|
ui.refreshQueueStats();
|
|
254
265
|
|
|
255
266
|
const taskSearchQuery = ref('');
|
|
267
|
+
// Load preference from localStorage, default to true
|
|
268
|
+
const preferEventName = ref(localStorage.getItem('preferEventName') !== 'false');
|
|
269
|
+
|
|
270
|
+
// Persist preference to localStorage when changed
|
|
271
|
+
watch(preferEventName, (newValue) => {
|
|
272
|
+
localStorage.setItem('preferEventName', String(newValue));
|
|
273
|
+
});
|
|
256
274
|
|
|
257
275
|
const filteredTaskCount = computed(() => {
|
|
258
276
|
if (!taskSearchQuery.value.trim()) return '';
|