미디어 선택 요청 흐름 분리

This commit is contained in:
2026-07-28 10:27:02 +09:00
parent 5e4ccbf2bf
commit 9f3ef337ef
10 changed files with 267 additions and 83 deletions

View File

@@ -5,7 +5,10 @@ import {
buildMediaPickerPageItems,
buildMediaPickerRangeLabel,
buildMediaPickerUploadHint,
createMediaPickerFetchQuery,
createDefaultMediaPickerPagination,
createMediaUploadFormData,
findUploadSizeLimitError,
getGallerySelectionOrder as getGallerySelectionOrderFromSelection,
getMediaPickerAcceptForTarget,
getMediaPickerKindForTarget,
@@ -15,6 +18,7 @@ import {
isUploadFileAllowedForMediaTarget,
normalizeMediaPickerPage,
normalizeMediaPickerResponse,
resolveUploadedMediaFiles,
resolveSelectedMediaItems,
toggleMediaSelectionState
} from '../lib/markdown-editor-media.js'
@@ -26,11 +30,15 @@ export const ADMIN_MARKDOWN_MEDIA_PICKER_PAGE_SIZE = 50
* 관리자 Markdown 에디터의 미디어 선택 모달 상태를 관리한다.
* @param {Object} options - 상태 옵션
* @param {import('vue').Ref<Object>|import('vue').ComputedRef<Object>} options.uploadSizeLimits - 업로드 한도
* @param {import('vue').Ref<number>|import('vue').ComputedRef<number>} [options.uploadMaxFileCount] - 한 번에 업로드 가능한 파일 수
* @param {import('vue').Ref<number>|import('vue').ComputedRef<number>} [options.uploadMaxTotalSize] - 한 번에 업로드 가능한 전체 용량
* @param {number} [options.pageSize=50] - 페이지 크기
* @returns {Object} 미디어 선택 모달 상태와 액션
*/
export const useAdminMarkdownMediaPicker = ({
uploadSizeLimits,
uploadMaxFileCount,
uploadMaxTotalSize,
pageSize = ADMIN_MARKDOWN_MEDIA_PICKER_PAGE_SIZE
}) => {
const mediaItems = ref([])
@@ -143,6 +151,104 @@ export const useAdminMarkdownMediaPicker = ({
mediaPickerPage.value = mediaPickerPagination.value.page || 1
}
/**
* 미디어 라이브러리 목록을 조회한다.
* @returns {Promise<void>}
*/
const fetchMediaItems = async () => {
isLoadingMedia.value = true
try {
const response = await $fetch('/admin/api/media', {
query: createMediaPickerFetchQuery({
page: mediaPickerPage.value,
pageSize,
kind: mediaPickerKind.value,
searchQuery: mediaSearchQuery.value
})
})
applyMediaPickerResponse(response)
} finally {
isLoadingMedia.value = false
}
}
/**
* 미디어 파일을 업로드한다.
* @param {FileList|Array<File>} files - 업로드 파일 목록
* @returns {Promise<Object[]>} 업로드된 파일 목록
*/
const uploadMediaFiles = async (files) => {
const sizeLimitError = findUploadSizeLimitError({
files,
maxFileCount: unref(uploadMaxFileCount),
maxTotalSize: unref(uploadMaxTotalSize),
uploadSizeLimits: unref(uploadSizeLimits)
})
if (sizeLimitError) {
throw new Error(sizeLimitError)
}
const result = await $fetch('/admin/api/uploads', {
method: 'POST',
body: createMediaUploadFormData(files)
})
return resolveUploadedMediaFiles(result)
}
/**
* 업로드 상태를 관리하며 미디어 파일을 업로드한다.
* @param {FileList|Array<File>} files - 업로드 파일 목록
* @returns {Promise<Object[]>} 업로드된 파일 목록
*/
const uploadMediaFilesWithState = async (files) => {
if (!files?.length || isUploading.value) {
return []
}
isUploading.value = true
try {
return await uploadMediaFiles(files)
} finally {
isUploading.value = false
}
}
/**
* 현재 미디어 선택 모달에서 파일을 업로드하고 선택 상태를 갱신한다.
* @param {FileList|Array<File>} files - 업로드 파일 목록
* @returns {Promise<Object[]>} 업로드된 파일 목록
*/
const uploadFilesIntoMediaPicker = async (files) => {
if (!files?.length || isUploading.value) {
return []
}
isUploading.value = true
try {
const uploadedFiles = await uploadMediaFiles(files)
selectUploadedMediaFiles(uploadedFiles)
activeMediaPickerTab.value = 'library'
mediaSearchQuery.value = ''
mediaPickerPage.value = 1
try {
await fetchMediaItems()
} catch {
prependUploadedMediaItems(uploadedFiles)
}
return uploadedFiles
} finally {
isUploading.value = false
}
}
/**
* 미디어 선택 페이지를 변경한다.
* @param {number} page - 이동할 페이지
@@ -261,6 +367,10 @@ export const useAdminMarkdownMediaPicker = ({
openMediaPickerState,
closeMediaPickerState,
applyMediaPickerResponse,
fetchMediaItems,
uploadMediaFiles,
uploadMediaFilesWithState,
uploadFilesIntoMediaPicker,
setMediaPickerPage,
toggleMediaSelection,
resolveCurrentSelectedMediaItems,