summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorLauri Ojansivu <x@xet7.org>2020-05-13 03:28:02 +0300
committerLauri Ojansivu <x@xet7.org>2020-05-13 03:28:02 +0300
commit851bfa53e684a6b9d8685bea01701af78549f0d2 (patch)
tree277243481c3c1a38324638f5684f4ee75b6e50d6 /client
parentba01ebe05d80cb468c22f9d780855af1cf14124a (diff)
parenta570c4a86157ce4b60e056a4f0583ebc0fe009cf (diff)
downloadwekan-851bfa53e684a6b9d8685bea01701af78549f0d2.tar.gz
wekan-851bfa53e684a6b9d8685bea01701af78549f0d2.tar.bz2
wekan-851bfa53e684a6b9d8685bea01701af78549f0d2.zip
Merge branch 'add-more-import-export-options' of https://github.com/brymut/wekan into brymut-add-more-import-export-options
Diffstat (limited to 'client')
-rw-r--r--client/components/import/csvMembersMapper.js37
-rw-r--r--client/components/import/import.jade2
-rw-r--r--client/components/import/import.js52
-rw-r--r--client/components/sidebar/sidebar.jade19
-rw-r--r--client/components/sidebar/sidebar.js59
5 files changed, 155 insertions, 14 deletions
diff --git a/client/components/import/csvMembersMapper.js b/client/components/import/csvMembersMapper.js
new file mode 100644
index 00000000..cf8d5837
--- /dev/null
+++ b/client/components/import/csvMembersMapper.js
@@ -0,0 +1,37 @@
+export function getMembersToMap(data) {
+ // 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 = [];
+ const importedMembers = [];
+ let membersIndex;
+
+ for (let i = 0; i < data[0].length; i++) {
+ if (data[0][i].toLowerCase() === 'members') {
+ membersIndex = i;
+ }
+ }
+
+ for (let i = 1; i < data.length; i++) {
+ if (data[i][membersIndex]) {
+ for (const importedMember of data[i][membersIndex].split(' ')) {
+ if (importedMember && importedMembers.indexOf(importedMember) === -1) {
+ importedMembers.push(importedMember);
+ }
+ }
+ }
+ }
+
+ for (let importedMember of importedMembers) {
+ importedMember = {
+ username: importedMember,
+ id: importedMember,
+ };
+ const wekanUser = Users.findOne({ username: importedMember.username });
+ if (wekanUser) importedMember.wekanId = wekanUser._id;
+ membersToMap.push(importedMember);
+ }
+
+ return membersToMap;
+}
diff --git a/client/components/import/import.jade b/client/components/import/import.jade
index 1551a7dd..2bea24ae 100644
--- a/client/components/import/import.jade
+++ b/client/components/import/import.jade
@@ -13,7 +13,7 @@ template(name="import")
template(name="importTextarea")
form
p: label(for='import-textarea') {{_ instruction}} {{_ 'import-board-instruction-about-errors'}}
- textarea.js-import-json(placeholder="{{_ 'import-json-placeholder'}}" autofocus)
+ textarea.js-import-json(placeholder="{{_ importPlaceHolder}}" autofocus)
| {{jsonText}}
input.primary.wide(type="submit" value="{{_ 'import'}}")
diff --git a/client/components/import/import.js b/client/components/import/import.js
index 6368885b..673900fd 100644
--- a/client/components/import/import.js
+++ b/client/components/import/import.js
@@ -1,5 +1,8 @@
import trelloMembersMapper from './trelloMembersMapper';
import wekanMembersMapper from './wekanMembersMapper';
+import csvMembersMapper from './csvMembersMapper';
+
+const Papa = require('papaparse');
BlazeComponent.extendComponent({
title() {
@@ -30,20 +33,30 @@ BlazeComponent.extendComponent({
}
},
- importData(evt) {
+ importData(evt, dataSource) {
evt.preventDefault();
- const dataJson = this.find('.js-import-json').value;
- try {
- const dataObject = JSON.parse(dataJson);
- this.setError('');
- this.importedData.set(dataObject);
- const membersToMap = this._prepareAdditionalData(dataObject);
- // store members data and mapping in Session
- // (we go deep and 2-way, so storing in data context is not a viable option)
+ const input = this.find('.js-import-json').value;
+ if (dataSource === 'csv') {
+ const csv = input.indexOf('\t') > 0 ? input.replace(/(\t)/g, ',') : input;
+ const ret = Papa.parse(csv);
+ if (ret && ret.data && ret.data.length) this.importedData.set(ret.data);
+ else throw new Meteor.Error('error-csv-schema');
+ const membersToMap = this._prepareAdditionalData(ret.data);
this.membersToMap.set(membersToMap);
this.nextStep();
- } catch (e) {
- this.setError('error-json-malformed');
+ } else {
+ try {
+ const dataObject = JSON.parse(input);
+ this.setError('');
+ this.importedData.set(dataObject);
+ const membersToMap = this._prepareAdditionalData(dataObject);
+ // store members data and mapping in Session
+ // (we go deep and 2-way, so storing in data context is not a viable option)
+ this.membersToMap.set(membersToMap);
+ this.nextStep();
+ } catch (e) {
+ this.setError('error-json-malformed');
+ }
}
},
@@ -91,6 +104,9 @@ BlazeComponent.extendComponent({
case 'wekan':
membersToMap = wekanMembersMapper.getMembersToMap(dataObject);
break;
+ case 'csv':
+ membersToMap = csvMembersMapper.getMembersToMap(dataObject);
+ break;
}
return membersToMap;
},
@@ -109,11 +125,23 @@ BlazeComponent.extendComponent({
return `import-board-instruction-${Session.get('importSource')}`;
},
+ importPlaceHolder() {
+ const importSource = Session.get('importSource');
+ if (importSource === 'csv') {
+ return 'import-csv-placeholder';
+ } else {
+ return 'import-json-placeholder';
+ }
+ },
+
events() {
return [
{
submit(evt) {
- return this.parentComponent().importData(evt);
+ return this.parentComponent().importData(
+ evt,
+ Session.get('importSource'),
+ );
},
},
];
diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade
index 6bfedc9c..280eaeaf 100644
--- a/client/components/sidebar/sidebar.jade
+++ b/client/components/sidebar/sidebar.jade
@@ -230,6 +230,8 @@ template(name="chooseBoardSource")
a(href="{{pathFor '/import/trello'}}") {{_ 'from-trello'}}
li
a(href="{{pathFor '/import/wekan'}}") {{_ 'from-wekan'}}
+ li
+ a(href="{{pathFor '/import/csv'}}") {{_ 'from-csv'}}
template(name="archiveBoardPopup")
p {{_ 'close-board-pop'}}
@@ -300,7 +302,7 @@ template(name="boardMenuPopup")
ul.pop-over-list
if withApi
li
- a(href="{{exportUrl}}", download="{{exportFilename}}")
+ a.js-export-board
i.fa.fa-share-alt
| {{_ 'export-board'}}
li
@@ -360,6 +362,21 @@ template(name="boardMenuPopup")
i.fa.fa-sitemap
| {{_ 'subtask-settings'}}
+template(name="exportBoard")
+ ul.pop-over-list
+ li
+ a(href="{{exportUrl}}", download="{{exportJsonFilename}}")
+ i.fa.fa-share-alt
+ | {{_ 'export-board-json'}}
+ li
+ a(href="{{exportCsvUrl}}", download="{{exportCsvFilename}}")
+ i.fa.fa-share-alt
+ | {{_ 'export-board-csv'}}
+ li
+ a(href="{{exportTsvUrl}}", download="{{exportTsvFilename}}")
+ i.fa.fa-share-alt
+ | {{_ 'export-board-tsv'}}
+
template(name="labelsWidget")
.board-widget.board-widget-labels
h3
diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js
index cbe00797..0541df5e 100644
--- a/client/components/sidebar/sidebar.js
+++ b/client/components/sidebar/sidebar.js
@@ -1,3 +1,4 @@
+sidebar.js;
import { Cookies } from 'meteor/ostrio:cookies';
const cookies = new Cookies();
Sidebar = null;
@@ -213,6 +214,7 @@ Template.boardMenuPopup.events({
'click .js-import-board': Popup.open('chooseBoardSource'),
'click .js-subtask-settings': Popup.open('boardSubtaskSettings'),
'click .js-card-settings': Popup.open('boardCardSettings'),
+ 'click .js-export-board': Popup.open('exportBoard'),
});
Template.boardMenuPopup.onCreated(function() {
@@ -405,6 +407,63 @@ BlazeComponent.extendComponent({
},
}).register('chooseBoardSourcePopup');
+BlazeComponent.extendComponent({
+ template() {
+ return 'exportBoard';
+ },
+ withApi() {
+ return Template.instance().apiEnabled.get();
+ },
+ exportUrl() {
+ const params = {
+ boardId: Session.get('currentBoard'),
+ };
+ const queryParams = {
+ authToken: Accounts._storedLoginToken(),
+ };
+ return FlowRouter.path('/api/boards/:boardId/export', params, queryParams);
+ },
+ exportCsvUrl() {
+ const params = {
+ boardId: Session.get('currentBoard'),
+ };
+ const queryParams = {
+ authToken: Accounts._storedLoginToken(),
+ };
+ return FlowRouter.path(
+ '/api/boards/:boardId/export/csv',
+ params,
+ queryParams,
+ );
+ },
+ exportTsvUrl() {
+ const params = {
+ boardId: Session.get('currentBoard'),
+ };
+ const queryParams = {
+ authToken: Accounts._storedLoginToken(),
+ delimiter: '\t',
+ };
+ return FlowRouter.path(
+ '/api/boards/:boardId/export/csv',
+ params,
+ queryParams,
+ );
+ },
+ exportJsonFilename() {
+ const boardId = Session.get('currentBoard');
+ return `wekan-export-board-${boardId}.json`;
+ },
+ exportCsvFilename() {
+ const boardId = Session.get('currentBoard');
+ return `wekan-export-board-${boardId}.csv`;
+ },
+ exportTsvFilename() {
+ const boardId = Session.get('currentBoard');
+ return `wekan-export-board-${boardId}.tsv`;
+ },
+}).register('exportBoardPopup');
+
Template.labelsWidget.events({
'click .js-label': Popup.open('editLabel'),
'click .js-add-label': Popup.open('createLabel'),