@necrolab/dashboard 0.5.15 → 0.5.17

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 (137) hide show
  1. package/backend/api.js +2 -3
  2. package/eslint.config.js +46 -0
  3. package/index.html +2 -1
  4. package/package.json +5 -2
  5. package/src/App.vue +70 -566
  6. package/src/assets/css/base/mixins.scss +72 -0
  7. package/src/assets/css/base/reset.scss +0 -2
  8. package/src/assets/css/base/scroll.scss +43 -36
  9. package/src/assets/css/base/typography.scss +9 -10
  10. package/src/assets/css/base/variables.scss +43 -0
  11. package/src/assets/css/components/accessibility.scss +37 -0
  12. package/src/assets/css/components/buttons.scss +61 -74
  13. package/src/assets/css/components/forms.scss +31 -32
  14. package/src/assets/css/components/headers.scss +13 -21
  15. package/src/assets/css/components/modals.scss +2 -2
  16. package/src/assets/css/components/search-groups.scss +28 -22
  17. package/src/assets/css/components/tables.scss +5 -7
  18. package/src/assets/css/components/toasts.scss +7 -7
  19. package/src/assets/css/components/utilities.scss +295 -0
  20. package/src/assets/css/main.scss +55 -139
  21. package/src/components/Auth/LoginForm.vue +7 -86
  22. package/src/components/Console/ConsoleToolbar.vue +123 -0
  23. package/src/components/Editors/Account/Account.vue +12 -12
  24. package/src/components/Editors/Account/AccountView.vue +38 -111
  25. package/src/components/Editors/Account/CreateAccount.vue +11 -61
  26. package/src/components/Editors/Account/{AccountCreator.vue → CreateAccountBatch.vue} +28 -59
  27. package/src/components/Editors/AdminFileEditor.vue +179 -0
  28. package/src/components/Editors/Profile/CreateProfile.vue +77 -150
  29. package/src/components/Editors/Profile/Profile.vue +20 -21
  30. package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
  31. package/src/components/Editors/Profile/ProfileView.vue +41 -116
  32. package/src/components/Editors/ProxyFileEditor.vue +86 -0
  33. package/src/components/Editors/TagLabel.vue +16 -55
  34. package/src/components/Editors/TagToggle.vue +20 -8
  35. package/src/components/Filter/Filter.vue +66 -79
  36. package/src/components/Filter/FilterPreview.vue +153 -135
  37. package/src/components/Filter/PriceSortToggle.vue +36 -43
  38. package/src/components/Table/Header.vue +1 -1
  39. package/src/components/Table/Table.vue +45 -51
  40. package/src/components/Tasks/CheckStock.vue +7 -16
  41. package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
  42. package/src/components/Tasks/Controls/MobileControls.vue +5 -20
  43. package/src/components/Tasks/CreateTaskAXS.vue +20 -118
  44. package/src/components/Tasks/CreateTaskTM.vue +33 -189
  45. package/src/components/Tasks/EventDetailRow.vue +21 -0
  46. package/src/components/Tasks/MassEdit.vue +6 -16
  47. package/src/components/Tasks/QuickSettings.vue +140 -216
  48. package/src/components/Tasks/ScrapeVenue.vue +4 -13
  49. package/src/components/Tasks/Stats.vue +20 -39
  50. package/src/components/Tasks/Task.vue +64 -270
  51. package/src/components/Tasks/TaskLabel.vue +9 -3
  52. package/src/components/Tasks/TaskView.vue +45 -64
  53. package/src/components/Tasks/Utilities.vue +10 -44
  54. package/src/components/Tasks/ViewTask.vue +23 -107
  55. package/src/components/icons/Close.vue +2 -8
  56. package/src/components/icons/Gear.vue +8 -8
  57. package/src/components/icons/Hash.vue +5 -0
  58. package/src/components/icons/Key.vue +2 -8
  59. package/src/components/icons/Pencil.vue +2 -8
  60. package/src/components/icons/Profile.vue +2 -8
  61. package/src/components/icons/Sell.vue +2 -8
  62. package/src/components/icons/Spinner.vue +4 -7
  63. package/src/components/icons/Wildcard.vue +2 -8
  64. package/src/components/icons/index.js +3 -5
  65. package/src/components/ui/ActionButtonGroup.vue +113 -52
  66. package/src/components/ui/BalanceIndicator.vue +60 -0
  67. package/src/components/ui/EmptyState.vue +24 -0
  68. package/src/components/ui/EnableDisableToggle.vue +23 -0
  69. package/src/components/ui/FormField.vue +49 -49
  70. package/src/components/ui/IconLabel.vue +23 -0
  71. package/src/components/ui/InfoRow.vue +21 -54
  72. package/src/components/ui/Modal.vue +161 -54
  73. package/src/components/ui/Navbar.vue +63 -44
  74. package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
  75. package/src/components/ui/ReconnectIndicator.vue +111 -124
  76. package/src/components/ui/SectionCard.vue +6 -14
  77. package/src/components/ui/Splash.vue +2 -10
  78. package/src/components/ui/StatusBadge.vue +26 -28
  79. package/src/components/ui/TaskToggle.vue +54 -0
  80. package/src/components/ui/controls/CountryChooser.vue +29 -66
  81. package/src/components/ui/controls/EyeToggle.vue +1 -1
  82. package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
  83. package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
  84. package/src/components/ui/controls/atomic/MultiDropdown.vue +72 -120
  85. package/src/components/ui/controls/atomic/Switch.vue +21 -84
  86. package/src/composables/useCodeEditor.js +117 -0
  87. package/src/composables/useColorMapping.js +15 -0
  88. package/src/composables/useCopyToClipboard.js +1 -1
  89. package/src/composables/useDateFormatting.js +21 -0
  90. package/src/composables/useDeviceDetection.js +14 -0
  91. package/src/composables/useDropdownPosition.js +1 -4
  92. package/src/composables/useDynamicTableHeight.js +31 -0
  93. package/src/composables/useEnableDisable.js +6 -0
  94. package/src/composables/useFilterCSS.js +71 -0
  95. package/src/composables/useFormValidation.js +92 -0
  96. package/src/composables/useGetAllTags.js +9 -0
  97. package/src/composables/useIOSViewportHandling.js +76 -0
  98. package/src/composables/useNotchHandling.js +306 -0
  99. package/src/composables/useRowSelection.js +0 -3
  100. package/src/composables/useTableRender.js +23 -0
  101. package/src/composables/useTicketPricing.js +16 -0
  102. package/src/composables/useWindowDimensions.js +21 -0
  103. package/src/composables/useZoomPrevention.js +96 -0
  104. package/src/constants/tableLayout.js +14 -0
  105. package/src/libs/Filter.js +14 -20
  106. package/src/libs/panzoom.js +1 -5
  107. package/src/libs/utils/array.js +58 -0
  108. package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
  109. package/src/libs/utils/eventUrl.js +40 -0
  110. package/src/libs/utils/string.js +3 -0
  111. package/src/libs/utils/time.js +20 -0
  112. package/src/libs/utils/validation.js +64 -0
  113. package/src/main.js +0 -2
  114. package/src/stores/connection.js +1 -29
  115. package/src/stores/logger.js +6 -12
  116. package/src/stores/sampleData.js +1 -2
  117. package/src/stores/ui.js +80 -71
  118. package/src/utils/tableHelpers.js +1 -0
  119. package/src/views/Accounts.vue +19 -38
  120. package/src/views/Console.vue +74 -253
  121. package/src/views/Editor.vue +47 -1114
  122. package/src/views/FilterBuilder.vue +190 -461
  123. package/src/views/Login.vue +3 -28
  124. package/src/views/Profiles.vue +17 -32
  125. package/src/views/Tasks.vue +51 -38
  126. package/tailwind.config.js +82 -71
  127. package/workbox-config.cjs +47 -5
  128. package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
  129. package/exit +0 -209
  130. package/run +0 -177
  131. package/src/assets/css/base/color-fallbacks.scss +0 -10
  132. package/src/assets/img/background.svg.backup +0 -11
  133. package/src/components/icons/SquareCheck.vue +0 -18
  134. package/src/components/icons/SquareUncheck.vue +0 -18
  135. package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
  136. package/switch-branch.sh +0 -41
  137. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
package/src/stores/ui.js CHANGED
@@ -3,7 +3,20 @@ import { defineStore } from "pinia";
3
3
  import { ConnectionHandler } from "@/stores/connection.js";
4
4
  import { toast } from "vue3-toastify";
5
5
  import { createLogger } from "@/stores/logger";
6
- import { timeDifference, betterSort, sortTaskIds } from "@/stores/utils";
6
+ import { timeDifference } from "@/libs/utils/time";
7
+ import { betterSort, sortTaskIds } from "@/libs/utils/array";
8
+
9
+ const TOAST_CONFIG = {
10
+ autoClose: 1400,
11
+ pauseOnHover: false,
12
+ hideProgressBar: false,
13
+ closeOnClick: true,
14
+ pauseOnFocusLoss: false,
15
+ transition: "slide",
16
+ position: "top-right",
17
+ closeButton: true,
18
+ newestOnTop: true
19
+ };
7
20
 
8
21
  import mockTaskData from "@/stores/sampleData.js";
9
22
  import { useRouter } from "vue-router";
@@ -56,13 +69,10 @@ export const useUIStore = defineStore("ui", () => {
56
69
  });
57
70
  const taskIdOrder = ref(Object.keys(tasks.value));
58
71
  const modalData = ref({});
59
- const taskFilter = ref("All"); // 'All' or 'Checkout'
72
+ const taskFilter = ref("All");
60
73
  const selectedTaskForView = ref(null);
61
74
  const connection = new ConnectionHandler();
62
75
 
63
- const startPoint = ref(0);
64
- const pullChange = ref(0);
65
-
66
76
  const currentEvent = ref("");
67
77
  const currentCountry = ref({ id: "US", siteId: "TM_US", url: "https://www.ticketmaster.com" });
68
78
  const currentModule = ref("TM");
@@ -99,19 +109,33 @@ export const useUIStore = defineStore("ui", () => {
99
109
  });
100
110
  const currentDropdown = ref("");
101
111
 
102
- // Set the _timeLeftString property every second
103
- setInterval(() => {
104
- const t1 = new Date();
105
- for (const [key, value] of Object.entries(tasks.value)) {
106
- if (value.expirationTime)
107
- tasks.value[key]._timeLeftString =
108
- value.expirationTime == "Invalid Date"
109
- ? "No Cartholds"
110
- : timeDifference(Date.parse(value.expirationTime), t1.getTime());
111
- else tasks.value[key]._timeLeftString = undefined;
112
+ // Optimized: Use requestAnimationFrame instead of setInterval to reduce CPU waste
113
+ // Only update times when tab is visible and at most once per second
114
+ let lastTimeUpdate = 0;
115
+ let lastSyncCheck = 0;
116
+ let rafId = null;
117
+
118
+ const updateTaskTimes = (timestamp) => {
119
+ // Only update once per second
120
+ if (timestamp - lastTimeUpdate >= 1000) {
121
+ lastTimeUpdate = timestamp;
122
+ const now = Date.now();
123
+
124
+ for (const [key, value] of Object.entries(tasks.value)) {
125
+ if (value.expirationTime) {
126
+ tasks.value[key]._timeLeftString =
127
+ value.expirationTime == "Invalid Date"
128
+ ? "No Cartholds"
129
+ : timeDifference(Date.parse(value.expirationTime), now);
130
+ } else {
131
+ tasks.value[key]._timeLeftString = undefined;
132
+ }
133
+ }
112
134
  }
113
135
 
114
- if (t1.getSeconds() % 10 === 0) {
136
+ // Sync taskIdOrder every 10 seconds (optimized with Map for O(1) lookups)
137
+ if (timestamp - lastSyncCheck >= 10000) {
138
+ lastSyncCheck = timestamp;
115
139
  const allIds = new Set(Object.keys(tasks.value));
116
140
  const orderIds = new Set(taskIdOrder.value);
117
141
 
@@ -123,20 +147,44 @@ export const useUIStore = defineStore("ui", () => {
123
147
 
124
148
  if (missingIds.length > 0) {
125
149
  missingIds.sort(sortTaskIds);
150
+ // Optimized: Binary search for insertion point
126
151
  for (const id of missingIds) {
127
- let pos = taskIdOrder.value.length;
128
- for (let i = 0; i < taskIdOrder.value.length; i++) {
129
- if (sortTaskIds(id, taskIdOrder.value[i]) < 0) {
130
- pos = i;
131
- break;
152
+ let left = 0;
153
+ let right = taskIdOrder.value.length;
154
+ while (left < right) {
155
+ const mid = Math.floor((left + right) / 2);
156
+ if (sortTaskIds(id, taskIdOrder.value[mid]) < 0) {
157
+ right = mid;
158
+ } else {
159
+ left = mid + 1;
132
160
  }
133
161
  }
134
- taskIdOrder.value.splice(pos, 0, id);
162
+ taskIdOrder.value.splice(left, 0, id);
135
163
  }
136
164
  }
137
165
  }
138
166
  }
139
- }, 1000);
167
+
168
+ rafId = requestAnimationFrame(updateTaskTimes);
169
+ };
170
+
171
+ rafId = requestAnimationFrame(updateTaskTimes);
172
+
173
+ // Pause updates when tab is hidden to save CPU
174
+ document.addEventListener('visibilitychange', () => {
175
+ if (document.hidden) {
176
+ if (rafId) {
177
+ cancelAnimationFrame(rafId);
178
+ rafId = null;
179
+ }
180
+ } else {
181
+ if (!rafId) {
182
+ lastTimeUpdate = 0;
183
+ lastSyncCheck = 0;
184
+ rafId = requestAnimationFrame(updateTaskTimes);
185
+ }
186
+ }
187
+ });
140
188
 
141
189
  connection.init("/api/updates?type=tasks");
142
190
 
@@ -155,7 +203,6 @@ export const useUIStore = defineStore("ui", () => {
155
203
  document.body.style.top = `-${scrollY}px`;
156
204
  document.body.style.width = "100%";
157
205
  document.body.style.height = "100%";
158
- document.body.style.left = "0"; // Add left positioning
159
206
 
160
207
  // iOS specific properties
161
208
  document.body.style.overflow = "hidden";
@@ -360,19 +407,16 @@ export const useUIStore = defineStore("ui", () => {
360
407
  return selected;
361
408
  };
362
409
 
363
- const getSelectedProfiles = () => {
364
- const res = search.value.profiles.results.filter((p) => p.selected);
365
- if (res.length === 0) return search.value.profiles.results;
366
- else return res;
367
- };
368
- const getSelectedAccounts = () => {
369
- const res = search.value.accounts.results.filter((p) => p.selected);
370
- if (res.length === 0) return search.value.accounts.results;
371
- else return res;
410
+ const getSelectedItems = (source) => {
411
+ const res = source.results.filter((p) => p.selected);
412
+ return res.length === 0 ? source.results : res;
372
413
  };
373
414
 
415
+ const getSelectedProfiles = () => getSelectedItems(search.value.profiles);
416
+ const getSelectedAccounts = () => getSelectedItems(search.value.accounts);
417
+
374
418
  const startSpinner = (msg) => {
375
- if (router.currentRoute.value.name == "login" || window.location.href.includes(":5173")) return;
419
+ if (router.currentRoute.value.name == "login") return;
376
420
  showSpinner.value = true;
377
421
  spinnerMessage.value = msg;
378
422
  preventScroll();
@@ -421,17 +465,12 @@ export const useUIStore = defineStore("ui", () => {
421
465
  reverseTasks,
422
466
 
423
467
  // refresh
424
- startPoint,
425
- pullChange,
426
- setStartPoint: (point) => (startPoint.value = point),
427
- setPullChange: () => (pullChange.value = length),
428
468
  tasks,
429
469
 
430
470
  // top main checkbox
431
471
  mainCheckbox,
432
472
  toggleMainCheckbox,
433
473
 
434
- createAcconts: (cnfg) => connection.sendCreateAccounts(cnfg),
435
474
 
436
475
  // single
437
476
  deleteTask: (taskId) => {
@@ -472,14 +511,6 @@ export const useUIStore = defineStore("ui", () => {
472
511
  const selectedTasks = getSelectedTasks();
473
512
  for (const value of Object.values(selectedTasks)) connection.sendDeleteTask(value.taskId);
474
513
  },
475
- foldTasks: () => {
476
- const selectedTasks = getSelectedTasks();
477
- for (const key of Object.keys(selectedTasks)) tasks.value[key].isExpanded = false;
478
- },
479
- expandTasks: () => {
480
- const selectedTasks = getSelectedTasks();
481
- for (const key of Object.keys(selectedTasks)) tasks.value[key].isExpanded = true;
482
- },
483
514
  startTasks: () => {
484
515
  const selectedTasks = getSelectedTasks();
485
516
  for (const value of Object.values(selectedTasks)) if (!value.active) connection.sendStartTask(value.taskId);
@@ -509,30 +540,8 @@ export const useUIStore = defineStore("ui", () => {
509
540
  massEditPresaleCode: (eventId, presaleCode) => connection.sendMassEditPresaleCode(eventId, presaleCode),
510
541
 
511
542
  // alerts
512
- showError: (err) =>
513
- toast.error(err, {
514
- autoClose: 1400,
515
- pauseOnHover: false,
516
- hideProgressBar: false,
517
- closeOnClick: true,
518
- pauseOnFocusLoss: false,
519
- transition: "slide",
520
- position: "top-right",
521
- closeButton: true,
522
- newestOnTop: true
523
- }),
524
- showSuccess: (msg) =>
525
- toast.success(msg, {
526
- autoClose: 1400,
527
- pauseOnHover: false,
528
- hideProgressBar: false,
529
- closeOnClick: true,
530
- pauseOnFocusLoss: false,
531
- transition: "slide",
532
- position: "top-right",
533
- closeButton: true,
534
- newestOnTop: true
535
- }),
543
+ showError: (err) => toast.error(err, TOAST_CONFIG),
544
+ showSuccess: (msg) => toast.success(msg, TOAST_CONFIG),
536
545
  // Country
537
546
  currentCountry,
538
547
  setCurrentCountry: (country, closeModal, newModule) => {
@@ -0,0 +1 @@
1
+ export const getRowClass = (index) => index % 2 === 1 ? 'table-row-even' : 'table-row-odd';
@@ -13,7 +13,8 @@
13
13
  <button
14
14
  :disabled="ui.disabledButtons['create-accounts']"
15
15
  @click="ui.toggleModal('account-creator', true)"
16
- class="smooth-hover">
16
+ class="smooth-hover"
17
+ aria-label="Create accounts">
17
18
  <PlayIcon class="w-4 h-4" />
18
19
  </button>
19
20
  </li>
@@ -21,7 +22,8 @@
21
22
  <button
22
23
  :disabled="ui.disabledButtons['add-accounts']"
23
24
  @click="ui.toggleModal('create-account', true)"
24
- class="smooth-hover">
25
+ class="smooth-hover"
26
+ aria-label="Add account">
25
27
  <PlusIcon class="w-4 h-4" />
26
28
  </button>
27
29
  </li>
@@ -38,6 +40,7 @@
38
40
  <input
39
41
  class="h-10 w-44 text-white text-sm p-2 bg-dark-500 flex items-center relative"
40
42
  placeholder="Search Email"
43
+ aria-label="Search email"
41
44
  autocomplete="new-password"
42
45
  data-dashlane-rid=""
43
46
  data-dashlane-label=""
@@ -58,59 +61,41 @@
58
61
 
59
62
  <div class="ml-auto gap-2 hidden md:flex">
60
63
  <div
61
- class="bg-dark-400 border border-dark-650 justify-between px-4 w-44 text-white text-xs font-medium items-center rounded-md ml-auto h-10 hidden md:flex">
64
+ class="bg-dark-400 dark-border-rounded-md flex-between px-4 w-44 text-button ml-auto h-10 hidden md:flex">
62
65
  <p>Privacy</p>
63
66
  <Switch class="scale-75" v-model="privacy" />
64
67
  </div>
65
68
  <button
66
69
  :disabled="ui.disabledButtons['create-accounts']"
67
- class="bg-dark-400 disabled:opacity-70 smooth-hover border border-dark-650 hover:border-dark-700 w-44 flex text-white text-xs font-medium justify-center items-center rounded-md ml-auto h-10"
70
+ class="bg-dark-400 disabled:opacity-70 smooth-hover dark-border-rounded-md hover:border-dark-700 btn-focus-ring w-44 flex items-center justify-center gap-2 text-button ml-auto h-10"
68
71
  @click="ui.toggleModal('account-creator')">
69
72
  Create Accounts
70
- <PlayIcon class="ml-2" />
73
+ <PlayIcon class="icon-md" />
71
74
  </button>
72
75
 
73
76
  <button
74
77
  :disabled="ui.disabledButtons['add-accounts']"
75
- class="bg-dark-400 disabled:opacity-70 smooth-hover border border-dark-650 hover:border-dark-700 w-44 flex text-white text-xs font-medium justify-center items-center rounded-md ml-auto h-10"
78
+ class="bg-dark-400 disabled:opacity-70 smooth-hover dark-border-rounded-md hover:border-dark-700 btn-focus-ring w-44 flex items-center justify-center gap-2 text-button ml-auto h-10"
76
79
  @click="ui.toggleModal('create-account')">
77
80
  Add Account
78
- <PlusIcon class="ml-2" />
81
+ <PlusIcon class="icon-md" />
79
82
  </button>
80
83
  </div>
81
84
  </div>
82
85
 
83
86
  <!-- Tasks (Table) -->
84
- <AccountView :accounts="processedTasks" class="max-h-big-acc" />
87
+ <AccountView :accounts="processedTasks" />
85
88
 
86
89
  <!-- Modal -->
87
90
  <transition-group name="fade">
88
91
  <CreateAccount v-if="activeModal === 'create-account'" />
89
- <AccountCreator v-if="activeModal === 'account-creator'" />
92
+ <CreateAccountBatch v-if="activeModal === 'account-creator'" />
90
93
  </transition-group>
91
94
  </div>
92
95
  </template>
93
- <style lang="scss" scoped>
94
- /* Page buttons styling - match Tasks page */
95
- button.bg-dark-400 {
96
- &:active,
97
- &:focus {
98
- outline: 1px solid oklch(0.72 0.15 145);
99
- outline-offset: 0;
100
- border-color: oklch(0.72 0.15 145) !important;
101
- }
102
- }
103
-
104
- .max-h-big-acc {
105
- max-height: calc(100vh - 14rem);
106
- overflow: auto;
107
- }
108
- </style>
109
96
  <script setup>
110
- import { computed, watch, ref } from "vue";
97
+ import { computed, defineAsyncComponent, watch, ref } from "vue";
111
98
  import AccountView from "@/components/Editors/Account/AccountView.vue";
112
- import AccountCreator from "@/components/Editors/Account/AccountCreator.vue";
113
- import CreateAccount from "@/components/Editors/Account/CreateAccount.vue";
114
99
  import { useUIStore } from "@/stores/ui";
115
100
  import { PlusIcon, PlayIcon, MailIcon } from "@/components/icons";
116
101
  import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
@@ -118,6 +103,10 @@ import TagToggle from "@/components/Editors/TagToggle.vue";
118
103
  import Switch from "@/components/ui/controls/atomic/Switch.vue";
119
104
  import EyeToggle from "@/components/ui/controls/EyeToggle.vue";
120
105
 
106
+ // Lazy-loaded modal components
107
+ const CreateAccountBatch = defineAsyncComponent(() => import("@/components/Editors/Account/CreateAccountBatch.vue"));
108
+ const CreateAccount = defineAsyncComponent(() => import("@/components/Editors/Account/CreateAccount.vue"));
109
+
121
110
  const ui = useUIStore();
122
111
  const activeModal = computed(() => ui.activeModal);
123
112
  const allTags = ref([]);
@@ -156,15 +145,7 @@ watch(
156
145
  ui.search.accounts.results = filterAccounts();
157
146
  }
158
147
  );
159
- const getAllTags = () => {
160
- let tags = ["Any"];
161
- ui.search.accounts.results.forEach((p) =>
162
- p.tags.forEach((tag) => {
163
- if (!tags.includes(tag)) tags.push(tag);
164
- })
165
- );
166
- return tags;
167
- };
148
+ import { useGetAllTags } from "@/composables/useGetAllTags";
168
149
 
169
- allTags.value = getAllTags();
150
+ allTags.value = useGetAllTags(ui.search.accounts.results);
170
151
  </script>