Skip to content

Commit fe0420c

Browse files
committed
cr
1 parent ea683a6 commit fe0420c

File tree

8 files changed

+82
-20
lines changed

8 files changed

+82
-20
lines changed

app/components/Package/DeprecatePackageModal.vue

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ const props = withDefaults(
99
defineProps<{
1010
packageName: string
1111
version?: string
12+
/** When true, the package or version is already deprecated; form is hidden and state cannot be changed. */
13+
isAlreadyDeprecated?: boolean
1214
}>(),
13-
{ version: '' },
15+
{ version: '', isAlreadyDeprecated: false },
1416
)
1517
1618
const { t } = useI18n()
@@ -32,6 +34,7 @@ const modalTitle = computed(() =>
3234
)
3335
3436
async function handleDeprecate() {
37+
if (props.isAlreadyDeprecated) return
3538
const message = deprecateMessage.value.trim()
3639
if (!isConnected.value) return
3740
@@ -119,8 +122,32 @@ defineExpose({ open, close })
119122

120123
<template>
121124
<Modal ref="dialogRef" :modal-title="modalTitle" id="deprecate-package-modal" class="max-w-md">
125+
<!-- Already deprecated: read-only, no form -->
126+
<div v-if="isAlreadyDeprecated" class="space-y-4">
127+
<div
128+
class="flex items-center gap-3 p-4 bg-amber-500/10 border border-amber-500/20 rounded-lg"
129+
>
130+
<span class="i-carbon-warning-alt text-amber-500 w-6 h-6" aria-hidden="true" />
131+
<div>
132+
<p class="font-mono text-sm text-fg">
133+
{{ $t('package.deprecation.modal.already_deprecated') }}
134+
</p>
135+
<p class="text-xs text-fg-muted">
136+
{{ $t('package.deprecation.modal.already_deprecated_detail') }}
137+
</p>
138+
</div>
139+
</div>
140+
<button
141+
type="button"
142+
class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
143+
@click="close"
144+
>
145+
{{ $t('common.close') }}
146+
</button>
147+
</div>
148+
122149
<!-- Success state -->
123-
<div v-if="deprecateSuccess" class="space-y-4">
150+
<div v-else-if="deprecateSuccess" class="space-y-4">
124151
<div
125152
class="flex items-center gap-3 p-4 bg-green-500/10 border border-green-500/20 rounded-lg"
126153
>
@@ -141,7 +168,7 @@ defineExpose({ open, close })
141168
</button>
142169
</div>
143170

144-
<!-- Form (only shown when connected; parent only opens modal when isConnected) -->
171+
<!-- Form (only shown when not already deprecated and connected) -->
145172
<div v-else class="space-y-4">
146173
<div>
147174
<label for="deprecate-message" class="block text-sm font-medium text-fg mb-1">

app/pages/package/[[org]]/[name].vue

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ const latestVersion = computed(() => {
204204
return pkg.value.versions[latestTag] ?? null
205205
})
206206
207+
/** True when the currently displayed version (or resolved version) is deprecated; used to hide deprecate button. */
208+
const isCurrentVersionDeprecated = computed(() => {
209+
if (displayVersion.value?.deprecated) return true
210+
const ver = resolvedVersion.value
211+
return !!(ver && pkg.value?.versions?.[ver]?.deprecated)
212+
})
213+
207214
const deprecationNotice = computed(() => {
208215
if (!displayVersion.value?.deprecated) return null
209216
@@ -1202,19 +1209,18 @@ onKeyStroke(
12021209
<!-- Maintainers (with admin actions when connected) -->
12031210
<PackageMaintainers :package-name="pkg.name" :maintainers="pkg.maintainers" />
12041211

1205-
<!-- Deprecation (when connected as package owner) -->
1206-
<div v-if="isConnected && resolvedVersion && isPackageOwner" class="space-y-1">
1212+
<!-- Deprecation (when connected as package owner; hidden when current version is already deprecated) -->
1213+
<div
1214+
v-if="isConnected && resolvedVersion && isPackageOwner && !isCurrentVersionDeprecated"
1215+
class="space-y-1"
1216+
>
12071217
<button
12081218
type="button"
12091219
class="flex items-center justify-center w-full px-3 py-1.5 bg-bg-subtle rounded text-sm font-mono text-red-400 hover:text-red-500 transition-colors inline-flex items-center gap-1.5 w-full"
12101220
@click="deprecateModal?.open()"
12111221
>
12121222
<span class="i-carbon-warning-alt w-4 h-4 shrink-0" aria-hidden="true" />
1213-
{{
1214-
deprecationNotice
1215-
? $t('package.deprecation.action_change')
1216-
: $t('package.deprecation.action')
1217-
}}
1223+
{{ $t('package.deprecation.action') }}
12181224
</button>
12191225
</div>
12201226
</div>
@@ -1243,6 +1249,7 @@ onKeyStroke(
12431249
ref="deprecateModal"
12441250
:package-name="pkg.name"
12451251
:version="resolvedVersion ?? ''"
1252+
:is-already-deprecated="isCurrentVersionDeprecated"
12461253
/>
12471254
</ClientOnly>
12481255
</main>

i18n/locales/en.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@
122122
"copy_name": "Copy package name",
123123
"deprecation": {
124124
"action": "Deprecate",
125-
"action_change": "Change deprecation",
126125
"package": "This package has been deprecated.",
127126
"version": "This version has been deprecated.",
128127
"no_reason": "No reason provided",
@@ -135,7 +134,9 @@
135134
"success": "Package deprecated",
136135
"success_detail": "The package has been deprecated.",
137136
"version": "Version",
138-
"version_placeholder": "Leave empty to deprecate the whole package"
137+
"version_placeholder": "Leave empty to deprecate the whole package",
138+
"already_deprecated": "Already deprecated",
139+
"already_deprecated_detail": "This package or version is already deprecated. Deprecation status cannot be changed."
139140
}
140141
},
141142
"replacement": {

i18n/locales/zh-CN.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@
122122
"copy_name": "复制包名",
123123
"deprecation": {
124124
"action": "废弃",
125-
"action_change": "修改弃用",
126125
"package": "这个包已经被弃用。",
127126
"version": "这个版本已经被弃用。",
128127
"no_reason": "没有提供原因",
@@ -135,7 +134,9 @@
135134
"success": "包已废弃",
136135
"success_detail": "这个包已废弃。",
137136
"version": "版本",
138-
"version_placeholder": "留空则废弃整个包"
137+
"version_placeholder": "留空则废弃整个包",
138+
"already_deprecated": "已废弃",
139+
"already_deprecated_detail": "该包或版本已处于废弃状态,无法再修改废弃状态。"
139140
}
140141
},
141142
"replacement": {

lunaria/files/en-GB.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@
122122
"copy_name": "Copy package name",
123123
"deprecation": {
124124
"action": "Deprecate",
125-
"action_change": "Change deprecation",
126125
"package": "This package has been deprecated.",
127126
"version": "This version has been deprecated.",
128127
"no_reason": "No reason provided",
@@ -135,7 +134,9 @@
135134
"success": "Package deprecated",
136135
"success_detail": "The package has been deprecated.",
137136
"version": "Version",
138-
"version_placeholder": "Leave empty to deprecate the whole package"
137+
"version_placeholder": "Leave empty to deprecate the whole package",
138+
"already_deprecated": "Already deprecated",
139+
"already_deprecated_detail": "This package or version is already deprecated. Deprecation status cannot be changed."
139140
}
140141
},
141142
"replacement": {

lunaria/files/en-US.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@
122122
"copy_name": "Copy package name",
123123
"deprecation": {
124124
"action": "Deprecate",
125-
"action_change": "Change deprecation",
126125
"package": "This package has been deprecated.",
127126
"version": "This version has been deprecated.",
128127
"no_reason": "No reason provided",
@@ -135,7 +134,9 @@
135134
"success": "Package deprecated",
136135
"success_detail": "The package has been deprecated.",
137136
"version": "Version",
138-
"version_placeholder": "Leave empty to deprecate the whole package"
137+
"version_placeholder": "Leave empty to deprecate the whole package",
138+
"already_deprecated": "Already deprecated",
139+
"already_deprecated_detail": "This package or version is already deprecated. Deprecation status cannot be changed."
139140
}
140141
},
141142
"replacement": {

lunaria/files/zh-CN.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@
122122
"copy_name": "复制包名",
123123
"deprecation": {
124124
"action": "废弃",
125-
"action_change": "修改弃用",
126125
"package": "这个包已经被弃用。",
127126
"version": "这个版本已经被弃用。",
128127
"no_reason": "没有提供原因",
@@ -135,7 +134,9 @@
135134
"success": "包已废弃",
136135
"success_detail": "这个包已废弃。",
137136
"version": "版本",
138-
"version_placeholder": "留空则废弃整个包"
137+
"version_placeholder": "留空则废弃整个包",
138+
"already_deprecated": "已废弃",
139+
"already_deprecated_detail": "该包或版本已处于废弃状态,无法再修改废弃状态。"
139140
}
140141
},
141142
"replacement": {

test/nuxt/components/DeprecatePackageModal.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ describe('DeprecatePackageModal', () => {
114114
expect(versionInput.exists()).toBe(true)
115115
expect((versionInput.element as HTMLInputElement).value).toBe('2.0.0')
116116
})
117+
118+
it('shows already-deprecated message and no form when isAlreadyDeprecated is true', async () => {
119+
const component = await mountSuspended(DeprecatePackageModal, {
120+
props: { packageName: 'my-pkg', version: '1.0.0', isAlreadyDeprecated: true },
121+
...mountOptions,
122+
})
123+
124+
expect(component.find('#deprecate-message').exists()).toBe(false)
125+
expect(component.find('#deprecate-version').exists()).toBe(false)
126+
expect(component.html()).toMatch(/already deprecated|/i)
127+
})
117128
})
118129

119130
describe('exposed open() and close()', () => {
@@ -189,6 +200,18 @@ describe('DeprecatePackageModal', () => {
189200
expect(mockAddOperation).not.toHaveBeenCalled()
190201
})
191202

203+
it('handleDeprecate does nothing when isAlreadyDeprecated is true', async () => {
204+
mockIsConnected.value = true
205+
const component = await mountSuspended(DeprecatePackageModal, {
206+
props: { packageName: 'pkg', isAlreadyDeprecated: true },
207+
...mountOptions,
208+
})
209+
210+
await getVM(component).handleDeprecate?.()
211+
212+
expect(mockAddOperation).not.toHaveBeenCalled()
213+
})
214+
192215
it('handleDeprecate does nothing when message is empty', async () => {
193216
const component = await mountSuspended(DeprecatePackageModal, {
194217
props: { packageName: 'pkg' },

0 commit comments

Comments
 (0)