mirror of
https://github.com/modrinth/code.git
synced 2026-08-25 09:04:55 +00:00
feat: improve add dependency flow (#6075)
* fix: shadow on nav * feat: improve add dependency flow * feat: update suggested dependency style * feat: update dependency rows to use version number and update styles * feat: implement combobox select searched text on focus * feat: add Tabs.vue * feat: update nav tabs to use tabs * feat: improve project search dropdown * fix: dependency search not clearing inbound query * fix: combobox no options open state bug * feat: improve dependency project and version search
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { Labrinth, UploadProgress } from '@modrinth/api-client'
|
||||
import { SaveIcon, SpinnerIcon } from '@modrinth/assets'
|
||||
import {
|
||||
type ComboboxOption,
|
||||
createContext,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
@@ -49,16 +50,16 @@ export type VersionStage =
|
||||
| 'add-loaders'
|
||||
| 'add-mc-versions'
|
||||
| 'add-environment'
|
||||
| 'add-dependencies'
|
||||
| 'add-changelog'
|
||||
| 'from-details-loaders'
|
||||
| 'from-details-mc-versions'
|
||||
| 'from-details-environment'
|
||||
| 'from-details-dependencies'
|
||||
|
||||
export type SuggestedDependency = Labrinth.Versions.v3.Dependency & {
|
||||
name?: string
|
||||
icon?: string
|
||||
versionName?: string
|
||||
versionNumber?: string
|
||||
}
|
||||
|
||||
export interface PrimaryFile {
|
||||
@@ -79,6 +80,10 @@ export interface ManageVersionContextValue {
|
||||
projectsFetchLoading: Ref<boolean>
|
||||
handlingNewFiles: Ref<boolean>
|
||||
suggestedDependencies: Ref<SuggestedDependency[] | null>
|
||||
newDependencyProjectId: Ref<string | undefined>
|
||||
newDependencyType: Ref<Labrinth.Versions.v2.DependencyType>
|
||||
newDependencyVersionId: Ref<string | null>
|
||||
newDependencyVersions: Ref<ComboboxOption<string>[]>
|
||||
visibleSuggestedDependencies: ComputedRef<SuggestedDependency[]>
|
||||
primaryFile: ComputedRef<PrimaryFile | null>
|
||||
|
||||
@@ -105,6 +110,8 @@ export interface ManageVersionContextValue {
|
||||
replacePrimaryFile: (file: File) => Promise<void>
|
||||
getProject: (projectId: string) => Promise<Labrinth.Projects.v3.Project>
|
||||
getVersion: (versionId: string) => Promise<Labrinth.Versions.v3.Version>
|
||||
resetNewDependency: () => void
|
||||
addNewDependency: () => boolean
|
||||
|
||||
// Submission methods
|
||||
handleCreateVersion: () => Promise<void>
|
||||
@@ -178,6 +185,10 @@ export function createManageVersionContext(
|
||||
const dependencyVersions = ref<Record<string, Labrinth.Versions.v3.Version>>({})
|
||||
const projectsFetchLoading = ref(false)
|
||||
const suggestedDependencies = ref<SuggestedDependency[] | null>(null)
|
||||
const newDependencyProjectId = ref<string>()
|
||||
const newDependencyType = ref<Labrinth.Versions.v2.DependencyType>('required')
|
||||
const newDependencyVersionId = ref<string | null>(null)
|
||||
const newDependencyVersions = ref<ComboboxOption<string>[]>([])
|
||||
|
||||
const isSubmitting = ref(false)
|
||||
const isUploading = ref(false)
|
||||
@@ -254,6 +265,7 @@ export function createManageVersionContext(
|
||||
filesToAdd.value = []
|
||||
existingFilesToDelete.value = []
|
||||
inferredVersionData.value = undefined
|
||||
resetNewDependency()
|
||||
}
|
||||
|
||||
async function handleNewFiles(newFiles: File[]) {
|
||||
@@ -453,6 +465,44 @@ export function createManageVersionContext(
|
||||
return version
|
||||
}
|
||||
|
||||
function resetNewDependency() {
|
||||
newDependencyProjectId.value = undefined
|
||||
newDependencyVersionId.value = null
|
||||
newDependencyType.value = 'required'
|
||||
newDependencyVersions.value = []
|
||||
}
|
||||
|
||||
function addNewDependency() {
|
||||
if (!newDependencyProjectId.value) return false
|
||||
if (!draftVersion.value.dependencies) draftVersion.value.dependencies = []
|
||||
|
||||
const dependency: Labrinth.Versions.v3.Dependency = {
|
||||
project_id: newDependencyProjectId.value,
|
||||
version_id: newDependencyVersionId.value || undefined,
|
||||
dependency_type: newDependencyType.value,
|
||||
}
|
||||
|
||||
const alreadyAdded = draftVersion.value.dependencies.some((existing) => {
|
||||
if (existing.project_id !== dependency.project_id) return false
|
||||
if (!existing.version_id && !dependency.version_id) return true
|
||||
return existing.version_id === dependency.version_id
|
||||
})
|
||||
|
||||
if (alreadyAdded) {
|
||||
addNotification({
|
||||
title: 'Dependency already added',
|
||||
text: 'You cannot add the same dependency twice.',
|
||||
type: 'error',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
projectsFetchLoading.value = true
|
||||
draftVersion.value.dependencies.push(dependency)
|
||||
resetNewDependency()
|
||||
return true
|
||||
}
|
||||
|
||||
// Primary file computed
|
||||
const primaryFile = computed<PrimaryFile | null>(() => {
|
||||
const existingPrimaryFile = draftVersion.value.existing_files?.[0]
|
||||
@@ -537,6 +587,30 @@ export function createManageVersionContext(
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
watch(newDependencyProjectId, async () => {
|
||||
newDependencyVersionId.value = null
|
||||
newDependencyType.value = 'required'
|
||||
|
||||
if (!newDependencyProjectId.value) {
|
||||
newDependencyVersions.value = []
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const versions = await labrinth.versions_v3.getProjectVersions(newDependencyProjectId.value)
|
||||
newDependencyVersions.value = versions.map((version) => ({
|
||||
label: version.version_number,
|
||||
value: version.id,
|
||||
}))
|
||||
} catch (error: any) {
|
||||
addNotification({
|
||||
title: 'An error occurred',
|
||||
text: error.data ? error.data.description : error,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Watch loaders to infer environment if not set
|
||||
watch(
|
||||
() => draftVersion.value.loaders,
|
||||
@@ -603,7 +677,7 @@ export function createManageVersionContext(
|
||||
|
||||
if (dep.version_id) {
|
||||
const version = await getVersion(dep.version_id)
|
||||
dep.versionName = version.name
|
||||
dep.versionNumber = version.version_number
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`Failed to fetch project/version data for dependency:`, error)
|
||||
@@ -766,8 +840,6 @@ export function createManageVersionContext(
|
||||
return editingVersion.value ? 'Edit loaders' : 'Set loaders'
|
||||
case 'add-mc-versions':
|
||||
return editingVersion.value ? 'Edit game versions' : 'Set game versions'
|
||||
case 'add-dependencies':
|
||||
return editingVersion.value ? 'Edit dependencies' : 'Set dependencies'
|
||||
case 'add-environment':
|
||||
return editingVersion.value ? 'Edit environment' : 'Add environment'
|
||||
case 'add-changelog':
|
||||
@@ -801,6 +873,10 @@ export function createManageVersionContext(
|
||||
handlingNewFiles,
|
||||
projectsFetchLoading,
|
||||
suggestedDependencies,
|
||||
newDependencyProjectId,
|
||||
newDependencyType,
|
||||
newDependencyVersionId,
|
||||
newDependencyVersions,
|
||||
visibleSuggestedDependencies,
|
||||
primaryFile,
|
||||
|
||||
@@ -826,6 +902,8 @@ export function createManageVersionContext(
|
||||
replacePrimaryFile,
|
||||
getProject,
|
||||
getVersion,
|
||||
resetNewDependency,
|
||||
addNewDependency,
|
||||
handleNewFiles,
|
||||
handleCreateVersion,
|
||||
handleSaveVersionEdits,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LeftArrowIcon, RightArrowIcon, XIcon } from '@modrinth/assets'
|
||||
import { PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import type { StageConfigInput } from '@modrinth/ui'
|
||||
import { markRaw } from 'vue'
|
||||
|
||||
@@ -6,54 +6,27 @@ import DependenciesStage from '~/components/ui/create-project-version/stages/Dep
|
||||
|
||||
import type { ManageVersionContextValue } from '../manage-version-modal'
|
||||
|
||||
export const stageConfig: StageConfigInput<ManageVersionContextValue> = {
|
||||
id: 'add-dependencies',
|
||||
stageContent: markRaw(DependenciesStage),
|
||||
title: (ctx) => (ctx.editingVersion.value ? 'Edit version' : 'Dependencies'),
|
||||
skip: (ctx) => ctx.suggestedDependencies.value != null || ctx.projectType.value === 'modpack',
|
||||
leftButtonConfig: (ctx) =>
|
||||
ctx.editingVersion.value
|
||||
? {
|
||||
label: 'Cancel',
|
||||
icon: XIcon,
|
||||
onClick: () => ctx.modal.value?.hide(),
|
||||
}
|
||||
: {
|
||||
label: 'Back',
|
||||
icon: LeftArrowIcon,
|
||||
onClick: () => ctx.modal.value?.prevStage(),
|
||||
},
|
||||
rightButtonConfig: (ctx) =>
|
||||
ctx.editingVersion.value
|
||||
? ctx.saveButtonConfig()
|
||||
: {
|
||||
label: ctx.getNextLabel(),
|
||||
icon: RightArrowIcon,
|
||||
iconPosition: 'after',
|
||||
onClick: () => ctx.modal.value?.nextStage(),
|
||||
},
|
||||
nonProgressStage: (ctx) => ctx.editingVersion.value,
|
||||
}
|
||||
|
||||
export const fromDetailsStageConfig: StageConfigInput<ManageVersionContextValue> = {
|
||||
id: 'from-details-dependencies',
|
||||
stageContent: markRaw(DependenciesStage),
|
||||
title: 'Edit version',
|
||||
title: 'Add dependency',
|
||||
nonProgressStage: true,
|
||||
leftButtonConfig: (ctx) => ({
|
||||
label: 'Back',
|
||||
icon: LeftArrowIcon,
|
||||
onClick: () => ctx.modal.value?.setStage('metadata'),
|
||||
label: 'Cancel',
|
||||
icon: XIcon,
|
||||
onClick: () => {
|
||||
ctx.resetNewDependency()
|
||||
ctx.modal.value?.setStage('metadata')
|
||||
},
|
||||
}),
|
||||
rightButtonConfig: (ctx) => ({
|
||||
label: 'Add dependency',
|
||||
icon: PlusIcon,
|
||||
iconPosition: 'before',
|
||||
color: 'green',
|
||||
disabled: !ctx.newDependencyProjectId.value,
|
||||
onClick: () => {
|
||||
if (ctx.addNewDependency()) ctx.modal.value?.setStage('metadata')
|
||||
},
|
||||
}),
|
||||
rightButtonConfig: (ctx) =>
|
||||
ctx.editingVersion.value
|
||||
? {
|
||||
...ctx.saveButtonConfig(),
|
||||
}
|
||||
: {
|
||||
label: 'Add details',
|
||||
icon: RightArrowIcon,
|
||||
iconPosition: 'after',
|
||||
onClick: () => ctx.modal.value?.setStage('add-details'),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ import {
|
||||
fromDetailsStageConfig as fromDetailsFilesStageConfig,
|
||||
stageConfig as addFilesStageConfig,
|
||||
} from './add-files-stage'
|
||||
import {
|
||||
fromDetailsStageConfig as fromDetailsDependenciesStageConfig,
|
||||
stageConfig as dependenciesStageConfig,
|
||||
} from './dependencies-stage'
|
||||
import { fromDetailsStageConfig as fromDetailsDependenciesStageConfig } from './dependencies-stage'
|
||||
import { stageConfig as detailsStageConfig } from './details-stage'
|
||||
import {
|
||||
fromDetailsStageConfig as fromDetailsEnvironmentStageConfig,
|
||||
@@ -26,11 +23,10 @@ export const stageConfigs = [
|
||||
loadersStageConfig,
|
||||
mcVersionsStageConfig,
|
||||
environmentStageConfig,
|
||||
dependenciesStageConfig,
|
||||
metadataStageConfig,
|
||||
detailsStageConfig,
|
||||
|
||||
// Non-progress stages for editing from details page
|
||||
// Non-progress stages for editing from metadata/details pages
|
||||
fromDetailsLoadersStageConfig,
|
||||
fromDetailsMcVersionsStageConfig,
|
||||
fromDetailsEnvironmentStageConfig,
|
||||
|
||||
Reference in New Issue
Block a user