mirror of
https://github.com/yamadashy/repomix.git
synced 2026-02-03 11:33:39 +01:00
Implement cancel button for pack requests with improved user experience. The button now shows "Cancel" on hover during processing and allows users to abort ongoing requests. Also improved error messages for better clarity. - Add cancel functionality to PackButton with hover state - Implement request cancellation using AbortController - Improve error messages for remote repository processing failures - Update timeout handling and server configuration - Add proper event handling to prevent form submission conflicts
198 lines
5.4 KiB
TypeScript
198 lines
5.4 KiB
TypeScript
import { computed, onMounted, ref } from 'vue';
|
|
import type { FileInfo, PackResult } from '../components/api/client';
|
|
import { handlePackRequest } from '../components/utils/requestHandlers';
|
|
import { isValidRemoteValue } from '../components/utils/validation';
|
|
import { parseUrlParameters } from '../utils/urlParams';
|
|
import { usePackOptions } from './usePackOptions';
|
|
|
|
export type InputMode = 'url' | 'file' | 'folder';
|
|
|
|
export function usePackRequest() {
|
|
const packOptionsComposable = usePackOptions();
|
|
const { packOptions, getPackRequestOptions, resetOptions, applyUrlParameters, DEFAULT_PACK_OPTIONS } =
|
|
packOptionsComposable;
|
|
|
|
// Input states
|
|
const inputUrl = ref('');
|
|
const inputRepositoryUrl = ref('');
|
|
const mode = ref<InputMode>('url');
|
|
const uploadedFile = ref<File | null>(null);
|
|
|
|
// Request states
|
|
const loading = ref(false);
|
|
const error = ref<string | null>(null);
|
|
const errorType = ref<'error' | 'warning'>('error');
|
|
const result = ref<PackResult | null>(null);
|
|
const hasExecuted = ref(false);
|
|
|
|
// Request controller for cancellation
|
|
let requestController: AbortController | null = null;
|
|
const TIMEOUT_MS = 30_000;
|
|
|
|
// Computed validation
|
|
const isSubmitValid = computed(() => {
|
|
switch (mode.value) {
|
|
case 'url':
|
|
return !!inputUrl.value && isValidRemoteValue(inputUrl.value.trim());
|
|
case 'file':
|
|
case 'folder':
|
|
return !!uploadedFile.value;
|
|
default:
|
|
return false;
|
|
}
|
|
});
|
|
|
|
function setMode(newMode: InputMode) {
|
|
mode.value = newMode;
|
|
}
|
|
|
|
function handleFileUpload(file: File) {
|
|
uploadedFile.value = file;
|
|
}
|
|
|
|
function resetRequest() {
|
|
error.value = null;
|
|
errorType.value = 'error';
|
|
result.value = null;
|
|
hasExecuted.value = false;
|
|
}
|
|
|
|
async function submitRequest() {
|
|
if (!isSubmitValid.value) return;
|
|
|
|
// Cancel any pending request
|
|
if (requestController) {
|
|
requestController.abort();
|
|
}
|
|
requestController = new AbortController();
|
|
|
|
loading.value = true;
|
|
error.value = null;
|
|
errorType.value = 'error';
|
|
result.value = null;
|
|
hasExecuted.value = true;
|
|
inputRepositoryUrl.value = inputUrl.value;
|
|
|
|
// Set up automatic timeout
|
|
const timeoutId = setTimeout(() => {
|
|
if (requestController) {
|
|
requestController.abort('timeout');
|
|
}
|
|
}, TIMEOUT_MS);
|
|
|
|
try {
|
|
await handlePackRequest(
|
|
mode.value === 'url' ? inputUrl.value : '',
|
|
packOptions.format,
|
|
getPackRequestOptions.value,
|
|
{
|
|
onSuccess: (response) => {
|
|
result.value = response;
|
|
},
|
|
onError: (errorMessage) => {
|
|
error.value = errorMessage;
|
|
},
|
|
onAbort: (message) => {
|
|
error.value = message;
|
|
errorType.value = 'warning';
|
|
},
|
|
signal: requestController.signal,
|
|
file: mode.value === 'file' || mode.value === 'folder' ? uploadedFile.value || undefined : undefined,
|
|
},
|
|
);
|
|
} finally {
|
|
clearTimeout(timeoutId);
|
|
loading.value = false;
|
|
requestController = null;
|
|
}
|
|
}
|
|
|
|
async function repackWithSelectedFiles(selectedFiles: FileInfo[]) {
|
|
if (!result.value || selectedFiles.length === 0) return;
|
|
|
|
// Generate include patterns from selected files
|
|
const selectedPaths = selectedFiles.map((file) => file.path);
|
|
const includePatterns = selectedPaths.join(',');
|
|
|
|
// Temporarily update pack options with include patterns
|
|
const originalIncludePatterns = packOptions.includePatterns;
|
|
const originalIgnorePatterns = packOptions.ignorePatterns;
|
|
|
|
packOptions.includePatterns = includePatterns;
|
|
packOptions.ignorePatterns = ''; // Clear ignore patterns to ensure selected files are included
|
|
|
|
try {
|
|
// Use the same loading state as normal pack processing
|
|
await submitRequest();
|
|
|
|
// Update file selection state in the new result
|
|
if (result.value?.metadata?.allFiles) {
|
|
for (const file of result.value.metadata.allFiles) {
|
|
file.selected = selectedPaths.includes(file.path);
|
|
}
|
|
}
|
|
} finally {
|
|
// Restore original pack options
|
|
packOptions.includePatterns = originalIncludePatterns;
|
|
packOptions.ignorePatterns = originalIgnorePatterns;
|
|
}
|
|
}
|
|
|
|
function cancelRequest() {
|
|
if (requestController) {
|
|
requestController.abort('cancel');
|
|
requestController = null;
|
|
}
|
|
loading.value = false;
|
|
}
|
|
|
|
// Apply URL parameters after component mounts
|
|
// This must be done here (not during setup) because during SSR/hydration,
|
|
// browser globals like `window.location.search` are not available.
|
|
// Accessing them before mounting would cause errors in SSR environments.
|
|
onMounted(() => {
|
|
const urlParams = parseUrlParameters();
|
|
|
|
// Apply pack options from URL parameters
|
|
applyUrlParameters(urlParams);
|
|
|
|
// Apply repo URL from URL parameters
|
|
if (urlParams.repo) {
|
|
inputUrl.value = urlParams.repo;
|
|
}
|
|
});
|
|
|
|
return {
|
|
// Pack options (re-exported for convenience)
|
|
...packOptionsComposable,
|
|
|
|
// Input states
|
|
inputUrl,
|
|
inputRepositoryUrl,
|
|
mode,
|
|
uploadedFile,
|
|
|
|
// Request states
|
|
loading,
|
|
error,
|
|
errorType,
|
|
result,
|
|
hasExecuted,
|
|
|
|
// Computed
|
|
isSubmitValid,
|
|
|
|
// Actions
|
|
setMode,
|
|
handleFileUpload,
|
|
resetRequest,
|
|
submitRequest,
|
|
repackWithSelectedFiles,
|
|
cancelRequest,
|
|
|
|
// Pack option actions
|
|
resetOptions,
|
|
DEFAULT_PACK_OPTIONS,
|
|
};
|
|
}
|