UNPKG

@ubiquitypress/react-invenio-bulk-importer

Version:
855 lines (770 loc) 28.5 kB
import { default as cn } from 'classnames'; import { default as default_2 } from 'react'; import { FC } from 'react'; import { Icon } from 'semantic-ui-react'; import { Label } from 'semantic-ui-react'; /** * Represents an individual bucket in an aggregation. * This is the base bucket data from the API. */ export declare interface AggregationBucket { key: string; doc_count: number; } /** * Represents the configuration for an aggregation. */ export declare interface AggregationConfig { field: string; aggName: string; childAgg?: AggregationConfig; } /** * Represents aggregation data structure from the API. */ export declare interface AggregationData { buckets: AggregationBucket[]; } /** * Map of aggregation results from the API. */ export declare interface Aggregations { [key: string]: AggregationData; } /** * Extended bucket with UI state information. * Used by aggregation components for display and interaction. */ export declare interface Bucket extends AggregationBucket { label: string; is_selected: boolean; } export declare const BulkImporter: { ExportRecordButton: FC<ExportRecordButtonProps>; ExportSearchResultsButton: FC<ExportSearchResultsButtonProps>; Search: FC<SearchProps>; TaskDetails: FC<TaskDetailsProps>; }; /** * Capitalizes the first letter of a given string. * * @param string - The input string to capitalize * @returns The string with the first letter capitalized, or an empty string if input is null/undefined */ export declare const capitalizeFirstLetter: (string: string) => string; export { cn } /** * Creates a new InvenioSearchApi instance with the provided configuration. * * @param config - The configuration object for the search API * @returns A new InvenioSearchApi instance */ export declare const createSearchApi: (config: SearchApiConfig) => unknown; /** * Creates a configuration object for the search API with default settings. * * @param url - The base URL for the search API endpoint * @param headers - Additional HTTP headers to include in requests. Defaults to an empty object * @param withCredentials - Whether to include credentials (cookies, authorization headers) in cross-origin requests. Defaults to true * @returns A SearchApiConfig object containing axios configuration with the specified parameters */ export declare const createSearchApiConfig: (url: string, headers?: Record<string, string>, withCredentials?: boolean) => SearchApiConfig; /** Default sort option used when the query string is empty. */ export declare interface DefaultSortingOption { /** Sort key sent to the API. */ sortBy: string; } /** Triggers a browser download for an in-memory Blob. */ export declare const downloadBlob: (blob: Blob, filename: string) => void; /** Renders a button that exports a single Invenio record as CSV. */ export declare const ExportRecordButton: default_2.FC<ExportRecordButtonProps>; /** Props for rendering a single-record CSV export button. */ export declare interface ExportRecordButtonProps extends RecordsExportButtonBaseProps { /** Invenio record ID to export. */ recordId?: string | null; } /** Renders a button that exports the current records search as CSV. */ export declare const ExportSearchResultsButton: default_2.FC<ExportSearchResultsButtonProps>; /** Props for rendering a search-results CSV export button. */ export declare interface ExportSearchResultsButtonProps extends RecordsExportButtonBaseProps { } export declare const FileUploader: default_2.FC<FileUploaderProps>; export declare interface FileUploaderProps { taskId?: string; value?: File[]; onChange: (files: File[]) => void; accept?: string; maxFiles?: number; maxTotalSize?: number; skipEmptyFiles?: boolean; disabled?: boolean; error?: string; } export declare interface FileUploadProgress { fileName: string; loaded: number; total: number; percentage: number; } /** * Represents a filter value in the search. */ export declare interface FilterValue { field: string; value: string; label?: string; } export declare const formatDate: (dateString: string) => string; /** * Normalizes task field values for display in the UI. * * @param value - The raw task value to render. * @param formatter - Optional formatter for string-like values. * @returns A human-readable string suitable for UI display. */ export declare const formatDetailValue: (value?: string | number | boolean | null, formatter?: (value: string) => string) => string; /** * Formats the total size of selected files into a human-readable string. * Uses binary prefixes (Bytes, KB, MB, GB) for formatting. * @param bytes - The total size in bytes. * @return A formatted string representing the file size. */ export declare const formatFileSize: (bytes: number) => string; /** * Formats an internal task option key into a human-readable label. * * @param optionKey - The raw option key, typically snake_case. * @returns A UI-friendly label for the option. */ export declare const formatOptionLabel: (optionKey: string) => string; /** * Retrieves the CSRF token from browser cookies. * * This function looks for a cookie named 'csrftoken' and returns its value. * CSRF tokens are commonly used to prevent Cross-Site Request Forgery attacks * by ensuring that requests originate from the intended source. * * @returns The CSRF token string if found in cookies, otherwise null * */ export declare const getCsrfToken: () => string | null; export declare const getStatusColor: (status: InvenioImporterTaskStates | InvenioImporterRecordStates) => "green" | "red" | "blue" | "yellow" | "grey"; /** * Returns ordered task option entries suitable for deterministic rendering. * * @param options - Task options to read. * @returns Known task options in canonical display order. */ export declare const getTaskOptionEntries: (options?: TaskOptions | null) => [TaskOptionKey, boolean][]; export declare const getTotalSize: (uploadedFiles: UploadableFile[]) => number; export declare const getTotalSizeFormatted: (uploadedFiles: UploadableFile[]) => string; export declare interface ImporterTaskConfig { serializers: string[]; options: TaskOptions; } export declare const ImporterTaskStates: { readonly CREATED: "created"; readonly VALIDATING: "validating"; readonly VALIDATION_FAILED: "validated with failures"; readonly VALIDATED: "validated"; readonly IMPORTING: "importing"; readonly IMPORT_FAILED: "imported with failures"; readonly SUCCESS: "success"; readonly DAMAGED: "damaged"; }; export declare const ImportModal: () => default_2.JSX.Element; /** Initial React-SearchKit query state. */ export declare interface InitialQueryState { /** Selected facet filters. */ filters?: unknown[]; /** Hidden filters always sent with the query. */ hiddenParams?: unknown | null; /** Active result layout. */ layout?: string; /** Active page number. */ page?: number; /** Number of results per page. */ size?: number; /** Active sort key. */ sortBy?: string; /** Free-text search query. */ queryString?: string; } export declare interface InvenioImporterRecord { id: string; created: string; updated: string; links: { self: string; self_html: string; edit_html: string; metadata: string; }; revision_id: number; status: InvenioImporterRecordStates; src_data: { id: string; doi: string; title: string; version: string; keywords: string; filenames: string; publisher: string; 'rights.id': string; communities: string; description: string; 'access.files': string; 'imprint.isbn': string; 'languages.id': string; 'rights.title': string; 'creators.name': string; 'creators.type': string; 'imprint.pages': string; 'imprint.place': string; 'locations.lat': string; 'locations.lon': string; 'imprint.volume': string; 'imprint.edition': string; 'locations.place': string; 'subjects.scheme': string; 'creators.role.id': string; publication_date: string; 'resource_type.id': string; 'subjects.subject': string; 'contributors.name': string; 'contributors.type': string; 'identifiers.scheme': string; 'Imprint.series_name': string; 'creators.given_name': string; 'access.embargo.until': string; 'contributors.role.id': string; 'creators.family_name': string; 'references.reference': string; 'access.embargo.active': string; 'access.embargo.reason': string; 'locations.description': string; 'identifiers.identifier': string; 'contributors.given_name': string; 'contributors.family_name': string; 'creators.affiliations.id': string; 'creators.identifiers.gnd': string; 'creators.identifiers.ror': string; 'creators.identifiers.isni': string; 'creators.affiliations.name': string; 'creators.identifiers.orcid': string; 'related_identifiers.scheme': string; 'contributors.affiliations.id': string; 'contributors.identifiers.gnd': string; 'contributors.identifiers.ror': string; 'additional_descriptions.notes': string; 'contributors.identifiers.isni': string; 'contributors.affiliations.name': string; 'contributors.identifiers.orcid': string; 'related_identifiers.identifier': string; 'additional_descriptions.abstract': string; 'additional_descriptions.methods.eng': string; 'related_identifiers.relation_type.id': string; 'related_identifiers.resource_type.id': string; 'additional_titles.alternative-title.eng': string; }; errors: Array<{ msg: string; loc: string; type: string; }>; task: { id: string; }; generated_record_id?: string; serializer_data?: { files?: { enabled: boolean; }; access?: { files: string; record: string; }; metadata?: { title: string; rights?: Array<{ id: string; }>; version?: string; creators?: Array<{ affiliations?: Array<{ name: string; }>; person_or_org?: { type: string; given_name: string; family_name: string; identifiers?: Array<{ scheme: string; identifier: string; }>; }; }>; languages?: Array<{ id: string; }>; publisher?: string; description?: string; contributors?: Array<{ role?: { id: string; }; affiliations?: Array<{ name: string; }>; person_or_org?: { type: string; given_name: string; family_name: string; identifiers?: Array<{ scheme: string; identifier: string; }>; }; }>; resource_type?: { id: string; }; publication_date?: string; additional_descriptions?: Array<{ lang?: { id: string; }; type?: { id: string; }; description: string; }>; }; }; transformed_data?: { files?: { enabled: boolean; }; access?: { files: string; record: string; }; $schema?: string; metadata?: { title: string; rights?: Array<{ id: string; }>; version?: string; creators?: Array<{ affiliations?: Array<{ name: string; }>; person_or_org?: { name: string; type: string; given_name: string; family_name: string; identifiers?: Array<{ scheme: string; identifier: string; }>; }; }>; languages?: Array<{ id: string; }>; publisher?: string; description?: string; contributors?: Array<{ role?: { id: string; }; affiliations?: Array<{ name: string; }>; person_or_org?: { name: string; type: string; given_name: string; family_name: string; identifiers?: Array<{ scheme: string; identifier: string; }>; }; }>; resource_type?: { id: string; }; publication_date?: string; additional_descriptions?: Array<{ lang?: { id: string; }; type?: { id: string; }; description: string; }>; }; }; community_uuids?: { ids: string[]; default: string; }; record_files?: string[]; validated_record_files?: Array<{ key: string; size: number; origin: string; full_path: string; }>; existing_record_id?: string; } export declare interface InvenioImporterRecords { hits: { hits: InvenioImporterRecord[]; total: number; }; } export declare type InvenioImporterRecordStates = (typeof InvenioImporterRecordStatus)[keyof typeof InvenioImporterRecordStatus]; export declare const InvenioImporterRecordStatus: { readonly CREATED: "created"; readonly VALIDATING: "validating"; readonly SERIALIZER_VALIDATION_FAILED: "serializer validation failed"; readonly VALIDATION_FAILED: "validation failed"; readonly VALIDATED: "validated"; readonly IMPORT_FAILED: "import failed"; readonly IMPORTED: "success"; }; export declare type InvenioImporterTaskStates = (typeof ImporterTaskStates)[keyof typeof ImporterTaskStates]; export declare interface InvenioNewImportTask { title: string; description: string; mode: 'import' | 'delete'; status: string; startTime?: null; endTime?: null; recordType: string; serializer: string; options?: TaskOptions; } export declare interface InvenioTask { id: string; created: string; updated: string; links: { self: string; self_html: string; edit_html: string; metadata: string; }; revision_id: number; title: string; description: string; mode: string; record_type: string; serializer: string; start_time?: string | null; end_time?: string | null; records_status?: Record<InvenioImporterRecordStates, number> & { total_records: number; }; status: InvenioImporterTaskStates; files: { enabled: boolean; }; started_by: { id: number; username: string | null; email: string; }; options: TaskOptions; } declare interface LabelProps extends default_2.ComponentProps<typeof Label> { status: InvenioTask['status'] | InvenioImporterRecordStates; } /** Enabled search result layout modes. */ export declare interface LayoutOptions { /** Whether grid view is available. */ gridView: boolean; /** Whether list view is available. */ listView: boolean; } /** * Converts a raw API option key into a supported canonical task option key. * * @param optionKey - Raw option key from the API or form state. * @returns The canonical option key when supported, otherwise `null`. */ export declare const normalizeTaskOptionKey: (optionKey: string) => TaskOptionKey | null; export declare type OrchestrationSteps = (typeof OrchestrationStepsEnum)[keyof typeof OrchestrationStepsEnum]; export declare const OrchestrationStepsEnum: { readonly CREATING_TASK: "Creating Task"; readonly UPLOADING_METADATA: "Uploading Metadata"; readonly UPLOADING_FILES: "Uploading Files"; readonly UPDATING_METADATA: "Updating Metadata"; readonly UPDATING_FILES: "Updating Files"; readonly VALIDATING: "Validating"; readonly EXECUTING: "Executing"; readonly UPDATING: "Updating"; }; export declare interface OverridableComponents { [key: string]: default_2.ComponentType<unknown>; } export declare interface OverridableComponentsTyped<T = Record<string, unknown>> { [key: string]: default_2.ComponentType<T>; } /** Pagination configuration for search results. */ export declare interface PaginationOptions { /** Default selected page size. */ defaultValue: number; /** Maximum number of results SearchKit can page through. */ maxTotalResults: number; /** Available page size options. */ resultsPerPage: ResultsPerPageOption[]; } export declare const ProgressLoading: ({ progress, showPercentage }: ProgressLoadingProps) => default_2.JSX.Element; declare interface ProgressLoadingProps { progress: Record<OrchestrationSteps, number>; showPercentage?: boolean; } /** * Represents the query filters applied to the search. */ export declare interface QueryFilters { [fieldName: string]: FilterValue[] | FilterValue; } /** CSV export API configuration for records search. */ export declare interface RecordsExportApiConfig { /** Primary Accept header or ordered headers for export requests. */ accept: string | string[]; /** Additional Accept headers retried after 406 responses. */ fallbackAccepts?: string[]; /** Download filename used when the API does not provide one. */ filename: string; /** Additional headers sent with the export request. */ headers?: Record<string, string>; /** Whether exports should include current pagination params. */ includePagination: boolean; /** Records API URL used for search exports. */ url: string; } /** Options shared by single-record and search-result CSV export requests. */ declare interface RecordsExportApiOptions { /** Primary Accept header or ordered list of Accept headers to try first. */ accept?: string | string[]; /** Additional Accept headers to retry when the API rejects a media type. */ fallbackAccepts?: string[]; /** Download filename to use when the API does not provide one. */ filename?: string; /** Additional request headers to send with the export request. */ headers?: Record<string, string>; /** Records API URL used as the export endpoint. */ url?: string; } /** Shared visual options for CSV export buttons. */ declare interface RecordsExportButtonBaseProps extends RecordsExportApiOptions { /** Whether the Semantic UI button should use basic styling. */ basic?: boolean; /** Additional CSS class name applied to the button. */ className?: string; /** Whether the Semantic UI button should use compact spacing. */ compact?: boolean; /** Visible button label shown when iconOnly is false. */ content?: string; /** Whether the export button is disabled. */ disabled?: boolean; /** Whether to render only the export icon. */ iconOnly?: boolean; /** Whether search exports should include current pagination params. */ includePagination?: boolean; /** React-SearchKit query state used by search-result export. */ queryState?: Record<string, unknown>; /** Semantic UI button size. */ size?: 'mini' | 'tiny' | 'small' | 'medium' | 'large'; /** Tooltip text shown when the export button has no error. */ title?: string; } /** Results-per-page dropdown option. */ export declare interface ResultsPerPageOption { /** Human-readable option label. */ text: string; /** Page size value sent to SearchKit. */ value: number; } /** * Removes unsupported or malformed task option entries from an unknown input. * * @param options - Raw options payload from the API or form state. * @returns A sanitized task options object containing only known boolean flags. */ export declare const sanitizeTaskOptions: (options: unknown) => TaskOptions; /** Renders the reusable SearchKit-powered importer search UI. */ export declare const Search: default_2.FC<SearchProps>; /** Axios configuration used by the SearchKit API client. */ export declare interface SearchApiConfig { /** Axios request options for the search endpoint. */ axios: { /** Headers sent with each search request. */ headers?: Record<string, string>; /** Search endpoint URL. */ url?: string; /** Whether requests should include browser credentials. */ withCredentials?: boolean; }; /** Invenio-specific SearchKit serializer configuration. */ invenio?: { /** Name of the request serializer used by React-SearchKit. */ requestSerializer?: string; }; } /** Search API config override accepted by the Search component. */ declare type SearchApiConfigOverride = Partial<Omit<SearchApiConfig, 'axios'>> & { /** Partial Axios config merged with the default SearchKit Axios config. */ axios?: Partial<SearchApiConfig['axios']>; }; /** Full configuration object for the reusable search UI. */ export declare interface SearchConfig { /** Facet aggregation configuration consumed by SearchKit. */ aggs: unknown[]; /** SearchKit application ID used for overridable component keys. */ appId: string; /** Sort options used before the user enters a query. */ defaultSortingOnEmptyQueryString: DefaultSortingOption[]; /** Records CSV export configuration. */ exportApi: RecordsExportApiConfig; /** Initial SearchKit query state. */ initialQueryState: InitialQueryState; /** Enabled result layout modes. */ layoutOptions: LayoutOptions; /** Pagination and page-size configuration. */ paginationOptions: PaginationOptions; /** Base UI route used for task detail links. */ resultPath: string; /** Search API configuration. */ searchApi: SearchApiConfig; /** Sort dropdown options. */ sortOptions: SortOption[]; /** Whether manual sort direction controls are disabled. */ sortOrderDisabled: boolean; /** Whether to render the search-level CSV export button. */ showExportButton?: boolean; /** Whether to render facet filters. */ showFacets?: boolean; /** Whether to render the new import modal trigger. */ showImportModal?: boolean; /** Whether to render pagination and page-size controls. */ showSearchFooter?: boolean; } /** Partial search config accepted by the Search component. */ export declare type SearchConfigOverride = Partial<Omit<SearchConfig, 'exportApi' | 'searchApi'>> & { /** Partial CSV export config merged with the default export config. */ exportApi?: Partial<RecordsExportApiConfig>; /** Partial search API config merged with the default search API config. */ searchApi?: SearchApiConfigOverride; }; /** Props for rendering the reusable Search component. */ export declare interface SearchProps { /** Optional search configuration overrides. */ config?: SearchConfigOverride; /** Optional component override registry for react-overridable. */ overriddenComponents?: OverridableComponents; } /** * Search results data structure from the API. */ export declare interface SearchResultsData { aggregations?: Aggregations; hits?: unknown[]; total?: number; } /** Sort option shown in the search sort dropdown. */ export declare interface SortOption { /** Sort key sent to the API. */ sortBy: string; /** Human-readable sort option label. */ text: string; } export declare const Spinner: () => default_2.JSX.Element; export declare const StatusIcon: default_2.FC<StatusIconProps>; declare interface StatusIconProps extends default_2.ComponentProps<typeof Icon> { status: InvenioTask['status'] | InvenioImporterRecordStates; } export declare const StatusLabel: default_2.FC<LabelProps>; /** * Canonical task option keys supported by the UI and API payloads. * * This list is used as the single source of truth for typing, sanitization, * and ordered rendering of task options across the application. */ export declare const TASK_OPTION_KEYS: readonly ["doi_minting", "publish"]; export declare const TaskConfiguration: default_2.FC<TaskConfigurationProps>; declare interface TaskConfigurationProps { task: InvenioTask; } export declare const TaskDetails: default_2.FC<TaskDetailsProps>; export declare interface TaskDetailsProps { taskId: string; } export declare const TaskHeader: default_2.FC<TaskHeaderProps>; declare interface TaskHeaderProps { task: InvenioTask; totalRecords: number; validatedRecords: number; errorRecords: number; successRecords: number; isRefreshing: boolean; isRunningTask: boolean; onRefresh: () => void; onRunTask: () => Promise<void>; } /** * Union of supported task option keys. */ export declare type TaskOptionKey = (typeof TASK_OPTION_KEYS)[number]; /** * Task option flags accepted by the importer. * * The shape is partial because the API may omit options that are not available * for a given record type. */ export declare type TaskOptions = Partial<Record<TaskOptionKey, boolean>>; export declare interface TaskOrchestrationOptions { autoValidate?: boolean; autoExecute?: boolean; onProgress?: (step: OrchestrationSteps, progress?: number) => void; onError?: (error: Error, step: OrchestrationSteps) => void; } export declare const TaskRecordItem: default_2.FC<TaskRecordItemProps>; /** Props for rendering a single importer task record row. */ export declare interface TaskRecordItemProps { /** Importer record displayed by the table row. */ result: InvenioImporterRecord; /** Row index supplied by React-SearchKit. */ index: number; } export declare interface UploadableFile { file: File; id: string; error?: string; } /** * Custom hook for managing file uploads. * Provides functionality to add, remove, and clear files, * along with validation against accepted types and size limits. */ export declare const useFileUploader: ({ onUploadError }?: UseFileUploaderProps) => { uploadFiles: UploadableFile[]; isUploading: boolean; addFiles: (newFiles: File[], accept?: string, maxFiles?: number, maxTotalSize?: number, skipEmptyFiles?: boolean) => UploadableFile[]; removeFile: (fileId: string) => void; clearFiles: () => void; }; declare interface UseFileUploaderProps { taskId?: string; onUploadComplete?: (files: File[]) => void; onUploadError?: (error: string) => void; } export { }