Skip to content

Commit 2bbde15

Browse files
feat: add clear inbox and sent items functionality (#720)
- Add clear inbox/sent items APIs for users and admins - Implement ENABLE_USER_DELETE_EMAIL permission checks - Fix multilingual support for success messages - Update Vue to 3.5.21 and Wrangler to 4.34.0 - Add UI components for clearing email data in account settings 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <[email protected]>
1 parent 37cf077 commit 2bbde15

File tree

12 files changed

+1547
-1326
lines changed

12 files changed

+1547
-1326
lines changed

frontend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"naive-ui": "^2.42.0",
3131
"postal-mime": "^2.4.4",
3232
"vooks": "^0.2.12",
33-
"vue": "^3.5.20",
33+
"vue": "^3.5.21",
3434
"vue-clipboard3": "^2.0.0",
3535
"vue-i18n": "^11.1.11",
3636
"vue-router": "^4.5.1"
@@ -47,7 +47,7 @@
4747
"vite-plugin-wasm": "^3.5.0",
4848
"workbox-build": "^7.3.0",
4949
"workbox-window": "^7.3.0",
50-
"wrangler": "^4.33.0"
50+
"wrangler": "^4.34.0"
5151
},
5252
"packageManager": "[email protected]+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
5353
}

frontend/pnpm-lock.yaml

Lines changed: 282 additions & 273 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/views/admin/Account.vue

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ const { t } = useI18n({
3333
itemCount: 'itemCount',
3434
query: 'Query',
3535
addressQueryTip: 'Leave blank to query all addresses',
36-
actions: 'Actions'
36+
clearInbox: 'Clear Inbox',
37+
clearSentItems: 'Clear Sent Items',
38+
clearInboxTip: 'Are you sure to clear inbox for this email?',
39+
clearSentItemsTip: 'Are you sure to clear sent items for this email?',
40+
actions: 'Actions',
41+
success: 'Success',
3742
},
3843
zh: {
3944
name: '名称',
@@ -52,14 +57,21 @@ const { t } = useI18n({
5257
itemCount: '总数',
5358
query: '查询',
5459
addressQueryTip: '留空查询所有地址',
60+
clearInbox: '清空收件箱',
61+
clearSentItems: '清空发件箱',
62+
clearInboxTip: '确定要清空这个邮箱的收件箱吗?',
63+
clearSentItemsTip: '确定要清空这个邮箱的发件箱吗?',
5564
actions: '操作',
65+
success: '成功',
5666
}
5767
}
5868
});
5969
6070
const showEmailCredential = ref(false)
6171
const curEmailCredential = ref("")
6272
const curDeleteAddressId = ref(0);
73+
const curClearInboxAddressId = ref(0);
74+
const curClearSentItemsAddressId = ref(0);
6375
6476
const addressQuery = ref("")
6577
@@ -68,6 +80,8 @@ const count = ref(0)
6880
const page = ref(1)
6981
const pageSize = ref(20)
7082
const showDeleteAccount = ref(false)
83+
const showClearInbox = ref(false)
84+
const showClearSentItems = ref(false)
7185
7286
const showCredential = async (id) => {
7387
try {
@@ -83,7 +97,7 @@ const showCredential = async (id) => {
8397
const deleteEmail = async () => {
8498
try {
8599
await api.adminDeleteAddress(curDeleteAddressId.value)
86-
message.success("success");
100+
message.success(t("success"));
87101
await fetchData()
88102
} catch (error) {
89103
message.error(error.message || "error");
@@ -92,6 +106,34 @@ const deleteEmail = async () => {
92106
}
93107
}
94108
109+
const clearInbox = async () => {
110+
try {
111+
await api.fetch(`/admin/clear_inbox/${curClearInboxAddressId.value}`, {
112+
method: 'DELETE'
113+
});
114+
message.success(t("success"));
115+
await fetchData()
116+
} catch (error) {
117+
message.error(error.message || "error");
118+
} finally {
119+
showClearInbox.value = false
120+
}
121+
}
122+
123+
const clearSentItems = async () => {
124+
try {
125+
await api.fetch(`/admin/clear_sent_items/${curClearSentItemsAddressId.value}`, {
126+
method: 'DELETE'
127+
});
128+
message.success(t("success"));
129+
await fetchData()
130+
} catch (error) {
131+
message.error(error.message || "error");
132+
} finally {
133+
showClearSentItems.value = false
134+
}
135+
}
136+
95137
const fetchData = async () => {
96138
try {
97139
addressQuery.value = addressQuery.value.trim()
@@ -228,6 +270,32 @@ const columns = [
228270
),
229271
show: row.send_count > 0
230272
},
273+
{
274+
label: () => h(NButton,
275+
{
276+
text: true,
277+
onClick: () => {
278+
curClearInboxAddressId.value = row.id;
279+
showClearInbox.value = true;
280+
}
281+
},
282+
{ default: () => t('clearInbox') }
283+
),
284+
show: row.mail_count > 0
285+
},
286+
{
287+
label: () => h(NButton,
288+
{
289+
text: true,
290+
onClick: () => {
291+
curClearSentItemsAddressId.value = row.id;
292+
showClearSentItems.value = true;
293+
}
294+
},
295+
{ default: () => t('clearSentItems') }
296+
),
297+
show: row.send_count > 0
298+
},
231299
{
232300
label: () => h(NButton,
233301
{
@@ -281,6 +349,22 @@ onMounted(async () => {
281349
</n-button>
282350
</template>
283351
</n-modal>
352+
<n-modal v-model:show="showClearInbox" preset="dialog" :title="t('clearInbox')">
353+
<p>{{ t('clearInboxTip') }}</p>
354+
<template #action>
355+
<n-button :loading="loading" @click="clearInbox" size="small" tertiary type="error">
356+
{{ t('clearInbox') }}
357+
</n-button>
358+
</template>
359+
</n-modal>
360+
<n-modal v-model:show="showClearSentItems" preset="dialog" :title="t('clearSentItems')">
361+
<p>{{ t('clearSentItemsTip') }}</p>
362+
<template #action>
363+
<n-button :loading="loading" @click="clearSentItems" size="small" tertiary type="error">
364+
{{ t('clearSentItems') }}
365+
</n-button>
366+
</template>
367+
</n-modal>
284368
<n-input-group>
285369
<n-input v-model:value="addressQuery" clearable :placeholder="t('addressQueryTip')"
286370
@keydown.enter="fetchData" />

frontend/src/views/index/AccountSettings.vue

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import { api } from '../../api'
88
import { getRouterPathWithLang } from '../../utils'
99
1010
const {
11-
jwt, settings, showAddressCredential, loading
11+
jwt, settings, showAddressCredential, loading, openSettings
1212
} = useGlobalState()
1313
const router = useRouter()
1414
const message = useMessage()
1515
1616
const showLogout = ref(false)
1717
const showDeleteAccount = ref(false)
18+
const showClearInbox = ref(false)
19+
const showClearSentItems = ref(false)
1820
const { locale, t } = useI18n({
1921
messages: {
2022
en: {
@@ -24,6 +26,11 @@ const { locale, t } = useI18n({
2426
logoutConfirm: 'Are you sure to logout?',
2527
deleteAccount: "Delete Account",
2628
deleteAccountConfirm: "Are you sure to delete your account and all emails for this account?",
29+
clearInbox: "Clear Inbox",
30+
clearSentItems: "Clear Sent Items",
31+
clearInboxConfirm: "Are you sure to clear all emails in your inbox?",
32+
clearSentItemsConfirm: "Are you sure to clear all emails in your sent items?",
33+
success: "Success",
2734
},
2835
zh: {
2936
logout: '退出登录',
@@ -32,6 +39,11 @@ const { locale, t } = useI18n({
3239
logoutConfirm: '确定要退出登录吗?',
3340
deleteAccount: "删除账户",
3441
deleteAccountConfirm: "确定要删除你的账户和其中的所有邮件吗?",
42+
clearInbox: "清空收件箱",
43+
clearSentItems: "清空发件箱",
44+
clearInboxConfirm: "确定要清空你收件箱中的所有邮件吗?",
45+
clearSentItemsConfirm: "确定要清空你发件箱中的所有邮件吗?",
46+
success: "成功",
3547
}
3648
}
3749
});
@@ -54,6 +66,32 @@ const deleteAccount = async () => {
5466
message.error(error.message || "error");
5567
}
5668
};
69+
70+
const clearInbox = async () => {
71+
try {
72+
await api.fetch(`/api/clear_inbox`, {
73+
method: 'DELETE'
74+
});
75+
message.success(t("success"));
76+
} catch (error) {
77+
message.error(error.message || "error");
78+
} finally {
79+
showClearInbox.value = false;
80+
}
81+
};
82+
83+
const clearSentItems = async () => {
84+
try {
85+
await api.fetch(`/api/clear_sent_items`, {
86+
method: 'DELETE'
87+
});
88+
message.success(t("success"));
89+
} catch (error) {
90+
message.error(error.message || "error");
91+
} finally {
92+
showClearSentItems.value = false;
93+
}
94+
};
5795
</script>
5896

5997
<template>
@@ -62,10 +100,19 @@ const deleteAccount = async () => {
62100
<n-button @click="showAddressCredential = true" type="primary" secondary block strong>
63101
{{ t('showAddressCredential') }}
64102
</n-button>
103+
<n-button v-if="openSettings.enableUserDeleteEmail" @click="showClearInbox = true" type="warning" secondary
104+
block strong>
105+
{{ t('clearInbox') }}
106+
</n-button>
107+
<n-button v-if="openSettings.enableUserDeleteEmail" @click="showClearSentItems = true" type="warning"
108+
secondary block strong>
109+
{{ t('clearSentItems') }}
110+
</n-button>
65111
<n-button @click="showLogout = true" secondary block strong>
66112
{{ t('logout') }}
67113
</n-button>
68-
<n-button @click="showDeleteAccount = true" type="error" secondary block strong>
114+
<n-button v-if="openSettings.enableUserDeleteEmail" @click="showDeleteAccount = true" type="error" secondary
115+
block strong>
69116
{{ t('deleteAccount') }}
70117
</n-button>
71118
</n-card>
@@ -85,6 +132,22 @@ const deleteAccount = async () => {
85132
</n-button>
86133
</template>
87134
</n-modal>
135+
<n-modal v-model:show="showClearInbox" preset="dialog" :title="t('clearInbox')">
136+
<p>{{ t('clearInboxConfirm') }}</p>
137+
<template #action>
138+
<n-button :loading="loading" @click="clearInbox" size="small" tertiary type="warning">
139+
{{ t('clearInbox') }}
140+
</n-button>
141+
</template>
142+
</n-modal>
143+
<n-modal v-model:show="showClearSentItems" preset="dialog" :title="t('clearSentItems')">
144+
<p>{{ t('clearSentItemsConfirm') }}</p>
145+
<template #action>
146+
<n-button :loading="loading" @click="clearSentItems" size="small" tertiary type="warning">
147+
{{ t('clearSentItems') }}
148+
</n-button>
149+
</template>
150+
</n-modal>
88151
</div>
89152
</template>
90153

pages/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"author": "",
1212
"license": "ISC",
1313
"devDependencies": {
14-
"wrangler": "^4.33.0"
14+
"wrangler": "^4.34.0"
1515
},
1616
"packageManager": "[email protected]+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
1717
}

vitepress-docs/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
"version": "1.0.5",
55
"type": "module",
66
"devDependencies": {
7-
"@types/node": "^24.3.0",
7+
"@types/node": "^24.3.1",
88
"vitepress": "^1.6.4",
9-
"wrangler": "^4.33.0"
9+
"wrangler": "^4.34.0"
1010
},
1111
"scripts": {
1212
"dev": "vitepress dev docs",

0 commit comments

Comments
 (0)