release: v1.0.4
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
Publish Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Canceled after 0s
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Canceled after 0s
Publish Docker image / merge (push) Canceled after 0s
ci / ci (22, ubuntu-latest) (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
Add PasswordInput with show/hide toggle, align legacy setup/register routing, merge duplicate i18n keys, and remove unused jose dependency.
This commit is contained in:
1 parent
661146ce20
commit
7c45a78572
13 files changed
+107
-70
No files matched your search
@@ -23,6 +23,18 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
cache: npm
|
||||
|
||||
- name: Install npm 11
|
||||
run: npm install -g npm@11.12.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Extract release notes from CHANGELOG
|
||||
id: notes
|
||||
run: |
|
||||
|
||||
@@ -36,3 +36,7 @@ data
|
||||
|
||||
# 本地 Git hooks 模板(仅安装在 .git/hooks/,不进仓库)
|
||||
git-hooks/
|
||||
|
||||
# 飞牛 fpk 工程与产物(仅本地维护,不进仓库)
|
||||
scripts/fpk/
|
||||
dist-fpk/
|
||||
@@ -2,6 +2,21 @@
|
||||
|
||||
本仓库自 **v1.0.0** 起作为正式版维护;此前历史提交已归档重置。
|
||||
|
||||
## [1.0.4] - 2026-08-25
|
||||
|
||||
### 新增
|
||||
|
||||
- 密码输入框支持显示/隐藏切换(`PasswordInput` 组件,含无障碍文案)
|
||||
|
||||
### 改进
|
||||
|
||||
- 遗留 `ADMIN_SECRET` 部署:`/setup`、`/register` 路由与 `needsMigration` 检测对齐
|
||||
- 合并重复的密码不一致 i18n 文案;移除未使用的 `jose` 依赖
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复 `PasswordInput` 导致 CI typecheck 失败
|
||||
|
||||
## [1.0.3] - 2026-08-23
|
||||
|
||||
### 修复
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
import logoLight from '~/assets/image/logo-light.png'
|
||||
import logoDark from '~/assets/image/logo-dark.png'
|
||||
|
||||
const emit = defineEmits<{
|
||||
success: []
|
||||
}>()
|
||||
|
||||
const router = useRouter()
|
||||
const { login, fetchStatus, authStatus } = useAuth()
|
||||
const toast = useToast()
|
||||
@@ -47,7 +43,6 @@ async function submit() {
|
||||
username.value = ''
|
||||
password.value = ''
|
||||
secret.value = ''
|
||||
emit('success')
|
||||
toast.add({ title: t('auth.loginSuccess'), color: 'success' })
|
||||
} else {
|
||||
toast.add({
|
||||
@@ -108,15 +103,11 @@ async function submit() {
|
||||
>
|
||||
{{ t('auth.adminSecret') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="admin-secret"
|
||||
v-model="secret"
|
||||
type="password"
|
||||
:placeholder="t('auth.adminSecretPlaceholder')"
|
||||
autocomplete="current-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
@keyup.enter="submit"
|
||||
/>
|
||||
<p class="text-xs leading-relaxed text-muted">
|
||||
@@ -151,15 +142,11 @@ async function submit() {
|
||||
>
|
||||
{{ t('auth.password') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="login-password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
:placeholder="t('auth.password')"
|
||||
autocomplete="current-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
@keyup.enter="submit"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const model = defineModel<string>({ default: '' })
|
||||
|
||||
defineProps<{
|
||||
id?: string
|
||||
placeholder?: string
|
||||
autocomplete?: string
|
||||
}>()
|
||||
|
||||
const show = ref(false)
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UInput
|
||||
:id="id"
|
||||
v-model="model"
|
||||
:type="show ? 'text' : 'password'"
|
||||
:placeholder="placeholder"
|
||||
:autocomplete="autocomplete"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full', trailing: 'pe-1' }"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<template #trailing>
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="link"
|
||||
size="sm"
|
||||
:icon="show ? 'i-lucide-eye-off' : 'i-lucide-eye'"
|
||||
:aria-label="show ? t('auth.hidePassword') : t('auth.showPassword')"
|
||||
:aria-pressed="show"
|
||||
:aria-controls="id"
|
||||
type="button"
|
||||
@click="() => { show = !show }"
|
||||
/>
|
||||
</template>
|
||||
</UInput>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(::-ms-reveal) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -38,7 +38,7 @@ async function submit() {
|
||||
if (!canSubmit.value || loading.value) return
|
||||
|
||||
if (newPassword.value !== confirmPassword.value) {
|
||||
toast.add({ title: t('password.mismatch'), color: 'error' })
|
||||
toast.add({ title: t('auth.passwordMismatch'), color: 'error' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,14 +101,10 @@ async function submit() {
|
||||
>
|
||||
{{ t('password.current') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="current-password"
|
||||
v-model="currentPassword"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -119,15 +115,11 @@ async function submit() {
|
||||
>
|
||||
{{ t('password.new') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="new-password"
|
||||
v-model="newPassword"
|
||||
type="password"
|
||||
:placeholder="t('password.newPlaceholder')"
|
||||
autocomplete="new-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
/>
|
||||
<PasswordStrength :password="newPassword" />
|
||||
</div>
|
||||
@@ -139,14 +131,10 @@ async function submit() {
|
||||
>
|
||||
{{ t('password.confirmNew') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="confirm-new-password"
|
||||
v-model="confirmPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
+3
-11
@@ -22,7 +22,7 @@ const canSubmit = computed(() =>
|
||||
|
||||
onMounted(async () => {
|
||||
const status = await fetchStatus()
|
||||
if (!status.initialized) {
|
||||
if (!status.initialized && !status.legacyMode) {
|
||||
await router.replace('/setup')
|
||||
return
|
||||
}
|
||||
@@ -118,15 +118,11 @@ async function submit() {
|
||||
>
|
||||
{{ t('auth.password') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="register-password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
:placeholder="t('setup.passwordPlaceholder')"
|
||||
autocomplete="new-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
/>
|
||||
<PasswordStrength :password="password" />
|
||||
</div>
|
||||
@@ -138,15 +134,11 @@ async function submit() {
|
||||
>
|
||||
{{ t('auth.confirmPassword') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="register-confirm"
|
||||
v-model="confirmPassword"
|
||||
type="password"
|
||||
:placeholder="t('setup.confirmPlaceholder')"
|
||||
autocomplete="new-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
+9
-11
@@ -9,7 +9,8 @@ const { setup, migrate, fetchStatus } = useAuth()
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
|
||||
const isMigrate = computed(() => route.query.migrate === '1')
|
||||
const needsMigration = ref(false)
|
||||
const isMigrate = computed(() => needsMigration.value || route.query.migrate === '1')
|
||||
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
@@ -26,6 +27,11 @@ const canSubmit = computed(() =>
|
||||
|
||||
onMounted(async () => {
|
||||
const status = await fetchStatus()
|
||||
needsMigration.value = status.needsMigration
|
||||
if (status.legacyMode && !status.needsMigration) {
|
||||
await router.replace('/')
|
||||
return
|
||||
}
|
||||
if (status.initialized && !status.needsMigration) {
|
||||
await router.replace('/')
|
||||
}
|
||||
@@ -129,15 +135,11 @@ async function submit() {
|
||||
>
|
||||
{{ t('auth.password') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="setup-password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
:placeholder="t('setup.passwordPlaceholder')"
|
||||
autocomplete="new-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
/>
|
||||
<PasswordStrength :password="password" />
|
||||
</div>
|
||||
@@ -149,15 +151,11 @@ async function submit() {
|
||||
>
|
||||
{{ t('auth.confirmPassword') }}
|
||||
</label>
|
||||
<UInput
|
||||
<PasswordInput
|
||||
id="setup-confirm"
|
||||
v-model="confirmPassword"
|
||||
type="password"
|
||||
:placeholder="t('setup.confirmPlaceholder')"
|
||||
autocomplete="new-password"
|
||||
size="lg"
|
||||
class="w-full"
|
||||
:ui="{ root: 'w-full' }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
"setupFailed": "Setup failed. Check your input",
|
||||
"migrateFailed": "Migration failed. Check your input",
|
||||
"passwordMismatch": "Passwords do not match",
|
||||
"showPassword": "Show password",
|
||||
"hidePassword": "Hide password",
|
||||
"registerSuccess": "Registered successfully",
|
||||
"errors": {
|
||||
"invalidUsername": "Username must be 3–32 letters, numbers, or underscores",
|
||||
@@ -93,7 +95,6 @@
|
||||
"new": "New password",
|
||||
"confirmNew": "Confirm new password",
|
||||
"newPlaceholder": "Set new password",
|
||||
"mismatch": "New passwords do not match",
|
||||
"changed": "Password updated",
|
||||
"tooShort": "New password must be at least 8 characters",
|
||||
"changeFailed": "Failed to change password",
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
"setupFailed": "初始化失败,请检查输入",
|
||||
"migrateFailed": "迁移失败,请检查输入",
|
||||
"passwordMismatch": "两次输入的密码不一致",
|
||||
"showPassword": "显示密码",
|
||||
"hidePassword": "隐藏密码",
|
||||
"registerSuccess": "注册成功",
|
||||
"errors": {
|
||||
"invalidUsername": "用户名需为 3–32 位字母、数字或下划线",
|
||||
@@ -93,7 +95,6 @@
|
||||
"new": "新密码",
|
||||
"confirmNew": "确认新密码",
|
||||
"newPlaceholder": "设置新密码",
|
||||
"mismatch": "两次输入的新密码不一致",
|
||||
"changed": "密码已修改",
|
||||
"tooShort": "新密码至少 8 位",
|
||||
"changeFailed": "修改密码失败",
|
||||
|
||||
Generated
+2
-12
@@ -1,19 +1,18 @@
|
||||
{
|
||||
"name": "pichost",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pichost",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iconify-json/lucide": "^1.2.114",
|
||||
"@nuxt/ui": "^4.9.0",
|
||||
"@nuxtjs/i18n": "^10.6.0",
|
||||
"jose": "^6.0.11",
|
||||
"nuxt": "^4.4.8",
|
||||
"sharp": "^0.35.3",
|
||||
"tailwindcss": "^4.3.1"
|
||||
@@ -12242,15 +12241,6 @@
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/jose/-/jose-6.2.3.tgz",
|
||||
"integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
||||
+1
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pichost",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"description": "Self-hosted image hosting for your NAS / home server — Nuxt admin UI, local disk storage, server-side WebP compression, referer protection, Twikoo/EasyImage compatible.",
|
||||
"homepage": "https://github.com/O96u/PicHost#readme",
|
||||
"repository": {
|
||||
@@ -39,7 +39,6 @@
|
||||
"@iconify-json/lucide": "^1.2.114",
|
||||
"@nuxt/ui": "^4.9.0",
|
||||
"@nuxtjs/i18n": "^10.6.0",
|
||||
"jose": "^6.0.11",
|
||||
"nuxt": "^4.4.8",
|
||||
"sharp": "^0.35.3",
|
||||
"tailwindcss": "^4.3.1"
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@ import { defineConfig } from 'vitest/config'
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: 'node',
|
||||
include: ['server/**/*.test.ts']
|
||||
include: ['server/**/*.test.ts', 'scripts/**/*.test.ts']
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user