Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ui-storagebrowser] adds trash functionality #4014

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/filebrowser/src/filebrowser/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def get_all_filesystems(request):
user_home_dir = fs_home_dir_mapping[fs](request.user)
config = _get_config(fs, request)

filesystems.append({'file_system': fs, 'user_home_directory': user_home_dir, 'config': config})
filesystems.append({'name': fs, 'user_home_directory': user_home_dir, 'config': config})

return JsonResponse(filesystems, safe=False)

Expand Down
10 changes: 5 additions & 5 deletions apps/filebrowser/src/filebrowser/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,8 @@ def test_get_all_filesystems_without_hdfs(self):

assert response.status_code == 200
assert response_data == [
{'file_system': 's3a', 'user_home_directory': 's3a://test-bucket/test-user-home-dir/', 'config': {}},
{'file_system': 'ofs', 'user_home_directory': 'ofs://', 'config': {}},
{'name': 's3a', 'user_home_directory': 's3a://test-bucket/test-user-home-dir/', 'config': {}},
{'name': 'ofs', 'user_home_directory': 'ofs://', 'config': {}},
]

def test_get_all_filesystems_success(self):
Expand All @@ -776,7 +776,7 @@ def test_get_all_filesystems_success(self):
assert response.status_code == 200
assert response_data == [
{
'file_system': 'hdfs',
'name': 'hdfs',
'user_home_directory': '/user/test-user',
'config': {
'is_trash_enabled': False,
Expand All @@ -787,8 +787,8 @@ def test_get_all_filesystems_success(self):
'supergroup': 'test-supergroup',
},
},
{'file_system': 's3a', 'user_home_directory': 's3a://test-bucket/test-user-home-dir/', 'config': {}},
{'file_system': 'ofs', 'user_home_directory': 'ofs://', 'config': {}},
{'name': 's3a', 'user_home_directory': 's3a://test-bucket/test-user-home-dir/', 'config': {}},
{'name': 'ofs', 'user_home_directory': 'ofs://', 'config': {}},
]


Expand Down
2 changes: 1 addition & 1 deletion desktop/core/src/desktop/api_public.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ def storage_trash_bulk_restore(request):
return filebrowser_api.bulk_op(django_request, filebrowser_api.trash_restore)


@api_view(["DELETE"])
@api_view(["POST"])
def storage_trash_purge(request):
django_request = get_django_request(request)
return filebrowser_api.trash_purge(django_request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ import useLoadData from '../../../utils/hooks/useLoadData/useLoadData';

const mockData = jest.fn().mockReturnValue({
logs: ['Log entry 1', 'Log entry 2'],
hue_hostname: 'test-hostname'
hueHostname: 'test-hostname'
});

const emptyMockData = jest.fn().mockReturnValue({
logs: [],
hue_hostname: 'test-hostname'
hueHostname: 'test-hostname'
});

jest.mock('../../../utils/hooks/useLoadData/useLoadData');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,14 @@ import './ServerLogsTab.scss';

interface ServerLogsData {
logs: string[];
hue_hostname: string;
hueHostname: string;
}

const ServerLogs: React.FC = (): JSX.Element => {
const [filter, setFilter] = useState<string>('');
const [wrapLogs, setWrapLogs] = useState(true);
const { t } = i18nReact.useTranslation();
const {
data: logsData,
loading,
error
} = useLoadData<ServerLogsData>(SERVER_LOGS_API_URL, {
const { data, loading, error } = useLoadData<ServerLogsData>(SERVER_LOGS_API_URL, {
params: {
reverse: true
}
Expand All @@ -62,15 +58,15 @@ const ServerLogs: React.FC = (): JSX.Element => {
<ServerLogsHeader
onFilterChange={setFilter}
onWrapLogsChange={setWrapLogs}
hostName={logsData?.hue_hostname ?? ''}
hostName={data?.hueHostname ?? ''}
/>
{logsData && (logsData.logs.length === 0 || logsData.logs[0] === '') && (
{data && (data.logs.length === 0 || data.logs[0] === '') && (
<pre className="server__no-logs-found">No logs found!</pre>
)}

{logsData && logsData.logs.length > 0 && logsData.logs[0] !== '' && (
{data && data.logs.length > 0 && data.logs[0] !== '' && (
<div className="server__display-logs">
{logsData.logs.map((line, index) => (
{data.logs.map((line, index) => (
<div
className={`server__log-line ${wrapLogs ? 'server_wrap' : ''}`}
key={'logs_' + index}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,7 @@ $icon-margin: 5px;
.hue-filechooser-modal__path-browser-panel {
display: flex;
align-items: center;
gap: vars.$fluidx-spacing-xs;
}

.hue-filechooser-modal__destPath {
flex: 0 0 auto;
font-weight: 600;
gap: 2px;
}

.hue-filechooser-modal__search {
Expand Down Expand Up @@ -65,6 +60,7 @@ $icon-margin: 5px;
.hue-filechooser-modal__table-cell-icon {
color: vars.$fluidx-blue-700;
margin-right: 6px;
vertical-align: middle;
}

.hue-filechooser-modal__table-row {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ describe('FileChooserModal', () => {
);
await waitFor(() => {
expect(screen.getByText('Select File')).toBeInTheDocument();
expect(screen.getByText('Destination Path:')).toBeInTheDocument();
expect(screen.getByText('Cancel')).toBeInTheDocument();
expect(screen.getByText('Submit')).toBeInTheDocument();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ const FileChooserModal = ({
>
<div className="hue-filechooser-modal__body">
<div className="hue-filechooser-modal__path-browser-panel">
<span className="hue-filechooser-modal__destPath">{t('Destination Path:')}</span>
<PathBrowser
filePath={destPath}
onFilepathChange={setDestPath}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ const StorageBrowserPage = (): JSX.Element => {
<Tabs
className="hue-storage-browser__tab"
destroyInactiveTabPane
defaultActiveKey={urlFileSystem ?? data?.[0]?.file_system}
items={data?.map(fs => ({
label: fs.file_system.toUpperCase(),
key: fs.file_system,
children: <StorageBrowserTab fileSystem={fs} />
defaultActiveKey={urlFileSystem ?? data?.[0]?.name}
items={data?.map(fileSystem => ({
label: fileSystem.name.toUpperCase(),
key: fileSystem.name,
children: <StorageBrowserTab fileSystem={fileSystem} />
}))}
/>
</LoadingErrorWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
@use 'variables' as vars;
@use 'mixins';

.antd.cuix {
.hue-storage-browser-tab-content {
Expand All @@ -24,8 +25,43 @@
}

.hue-storage-browser__title-bar {
display: flex;
justify-content: space-between;
}

.hue-storage-browser__title {
display: flex;
gap: vars.$fluidx-spacing-xs;
max-width: 70%;
}

.hue-path-browser__refresh-btn {
padding: vars.$fluidx-spacing-xxs;;

&:hover {
background-color: transparent;
}

&:focus {
background-color: transparent;
}
}

.hue-path-browser__home-btn {
padding: vars.$fluidx-spacing-xxs;

&:hover {
background-color: transparent;
}

&:focus {
background-color: transparent;
}
}

.hue-storage-browser__home-bar-right {
display: flex;
gap: vars.$fluidx-spacing-s;
}

.hue-storage-browser__icon {
Expand All @@ -38,16 +74,16 @@
font-size: vars.$fluidx-heading-h3-size;
line-height: vars.$fluidx-heading-h3-line-height;
font-weight: vars.$fluidx-heading-h3-weight;
width: 100%;
@include mixins.nowrap-ellipsis;

display: inline;
}

.hue-storage-browser__path-browser-panel {
display: flex;
align-items: center;
gap: vars.$fluidx-spacing-xs;
}

.hue-storage-browser__filePath {
flex: 0 0 auto;
font-weight: 600;
gap: 2px;
margin-left: vars.$fluidx-spacing-xxs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ import BucketIcon from '@cloudera/cuix-core/icons/react/BucketIcon';

import PathBrowser from '../../../reactComponents/PathBrowser/PathBrowser';
import StorageDirectoryPage from '../StorageDirectoryPage/StorageDirectoryPage';
import { FILE_STATS_API_URL } from '../api';
import { BrowserViewType, FileStats, FileSystem } from '../types';
import { FILE_STATS_API_URL, TRASH_PATH } from '../api';
import { BrowserViewType, FileStats, FileSystem, TrashPath } from '../types';
import useLoadData from '../../../utils/hooks/useLoadData/useLoadData';
import { BorderlessButton } from 'cuix/dist/components/Button';

import './StorageBrowserTab.scss';
import StorageFilePage from '../StorageFilePage/StorageFilePage';
import changeURL from '../../../utils/url/changeURL';
import LoadingErrorWrapper from '../../../reactComponents/LoadingErrorWrapper/LoadingErrorWrapper';
import { getFileSystemAndPath } from '../../../reactComponents/PathBrowser/PathBrowser.util';
import RefreshIcon from '@cloudera/cuix-core/icons/react/RefreshIcon';
import HomeIcon from '@cloudera/cuix-core/icons/react/HomeIcon';
import DeleteIcon from '@cloudera/cuix-core/icons/react/DeleteIcon';

interface StorageBrowserTabProps {
fileSystem: FileSystem;
Expand All @@ -46,13 +50,19 @@ const StorageBrowserTab = ({ fileSystem, testId }: StorageBrowserTabProps): JSX.
const urlFilePath = decodeURIComponent(urlSearchParams.get('path') ?? '');
const { fileSystem: urlFileSystem } = getFileSystemAndPath(urlFilePath);
const initialFilePath =
urlFileSystem === fileSystem.file_system ? urlFilePath : fileSystem.user_home_directory;
urlFileSystem === fileSystem.name ? urlFilePath : fileSystem.userHomeDirectory;

const [filePath, setFilePath] = useState<string>(initialFilePath);
const fileName = filePath.split('/').pop() ?? '';
const fileName =
filePath.split('/').pop() !== '' ? filePath.split('/').pop() : filePath.split('://')[0];

const { t } = i18nReact.useTranslation();

const { data: trash, reloadData: reloadTrashData } = useLoadData<TrashPath>(TRASH_PATH, {
params: { path: fileSystem.userHomeDirectory },
skip: !fileSystem.config?.isTrashEnabled || !fileSystem.userHomeDirectory
});

const {
data: fileStats,
loading,
Expand Down Expand Up @@ -80,12 +90,12 @@ const StorageBrowserTab = ({ fileSystem, testId }: StorageBrowserTabProps): JSX.
enabled: error?.response?.status === 404,
message: t('Error: Path "{{path}}" not found.', { path: filePath }),
action: t('Go to home directory'),
onClick: () => setFilePath(fileSystem.user_home_directory)
onClick: () => setFilePath(fileSystem.userHomeDirectory)
},
{
enabled: !!error && error?.response?.status !== 404,
message: t('An error occurred while fetching filesystem "{{fileSystem}}".', {
fileSystem: fileSystem.file_system.toUpperCase()
fileSystem: fileSystem.name.toUpperCase()
}),
action: t('Retry'),
onClick: reloadData
Expand All @@ -96,16 +106,51 @@ const StorageBrowserTab = ({ fileSystem, testId }: StorageBrowserTabProps): JSX.
<LoadingErrorWrapper loading={loading} errors={errorConfig}>
<div className="hue-storage-browser-tab-content" data-testid={testId}>
<div className="hue-storage-browser__title-bar" data-testid={`${testId}-title-bar`}>
<BucketIcon className="hue-storage-browser__icon" data-testid={`${testId}-icon`} />
<h3 className="hue-storage-browser__folder-name" data-testid={`${testId}-folder-namer`}>
{fileName}
</h3>
<div className="hue-storage-browser__title">
<BucketIcon className="hue-storage-browser__icon" data-testid={`${testId}-icon`} />
<h3 className="hue-storage-browser__folder-name" data-testid={`${testId}-folder-namer`}>
{fileName}
</h3>
</div>
<div className="hue-storage-browser__home-bar-right">
<BorderlessButton
onClick={() => {
setFilePath(fileSystem.userHomeDirectory);
}}
className="hue-path-browser__home-btn"
data-event={''}
title={t('Home')}
icon={<HomeIcon />}
>
{t('Home')}
</BorderlessButton>
{fileSystem.config?.isTrashEnabled && (
<BorderlessButton
onClick={() => setFilePath(trash?.trashPath ?? '')}
className="hue-path-browser__home-btn"
data-event={''}
title={t('Trash')}
icon={<DeleteIcon />}
disabled={!trash?.trashPath}
>
{t('Trash')}
</BorderlessButton>
)}
<BorderlessButton
onClick={() => reloadData()}
className="hue-path-browser__refresh-btn"
data-event={''}
title={t('Refresh')}
icon={<RefreshIcon />}
>
{t('Refresh')}
</BorderlessButton>
</div>
</div>
<div
className="hue-storage-browser__path-browser-panel"
data-testid={`${testId}-path-browser-panel`}
>
<span className="hue-storage-browser__filePath">{t('File Path:')}</span>
<PathBrowser
filePath={filePath}
onFilepathChange={setFilePath}
Expand All @@ -117,7 +162,8 @@ const StorageBrowserTab = ({ fileSystem, testId }: StorageBrowserTabProps): JSX.
<StorageDirectoryPage
fileStats={fileStats}
onFilePathChange={setFilePath}
config={fileSystem.config}
fileSystem={fileSystem}
reloadTrashData={reloadTrashData}
/>
)}
{fileStats?.type === BrowserViewType.file && !loading && (
Expand Down
Loading
Loading