import.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import trelloMembersMapper from './trelloMembersMapper';
  2. import wekanMembersMapper from './wekanMembersMapper';
  3. BlazeComponent.extendComponent({
  4. title() {
  5. return `import-board-title-${Session.get('importSource')}`;
  6. },
  7. }).register('importHeaderBar');
  8. BlazeComponent.extendComponent({
  9. onCreated() {
  10. this.error = new ReactiveVar('');
  11. this.steps = ['importTextarea', 'importMapMembers'];
  12. this._currentStepIndex = new ReactiveVar(0);
  13. this.importedData = new ReactiveVar();
  14. this.membersToMap = new ReactiveVar([]);
  15. this.importSource = Session.get('importSource');
  16. },
  17. currentTemplate() {
  18. return this.steps[this._currentStepIndex.get()];
  19. },
  20. nextStep() {
  21. const nextStepIndex = this._currentStepIndex.get() + 1;
  22. if (nextStepIndex >= this.steps.length) {
  23. this.finishImport();
  24. } else {
  25. this._currentStepIndex.set(nextStepIndex);
  26. }
  27. },
  28. importData(evt) {
  29. evt.preventDefault();
  30. const dataJson = this.find('.js-import-json').value;
  31. try {
  32. const dataObject = JSON.parse(dataJson);
  33. this.setError('');
  34. this.importedData.set(dataObject);
  35. const membersToMap = this._prepareAdditionalData(dataObject);
  36. // store members data and mapping in Session
  37. // (we go deep and 2-way, so storing in data context is not a viable option)
  38. this.membersToMap.set(membersToMap);
  39. this.nextStep();
  40. } catch (e) {
  41. this.setError('error-json-malformed');
  42. }
  43. },
  44. setError(error) {
  45. this.error.set(error);
  46. },
  47. finishImport() {
  48. const additionalData = {};
  49. const membersMapping = this.membersToMap.get();
  50. if (membersMapping) {
  51. const mappingById = {};
  52. membersMapping.forEach((member) => {
  53. if (member.wekanId) {
  54. mappingById[member.id] = member.wekanId;
  55. }
  56. });
  57. additionalData.membersMapping = mappingById;
  58. }
  59. this.membersToMap.set([]);
  60. Meteor.call('importBoard',
  61. this.importedData.get(),
  62. additionalData,
  63. this.importSource,
  64. Session.get('fromBoard'),
  65. (err, res) => {
  66. if (err) {
  67. this.setError(err.error);
  68. } else {
  69. Session.set('fromBoard', null);
  70. Utils.goBoardId(res);
  71. }
  72. }
  73. );
  74. },
  75. _prepareAdditionalData(dataObject) {
  76. const importSource = Session.get('importSource');
  77. let membersToMap;
  78. switch (importSource) {
  79. case 'trello':
  80. membersToMap = trelloMembersMapper.getMembersToMap(dataObject);
  81. break;
  82. case 'wekan':
  83. membersToMap = wekanMembersMapper.getMembersToMap(dataObject);
  84. break;
  85. }
  86. return membersToMap;
  87. },
  88. _screenAdditionalData() {
  89. return 'mapMembers';
  90. },
  91. }).register('import');
  92. BlazeComponent.extendComponent({
  93. template() {
  94. return 'importTextarea';
  95. },
  96. instruction() {
  97. return `import-board-instruction-${Session.get('importSource')}`;
  98. },
  99. events() {
  100. return [{
  101. submit(evt) {
  102. return this.parentComponent().importData(evt);
  103. },
  104. }];
  105. },
  106. }).register('importTextarea');
  107. BlazeComponent.extendComponent({
  108. onCreated() {
  109. this.autorun(() => {
  110. this.parentComponent().membersToMap.get().forEach(({ wekanId }) => {
  111. if (wekanId) {
  112. this.subscribe('user-miniprofile', wekanId);
  113. }
  114. });
  115. });
  116. },
  117. members() {
  118. return this.parentComponent().membersToMap.get();
  119. },
  120. _refreshMembers(listOfMembers) {
  121. return this.parentComponent().membersToMap.set(listOfMembers);
  122. },
  123. /**
  124. * Will look into the list of members to import for the specified memberId,
  125. * then set its property to the supplied value.
  126. * If unset is true, it will remove the property from the rest of the list as well.
  127. *
  128. * use:
  129. * - memberId = null to use selected member
  130. * - value = null to unset a property
  131. * - unset = true to ensure property is only set on 1 member at a time
  132. */
  133. _setPropertyForMember(property, value, memberId, unset = false) {
  134. const listOfMembers = this.members();
  135. let finder = null;
  136. if(memberId) {
  137. finder = (member) => member.id === memberId;
  138. } else {
  139. finder = (member) => member.selected;
  140. }
  141. listOfMembers.forEach((member) => {
  142. if(finder(member)) {
  143. if(value !== null) {
  144. member[property] = value;
  145. } else {
  146. delete member[property];
  147. }
  148. if(!unset) {
  149. // we shortcut if we don't care about unsetting the others
  150. return false;
  151. }
  152. } else if(unset) {
  153. delete member[property];
  154. }
  155. return true;
  156. });
  157. // Session.get gives us a copy, we have to set it back so it sticks
  158. this._refreshMembers(listOfMembers);
  159. },
  160. setSelectedMember(memberId) {
  161. return this._setPropertyForMember('selected', true, memberId, true);
  162. },
  163. /**
  164. * returns the member with specified id,
  165. * or the selected member if memberId is not specified
  166. */
  167. getMember(memberId = null) {
  168. const allMembers = this.members();
  169. let finder = null;
  170. if (memberId) {
  171. finder = (user) => user.id === memberId;
  172. } else {
  173. finder = (user) => user.selected;
  174. }
  175. return allMembers.find(finder);
  176. },
  177. mapSelectedMember(wekanId) {
  178. return this._setPropertyForMember('wekanId', wekanId, null);
  179. },
  180. unmapMember(memberId){
  181. return this._setPropertyForMember('wekanId', null, memberId);
  182. },
  183. onSubmit(evt) {
  184. evt.preventDefault();
  185. this.parentComponent().nextStep();
  186. },
  187. onMapMember(evt) {
  188. const memberToMap = this.currentData();
  189. if(memberToMap.wekan) {
  190. // todo xxx ask for confirmation?
  191. this.unmapMember(memberToMap.id);
  192. } else {
  193. this.setSelectedMember(memberToMap.id);
  194. Popup.open('importMapMembersAdd')(evt);
  195. }
  196. },
  197. events() {
  198. return [{
  199. 'submit': this.onSubmit,
  200. 'click .js-select-member': this.onMapMember,
  201. }];
  202. },
  203. }).register('importMapMembers');
  204. BlazeComponent.extendComponent({
  205. onRendered() {
  206. this.find('.js-map-member input').focus();
  207. },
  208. onSelectUser(){
  209. Popup.getOpenerComponent().mapSelectedMember(this.currentData()._id);
  210. Popup.back();
  211. },
  212. events() {
  213. return [{
  214. 'click .js-select-import': this.onSelectUser,
  215. }];
  216. },
  217. }).register('importMapMembersAddPopup');