feature (metadata): attach metadata to ls to enable/disable features

This commit is contained in:
Mickael Kerjean
2018-07-18 14:10:33 +10:00
parent 1c7a7bf8df
commit c5f2839fd7
8 changed files with 43 additions and 45 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ node_modules/
babel_cache/ babel_cache/
dist/ dist/
.DS_Store .DS_Store
package-lock.json
\#*\# \#*\#
.\#* .\#*
*.log *.log

View File

@ -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;

View File

@ -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>

View File

@ -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
} }

View File

@ -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>

View File

@ -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"/>

View File

@ -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);
} }

View File

@ -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){