mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-03 21:17:33 +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/
|
babel_cache/
|
||||||
dist/
|
dist/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
package-lock.json
|
||||||
\#*\#
|
\#*\#
|
||||||
.\#*
|
.\#*
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@ -53,6 +53,7 @@ class FileSystem{
|
|||||||
path: path,
|
path: path,
|
||||||
results: null,
|
results: null,
|
||||||
access_count: 0,
|
access_count: 0,
|
||||||
|
metadata: null
|
||||||
}, _files);
|
}, _files);
|
||||||
store.access_count += 1;
|
store.access_count += 1;
|
||||||
store.results = response.results || [];
|
store.results = response.results || [];
|
||||||
@ -60,6 +61,7 @@ class FileSystem{
|
|||||||
f.path = pathBuilder(path, f.name);
|
f.path = pathBuilder(path, f.name);
|
||||||
return f;
|
return f;
|
||||||
});
|
});
|
||||||
|
store.metadata = response.metadata;
|
||||||
|
|
||||||
if(_files && _files.results){
|
if(_files && _files.results){
|
||||||
// find out which entry we want to keep from the cache
|
// find out which entry we want to keep from the cache
|
||||||
@ -82,7 +84,11 @@ class FileSystem{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(this.current_path === path){
|
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_update = new Date();
|
||||||
store.last_access = new Date();
|
store.last_access = new Date();
|
||||||
@ -99,7 +105,11 @@ class FileSystem{
|
|||||||
return cache.get(cache.FILE_PATH, path).then((response) => {
|
return cache.get(cache.FILE_PATH, path).then((response) => {
|
||||||
if(!response || !response.results) return null;
|
if(!response || !response.results) return null;
|
||||||
if(this.current_path === path){
|
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;
|
return response;
|
||||||
});
|
});
|
||||||
@ -107,7 +117,11 @@ class FileSystem{
|
|||||||
return cache.upsert(cache.FILE_PATH, path, (response) => {
|
return cache.upsert(cache.FILE_PATH, path, (response) => {
|
||||||
if(!response || !response.results) return null;
|
if(!response || !response.results) return null;
|
||||||
if(this.current_path === path){
|
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.last_access = new Date();
|
||||||
response.access_count += 1;
|
response.access_count += 1;
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export class FilesPage extends React.Component {
|
|||||||
show_hidden: settings_get('filespage_show_hidden') || CONFIG["display_hidden"],
|
show_hidden: settings_get('filespage_show_hidden') || CONFIG["display_hidden"],
|
||||||
view: settings_get('filespage_view') || 'grid',
|
view: settings_get('filespage_view') || 'grid',
|
||||||
files: [],
|
files: [],
|
||||||
|
metadata: null,
|
||||||
frequents: [],
|
frequents: [],
|
||||||
page_number: PAGE_NUMBER_INIT,
|
page_number: PAGE_NUMBER_INIT,
|
||||||
loading: true,
|
loading: true,
|
||||||
@ -101,7 +102,12 @@ export class FilesPage extends React.Component {
|
|||||||
if(this.state.show_hidden === false){
|
if(this.state.show_hidden === false){
|
||||||
files = files.filter((file) => file.name[0] === "." ? false : true);
|
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{
|
}else{
|
||||||
notify.send(res, 'error');
|
notify.send(res, 'error');
|
||||||
}
|
}
|
||||||
@ -172,7 +178,7 @@ export class FilesPage extends React.Component {
|
|||||||
<NgIf cond={this.state.path === '/'}>
|
<NgIf cond={this.state.path === '/'}>
|
||||||
<FrequentlyAccess files={this.state.frequents}/>
|
<FrequentlyAccess files={this.state.frequents}/>
|
||||||
</NgIf>
|
</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} />
|
<Uploader path={this.state.path} />
|
||||||
</NgIf>
|
</NgIf>
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
|
|||||||
@ -18,31 +18,15 @@ import { FileZone } from './filezone';
|
|||||||
export class FileSystem extends React.Component {
|
export class FileSystem extends React.Component {
|
||||||
constructor(props){
|
constructor(props){
|
||||||
super(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() {
|
render() {
|
||||||
|
const metadata = this.props.metadata || {};
|
||||||
|
|
||||||
return this.props.connectDropFile(
|
return this.props.connectDropFile(
|
||||||
<div className="component_filesystem">
|
<div className="component_filesystem">
|
||||||
<Container>
|
<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}>
|
<NgIf cond={this.props.fileIsOver}>
|
||||||
<FileZone path={this.props.path} />
|
<FileZone path={this.props.path} />
|
||||||
</NgIf>
|
</NgIf>
|
||||||
@ -51,13 +35,13 @@ export class FileSystem extends React.Component {
|
|||||||
{
|
{
|
||||||
this.props.files.map((file, index) => {
|
this.props.files.map((file, index) => {
|
||||||
if(file.type === 'directory' || file.type === 'file' || file.type === 'link' || file.type === 'bucket'){
|
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>
|
</ReactCSSTransitionGroup>
|
||||||
</NgIf>
|
</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
|
There is nothing here
|
||||||
</NgIf>
|
</NgIf>
|
||||||
</Container>
|
</Container>
|
||||||
@ -68,5 +52,6 @@ export class FileSystem extends React.Component {
|
|||||||
|
|
||||||
FileSystem.PropTypes = {
|
FileSystem.PropTypes = {
|
||||||
path: PropTypes.string.isRequired,
|
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){
|
canDrag(props, monitor){
|
||||||
|
if (props.metadata.can_move === false){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return props.file.icon === 'loading'? false : true;
|
return props.file.icon === 'loading'? false : true;
|
||||||
},
|
},
|
||||||
endDrag(props, monitor, component){
|
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)}/>
|
<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} />
|
<Message message={this.state.message} />
|
||||||
<DateTime show={this.state.icon !== 'loading'} timestamp={this.props.file.time} />
|
<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>
|
</Card>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@ -291,10 +294,10 @@ const ActionButton = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="component_action">
|
<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" />
|
<Icon name="edit" onClick={onRename} className="component_updater--icon" />
|
||||||
</NgIf>
|
</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"/>
|
<Icon name="delete" onClick={onDelete} className="component_updater--icon"/>
|
||||||
</NgIf>
|
</NgIf>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -57,20 +57,12 @@ export class NewThing extends React.Component {
|
|||||||
this.props.onSortUpdate(e);
|
this.props.onSortUpdate(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SEARCH BAR: WIP
|
|
||||||
// <div className="search">
|
|
||||||
// <label>
|
|
||||||
// <input type="text" />
|
|
||||||
// <Icon name="search_dark"/>
|
|
||||||
// </label>
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="menubar no-select">
|
<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_file !== false} 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_directory !== false} onClick={this.onNew.bind(this, 'directory')} type="inline">New Directory</NgIf>
|
||||||
<Dropdown className="view sort" onChange={this.onSortChange.bind(this)}>
|
<Dropdown className="view sort" onChange={this.onSortChange.bind(this)}>
|
||||||
<DropdownButton>
|
<DropdownButton>
|
||||||
<Icon name="sort"/>
|
<Icon name="sort"/>
|
||||||
|
|||||||
@ -10,10 +10,11 @@ export class FileDownloader extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClick(){
|
onClick(){
|
||||||
|
document.cookie = "download=yes; path=/; max-age=120;";
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: true,
|
loading: true,
|
||||||
id: window.setInterval(function(){
|
id: window.setInterval(function(){
|
||||||
if(document.cookie){
|
if(/download=yes/.test(document.cookie) === false){
|
||||||
this.setState({loading: false})
|
this.setState({loading: false})
|
||||||
window.clearInterval(this.state.id);
|
window.clearInterval(this.state.id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,10 +38,6 @@ class DownloadButton extends React.Component {
|
|||||||
loading: true
|
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;";
|
document.cookie = "download=yes; path=/; max-age=120;";
|
||||||
this.state.id = window.setInterval(() => {
|
this.state.id = window.setInterval(() => {
|
||||||
if(/download=yes/.test(document.cookie) === false){
|
if(/download=yes/.test(document.cookie) === false){
|
||||||
|
|||||||
Reference in New Issue
Block a user