Commit ce461579 authored by Matija Obreza's avatar Matija Obreza
Browse files

RepositoryBrowser files and folders with PagedLoader

- using new API endpoints with pagination params
parent 3fd4cdca
import RepositoryFile from 'model/repository/RepositoryFile';
import RepositoryFolder from 'model/repository/RepositoryFolder';
import ImageGallery from 'model/repository/ImageGallery';
import Page from 'model/Page';
/*
* Defined in Swagger as '#/definitions/FolderDetails'
*/
class FolderDetails {
public files: RepositoryFile[];
public files: Page<RepositoryFile>;
public folder: RepositoryFolder;
public subFolders: RepositoryFolder[];
public subFolders: Page<RepositoryFolder>;
public gallery: ImageGallery;
}
......
import { normalize } from 'path';
// Constants
import {RECEIVE_FOLDER_DETAILS, RECEIVE_IMAGE_GALLERY, UPDATE_SUBFOLDER_LIST, UPDATE_FILE_LIST, RECEIVE_FILE} from 'repository/constants';
import {RECEIVE_FOLDER_DETAILS, RECEIVE_IMAGE_GALLERY, UPDATE_SUBFOLDER_LIST, UPDATE_FILE_LIST, RECEIVE_FILE, RECEIVE_SUBFOLDERS, RECEIVE_FILES} from 'repository/constants';
// Model
import FolderDetails from 'model/repository/FolderDetails';
......@@ -16,6 +16,7 @@ import RepositoryFolder from 'model/repository/RepositoryFolder';
import ImageGallery from 'model/repository/ImageGallery';
import navigateTo from 'actions/navigation';
import * as _ from 'lodash';
import Page from 'model/Page';
const receiveFolder = (folder: FolderDetails, error = null) => ({
......@@ -43,6 +44,16 @@ const updateFiles = (deletedFile: RepositoryFile) => ({
payload: { deletedFile },
});
const receiveMoreFolders = (paged: Page<RepositoryFolder>) => ({
type: RECEIVE_SUBFOLDERS,
payload: { paged },
});
const receiveMoreFiles = (paged: Page<RepositoryFile>) => ({
type: RECEIVE_FILES,
payload: { paged },
});
// Get folder details
export const getFolder = (path: string = '/') => (dispatch, getState) => {
return RepositoryService.getFolder(normalize(path))
......@@ -54,6 +65,29 @@ export const getFolder = (path: string = '/') => (dispatch, getState) => {
});
};
export const loadMoreFolders = (path: string = '/', paged: Page<RepositoryFolder>) => (dispatch, getState) => {
return RepositoryService.listSubfolders(path, Page.nextPage(paged))
.then((paged) => {
dispatch(receiveMoreFolders(paged));
return paged;
})
.catch((error) => {
log('Error', error);
});
};
export const loadMoreFiles = (path: string = '/', paged: Page<RepositoryFile>) => (dispatch, getState) => {
return RepositoryService.listFiles(path, Page.nextPage(paged))
.then((paged) => {
dispatch(receiveMoreFiles(paged));
return paged;
})
.catch((error) => {
log('Error', error);
});
};
// Get folder details
export const deleteFolder = (path: string) => (dispatch, getState) => {
......
......@@ -4,5 +4,8 @@ export const RECEIVE_IMAGE_GALLERY = 'App/Repository/RECEIVE_IMAGE_GALLERY';
export const RECEIVE_FILE = 'App/Repository/RECEIVE_FILE';
export const UPDATE_SUBFOLDER_LIST = 'App/Repository/UPDATE_SUBFOLDER_LIST';
export const UPDATE_FILE_LIST = 'App/Repository/UPDATE_FILE_LIST';
export const RECEIVE_SUBFOLDERS = 'App/Repository/RECEIVE_SUBFOLDERS';
export const RECEIVE_FILES = 'App/Repository/RECEIVE_FILES';
export const EDIT_FOLDER_FORM = 'Form/Repository/EDIT_FOLDER_FORM';
export const EDIT_FILE_FORM = 'Form/Repository/EDIT_FILE_FORM';
import update from 'immutability-helper';
import { IReducerAction } from 'model/common.model';
import {RECEIVE_FOLDER_DETAILS, RECEIVE_IMAGE_GALLERY, UPDATE_SUBFOLDER_LIST, UPDATE_FILE_LIST, RECEIVE_FILE} from 'repository/constants';
import {RECEIVE_FOLDER_DETAILS, RECEIVE_IMAGE_GALLERY, UPDATE_SUBFOLDER_LIST, UPDATE_FILE_LIST, RECEIVE_FILE, RECEIVE_SUBFOLDERS, RECEIVE_FILES } from 'repository/constants';
import RepositoryFile from 'model/repository/RepositoryFile';
import FolderDetails from 'model/repository/FolderDetails';
import ImageGallery from 'model/repository/ImageGallery';
......@@ -30,15 +30,47 @@ export default function reducer(state = INITIAL_STATE, action: IReducerAction =
break;
}
case RECEIVE_SUBFOLDERS: {
const { paged } = action.payload;
return !state.folder.subFolders || paged.number === 0 ? update(state, {
folder: { subFolders: { $set: paged } },
}) :
update(state, {
folder: { subFolders: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
} },
});
}
case RECEIVE_FILES: {
const { paged } = action.payload;
return !state.folder.files || paged.number === 0 ? update(state, {
folder: { files: { $set: paged } },
}) :
update(state, {
folder: { files: {
content: {$push: paged.content},
number: {$set: paged.number},
last: {$set: paged.last},
} },
});
}
case UPDATE_SUBFOLDER_LIST: {
const { subFolder } = action.payload;
const receivedIndex = state.folder ? state.folder.subFolders.findIndex((item) => item.uuid === subFolder.uuid) : -1;
const receivedIndex = state.folder ? state.folder.subFolders.content.findIndex((item) => item.uuid === subFolder.uuid) : -1;
if (receivedIndex === -1) {
const newSubFolders = [...state.folder.subFolders, subFolder];
const newSubFolders = [...state.folder.subFolders.content, subFolder];
return update(state, {
folder: {
subFolders: {
$set: newSubFolders,
content: {
$set: newSubFolders,
},
},
},
});
......@@ -50,7 +82,7 @@ export default function reducer(state = INITIAL_STATE, action: IReducerAction =
const { deletedFile } = action.payload;
const files: RepositoryFile[] = [];
if (state.folder && state.folder.files) {
state.folder.files.forEach((item) => {
state.folder.files.content.forEach((item) => {
if (item.uuid !== deletedFile.uuid) {
files.push(item);
}
......
......@@ -4,7 +4,7 @@ import { translate } from 'react-i18next';
import { bindActionCreators } from 'redux';
import { normalize } from 'path';
import { getFolder, uploadFile, deleteFolder, createGallery, removeFile } from 'repository/actions/admin';
import { getFolder, uploadFile, deleteFolder, createGallery, removeFile, loadMoreFiles, loadMoreFolders } from 'repository/actions/admin';
import FolderDetails from 'model/repository/FolderDetails';
// import RepositoryFile from 'model/repository/RepositoryFile';
......@@ -26,6 +26,9 @@ import Grid from '@material-ui/core/Grid';
import FileUploader from 'ui/common/file-uploader';
import CreateFolderDialog from './CreateFolderDialog';
import UpdateFolderDialog from './UpdateFolderDialog';
import PagedLoader from 'ui/common/PagedLoader';
import RepositoryFile from 'model/repository/RepositoryFile';
import Page from 'model/Page';
interface IRepositoryBrowserProps extends React.ClassAttributes<any> {
t?: any;
......@@ -38,6 +41,8 @@ interface IRepositoryBrowserProps extends React.ClassAttributes<any> {
uploadFile: (path: string, file: File) => any;
deleteFolder: (path: string) => any;
removeFile: (uuid: string) => any;
loadMoreFiles: (path: string, paged: Page<RepositoryFile>) => any;
loadMoreFolders: (path: string, paged: Page<RepositoryFolder>) => any;
createGallery: (path: string, title: string, description?: string) => any;
navigateTo: (path: string, qs?: any) => any;
}
......@@ -114,6 +119,26 @@ class RepositoryBrowser extends React.Component<IRepositoryBrowserProps, any> {
navigateTo(`/admin/repository/g${folderPath}/`);
}
protected renderSubfolder = (subFolder: RepositoryFolder) => (
<FolderCard compact key={ subFolder.uuid } folder={ subFolder } />
)
protected loadMoreFolders = (paged: Page<RepositoryFolder>) => {
const { folder, loadMoreFolders } = this.props;
return loadMoreFolders(folder.folder.path, paged);
}
protected renderFile = (file: RepositoryFile) => (
<Grid key={ file.uuid } item xs={ 12 }>
<FileCard file={ file } deleteFile={ this.deleteFile } editFile={ this.handleEditButton }/>
</Grid>
)
protected loadMoreFiles = (paged: Page<RepositoryFile>) => {
const { folder, loadMoreFiles } = this.props;
return loadMoreFiles(folder.folder.path, paged);
}
public render() {
const { folder, root, path, t } = this.props;
......@@ -143,11 +168,11 @@ class RepositoryBrowser extends React.Component<IRepositoryBrowserProps, any> {
<PageContents className={ `container-spacing-horizontal pt-1rem` }>
<div>
{ folder.folder && root !== `${folder.folder.path}/` && <FolderCard compact key="parent" folder={ parentFolder } /> }
{ folder.subFolders.map((subFolder) => <FolderCard compact key={ subFolder.uuid } folder={ subFolder } />) }
<PagedLoader paged={ folder.subFolders } itemRenderer={ this.renderSubfolder } loadMore={ this.loadMoreFolders } />
</div>
<Grid item>
<Grid container spacing={ 16 }>
{ folder.files.map((file) => <Grid key={ file.uuid } item xs={ 12 }><FileCard file={ file } deleteFile={ this.deleteFile } editFile={ this. handleEditButton }/></Grid>) }
<PagedLoader paged={ folder.files } itemRenderer={ this.renderFile } loadMore={ this.loadMoreFiles } />
</Grid>
</Grid>
<div>
......@@ -170,6 +195,8 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
getFolder,
loadMoreFiles,
loadMoreFolders,
uploadFile,
deleteFolder,
removeFile,
......
import * as UrlTemplate from 'url-template';
import * as QueryString from 'query-string';
import { axiosBackend } from 'utilities/requestUtils';
import FolderDetails from 'model/repository/FolderDetails';
import ImageGallery from 'model/repository/ImageGallery';
import RepositoryFile from 'model/repository/RepositoryFile';
import RepositoryFolder from 'model/repository/RepositoryFolder';
import Page, { IPageRequest } from 'model/Page';
const URL_GET_FILE = UrlTemplate.parse(`/api/v1/repository/file/{fileUuid}`);
const URL_REMOVE_FILE = UrlTemplate.parse(`/api/v1/repository/file/{fileUuid}`);
......@@ -13,6 +15,10 @@ const URL_UPDATE_FILE = `/api/v1/repository/file`;
const URL_MOVE_AND_RENAME_FILE = UrlTemplate.parse(`/api/v1/repository/file/{fileUuid}/move`);
const URL_UPDATE_FOLDER = `/api/v1/repository/folder`;
const URL_GET_FOLDER = UrlTemplate.parse(`/api/v1/repository/folder`);
const URL_LIST_SUBFOLDERS = `/api/v1/repository/folder`;
const URL_LIST_FILES = `/api/v1/repository/folder`;
const URL_ENSURE_FOLDER = UrlTemplate.parse(`/api/v1/repository/folder`);
const URL_DELETE_FOLDER = UrlTemplate.parse(`/api/v1/repository/folder`);
const URL_RENAME_FOLDER = UrlTemplate.parse(`/api/v1/repository/folder/{folderUuid}/rename`);
......@@ -136,6 +142,54 @@ class FileRepositoryService {
}).then(({ data }) => data as FolderDetails);
}
/**
* listSubfolders at /api/v1/repository/folder/**
*
* @param path URL path
*/
public static listSubfolders(path: string, page: IPageRequest): Promise<Page<RepositoryFolder>> {
const qs = QueryString.stringify({
p: page.page || undefined,
l: page.size || undefined,
d: page.direction ? page.direction : undefined,
s: page.properties || undefined,
}, {});
const apiUrl = URL_LIST_SUBFOLDERS + path + `?folders&${qs}`;
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as Page<RepositoryFolder>);
}
/**
* listFiles at /api/v1/repository/folder/**
*
* @param path URL path
*/
public static listFiles(path: string, page: IPageRequest): Promise<Page<RepositoryFile>> {
const qs = QueryString.stringify({
p: page.page || undefined,
l: page.size || undefined,
d: page.direction ? page.direction : undefined,
s: page.properties || undefined,
}, {});
const apiUrl = URL_LIST_FILES + path + `?files&${qs}`;
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */ };
return axiosBackend.request({
url: apiUrl,
method: 'GET',
...content,
}).then(({ data }) => data as Page<RepositoryFile>);
}
/**
* ensureFolder at /api/v1/repository/folder/**
*
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment