mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-03 13:11:46 +08:00
feature (metadata): attach metadata to ls to enable/disable features
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@ node_modules/
|
||||
babel_cache/
|
||||
dist/
|
||||
.DS_Store
|
||||
package-lock.json
|
||||
\#*\#
|
||||
.\#*
|
||||
*.log
|
||||
|
||||
@ -53,6 +53,7 @@ class FileSystem{
|
||||
path: path,
|
||||
results: null,
|
||||
access_count: 0,
|
||||
metadata: null
|
||||
}, _files);
|
||||
store.access_count += 1;
|
||||
store.results = response.results || [];
|
||||
@ -60,6 +61,7 @@ class FileSystem{
|
||||
f.path = pathBuilder(path, f.name);
|
||||
return f;
|
||||
});
|
||||
store.metadata = response.metadata;
|
||||
|
||||
if(_files && _files.results){
|
||||
// find out which entry we want to keep from the cache
|
||||
@ -82,7 +84,11 @@ class FileSystem{
|
||||
}
|
||||
|
||||
if(this.current_path === path){
|
||||
this.obs && this.obs.next({status: 'ok', results: store.results});
|
||||
this.obs && this.obs.next({
|
||||
status: 'ok',
|
||||
results: store.results,
|
||||
metadata: store.metadata
|
||||
});
|
||||
}
|
||||
store.last_update = new Date();
|
||||
store.last_access = new Date();
|
||||
@ -99,7 +105,11 @@ class FileSystem{
|
||||
return cache.get(cache.FILE_PATH, path).then((response) => {
|
||||
if(!response || !response.results) return null;
|
||||
if(this.current_path === path){
|
||||
this.obs && this.obs.next({status: 'ok', results: response.results});
|
||||
this.obs && this.obs.next({
|
||||
status: 'ok',
|
||||
results: response.results,
|
||||
metadata: response.metadata
|
||||
});
|
||||
}
|
||||
return response;
|
||||
});
|
||||
@ -107,7 +117,11 @@ class FileSystem{
|
||||
return cache.upsert(cache.FILE_PATH, path, (response) => {
|
||||
if(!response || !response.results) return null;
|
||||
if(this.current_path === path){
|
||||
this.obs && this.obs.next({status: 'ok', results: response.results});
|
||||
this.obs && this.obs.next({
|
||||
status: 'ok',
|
||||
results: response.results,
|
||||
metadata: response.metadata
|
||||
});
|
||||
}
|
||||
response.last_access = new Date();
|
||||
response.access_count += 1;
|
||||
|
||||
@ -25,6 +25,7 @@ export class FilesPage extends React.Component {
|
||||
show_hidden: settings_get('filespage_show_hidden') || CONFIG["display_hidden"],
|
||||
view: settings_get('filespage_view') || 'grid',
|
||||
files: [],
|
||||
metadata: null,
|
||||
frequents: [],
|
||||
page_number: PAGE_NUMBER_INIT,
|
||||
loading: true,
|
||||
@ -101,7 +102,12 @@ export class FilesPage extends React.Component {
|
||||
if(this.state.show_hidden === false){
|
||||
files = files.filter((file) => file.name[0] === "." ? false : true);
|
||||
}
|
||||
this.setState({files: sort(files, this.state.sort), loading: false, page_number: PAGE_NUMBER_INIT});
|
||||
this.setState({
|
||||
metadata: res.metadata,
|
||||
files: sort(files, this.state.sort),
|
||||
loading: false,
|
||||
page_number: PAGE_NUMBER_INIT
|
||||
});
|
||||
}else{
|
||||
notify.send(res, 'error');
|
||||
}
|
||||
@ -172,7 +178,7 @@ export class FilesPage extends React.Component {
|
||||
<NgIf cond={this.state.path === '/'}>
|
||||
<FrequentlyAccess files={this.state.frequents}/>
|
||||
</NgIf>
|
||||
<FileSystem path={this.state.path} sort={this.state.sort} view={this.state.view} onSort={this.onSort.bind(this)} onView={this.onView.bind(this)} files={this.state.files.slice(0, this.state.page_number * 24)} />
|
||||
<FileSystem path={this.state.path} sort={this.state.sort} view={this.state.view} onSort={this.onSort.bind(this)} onView={this.onView.bind(this)} files={this.state.files.slice(0, this.state.page_number * 24)} metadata={this.state.metadata} />
|
||||
<Uploader path={this.state.path} />
|
||||
</NgIf>
|
||||
</InfiniteScroll>
|
||||
|
||||
@ -18,31 +18,15 @@ import { FileZone } from './filezone';
|
||||
export class FileSystem extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
creating: null,
|
||||
access_right: this._findAccessRight(props.files)
|
||||
};
|
||||
}
|
||||
|
||||
_findAccessRight(files){
|
||||
for(let i=0, l=files.length; i< l; i++){
|
||||
let file = files[i];
|
||||
if(file.name === './' && file.type === 'metadata'){
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return {can_create_file: true, can_create_directory: true};
|
||||
}
|
||||
|
||||
onComponentPropsUpdate(props){
|
||||
this.setState({access_right: this._findAccessRight(props.files)});
|
||||
}
|
||||
|
||||
render() {
|
||||
const metadata = this.props.metadata || {};
|
||||
|
||||
return this.props.connectDropFile(
|
||||
<div className="component_filesystem">
|
||||
<Container>
|
||||
<NewThing path={this.props.path} sort={this.props.sort} view={this.props.view} onViewUpdate={(value) => this.props.onView(value)} onSortUpdate={(value) => {this.props.onSort(value);}} accessRight={this.state.access_right}></NewThing>
|
||||
<NewThing path={this.props.path} sort={this.props.sort} view={this.props.view} onViewUpdate={(value) => this.props.onView(value)} onSortUpdate={(value) => {this.props.onSort(value);}} accessRight={metadata}></NewThing>
|
||||
<NgIf cond={this.props.fileIsOver}>
|
||||
<FileZone path={this.props.path} />
|
||||
</NgIf>
|
||||
@ -51,13 +35,13 @@ export class FileSystem extends React.Component {
|
||||
{
|
||||
this.props.files.map((file, index) => {
|
||||
if(file.type === 'directory' || file.type === 'file' || file.type === 'link' || file.type === 'bucket'){
|
||||
return ( <ExistingThing view={this.props.view} key={file.name+(file.icon || '')} file={file} path={this.props.path} /> );
|
||||
return ( <ExistingThing view={this.props.view} key={file.name+(file.icon || '')} file={file} path={this.props.path} metadata={metadata} /> );
|
||||
}
|
||||
})
|
||||
}
|
||||
</ReactCSSTransitionGroup>
|
||||
</NgIf>
|
||||
<NgIf className="error" cond={this.props.files.length === 0 && !this.state.creating}>
|
||||
<NgIf className="error" cond={this.props.files.length === 0}>
|
||||
There is nothing here
|
||||
</NgIf>
|
||||
</Container>
|
||||
@ -68,5 +52,6 @@ export class FileSystem extends React.Component {
|
||||
|
||||
FileSystem.PropTypes = {
|
||||
path: PropTypes.string.isRequired,
|
||||
files: PropTypes.array.isRequired
|
||||
files: PropTypes.array.isRequired,
|
||||
metadata: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
@ -19,6 +19,9 @@ const fileSource = {
|
||||
};
|
||||
},
|
||||
canDrag(props, monitor){
|
||||
if (props.metadata.can_move === false){
|
||||
return false;
|
||||
}
|
||||
return props.file.icon === 'loading'? false : true;
|
||||
},
|
||||
endDrag(props, monitor, component){
|
||||
@ -211,7 +214,7 @@ export class ExistingThing extends React.Component {
|
||||
<Filename filename={this.props.file.name} filesize={this.props.file.size} filetype={this.props.file.type} onRename={this.onRename.bind(this)} is_renaming={this.state.is_renaming} onRenameCancel={this.onRenameRequest.bind(this, false)}/>
|
||||
<Message message={this.state.message} />
|
||||
<DateTime show={this.state.icon !== 'loading'} timestamp={this.props.file.time} />
|
||||
<ActionButton onClickRename={this.onRenameRequest.bind(this)} onClickDelete={this.onDeleteRequest.bind(this)} is_renaming={this.state.is_renaming} can_move={this.props.file.can_move !== false} can_delete={this.props.file.can_delete !== false} />
|
||||
<ActionButton onClickRename={this.onRenameRequest.bind(this)} onClickDelete={this.onDeleteRequest.bind(this)} is_renaming={this.state.is_renaming} can_rename={this.props.metadata.can_rename !== false} can_delete={this.props.metadata.can_delete !== false} />
|
||||
</Card>
|
||||
</Link>
|
||||
</div>
|
||||
@ -291,10 +294,10 @@ const ActionButton = (props) => {
|
||||
|
||||
return (
|
||||
<div className="component_action">
|
||||
<NgIf cond={props.can_move === true && props.is_renaming === false} type="inline">
|
||||
<NgIf cond={props.can_rename !== false && props.is_renaming === false} type="inline">
|
||||
<Icon name="edit" onClick={onRename} className="component_updater--icon" />
|
||||
</NgIf>
|
||||
<NgIf cond={props.can_delete === true} type="inline">
|
||||
<NgIf cond={props.can_delete !== false} type="inline">
|
||||
<Icon name="delete" onClick={onDelete} className="component_updater--icon"/>
|
||||
</NgIf>
|
||||
</div>
|
||||
|
||||
@ -57,20 +57,12 @@ export class NewThing extends React.Component {
|
||||
this.props.onSortUpdate(e);
|
||||
}
|
||||
|
||||
// SEARCH BAR: WIP
|
||||
// <div className="search">
|
||||
// <label>
|
||||
// <input type="text" />
|
||||
// <Icon name="search_dark"/>
|
||||
// </label>
|
||||
// </div>
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
<div className="menubar no-select">
|
||||
<NgIf cond={this.props.accessRight.can_create_file === true} onClick={this.onNew.bind(this, 'file')} type="inline">New File</NgIf>
|
||||
<NgIf cond={this.props.accessRight.can_create_directory === true} onClick={this.onNew.bind(this, 'directory')} type="inline">New Directory</NgIf>
|
||||
<NgIf cond={this.props.accessRight.can_create_file !== false} onClick={this.onNew.bind(this, 'file')} type="inline">New File</NgIf>
|
||||
<NgIf cond={this.props.accessRight.can_create_directory !== false} onClick={this.onNew.bind(this, 'directory')} type="inline">New Directory</NgIf>
|
||||
<Dropdown className="view sort" onChange={this.onSortChange.bind(this)}>
|
||||
<DropdownButton>
|
||||
<Icon name="sort"/>
|
||||
|
||||
@ -10,10 +10,11 @@ export class FileDownloader extends React.Component{
|
||||
}
|
||||
|
||||
onClick(){
|
||||
document.cookie = "download=yes; path=/; max-age=120;";
|
||||
this.setState({
|
||||
loading: true,
|
||||
id: window.setInterval(function(){
|
||||
if(document.cookie){
|
||||
if(/download=yes/.test(document.cookie) === false){
|
||||
this.setState({loading: false})
|
||||
window.clearInterval(this.state.id);
|
||||
}
|
||||
|
||||
@ -38,10 +38,6 @@ class DownloadButton extends React.Component {
|
||||
loading: true
|
||||
});
|
||||
|
||||
// This my friend is a dirty hack aiming to detect when we the download effectively start
|
||||
// so that we can display a spinner instead of having a user clicking the download button
|
||||
// 10 times. It works by sniffing a cookie in our session that will get destroy when
|
||||
// the server actually send a response
|
||||
document.cookie = "download=yes; path=/; max-age=120;";
|
||||
this.state.id = window.setInterval(() => {
|
||||
if(/download=yes/.test(document.cookie) === false){
|
||||
|
||||
Reference in New Issue
Block a user