Files
cloudflare_temp_email/frontend/src/views/index/AutoReply.vue
Dream Hunter 5f3762ef58 fix: auto-reply not triggering when source_prefix is empty (#880)
* fix: auto-reply not triggering when source_prefix is empty (#459)

- Empty source_prefix now matches all senders (was short-circuiting as falsy)
- Support regex matching with /pattern/ syntax in source_prefix
- Backward compatible: plain strings still use startsWith
- Use E2E_TEST_MODE switch to skip cloudflare:email import in tests
- Track reply() calls in E2E mock for testability

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: update auto-reply UI labels for regex support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update changelogs for auto-reply fix and regex feature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: upgrade version to v1.5.0

- Update version number to 1.5.0 in all package.json files and constants.ts
- Split CHANGELOG: v1.4.0 entries finalized, new v1.5.0(main) section with auto-reply changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add error logging for invalid regex in auto-reply source_prefix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: address CodeRabbit review suggestions

- Use const object instead of let for mock state tracking
- Add log when auto-reply subject/message falls back to defaults

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add source_prefix regex syntax to auto-reply docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:08:06 +08:00

140 lines
4.0 KiB
Vue

<script setup>
import { useI18n } from 'vue-i18n'
import { onMounted, ref } from 'vue'
import { useGlobalState } from '../../store'
import { api } from '../../api'
const message = useMessage()
const sourcePrefix = ref("")
const enableAutoReply = ref(false)
const autoReplyMessage = ref("")
const subject = ref("")
const name = ref("")
const { settings } = useGlobalState()
const { t } = useI18n({
locale: 'zh',
messages: {
en: {
success: 'Success',
settings: 'Settings',
sourcePrefix: 'Sender Filter',
sourcePrefixPlaceholder: 'Empty=all, prefix match, or /regex/',
name: 'Name',
enableAutoReply: 'Enable Auto Reply',
subject: 'Subject',
autoReply: 'Auto Reply',
save: 'Save',
},
zh: {
success: '成功',
settings: '设置',
sourcePrefix: '发件人过滤',
sourcePrefixPlaceholder: '留空=全部匹配,前缀匹配,或 /正则/',
name: '名称',
enableAutoReply: '启用自动回复',
subject: '主题',
autoReply: '自动回复',
save: '保存',
}
}
});
const fetchData = async () => {
try {
const res = await api.fetch("/api/auto_reply")
sourcePrefix.value = res.source_prefix || ""
enableAutoReply.value = res.enabled || false
name.value = res.name || ""
autoReplyMessage.value = res.message || ""
subject.value = res.subject || ""
} catch (error) {
message.error(error.message || "error");
}
}
const saveData = async () => {
try {
await api.fetch("/api/auto_reply", {
method: "POST",
body: JSON.stringify({
auto_reply: {
enabled: enableAutoReply.value,
source_prefix: sourcePrefix.value,
name: name.value,
message: autoReplyMessage.value,
subject: subject.value,
}
})
})
message.success(t("success"))
} catch (error) {
message.error(error.message || "error");
}
}
onMounted(async () => {
await fetchData()
})
</script>
<template>
<div class="center">
<n-card :bordered="false" embedded v-if="settings.address" :title='t("settings")'>
<div class="right">
<n-button type="primary" @click="saveData">{{ t('save') }}</n-button>
</div>
<div class="left">
<n-form-item :label="t('enableAutoReply')" label-placement="left">
<n-switch v-model:value="enableAutoReply" />
</n-form-item>
<n-form-item :label="t('name')" label-placement="left">
<n-input :disabled="!enableAutoReply" v-model:value="name" />
</n-form-item>
<n-form-item :label="t('sourcePrefix')" label-placement="left">
<n-input :disabled="!enableAutoReply" v-model:value="sourcePrefix"
:placeholder="t('sourcePrefixPlaceholder')" />
</n-form-item>
<n-form-item :label="t('subject')" label-placement="left">
<n-input :disabled="!enableAutoReply" v-model:value="subject" />
</n-form-item>
<n-form-item :label="t('autoReply')" label-placement="left">
<n-input :disabled="!enableAutoReply" type="textarea" v-model:value="autoReplyMessage" />
</n-form-item>
</div>
</n-card>
</div>
</template>
<style scoped>
.n-card {
max-width: 800px;
}
.n-button {
text-align: left;
}
.center {
display: flex;
text-align: center;
place-items: center;
justify-content: center;
}
.left {
text-align: left;
place-items: left;
justify-content: left;
}
.right {
text-align: right;
place-items: right;
justify-content: right;
}
</style>