diff --git a/.gitignore b/.gitignore index 9aa2aebd2e..1b9e60a676 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ test-results # Test coverage coverage/ +*.junit.xml # Playwright playwright-report/ diff --git a/app/components/Package/DeprecatePackageModal.vue b/app/components/Package/DeprecatePackageModal.vue new file mode 100644 index 0000000000..ba9dd07d53 --- /dev/null +++ b/app/components/Package/DeprecatePackageModal.vue @@ -0,0 +1,274 @@ + + + + + + + + + + + {{ + deprecateVersion + ? $t('package.deprecation.modal.already_deprecated_version') + : $t('package.deprecation.modal.already_deprecated') + }} + + + {{ $t('package.deprecation.modal.already_deprecated_detail') }} + + + + + {{ $t('common.close') }} + + + + + + + + + {{ $t('package.deprecation.modal.success') }} + + {{ $t('package.deprecation.modal.success_detail') }} + + + + + {{ $t('common.close') }} + + + + + + + + + + + {{ $t('package.deprecation.modal.already_deprecated_version') }} + + + {{ $t('package.deprecation.modal.already_deprecated_detail') }} + + + + + + {{ $t('package.deprecation.modal.reason') }} + + + + {{ deprecateMessage.length }} / {{ DEPRECATE_MESSAGE_MAX_LENGTH }} + + + + + {{ $t('package.deprecation.modal.version') }} + + + + + {{ deprecateError }} + + + {{ + isDeprecating + ? $t('package.deprecation.modal.deprecating') + : $t('package.deprecation.action') + }} + + + + diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index a7cc7c4bd4..59c47e4e6b 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -320,6 +320,21 @@ const latestVersion = computed(() => { return pkg.value.versions[latestTag] ?? null }) +/** True when the currently displayed version (or resolved version) is deprecated; used to hide deprecate button. */ +const isCurrentVersionDeprecated = computed(() => { + if (displayVersion.value?.deprecated) return true + const ver = resolvedVersion.value + return !!(ver && pkg.value?.versions?.[ver]?.deprecated) +}) + +/** Version strings that are already deprecated; passed to DeprecatePackageModal to avoid extra fetch. */ +const deprecatedVersions = computed(() => { + if (!pkg.value?.versions) return [] + return Object.entries(pkg.value.versions) + .filter(([, metadata]) => !!metadata.deprecated) + .map(([version]) => version) +}) + const deprecationNotice = computed(() => { if (!displayVersion.value?.deprecated) return null @@ -341,6 +356,17 @@ const deprecationNoticeMessage = useMarkdown(() => ({ text: deprecationNotice.value?.message ?? '', })) +const { isConnected, npmUser } = useConnector() +const deprecateModal = useTemplateRef<{ open: () => void }>('deprecateModal') + +const isPackageOwner = computed(() => { + const maintainers = pkg.value?.maintainers + const user = npmUser.value + if (!maintainers?.length || !user) return false + const userLower = user.toLowerCase() + return maintainers.some((m: { name?: string }) => (m.name ?? '').toLowerCase() === userLower) +}) + const publishSecurityDowngrade = computed(() => { const currentVersion = displayVersion.value?.version if (!currentVersion) return null @@ -989,6 +1015,21 @@ const showSkeleton = shallowRef(false) + + +
+ {{ + deprecateVersion + ? $t('package.deprecation.modal.already_deprecated_version') + : $t('package.deprecation.modal.already_deprecated') + }} +
+ {{ $t('package.deprecation.modal.already_deprecated_detail') }} +
{{ $t('package.deprecation.modal.success') }}
+ {{ $t('package.deprecation.modal.success_detail') }} +
+ {{ $t('package.deprecation.modal.already_deprecated_version') }} +
+ {{ deprecateMessage.length }} / {{ DEPRECATE_MESSAGE_MAX_LENGTH }} +