Browse Source

Import board: added UI

Xavier Priour 9 years ago
parent
commit
468694a84c

+ 2 - 0
client/components/boards/boardHeader.jade

@@ -107,6 +107,8 @@ template(name="createBoardPopup")
           | {{{_ 'board-private-info'}}}
         a.js-change-visibility {{_ 'change'}}.
     input.primary.wide(type="submit" value="{{_ 'create'}}")
+    | {{_ 'or'}}
+    a.js-import {{_ 'import-board'}}
 
 
 template(name="boardChangeTitlePopup")

+ 1 - 0
client/components/boards/boardHeader.js

@@ -145,6 +145,7 @@ BlazeComponent.extendComponent({
         this.setVisibility(this.currentData());
       },
       'click .js-change-visibility': this.toggleVisibilityMenu,
+      'click .js-import': Popup.open('boardImportBoard'),
       submit: this.onSubmit,
     }];
   },

+ 2 - 0
client/components/boards/boardHeader.styl

@@ -0,0 +1,2 @@
+a.js-import
+  text-decoration underline

+ 8 - 0
client/components/import/import.jade

@@ -0,0 +1,8 @@
+template(name="importPopup")
+  if error.get
+    .warning {{_ error.get}}
+  form
+    label
+      | {{_ getLabel}}
+      textarea.js-card-json(placeholder="{{_ 'import-json-placeholder'}}" autofocus)
+    input.primary.wide(type="submit" value="{{_ 'import'}}")

+ 80 - 0
client/components/import/import.js

@@ -0,0 +1,80 @@
+/**
+ * Abstract root for all import popup screens.
+ * Descendants must define:
+ * - getMethodName(): return the Meteor method to call for import, passing json data decoded as object
+ * and additional data (see below)
+ * - getAdditionalData(): return object containing additional data passed to Meteor method
+ * (like list ID and position for a card import)
+ * - getLabel(): i18n key for the text displayed in the popup, usually to explain how to get the data out of the
+ * source system.
+ */
+const ImportPopup = BlazeComponent.extendComponent({
+  template() {return 'importPopup';},
+  events() {
+    return [{
+      'submit': (evt) => {
+        evt.preventDefault();
+        const dataJson = $(evt.currentTarget).find('textarea').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);
+              Popup.close();
+            }
+          }
+        );
+      },
+    }];
+  },
+
+  onCreated() {
+    this.error = new ReactiveVar('');
+  },
+
+  setError(error) {
+    this.error.set(error);
+  },
+});
+
+ImportPopup.extendComponent({
+  getAdditionalData() {
+    const listId = this.data()._id;
+    const firstCardDom = $(`#js-list-${this.currentData()._id} .js-minicard:first`).get(0);
+    const sortIndex = Utils.calculateIndex(null, firstCardDom).base;
+    const result = {listId, sortIndex};
+    return result;
+  },
+
+  getMethodName() {
+    return 'importTrelloCard';
+  },
+
+  getLabel() {
+    return 'import-card-trello-instruction';
+  },
+}).register('listImportCardPopup');
+
+ImportPopup.extendComponent({
+  getAdditionalData() {
+    const result = {};
+    return result;
+  },
+
+  getMethodName() {
+    return 'importTrelloBoard';
+  },
+
+  getLabel() {
+    return 'import-board-trello-instruction';
+  },
+}).register('boardImportBoardPopup');
+

+ 0 - 9
client/components/lists/listHeader.jade

@@ -31,15 +31,6 @@ template(name="listActionPopup")
 template(name="listMoveCardsPopup")
   +boardLists
 
-template(name="listImportCardPopup")
-  if error.get
-    .warning {{_ error.get}}
-  form
-    label
-      | {{_ 'card-json'}}
-      textarea.js-card-json(placeholder="{{_ 'card-json-placeholder'}}" autofocus)
-    input.primary.wide(type="submit" value="{{_ 'import'}}")
-
 template(name="boardLists")
   ul.pop-over-list
     each currentBoard.lists

+ 0 - 39
client/components/lists/listHeader.js

@@ -49,45 +49,6 @@ Template.listActionPopup.events({
   },
 });
 
-
-BlazeComponent.extendComponent({
-  events() {
-    return [{
-      'submit': (evt) => {
-        evt.preventDefault();
-        const jsonData = $(evt.currentTarget).find('textarea').val();
-        const firstCardDom = $(`#js-list-${this.currentData()._id} .js-minicard:first`).get(0);
-        const sortIndex = Utils.calculateIndex(null, firstCardDom).base;
-        let trelloCard;
-        try {
-          trelloCard = JSON.parse(jsonData);
-        } catch (e) {
-          this.setError('error-json-malformed');
-          return;
-        }
-        Meteor.call('importTrelloCard', trelloCard, this.currentData()._id, sortIndex,
-          (error, response) => {
-            if (error) {
-              this.setError(error.error);
-            } else {
-              Filter.addException(response);
-              Popup.close();
-            }
-          }
-        );
-      },
-    }];
-  },
-
-  onCreated() {
-    this.error = new ReactiveVar('');
-  },
-
-  setError(error) {
-    this.error.set(error);
-  },
-}).register('listImportCardPopup');
-
 Template.listMoveCardsPopup.events({
   'click .js-select-list'() {
     const fromList = Template.parentData(2).data;

+ 6 - 2
i18n/en.i18n.json

@@ -54,6 +54,7 @@
     "boardChangeColorPopup-title": "Change Board Background",
     "boardChangeTitlePopup-title": "Rename Board",
     "boardChangeVisibilityPopup-title": "Change Visibility",
+    "boardImportBoardPopup-title": "Import board from Trello",
     "boardMenuPopup-title": "Board Menu",
     "boards": "Boards",
     "bucket-example": "Like “Bucket List” for example",
@@ -66,8 +67,6 @@
     "card-edit-attachments": "Edit attachments",
     "card-edit-labels": "Edit labels",
     "card-edit-members": "Edit members",
-    "card-json": "Go to a Trello card, select 'Share and more...' then 'Export JSON' and copy the resulting text",
-    "card-json-placeholder": "Paste your valid JSON data here",
     "card-labels-title": "Change the labels for the card.",
     "card-members-title": "Add or remove members of the board from the card.",
     "cardAttachmentsPopup-title": "Attach From",
@@ -136,7 +135,11 @@
     "header-logo-title": "Go back to your boards page.",
     "home": "Home",
     "import": "Import",
+    "import-board": "import from Trello",
+    "import-board-trello-instruction": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text",
     "import-card": "Import a Trello card",
+    "import-card-trello-instruction": "Go to a Trello card, select 'Share and more...' then 'Export JSON' and copy the resulting text",
+    "import-json-placeholder": "Paste your valid JSON data here",
     "info": "Infos",
     "initials": "Initials",
     "joined": "joined",
@@ -175,6 +178,7 @@
     "normal": "Normal",
     "normal-desc": "Can view and edit cards. Can't change settings.",
     "optional": "optional",
+    "or": "or",
     "page-maybe-private": "This page may be private. You may be able to view it by <a href='%s'>logging in</a>.",
     "page-not-found": "Page not found.",
     "password": "Password",

+ 20 - 5
models/import.js

@@ -1,5 +1,5 @@
 Meteor.methods({
-  importTrelloCard(trelloCard, listId, sortIndex) {
+  importTrelloCard(trelloCard, data) {
     // 1. check parameters are ok from a syntax point of view
     const DateString = Match.Where(function (dateAsString) {
       check(dateAsString, String);
@@ -22,14 +22,16 @@ Meteor.methods({
         })],
         members: [Object],
       }));
-      check(listId, String);
-      check(sortIndex, Number);
+      check(data, {
+        listId: String,
+        sortIndex: Number,
+      });
     } catch(e) {
       throw new Meteor.Error('error-json-schema');
     }
 
     // 2. check parameters are ok from a business point of view (exist & authorized)
-    const list = Lists.findOne(listId);
+    const list = Lists.findOne(data.listId);
     if(!list) {
       throw new Meteor.Error('error-list-doesNotExist');
     }
@@ -49,7 +51,7 @@ Meteor.methods({
       dateLastActivity: dateOfImport,
       description: trelloCard.desc,
       listId: list._id,
-      sort: sortIndex,
+      sort: data.sortIndex,
       title: trelloCard.name,
       // XXX use the original user?
       userId: Meteor.userId(),
@@ -127,4 +129,17 @@ Meteor.methods({
     });
     return cardId;
   },
+  importTrelloBoard(trelloBoard, data) {
+    // 1. check parameters are ok from a syntax point of view
+    try {
+      // XXX do proper checking
+      check(trelloBoard, Object);
+      check(data, Object);
+    } catch(e) {
+      throw new Meteor.Error('error-json-schema');
+    }
+    // 2. check parameters are ok from a business point of view (exist & authorized)
+    // XXX check we are allowed
+    // 3. create all elements
+  },
 });