Skip to content

Commit 2ffcc62

Browse files
committed
[FEATURE] Clear events automatically
1 parent 5a0bebe commit 2ffcc62

File tree

12 files changed

+512
-5
lines changed

12 files changed

+512
-5
lines changed

src/pages/settings/ui/settings-page-content/settings-page-content.vue

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,28 @@ import { useTitle } from '@vueuse/core'
33
import { storeToRefs } from 'pinia'
44
import { computed } from 'vue'
55
import { THEME_MODES, useSettingsStore } from '@/shared/stores'
6-
import { BadgeNumber, IconSvg } from '@/shared/ui'
6+
import { BadgeNumber, IconSvg, SelectControl } from '@/shared/ui'
77
88
const settingsStore = useSettingsStore()
9-
const { changeTheme, changeNavbar, changeEventCountsVisibility, changeActiveCodeEditor } =
10-
settingsStore
11-
const { themeType, isFixedHeader, isVisibleEventCounts, codeEditor } = storeToRefs(settingsStore)
9+
const {
10+
changeTheme,
11+
changeNavbar,
12+
changeEventCountsVisibility,
13+
setAutoDeleteEventsTime,
14+
changeActiveCodeEditor
15+
} = settingsStore
16+
const { themeType, isFixedHeader, isVisibleEventCounts, autoDeleteEventsTime, codeEditor } =
17+
storeToRefs(settingsStore)
1218
1319
const isDarkMode = computed(() => themeType.value === THEME_MODES.DARK)
1420
21+
const deleteEventsAfter = computed<string>({
22+
get: () => (autoDeleteEventsTime.value === 'none' ? 'none' : String(autoDeleteEventsTime.value)),
23+
set: (val) => {
24+
setAutoDeleteEventsTime(val)
25+
}
26+
})
27+
1528
// TODO: add throttle
1629
const changeCodeEditor = (event: Event) => {
1730
const editor = (event.target as HTMLInputElement).value
@@ -114,6 +127,21 @@ useTitle('Settings | Buggregator')
114127
</div>
115128
</div>
116129

130+
<div class="settings-page-content__title">
131+
Delete Events After:
132+
</div>
133+
134+
<SelectControl
135+
v-model="deleteEventsAfter"
136+
name="delete_events_after"
137+
:options="[
138+
{ value: 'none', text: 'No' },
139+
{ value: '1', text: '1 min' },
140+
{ value: '5', text: '5 min' },
141+
{ value: '10', text: '10 min' }
142+
]"
143+
/>
144+
117145
<div class="settings-page-content__title">
118146
Code Editor Open Link:
119147
</div>
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { storeToRefs } from "pinia";
2+
import { watch } from "vue";
3+
import { useEventsStore, useSettingsStore } from "../../stores";
4+
import type { EventId } from "../../types";
5+
import { useEventsApi } from "./use-events-api";
6+
7+
type AutoDeleteTime = number | "none";
8+
9+
const autoDeleteTimers = new Map<EventId, ReturnType<typeof setTimeout>>();
10+
let autoDeleteInitialized = false;
11+
12+
const toAutoDeleteMs = (val: AutoDeleteTime): number | null => {
13+
if (val === "none") return null;
14+
return val * 60 * 1000;
15+
};
16+
17+
const clearAutoDeleteTimer = (eventId: EventId) => {
18+
const timer = autoDeleteTimers.get(eventId);
19+
if (!timer) return;
20+
globalThis.clearTimeout(timer);
21+
autoDeleteTimers.delete(eventId);
22+
};
23+
24+
const clearAllAutoDeleteTimers = () => {
25+
autoDeleteTimers.forEach((timer) => globalThis.clearTimeout(timer));
26+
autoDeleteTimers.clear();
27+
};
28+
29+
export const ensureAutoDeleteWatcher = () => {
30+
if (autoDeleteInitialized) return;
31+
autoDeleteInitialized = true;
32+
33+
const eventsStore = useEventsStore();
34+
const settingsStore = useSettingsStore();
35+
const eventsApi = useEventsApi();
36+
37+
const { events, lockedIds } = storeToRefs(eventsStore);
38+
const { autoDeleteEventsTime } = storeToRefs(settingsStore);
39+
40+
const schedule = (eventId: EventId) => {
41+
const ms = toAutoDeleteMs(autoDeleteEventsTime.value);
42+
if (ms === null || autoDeleteTimers.has(eventId)) return;
43+
44+
const timer = globalThis.setTimeout(() => {
45+
autoDeleteTimers.delete(eventId);
46+
47+
const locked = lockedIds.value ?? [];
48+
if (locked.includes(eventId)) return;
49+
50+
void eventsApi.removeById(eventId);
51+
}, ms);
52+
53+
autoDeleteTimers.set(eventId, timer);
54+
};
55+
56+
const rescheduleAll = () => {
57+
clearAllAutoDeleteTimers();
58+
59+
const ms = toAutoDeleteMs(autoDeleteEventsTime.value);
60+
if (ms === null) return;
61+
62+
events.value.forEach(({ uuid }) => {
63+
schedule(uuid);
64+
});
65+
};
66+
67+
const syncTimers = (currentIds: Set<EventId>, prevIds: Set<EventId>) => {
68+
prevIds.forEach((id) => {
69+
if (!currentIds.has(id)) {
70+
clearAutoDeleteTimer(id);
71+
}
72+
});
73+
74+
if (toAutoDeleteMs(autoDeleteEventsTime.value) === null) return;
75+
76+
currentIds.forEach((id) => {
77+
if (!prevIds.has(id)) {
78+
schedule(id);
79+
}
80+
});
81+
};
82+
83+
watch(
84+
autoDeleteEventsTime,
85+
() => {
86+
rescheduleAll();
87+
},
88+
{ immediate: true },
89+
);
90+
91+
watch(
92+
() => events.value.map(({ uuid }) => uuid),
93+
(current, prev) => {
94+
const currentIds = new Set(current);
95+
const prevIds = new Set(prev ?? []);
96+
97+
syncTimers(currentIds, prevIds);
98+
},
99+
);
100+
101+
watch(
102+
() => lockedIds.value.slice(),
103+
(current, prev) => {
104+
const currentIds = new Set(current);
105+
const prevIds = new Set(prev ?? []);
106+
107+
const eventsIds = new Set(events.value.map(({ uuid }) => uuid));
108+
const unlockedIds = new Set(
109+
[...prevIds].filter((id) => !currentIds.has(id) && eventsIds.has(id)),
110+
);
111+
112+
syncTimers(currentIds, prevIds);
113+
syncTimers(unlockedIds, new Set<EventId>());
114+
},
115+
);
116+
};

src/shared/lib/use-events/use-events.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { useApiTransport } from "../use-api-transport";
1010
import { normalizeUnknownEvent } from "./normalize-unknown-event";
1111
import { type TUseEventsApi, useEventsApi } from "./use-events-api";
1212

13-
1413
type TUseEvents = () => {
1514
normalizeUnknownEvent: (event: ServerEvent<unknown>) => NormalizedEvent<unknown>
1615
events: TUseEventsApi

src/shared/stores/events/events-store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { defineStore } from "pinia";
22
import { PAGE_TYPES} from "../../constants";
3+
import { ensureAutoDeleteWatcher } from "../../lib/use-events/auto-delete-events";
34
import {useSettings} from "../../lib/use-settings";
45
import {
56
type EventId,
@@ -79,6 +80,7 @@ export const useEventsStore = defineStore("eventsStore", {
7980
async initialize (): Promise<void> {
8081
const {api: { getProjects }} = useSettings();
8182
this.initActiveProjectKey();
83+
ensureAutoDeleteWatcher();
8284

8385
try {
8486
const { data } = await getProjects();

src/shared/stores/settings/local-storage-actions.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,30 @@ export const setStoredEventsCountVisibility = (state: boolean) => {
7070
window?.localStorage?.setItem(LocalStorageKeys.EventCounts, String(state));
7171
}
7272

73+
export const getStoredAutoDeleteEventsTime = (): number | 'none' => {
74+
const raw = window?.localStorage?.getItem(
75+
LocalStorageKeys.AutoDeleteEventsTime,
76+
);
77+
if (raw === null) {
78+
return 'none';
79+
}
80+
const value = Number(raw);
81+
return Number.isFinite(value) && value > 0 ? value : 'none';
82+
};
83+
84+
export const setStoredAutoDeleteEventsTime = (minutes: number | 'none'): void => {
85+
if (minutes === 'none') {
86+
window?.localStorage?.removeItem(
87+
LocalStorageKeys.AutoDeleteEventsTime,
88+
);
89+
return;
90+
}
91+
92+
window?.localStorage?.setItem(
93+
LocalStorageKeys.AutoDeleteEventsTime,
94+
String(minutes),
95+
);
96+
};
7397

7498
export const getStoredPrimaryCodeEditor = (): string => {
7599
const storedCodeEditor = window?.localStorage?.getItem(LocalStorageKeys.CodeEditor);

src/shared/stores/settings/settings-store.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
getStoredFixedHeader,
88
getStoredActiveTheme,
99
setStoredEventsCountVisibility,
10+
getStoredAutoDeleteEventsTime,
11+
setStoredAutoDeleteEventsTime,
1012
setStoredFixedHeader,
1113
setStoredActiveTheme,
1214
getStoredPrimaryCodeEditor,
@@ -23,6 +25,7 @@ export const useSettingsStore = defineStore("settingsStore", {
2325
themeType: getStoredActiveTheme(),
2426
isFixedHeader: getStoredFixedHeader(),
2527
isVisibleEventCounts: getStoredEventsCountVisibility(),
28+
autoDeleteEventsTime: getStoredAutoDeleteEventsTime(),
2629
availableEvents: [] as EventType[],
2730
}),
2831
getters: {
@@ -72,6 +75,19 @@ export const useSettingsStore = defineStore("settingsStore", {
7275

7376
setStoredEventsCountVisibility(this.isVisibleEventCounts)
7477
},
78+
setAutoDeleteEventsTime(value: string | number | 'none') {
79+
const normalized =
80+
value === 'none'
81+
? 'none'
82+
: Number(value);
83+
84+
this.autoDeleteEventsTime =
85+
normalized === 'none' || !Number.isFinite(normalized) || normalized <= 0
86+
? 'none'
87+
: normalized;
88+
89+
setStoredAutoDeleteEventsTime(this.autoDeleteEventsTime);
90+
},
7591
changeActiveCodeEditor(editor: string) {
7692
this.codeEditor = editor;
7793

src/shared/types/local-storage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export enum LocalStorageKeys {
33
Theme = "theme",
44
Navbar = "navbar",
55
EventCounts = "event_counts",
6+
AutoDeleteEventsTime = "autodelete_events_time_in_minutes",
67
CodeEditor = "code_editor",
78
Token = "token",
89
}

0 commit comments

Comments
 (0)