diff options
author | Maxime Quandalle <maxime@quandalle.com> | 2015-11-25 09:41:34 -0800 |
---|---|---|
committer | Maxime Quandalle <maxime@quandalle.com> | 2015-11-25 09:46:30 -0800 |
commit | f565aed2596baaf9cd3da63110068177f7461e8e (patch) | |
tree | 6cfd70ebf5091925f7e9662029a0ca2135103120 /client/components/import/import.js | |
parent | 5763714d22c4533f173d1d34a1210acf548c4d58 (diff) | |
parent | db90771d9b1330eb8f7183c472545277b8ed9449 (diff) | |
download | wekan-f565aed2596baaf9cd3da63110068177f7461e8e.tar.gz wekan-f565aed2596baaf9cd3da63110068177f7461e8e.tar.bz2 wekan-f565aed2596baaf9cd3da63110068177f7461e8e.zip |
Merge GitHub PR #401
I also completed the release notes related to the import feature.
Closes #401
Diffstat (limited to 'client/components/import/import.js')
-rw-r--r-- | client/components/import/import.js | 235 |
1 files changed, 208 insertions, 27 deletions
diff --git a/client/components/import/import.js b/client/components/import/import.js index c6957fa9..63285e57 100644 --- a/client/components/import/import.js +++ b/client/components/import/import.js @@ -11,48 +11,122 @@ const ImportPopup = BlazeComponent.extendComponent({ return 'importPopup'; }, - events() { - return [{ - 'submit': (evt) => { - evt.preventDefault(); - const dataJson = $(evt.currentTarget).find('.js-import-json').val(); - let dataObject; - try { - dataObject = JSON.parse(dataJson); - } catch (e) { - this.setError('error-json-malformed'); - return; - } - Meteor.call(this.getMethodName(), dataObject, this.getAdditionalData(), - (error, response) => { - if (error) { - this.setError(error.error); - } else { - Filter.addException(response); - this.onFinish(response); - } - } - ); - }, - }]; + jsonText() { + return Session.get('import.text'); + }, + + membersMapping() { + return Session.get('import.membersToMap'); }, onCreated() { this.error = new ReactiveVar(''); + this.dataToImport = ''; + }, + + onFinish() { + Popup.close(); + }, + + onShowMapping(evt) { + this._storeText(evt); + Popup.open('mapMembers')(evt); + }, + + onSubmit(evt){ + evt.preventDefault(); + const dataJson = this._storeText(evt); + let dataObject; + try { + dataObject = JSON.parse(dataJson); + this.setError(''); + } catch (e) { + this.setError('error-json-malformed'); + return; + } + if(this._hasAllNeededData(dataObject)) { + this._import(dataObject); + } else { + this._prepareAdditionalData(dataObject); + Popup.open(this._screenAdditionalData())(evt); + + } + }, + + events() { + return [{ + submit: this.onSubmit, + 'click .show-mapping': this.onShowMapping, + }]; }, setError(error) { this.error.set(error); }, - onFinish() { - Popup.close(); + _import(dataObject) { + const additionalData = this.getAdditionalData(); + const membersMapping = this.membersMapping(); + if (membersMapping) { + const mappingById = {}; + membersMapping.forEach((member) => { + if (member.wekan) { + mappingById[member.id] = member.wekan._id; + } + }); + additionalData.membersMapping = mappingById; + } + Session.set('import.membersToMap', null); + Session.set('import.text', null); + Meteor.call(this.getMethodName(), dataObject, additionalData, + (error, response) => { + if (error) { + this.setError(error.error); + } else { + // ensure will display what we just imported + Filter.addException(response); + this.onFinish(response); + } + } + ); + }, + + _hasAllNeededData(dataObject) { + // import has no members or they are already mapped + return dataObject.members.length === 0 || this.membersMapping(); + }, + + _prepareAdditionalData(dataObject) { + // we will work on the list itself (an ordered array of objects) + // when a mapping is done, we add a 'wekan' field to the object representing the imported member + const membersToMap = dataObject.members; + // auto-map based on username + membersToMap.forEach((importedMember) => { + const wekanUser = Users.findOne({username: importedMember.username}); + if(wekanUser) { + importedMember.wekan = wekanUser; + } + }); + // store members data and mapping in Session + // (we go deep and 2-way, so storing in data context is not a viable option) + Session.set('import.membersToMap', membersToMap); + return membersToMap; + }, + + _screenAdditionalData() { + return 'mapMembers'; + }, + + _storeText() { + const dataJson = this.$('.js-import-json').val(); + Session.set('import.text', dataJson); + return dataJson; }, }); ImportPopup.extendComponent({ getAdditionalData() { - const listId = this.data()._id; + const listId = this.currentData()._id; const selector = `#js-list-${this.currentData()._id} .js-minicard:first`; const firstCardDom = $(selector).get(0); const sortIndex = Utils.calculateIndex(null, firstCardDom).base; @@ -88,3 +162,110 @@ ImportPopup.extendComponent({ }, }).register('boardImportBoardPopup'); +const ImportMapMembers = BlazeComponent.extendComponent({ + members() { + return Session.get('import.membersToMap'); + }, + _refreshMembers(listOfMembers) { + Session.set('import.membersToMap', listOfMembers); + }, + /** + * Will look into the list of members to import for the specified memberId, + * then set its property to the supplied value. + * If unset is true, it will remove the property from the rest of the list as well. + * + * use: + * - memberId = null to use selected member + * - value = null to unset a property + * - unset = true to ensure property is only set on 1 member at a time + */ + _setPropertyForMember(property, value, memberId, unset = false) { + const listOfMembers = this.members(); + let finder = null; + if(memberId) { + finder = (member) => member.id === memberId; + } else { + finder = (member) => member.selected; + } + listOfMembers.forEach((member) => { + if(finder(member)) { + if(value !== null) { + member[property] = value; + } else { + delete member[property]; + } + if(!unset) { + // we shortcut if we don't care about unsetting the others + return false; + } + } else if(unset) { + delete member[property]; + } + return true; + }); + // Session.get gives us a copy, we have to set it back so it sticks + this._refreshMembers(listOfMembers); + }, + setSelectedMember(memberId) { + return this._setPropertyForMember('selected', true, memberId, true); + }, + /** + * returns the member with specified id, + * or the selected member if memberId is not specified + */ + getMember(memberId = null) { + const allMembers = Session.get('import.membersToMap'); + let finder = null; + if(memberId) { + finder = (user) => user.id === memberId; + } else { + finder = (user) => user.selected; + } + return allMembers.find(finder); + }, + mapSelectedMember(wekan) { + return this._setPropertyForMember('wekan', wekan, null); + }, + unmapMember(memberId){ + return this._setPropertyForMember('wekan', null, memberId); + }, +}); + +ImportMapMembers.extendComponent({ + onMapMember(evt) { + const memberToMap = this.currentData(); + if(memberToMap.wekan) { + // todo xxx ask for confirmation? + this.unmapMember(memberToMap.id); + } else { + this.setSelectedMember(memberToMap.id); + Popup.open('mapMembersAdd')(evt); + } + }, + onSubmit(evt) { + evt.preventDefault(); + Popup.back(); + }, + events() { + return [{ + 'submit': this.onSubmit, + 'click .mapping': this.onMapMember, + }]; + }, +}).register('mapMembersPopup'); + +ImportMapMembers.extendComponent({ + onSelectUser(){ + this.mapSelectedMember(this.currentData()); + Popup.back(); + }, + events() { + return [{ + 'click .js-select-import': this.onSelectUser, + }]; + }, + onRendered() { + // todo XXX why do I not get the focus?? + this.find('.js-map-member input').focus(); + }, +}).register('mapMembersAddPopup'); |