Skip to content

Commit

Permalink
Merge pull request #602 from VeliovGroup/dev
Browse files Browse the repository at this point in the history
v1.9.10
  • Loading branch information
dr-dimitru authored Apr 17, 2018
2 parents 7cfe086 + 7dd3471 commit fbc5191
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ Thank you for contribution. Before you go:

Thank you for making this package better :)

## Do not forget to get rid of this default message
## Do not forget to get rid of this default message
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
- Give an expressive description what you have changed/added and why
- Make sure you're using correct markdown markup
- Make sure all code blocks starts with triple ``` (*backtick*) and have a syntax tag, for more read [this docs](https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting)
- Post addition/changes as issue ticket, we will manage it
- Post addition/changes as issue ticket, we will manage it
145 changes: 89 additions & 56 deletions docs/react-example.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,52 @@
*This example is for the front-end UI only. The server side [methods](https://github.com/VeliovGroup/Meteor-Files/wiki#api) and [publications](https://github.com/VeliovGroup/Meteor-Files/wiki/collection) are the same.*

## Brief:
In this example two components is used. First - to handle the uploads, adds a file input box and progress bar. Second - to show the file details (`FileIndividualFile.jsx`).
In this example two components is used. First - to handle the uploads, adds a file input box and progress bar. Second - to show the file details (`FileIndividualFile.js`).

- The individual file component allows to delete, rename, and view the files. Twitter Bootstrap is used for styling;
- Tested with `[email protected]`;
- Currently uses mixins to access the meteor data.
- Tested with `[email protected]` and `React16`;
- Uses the latest `withTracker` access the meteor data.
- Uses React Component (rather than deprecated createClass)

## Assumptions
- You have Meteor methods for `RemoveFile` and `RemoveFile`
- You have a publication called `files.all`
which is a FilesCollection, declared something like this:

## FileUpload.jsx:
```js
import { FilesCollection } from 'meteor/ostrio:files';

export const UserFiles = new FilesCollection({collectionName: 'userfiles'});
// optionally attach a schema
UserFiles.attachSchema(FilesCollection.schema);
```

## FileUpload.js:

```jsx
import { ReactMeteorData } from 'meteor/react-meteor-data';
import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import { Meteor } from 'meteor/meteor';
import IndividualFile from './FileIndividualFile.jsx';
import { _ } from 'meteor/underscore';
import React, { Component } from 'react';
import PropTypes from 'prop-types';

import IndividualFile from './FileIndividualFile.js';

const FileUploadComponent = React.createClass({
mixins: [ReactMeteorData],
const debug = require('debug')('demo:file');

getInitialState(){
return {
class FileUploadComponent extends Component {
constructor(props) {
super(props);

this.state = {
uploading: [],
progress: 0,
inProgress: false
}
},

getMeteorData() {
var handle = Meteor.subscribe('files.all');
return {
docsReadyYet: handle.ready(),
docs: UserFiles.find().fetch() // Collection is UserFiles
};
},

uploadIt(e){
"use strict";
this.uploadIt = this.uploadIt.bind(this);
}

uploadIt(e) {
e.preventDefault();

let self = this;
Expand All @@ -57,7 +66,7 @@ const FileUploadComponent = React.createClass({
streams: 'dynamic',
chunkSize: 'dynamic',
allowWebWorkers: true // If you see issues with uploads, change this to false
}, false);
}, false)

self.setState({
uploading: uploadInstance, // Keep track of this instance to use below
Expand All @@ -67,11 +76,11 @@ const FileUploadComponent = React.createClass({
// These are the event functions, don't need most of them, it shows where we are in the process
uploadInstance.on('start', function () {
console.log('Starting');
});
})

uploadInstance.on('end', function (error, fileObj) {
console.log('On end File Object: ', fileObj);
});
})

uploadInstance.on('uploaded', function (error, fileObj) {
console.log('uploaded: ', fileObj);
Expand All @@ -85,24 +94,24 @@ const FileUploadComponent = React.createClass({
progress: 0,
inProgress: false
});
});
})

uploadInstance.on('error', function (error, fileObj) {
console.log('Error during upload: ' + error);
console.log('Error during upload: ' + error)
});

uploadInstance.on('progress', function (progress, fileObj) {
console.log('Upload Percentage: ' + progress);
console.log('Upload Percentage: ' + progress)
// Update our progress bar
self.setState({
progress: progress
})
});
});

uploadInstance.start(); // Must manually start the upload
}
}
},
}

// This is our progress bar, bootstrap styled
// Remove this function if not needed
Expand All @@ -124,18 +133,18 @@ const FileUploadComponent = React.createClass({
</div>
</div>
}
},
}

render() {
if (this.data.docsReadyYet) {
'use strict';
debug("Rendering FileUpload",this.props.docsReadyYet);
if (this.props.files && this.props.docsReadyYet) {

let fileCursors = this.data.docs;
let fileCursors = this.props.files;

// Run through each file that the user has stored
// (make sure the subscription only sends files owned by this user)
let display = fileCursors.map((aFile, key) => {
// console.log('A file: ', aFile.link(), aFile.get('name'));
// console.log('A file: ', aFile.link(), aFile.get('name'))
let link = UserFiles.findOne({_id: aFile._id}).link(); //The "view/download" link

// Send out components that show details of each file
Expand All @@ -147,7 +156,7 @@ const FileUploadComponent = React.createClass({
fileSize={aFile.size}
/>
</div>
});
})

return <div>
<div className="row">
Expand All @@ -172,38 +181,62 @@ const FileUploadComponent = React.createClass({

</div>
}
else return <div></div>
else return <div>Loading file list</div>;
}
});

export default FileUploadComponent;
}

//
// This is the HOC - included in this file just for convenience, but usually kept
// in a separate file to provide separation of concerns.
//
export default withTracker( ( props ) => {
const filesHandle = Meteor.subscribe('files.all');
const docsReadyYet = filesHandle.ready();
const files = UserFiles.find({}, {sort: {name: 1}}).fetch();

return {
docsReadyYet,
files,
};
})(FileUploadComponent);
```

## Second Component: FileIndividualFile.jsx
## Second Component: FileIndividualFile.js

```jsx
import React from 'react';
const IndividualFile = React.createClass({
import React, { Component } from 'react';
import PropTypes from 'prop-types';

class IndividualFile extends Component {
constructor(props) {
super(props);

this.state = {
};

this.removeFile = this.removeFile.bind(this);
this.renameFile = this.renameFile.bind(this);

}

propTypes: {
fileName: React.PropTypes.string.isRequired,
fileSize: React.PropTypes.number.isRequired,
fileUrl: React.PropTypes.string,
fileId: React.PropTypes.string.isRequired
},
fileName: PropTypes.string.isRequired,
fileSize: PropTypes.number.isRequired,
fileUrl: PropTypes.string,
fileId: PropTypes.string.isRequired
}

removeFile(){
"use strict";
let conf = confirm('Are you sure you want to delete the file?') || false;
if (conf == true) {
Meteor.call('RemoveFile', this.props.fileId, function (err, res) {
if (err)
console.log(err);
});
})
}
},
}

renameFile(){
"use strict";

let validName = /[^a-zA-Z0-9 \.:\+()\-_%!&]/gi;
let prompt = window.prompt('New file name?', this.props.fileName);
Expand All @@ -218,9 +251,9 @@ const IndividualFile = React.createClass({
Meteor.call('RenameFile', this.props.fileId, prompt, function (err, res) {
if (err)
console.log(err);
});
})
}
},
}

render() {
return <div className="m-t-sm">
Expand Down Expand Up @@ -257,6 +290,6 @@ const IndividualFile = React.createClass({
</div>
</div>
}
});
}
export default IndividualFile;
```
2 changes: 1 addition & 1 deletion package.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package.describe({
name: 'ostrio:files',
version: '1.9.9',
version: '1.9.10',
summary: 'File upload via DDP/HTTP to server, 3rd party storage support: AWS S3, GridFS, DropBox and others',
git: 'https://github.com/VeliovGroup/Meteor-Files',
documentation: 'README.md'
Expand Down
26 changes: 16 additions & 10 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -918,17 +918,23 @@ export class FilesCollection extends FilesCollectionCore {
result.public = this.public;
this._updateFileTypes(result);

this.collection.insert(_.clone(result), (error, _id) => {
if (error) {
cb && cb(error);
this._debug('[FilesCollection] [Upload] [_finishUpload] Error:', error);
this.collection.insert(_.clone(result), (colInsert, _id) => {
if (colInsert) {
cb && cb(colInsert);
this._debug('[FilesCollection] [Upload] [_finishUpload] [insert] Error:', colInsert);
} else {
this._preCollection.update({_id: opts.fileId}, {$set: {isFinished: true}});
result._id = _id;
this._debug(`[FilesCollection] [Upload] [finish(ed)Upload] -> ${result.path}`);
this.onAfterUpload && this.onAfterUpload.call(this, result);
this.emit('afterUpload', result);
cb && cb(null, result);
this._preCollection.update({_id: opts.fileId}, {$set: {isFinished: true}}, (preUpdateError) => {
if (preUpdateError) {
cb && cb(preUpdateError);
this._debug('[FilesCollection] [Upload] [_finishUpload] [update] Error:', preUpdateError);
} else {
result._id = _id;
this._debug(`[FilesCollection] [Upload] [finish(ed)Upload] -> ${result.path}`);
this.onAfterUpload && this.onAfterUpload.call(this, result);
this.emit('afterUpload', result);
cb && cb(null, result);
}
});
}
});
}
Expand Down

0 comments on commit fbc5191

Please sign in to comment.