// Licensed to Cloudera, Inc. under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. Cloudera, Inc. licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import React, { useMemo, useState } from 'react'; import { BrowserViewType, FilePreview, FileStats } from '../types'; import './StorageFilePage.scss'; import { i18nReact } from '../../../utils/i18nReact'; import Button, { PrimaryButton } from 'cuix/dist/components/Button'; import { getFileMetaData, getFileType } from './StorageFilePage.util'; import { DOWNLOAD_API_URL, FILE_PREVIEW_API_URL, SAVE_FILE_API_URL } from '../api'; import huePubSub from '../../../utils/huePubSub'; import useSaveData from '../../../utils/hooks/useSaveData/useSaveData'; import Pagination from '../../../reactComponents/Pagination/Pagination'; import { DEFAULT_PREVIEW_PAGE_SIZE, EDITABLE_FILE_FORMATS, SupportedFileTypes } from '../../../utils/constants/storageBrowser'; import useLoadData from '../../../utils/hooks/useLoadData/useLoadData'; import { getLastKnownConfig } from '../../../config/hueConfig'; import LoadingErrorWrapper from '../../../reactComponents/LoadingErrorWrapper/LoadingErrorWrapper'; import { inTrash } from '../utils/utils'; import { getLastDirOrFileNameFromPath } from '../../../reactComponents/PathBrowser/PathBrowser.util'; interface StorageFilePageProps { onReload: () => void; fileStats: FileStats; } const StorageFilePage = ({ fileStats, onReload }: StorageFilePageProps): JSX.Element => { const config = getLastKnownConfig(); const fileName = getLastDirOrFileNameFromPath(fileStats.path); const fileType = getFileType(fileName); const { t } = i18nReact.useTranslation(); const [isEditing, setIsEditing] = useState(false); const [fileContent, setFileContent] = useState(); const [pageNumber, setPageNumber] = useState(1); const pageSize = DEFAULT_PREVIEW_PAGE_SIZE; const pageOffset = (pageNumber - 1) * pageSize; const { loading: isSaving, save } = useSaveData(SAVE_FILE_API_URL, { options: { qsEncodeData: true } // TODO: Remove once API supports RAW JSON payload }); const { data, loading, error } = useLoadData(FILE_PREVIEW_API_URL, { params: { path: fileStats.path, offset: pageOffset, length: pageSize }, onSuccess: d => setFileContent(d.contents), skip: fileStats.path === '' || fileStats.path === undefined || fileStats?.type !== BrowserViewType.file || !EDITABLE_FILE_FORMATS.has(fileType) }); const fileMetaData = useMemo(() => getFileMetaData(t, fileStats), [t, fileStats]); const handleEdit = () => { setIsEditing(true); }; const handleCancel = () => { setIsEditing(false); setFileContent(data?.contents); }; const handleSave = () => { setIsEditing(false); save( { path: fileStats.path, encoding: 'utf-8', contents: fileContent }, { onError: () => { setIsEditing(true); }, onSuccess: () => { onReload(); huePubSub.publish('hue.global.info', { message: t('Changes saved!') }); } } ); }; const handleDownload = () => { huePubSub.publish('hue.global.info', { message: t('Downloading your file, Please wait...') }); }; const fileDownloadUrl = `${DOWNLOAD_API_URL}?path=${fileStats.path}`; const filePreviewUrl = `${fileDownloadUrl}&&disposition=inline`; const isEditingEnabled = !error && !isEditing && config?.storage_browser.max_file_editor_size && config?.storage_browser.max_file_editor_size > fileStats.size && EDITABLE_FILE_FORMATS.has(fileType) && !inTrash(fileStats.path); const pageStats = { pageNumber: pageNumber, totalPages: Math.ceil(fileStats.size / pageSize), pageSize: 0, totalSize: 0 }; const errorConfig = [ { enabled: !!error && error.response?.status !== 422, message: t('An error occurred while fetching file content for path "{{path}}".', { path: fileStats.path }), actionText: t('Retry'), onClick: onReload } ]; return ( <>
{fileMetaData.map((row, index) => (
{row.map(item => (
{item.label}
{item.value}
))}
))}
{t('Content')}
{isEditingEnabled && ( {t('Edit')} )} {isEditing && ( <> {t('Save')} )} {config?.storage_browser.enable_file_download_button && ( {t('Download')} )}
{error?.response?.status !== 422 && (