Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: admin search mailbox && fix generateName multi dot && user jwt exp in 30 days && UI globalTabplacement && useSideMargin #214

Merged
merged 5 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
### function changs

- 增加用户注册功能,可绑定邮箱地址,绑定后可自动获取邮箱JWT凭证
- 增加默认以文本显示邮件,文本和HTML邮箱显示方式切换按钮
- 修复 `BUG` 随机生成的邮箱名字不合法 #211
- `admin` 邮件页面支持邮件内容搜索 #210
- 修复删除地址时邮件未删除的BUG #213
- UI 增加全局标签页位置配置, 侧边距配置

## v0.3.3

Expand Down
9 changes: 5 additions & 4 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import Header from './views/Header.vue';
import Footer from './views/Footer.vue';


const { localeCache, isDark, loading } = useGlobalState()
const { localeCache, isDark, loading, useSideMargin } = useGlobalState()
const theme = computed(() => isDark.value ? darkTheme : null)
const localeConfig = computed(() => localeCache.value == 'zh' ? zhCN : null)
const isMobile = useIsMobile()
const showSideMargin = computed(() => !isMobile.value && !useSideMargin.value);

const { locale } = useI18n({
useScope: 'global',
Expand Down Expand Up @@ -39,8 +40,8 @@ onMounted(async () => {
<n-spin description="loading..." :show="loading">
<n-message-provider>
<n-grid x-gap="12" :cols="12">
<n-gi v-if="!isMobile" span="1"></n-gi>
<n-gi :span="isMobile ? 12 : 10">
<n-gi v-if="!showSideMargin" span="1"></n-gi>
<n-gi :span="showSideMargin ? 12 : 10">
<div class="main">
<n-space vertical>
<n-layout style="min-height: 80vh;">
Expand All @@ -51,7 +52,7 @@ onMounted(async () => {
</n-space>
</div>
</n-gi>
<n-gi v-if="!isMobile" span="1"></n-gi>
<n-gi v-if="!showSideMargin" span="1"></n-gi>
</n-grid>
<n-back-top />
</n-message-provider>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {

const instance = axios.create({
baseURL: API_BASE,
timeout: 10000
timeout: 30000
});

const apiFetch = async (path, options = {}) => {
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export const useGlobalState = createGlobalState(
const userJwt = useStorage('userJwt', '');
const userTab = useStorage('userTab', 'user_settings');
const indexTab = useStorage('indexTab', 'mailbox');
const globalTabplacement = useStorage('globalTabplacement', 'top');
const useSideMargin = useStorage('useSideMargin', true);
const userOpenSettings = ref({
enable: false,
enableMailVerify: false,
Expand Down Expand Up @@ -91,6 +93,8 @@ export const useGlobalState = createGlobalState(
indexTab,
userOpenSettings,
userSettings,
globalTabplacement,
useSideMargin,
}
},
)
16 changes: 13 additions & 3 deletions frontend/src/views/Admin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import UserSettings from './admin/UserSettings.vue';
import Mails from './admin/Mails.vue';
import MailsUnknow from './admin/MailsUnknow.vue';
import Maintenance from './admin/Maintenance.vue';
import Appearance from './common/Appearance.vue';

const {
localeCache, adminAuth, showAdminAuth, adminTab, loading
localeCache, adminAuth, showAdminAuth, adminTab, loading, globalTabplacement
} = useGlobalState()
const message = useMessage()

Expand All @@ -44,7 +45,9 @@ const { t } = useI18n({
unknow: 'Mails with unknow receiver',
senderAccess: 'Sender Access Control',
sendBox: 'Send Box',
statistics: 'Statistics',
maintenance: 'Maintenance',
appearance: 'Appearance',
ok: 'OK',
},
zh: {
Expand All @@ -59,7 +62,9 @@ const { t } = useI18n({
unknow: '无收件人邮件',
senderAccess: '发件权限控制',
sendBox: '发件箱',
statistics: '统计',
maintenance: '维护',
appearance: '外观',
ok: '确定',
}
}
Expand All @@ -85,8 +90,7 @@ onMounted(async () => {
</n-button>
</template>
</n-modal>
<Statistics />
<n-tabs type="card" v-model:value="adminTab">
<n-tabs type="card" v-model:value="adminTab" :placement="globalTabplacement">
<n-tab-pane name="account" :tab="t('account')">
<Account />
</n-tab-pane>
Expand Down Expand Up @@ -114,9 +118,15 @@ onMounted(async () => {
<n-tab-pane name="sendBox" :tab="t('sendBox')">
<SendBox />
</n-tab-pane>
<n-tab-pane name="statistics" :tab="t('statistics')">
<Statistics />
</n-tab-pane>
<n-tab-pane name="maintenance" :tab="t('maintenance')">
<Maintenance />
</n-tab-pane>
<n-tab-pane name="appearance" :tab="t('appearance')">
<Appearance />
</n-tab-pane>
</n-tabs>
</div>
</template>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/views/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import SendBox from './index/SendBox.vue';
import SendMail from './index/SendMail.vue';
import AccountSettings from './index/AccountSettings.vue';

const { localeCache, settings, openSettings, indexTab } = useGlobalState()
const { localeCache, settings, openSettings, indexTab, globalTabplacement } = useGlobalState()

const { t } = useI18n({
locale: localeCache.value || 'zh',
Expand Down Expand Up @@ -45,7 +45,7 @@ const deleteMail = async (curMailId) => {
<template>
<div>
<AddressBar />
<n-tabs v-if="settings.address" type="card" v-model:value="indexTab">
<n-tabs v-if="settings.address" type="card" v-model:value="indexTab" :placement="globalTabplacement">
<n-tab-pane name="mailbox" :tab="t('mailbox')">
<MailBox :showEMailTo="false" :showReply="true" :enableUserDeleteEmail="openSettings.enableUserDeleteEmail"
:fetchMailData="fetchMailData" :deleteMail="deleteMail" />
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/views/User.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import UserBar from './user/UserBar.vue';
import BindAddress from './user/BindAddress.vue';

const {
localeCache, userTab, userOpenSettings, userSettings
localeCache, userTab, globalTabplacement, userSettings
} = useGlobalState()

const { t } = useI18n({
Expand All @@ -33,7 +33,7 @@ const { t } = useI18n({
<template>
<div>
<UserBar />
<n-tabs v-if="userSettings.user_email" type="card" v-model:value="userTab">
<n-tabs v-if="userSettings.user_email" type="card" v-model:value="userTab" :placement="globalTabplacement">
<n-tab-pane name="address_management" :tab="t('address_management')">
<AddressMangement />
</n-tab-pane>
Expand Down
18 changes: 14 additions & 4 deletions frontend/src/views/admin/Mails.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted } from 'vue';
import { ref, onMounted, watch } from 'vue';
import { useI18n } from 'vue-i18n'

import { useGlobalState } from '../../store'
Expand All @@ -16,19 +16,27 @@ const { t } = useI18n({
messages: {
en: {
addressQueryTip: 'Leave blank to query all addresses',
keywordQueryTip: 'Leave blank to not query by keyword',
query: 'Query',
},
zh: {
addressQueryTip: '留空查询所有地址',
keywordQueryTip: '留空不按关键字查询',
query: '查询',
}
}
});

const mailBoxKey = ref("")
const mailKeyword = ref("")

const queryAddress = () => {
mailBoxKey.value = adminMailTabAddress.value;
watch([adminMailTabAddress, mailKeyword], () => {
adminMailTabAddress.value = adminMailTabAddress.value.trim();
mailKeyword.value = mailKeyword.value.trim();
});

const queryMail = () => {
mailBoxKey.value = Date.now();
}

const fetchMailData = async (limit, offset) => {
Expand All @@ -37,6 +45,7 @@ const fetchMailData = async (limit, offset) => {
+ `?limit=${limit}`
+ `&offset=${offset}`
+ (adminMailTabAddress.value ? `&address=${adminMailTabAddress.value}` : '')
+ (mailKeyword.value ? `&keyword=${mailKeyword.value}` : '')
);
}

Expand All @@ -52,7 +61,8 @@ onMounted(async () => {
<div>
<n-input-group>
<n-input v-model:value="adminMailTabAddress" :placeholder="t('addressQueryTip')" />
<n-button @click="queryAddress" type="primary" tertiary>
<n-input v-model:value="mailKeyword" :placeholder="t('keywordQueryTip')" />
<n-button @click="queryMail" type="primary" tertiary>
{{ t('query') }}
</n-button>
</n-input-group>
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/views/admin/Maintenance.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const { t } = useI18n({
autoCleanup: "Auto cleanup",
cleanupSuccess: "Cleanup success",
save: "Save",
cronTip: "Enable cron cleanup, need to configure [crons] in worker, please refer to the document",
},
zh: {
tip: '请输入清理天数',
Expand All @@ -43,6 +44,7 @@ const { t } = useI18n({
cleanupSuccess: "清理成功",
cleanupNow: "立即清理",
save: "保存",
cronTip: "启用定时清理, 需在 worker 配置 [crons] 参数, 请参考文档",
}
}
});
Expand Down Expand Up @@ -93,6 +95,9 @@ onMounted(async () => {
<template>
<div class="center">
<n-card>
<n-alert :show-icon="false">
<span>{{ t('cronTip') }}</span>
</n-alert>
<n-form :model="cleanupModel">
<n-form-item-row :label="t('mailBoxLabel')">
<n-checkbox v-model:checked="cleanupModel.enableMailsAutoCleanup">
Expand Down Expand Up @@ -162,6 +167,10 @@ onMounted(async () => {
justify-content: center;
}

.n-alert {
margin-bottom: 20px;
}

.item {
display: flex;
margin: 10px;
Expand Down
82 changes: 82 additions & 0 deletions frontend/src/views/common/Appearance.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script setup>
import { useI18n } from 'vue-i18n'

import { useGlobalState } from '../../store'

const {
localeCache, mailboxSplitSize, useIframeShowMail, preferShowTextMail,
globalTabplacement, useSideMargin
} = useGlobalState()

const { t } = useI18n({
locale: localeCache.value || 'zh',
messages: {
en: {
mailboxSplitSize: 'Mailbox Split Size',
useIframeShowMail: 'Use iframe Show HTML Mail',
preferShowTextMail: 'Display text Mail by default',
useSideMargin: 'Turn on the side margins on the left and right sides of the page',
globalTabplacement: 'Global Tab Placement',
left: 'left',
top: 'top',
right: 'right',
bottom: 'bottom',
},
zh: {
mailboxSplitSize: '邮箱界面分栏大小',
preferShowTextMail: '默认以文本显示邮件',
useIframeShowMail: '使用iframe显示HTML邮件',
globalTabplacement: '全局选项卡位置',
useSideMargin: '开启页面左右两侧侧边距',
left: '左侧',
top: '顶部',
right: '右侧',
bottom: '底部',
}
}
});
</script>

<template>
<div class="center">
<n-card>
<n-form-item-row :label="t('mailboxSplitSize')">
<n-slider v-model:value="mailboxSplitSize" :min="0.25" :max="0.75" :step="0.01" :marks="{
0.25: '0.25',
0.5: '0.5',
0.75: '0.75'
}" />
</n-form-item-row>
<n-form-item-row :label="t('preferShowTextMail')">
<n-switch v-model:value="preferShowTextMail" :round="false" />
</n-form-item-row>
<n-form-item-row :label="t('useIframeShowMail')">
<n-switch v-model:value="useIframeShowMail" :round="false" />
</n-form-item-row>
<n-form-item-row :label="t('useSideMargin')">
<n-switch v-model:value="useSideMargin" :round="false" />
</n-form-item-row>
<n-form-item-row :label="t('globalTabplacement')">
<n-radio-group v-model:value="globalTabplacement">
<n-radio-button value="top" :label="t('top')" />
<n-radio-button value="left" :label="t('left')" />
<n-radio-button value="right" :label="t('right')" />
<n-radio-button value="bottom" :label="t('bottom')" />
</n-radio-group>
</n-form-item-row>
</n-card>
</div>
</template>

<style scoped>
.center {
display: flex;
justify-content: center;
}


.n-card {
max-width: 800px;
text-align: left;
}
</style>
26 changes: 3 additions & 23 deletions frontend/src/views/index/AccountSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { useRouter } from 'vue-router'

import { useGlobalState } from '../../store'
import { api } from '../../api'
import Appearance from '../common/Appearance.vue'

const {
jwt, localeCache, settings, showAddressCredential, loading,
mailboxSplitSize, useIframeShowMail, preferShowTextMail
jwt, localeCache, settings, showAddressCredential, loading
} = useGlobalState()
const router = useRouter()
const message = useMessage()
Expand All @@ -19,9 +19,6 @@ const { t } = useI18n({
locale: localeCache.value || 'zh',
messages: {
en: {
mailboxSplitSize: 'Mailbox Split Size',
useIframeShowMail: 'Use iframe Show HTML Mail',
preferShowTextMail: 'Display text Mail by default',
logout: "Logout",
delteAccount: "Delete Account",
showAddressCredential: 'Show Address Credential',
Expand All @@ -30,9 +27,6 @@ const { t } = useI18n({
delteAccountConfirm: "Are you sure to delete your account and all emails for this account?",
},
zh: {
mailboxSplitSize: '邮箱界面分栏大小',
preferShowTextMail: '默认以文本显示邮件',
useIframeShowMail: '使用iframe显示HTML邮件',
logout: '退出登录',
delteAccount: "删除账户",
showAddressCredential: '查看邮箱地址凭证',
Expand Down Expand Up @@ -66,21 +60,7 @@ const deleteAccount = async () => {
<template>
<div class="center" v-if="settings.address">
<n-card>
<n-card>
<n-form-item-row :label="t('mailboxSplitSize')">
<n-slider v-model:value="mailboxSplitSize" :min="0.25" :max="0.75" :step="0.01" :marks="{
0.25: '0.25',
0.5: '0.5',
0.75: '0.75'
}" />
</n-form-item-row>
<n-form-item-row :label="t('preferShowTextMail')">
<n-switch v-model:value="preferShowTextMail" :round="false" />
</n-form-item-row>
<n-form-item-row :label="t('useIframeShowMail')">
<n-switch v-model:value="useIframeShowMail" :round="false" />
</n-form-item-row>
</n-card>
<Appearance />
<n-button @click="showAddressCredential = true" type="primary" secondary block strong>
{{ t('showAddressCredential') }}
</n-button>
Expand Down
Loading