From 739a92e9a3866146987a332449d904613c6bb616 Mon Sep 17 00:00:00 2001 From: Jakob Date: Tue, 10 Sep 2019 12:31:25 +0200 Subject: [PATCH 1/3] first step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jakob 1. try Signed-off-by: Jakob remote calls are working Signed-off-by: Jakob litte changes Signed-off-by: Jakob small fixes Signed-off-by: Jakob incremental fetching Signed-off-by: Jakob integrated tiptap suggestions for test Signed-off-by: Jakob Update package-lock after rebase Signed-off-by: Julius Härtl Fix various errors Signed-off-by: Julius Härtl Cleanup mention plugin use Signed-off-by: Julius Härtl Downgrade tippy Signed-off-by: Julius Härtl --- package-lock.json | 442 ++++++++++++++++++--- package.json | 4 + src/components/card/CardSidebar.vue | 12 +- src/components/card/CommentItem.vue | 81 ++++ src/components/card/CommentsTabSidebar.vue | 319 +++++++++++++++ src/helpers/xml.js | 82 ++++ src/services/CommentApi.js | 126 ++++++ src/store/comment.js | 93 +++++ src/store/main.js | 6 +- 9 files changed, 1094 insertions(+), 71 deletions(-) create mode 100644 src/components/card/CommentItem.vue create mode 100644 src/components/card/CommentsTabSidebar.vue create mode 100644 src/helpers/xml.js create mode 100644 src/services/CommentApi.js create mode 100644 src/store/comment.js diff --git a/package-lock.json b/package-lock.json index bb8162ca6..6ac9cde21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8495,6 +8495,14 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fault": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.3.tgz", + "integrity": "sha512-sfFuP4X0hzrbGKjAUNXYvNqsZ5F6ohx/dZ9I0KQud/aiZNwg263r5L9yGB0clvXHCkzXh5W3t7RSHchggYIFmA==", + "requires": { + "format": "^0.2.2" + } + }, "fb-watchman": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", @@ -9048,6 +9056,11 @@ "mime-types": "^2.1.12" } }, + "format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=" + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -9119,22 +9132,26 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "optional": true }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "optional": true, "requires": { "delegates": "^1.0.0", @@ -9143,12 +9160,14 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "optional": true }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "optional": true, "requires": { "balanced-match": "^1.0.0", @@ -9157,32 +9176,38 @@ }, "chownr": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "optional": true }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, "debug": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "optional": true, "requires": { "ms": "^2.1.1" @@ -9190,22 +9215,26 @@ }, "deep-extend": { "version": "0.6.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { "version": "1.2.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "optional": true, "requires": { "minipass": "^2.2.1" @@ -9213,12 +9242,14 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { "aproba": "^1.0.3", @@ -9233,7 +9264,8 @@ }, "glob": { "version": "7.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -9246,12 +9278,14 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "iconv-lite": { "version": "0.4.24", - "bundled": true, + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -9259,7 +9293,8 @@ }, "ignore-walk": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "optional": true, "requires": { "minimatch": "^3.0.4" @@ -9267,7 +9302,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { "once": "^1.3.0", @@ -9276,17 +9312,20 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "optional": true }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "optional": true, "requires": { "number-is-nan": "^1.0.0" @@ -9294,12 +9333,14 @@ }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "optional": true, "requires": { "brace-expansion": "^1.1.7" @@ -9307,12 +9348,14 @@ }, "minimist": { "version": "0.0.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "optional": true }, "minipass": { "version": "2.3.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "optional": true, "requires": { "safe-buffer": "^5.1.2", @@ -9321,7 +9364,8 @@ }, "minizlib": { "version": "1.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "optional": true, "requires": { "minipass": "^2.2.1" @@ -9329,7 +9373,8 @@ }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "optional": true, "requires": { "minimist": "0.0.8" @@ -9337,12 +9382,14 @@ }, "ms": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "optional": true }, "needle": { "version": "2.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz", + "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", "optional": true, "requires": { "debug": "^4.1.0", @@ -9352,7 +9399,8 @@ }, "node-pre-gyp": { "version": "0.12.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", + "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -9369,7 +9417,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { "abbrev": "1", @@ -9378,12 +9427,14 @@ }, "npm-bundled": { "version": "1.0.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", "optional": true }, "npm-packlist": { "version": "1.4.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", + "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -9392,7 +9443,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -9403,17 +9455,20 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "optional": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "optional": true, "requires": { "wrappy": "1" @@ -9421,17 +9476,20 @@ }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -9440,17 +9498,20 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "optional": true }, "rc": { "version": "1.2.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "optional": true, "requires": { "deep-extend": "^0.6.0", @@ -9461,14 +9522,16 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } } }, "readable-stream": { "version": "2.3.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -9482,7 +9545,8 @@ }, "rimraf": { "version": "2.6.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "optional": true, "requires": { "glob": "^7.1.3" @@ -9490,37 +9554,44 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "optional": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, "semver": { "version": "5.7.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "optional": true, "requires": { "code-point-at": "^1.0.0", @@ -9530,7 +9601,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -9538,7 +9610,8 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "optional": true, "requires": { "ansi-regex": "^2.0.0" @@ -9546,12 +9619,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { "version": "4.4.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "optional": true, "requires": { "chownr": "^1.1.1", @@ -9565,12 +9640,14 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, "wide-align": { "version": "1.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "optional": true, "requires": { "string-width": "^1.0.2 || 2" @@ -9578,12 +9655,14 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "optional": true } } @@ -9611,6 +9690,11 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "fuse.js": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.5.tgz", + "integrity": "sha512-s9PGTaQIkT69HaeoTVjwGsLfb8V8ScJLx5XGFcKHg0MqLUH/UZ4EKOtqtXX9k7AFqCGxD1aJmYb8Q5VYDibVRQ==" + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -10030,6 +10114,11 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "highlight.js": { + "version": "9.15.10", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz", + "integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==" + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -12793,6 +12882,15 @@ "signal-exit": "^3.0.0" } }, + "lowlight": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.12.1.tgz", + "integrity": "sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w==", + "requires": { + "fault": "^1.0.2", + "highlight.js": "~9.15.0" + } + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -13937,6 +14035,11 @@ "wordwrap": "~1.0.0" } }, + "orderedmap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.0.0.tgz", + "integrity": "sha1-2Q/Cuh7QhRkJB9YB3sbmpT+NQbo=" + }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", @@ -15203,6 +15306,134 @@ "sisteransi": "^1.0.3" } }, + "prosemirror-collab": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.1.2.tgz", + "integrity": "sha512-ew0p0XWlp3PYc4h20hOfix8UPSRaJMRHQQCMoIUzxoiBgGGij/N4pXIY+w/iw5JISgP8QYyOy5arOYnCzFJQlQ==", + "requires": { + "prosemirror-state": "^1.0.0" + } + }, + "prosemirror-commands": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.0.8.tgz", + "integrity": "sha512-P9QdkYYBHWsrJ1JztQuHgeZS7DPCcijQduOj9oxFiqK8Fm6eTsVHzU1IwiRBe+FlK7tyQaerhu/F5K8sqnZ1Cw==", + "requires": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "prosemirror-dropcursor": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.2.0.tgz", + "integrity": "sha512-D7JrvOgN32PmOgfimdDMKCuYp4tGyCulpsd39/Nzvn9A+tCJmM8XY1PB07zkr2vjrjF09WYD3Ifer7Z3pk/YRw==", + "requires": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "prosemirror-gapcursor": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz", + "integrity": "sha512-k021MtJibWs3NaJI6S9tCXfTZ/kaugFZBndHkkWx3Zfk0QDUO6JfVATpflxADN6DUkRwJ7qWyHlLDWu71hxHFQ==", + "requires": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "prosemirror-history": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.0.4.tgz", + "integrity": "sha512-Kk2UisC9EzYcsNv+ILiQJWpsu0rbT6+oAAkvseFUHnudtfkmYAJu1+Xp3F0xTTCVmQdSqSLVk8qydllXUUOU4Q==", + "requires": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "rope-sequence": "^1.2.0" + } + }, + "prosemirror-inputrules": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.0.4.tgz", + "integrity": "sha512-RhuBghqUgYWm8ai/P+k1lMl1ZGvt6Cs3Xeur8oN0L1Yy+Z5GmsTp3fT8RVl+vJeGkItEAxAit9Qh7yZxixX7rA==", + "requires": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "prosemirror-keymap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.0.2.tgz", + "integrity": "sha512-aq3fBT3WMbwGNacUtMbS/mxd87hjJyjtUx5/h3q/P3FiVqHxmeA9snxQsZHYe0cWRziZePun8zw6kHFKLp/DAQ==", + "requires": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.0.0" + } + }, + "prosemirror-model": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.7.4.tgz", + "integrity": "sha512-yxdpPh9Uv5vAOZvmbhg4fsGUK1oHuQs69iX7cFZ0A4Y+AyMMWRCNKUt21uv84HbXb4I180l4pJE8ibaH/SwYiw==", + "requires": { + "orderedmap": "^1.0.0" + } + }, + "prosemirror-schema-list": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.0.4.tgz", + "integrity": "sha512-7Y0b6FIG6ATnCcDSLrZfU9yIfOG5Yad3DMNZ9W7GGfMSzdIl0aHExrsIUgviJZjovO2jtLJVbxWGjMR3OrTupA==", + "requires": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "prosemirror-state": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.2.4.tgz", + "integrity": "sha512-ViXpXond3BbSL12ENARQGq3Y8igwFMbTcy96xUNK8kfIcfQRlYlgYrBPXIkHC5+QZtbPrYlpuJ2+QyeSlSX9Cw==", + "requires": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "prosemirror-tables": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-0.9.5.tgz", + "integrity": "sha512-RlAF/D7OvnDCOL8B6Qt6KuBkb0w3SedTdrou7wH7Nn2ml7+M5xUalW/h1f7dMD3wjsU47/Cn8zTbEkCDIpIggw==", + "requires": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "prosemirror-transform": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.1.5.tgz", + "integrity": "sha512-hJyRcwykLrAAj/ziNbVK1P/ensiszWJ2fNwNiDM8ZWYiMPwM4cAd2jptj/znxJfIvaj0S0psWL1+VhKwPNJDSQ==", + "requires": { + "prosemirror-model": "^1.0.0" + } + }, + "prosemirror-utils": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/prosemirror-utils/-/prosemirror-utils-0.9.6.tgz", + "integrity": "sha512-UC+j9hQQ1POYfMc5p7UFxBTptRiGPR7Kkmbl3jVvU8VgQbkI89tR/GK+3QYC8n+VvBZrtAoCrJItNhWSxX3slA==" + }, + "prosemirror-view": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.12.0.tgz", + "integrity": "sha512-PcG2yGW75530a2DMrRPaFLvy83DUUSj0vImAILWUQQ77Rxhl6NnCVSrU8Pk6HooADOAyqDxxToPRoIz97aeZIA==", + "requires": { + "prosemirror-model": "^1.1.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -16167,6 +16398,11 @@ "inherits": "^2.0.1" } }, + "rope-sequence": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.2.2.tgz", + "integrity": "sha1-ScTlwvVKSOmQsFCSZ3HihxvLMc4=" + }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", @@ -18170,6 +18406,75 @@ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" }, + "tippy.js": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-4.3.5.tgz", + "integrity": "sha512-NDq3efte8nGK6BOJ1dDN1/WelAwfmh3UtIYXXck6+SxLzbIQNZE/cmRSnwScZ/FyiKdIcvFHvYUgqmoGx8CcyA==", + "requires": { + "popper.js": "^1.14.7" + } + }, + "tiptap": { + "version": "1.26.4", + "resolved": "https://registry.npmjs.org/tiptap/-/tiptap-1.26.4.tgz", + "integrity": "sha512-UCH0wufjGdKMuCUydL896sFYXEUWC3bE20h/oONABSf0gull+pqBEm7J1yCl7j50eYa9FiLgUBGPqPTzKLluxQ==", + "requires": { + "prosemirror-commands": "^1.0.8", + "prosemirror-dropcursor": "^1.2.0", + "prosemirror-gapcursor": "^1.0.4", + "prosemirror-inputrules": "^1.0.4", + "prosemirror-keymap": "^1.0.2", + "prosemirror-model": "^1.7.4", + "prosemirror-state": "^1.2.4", + "prosemirror-view": "^1.11.7", + "tiptap-commands": "^1.12.3", + "tiptap-utils": "^1.8.2" + } + }, + "tiptap-commands": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/tiptap-commands/-/tiptap-commands-1.12.3.tgz", + "integrity": "sha512-Dck51lePBwuHmkvkJ6+8V3DbInxAhZwtS2mPvVwz74pDUIcy17tCFw1eHUN50JoXIAci7acuxPKO/weVO1JAyw==", + "requires": { + "prosemirror-commands": "^1.0.8", + "prosemirror-inputrules": "^1.0.4", + "prosemirror-model": "^1.7.4", + "prosemirror-schema-list": "^1.0.4", + "prosemirror-state": "^1.2.4", + "prosemirror-tables": "^0.9.5", + "prosemirror-utils": "^0.9.6", + "tiptap-utils": "^1.8.2" + } + }, + "tiptap-extensions": { + "version": "1.28.4", + "resolved": "https://registry.npmjs.org/tiptap-extensions/-/tiptap-extensions-1.28.4.tgz", + "integrity": "sha512-UAtxngKifjrMtJFmi3D9RCNC5LJutq4yn1Np0cqJ4dTnvhWR49PqN6gKjlMYyzyutiLLQk+/3GM/E6EfVwmHOA==", + "requires": { + "lowlight": "^1.12.1", + "prosemirror-collab": "^1.1.2", + "prosemirror-history": "^1.0.4", + "prosemirror-model": "^1.7.4", + "prosemirror-state": "^1.2.4", + "prosemirror-tables": "^0.9.5", + "prosemirror-transform": "^1.1.5", + "prosemirror-utils": "^0.9.6", + "prosemirror-view": "^1.11.7", + "tiptap": "^1.26.4", + "tiptap-commands": "^1.12.3" + } + }, + "tiptap-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/tiptap-utils/-/tiptap-utils-1.8.2.tgz", + "integrity": "sha512-pyx+3p4fICGM7JU1mcsnRx5jXvLrCL8Nm/9yjeWEZXpAC85L/btY0eFo2Oz4+dKg39+1EGNHheodujx3ngw4lQ==", + "requires": { + "prosemirror-model": "^1.7.4", + "prosemirror-state": "^1.2.4", + "prosemirror-tables": "^0.9.5", + "prosemirror-utils": "^0.9.6" + } + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -18965,6 +19270,11 @@ "browser-process-hrtime": "^0.1.2" } }, + "w3c-keyname": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.1.1.tgz", + "integrity": "sha512-8kSrsGClLiL4kb5/pTxglejUlEAPk3GXtkBblSMrQDxKz0NkMRTVTPBZm6QCNqPOCPsdNvae5XfV+RJZgeGXEA==" + }, "walker": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", diff --git a/package.json b/package.json index 4f8484287..52a5a0b3f 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,10 @@ "nextcloud-vue-collections": "^0.7.1", "url-search-params-polyfill": "^7.0.1", "vue": "^2.6.11", + "fuse.js": "^3.4.5", + "tippy.js": "^4.3.5", + "tiptap": "^1.26.3", + "tiptap-extensions": "^1.28.3", "vue-click-outside": "^1.0.7", "vue-color": "^2.7.0", "vue-easymde": "^1.0.1", diff --git a/src/components/card/CardSidebar.vue b/src/components/card/CardSidebar.vue index bde96bb86..e9a17b040 100644 --- a/src/components/card/CardSidebar.vue +++ b/src/components/card/CardSidebar.vue @@ -21,7 +21,7 @@ --> + + + + diff --git a/src/components/card/CommentsTabSidebar.vue b/src/components/card/CommentsTabSidebar.vue new file mode 100644 index 000000000..79bf9cc3e --- /dev/null +++ b/src/components/card/CommentsTabSidebar.vue @@ -0,0 +1,319 @@ + + + + + diff --git a/src/helpers/xml.js b/src/helpers/xml.js new file mode 100644 index 000000000..de5b0ad99 --- /dev/null +++ b/src/helpers/xml.js @@ -0,0 +1,82 @@ +const xmlToJson = (xml) => { + let obj = {} + if (xml.nodeType === 1) { + if (xml.attributes.length > 0) { + obj['@attributes'] = {} + for (let j = 0; j < xml.attributes.length; j++) { + const attribute = xml.attributes.item(j) + obj['@attributes'][attribute.nodeName] = attribute.nodeValue + } + } + } else if (xml.nodeType === 3) { + obj = xml.nodeValue + } + if (xml.hasChildNodes()) { + for (let i = 0; i < xml.childNodes.length; i++) { + const item = xml.childNodes.item(i) + const nodeName = item.nodeName + if (typeof (obj[nodeName]) === 'undefined') { + obj[nodeName] = xmlToJson(item) + } else { + if (typeof obj[nodeName].push === 'undefined') { + var old = obj[nodeName] + obj[nodeName] = [] + obj[nodeName].push(old) + } + obj[nodeName].push(xmlToJson(item)) + } + } + } + return obj +} +const parseXml = (xml) => { + let dom = null + try { + dom = (new DOMParser()).parseFromString(xml, 'text/xml') + } catch (e) { + console.error('Failed to parse xml document', e) + } + return dom +} +const xmlToTagList = (xml) => { + + let json = xmlToJson(parseXml(xml)) + let list = json['d:multistatus']['d:response'] + + // no element + if (list === undefined) { + return [] + } + let result = [] + + // one element + if (Array.isArray(list) === false) { + let tag = list['d:propstat'] + result.push({ + cardId: tag['d:prop']['oc:objectId']['#text'], + id: tag['d:prop']['oc:id']['#text'], + uId: tag['d:prop']['oc:actorId']['#text'], + creationDateTime: tag['d:prop']['oc:creationDateTime']['#text'], + message: tag['d:prop']['oc:message']['#text'] + }) + + // two or more elements + } else { + for (let index in list) { + let tag = list[index]['d:propstat'] + if (tag['d:status']['#text'] !== 'HTTP/1.1 200 OK') { + continue + } + result.push({ + cardId: tag['d:prop']['oc:objectId']['#text'], + id: tag['d:prop']['oc:id']['#text'], + uId: tag['d:prop']['oc:actorId']['#text'], + creationDateTime: tag['d:prop']['oc:creationDateTime']['#text'], + message: tag['d:prop']['oc:message']['#text'] + }) + } + } + return result +} + +export default xmlToTagList diff --git a/src/services/CommentApi.js b/src/services/CommentApi.js new file mode 100644 index 000000000..aaa35b5d3 --- /dev/null +++ b/src/services/CommentApi.js @@ -0,0 +1,126 @@ +/* + * @copyright Copyright (c) 2018 Michael Weimann + * + * @author Michael Weimann + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +import axios from 'nextcloud-axios' +import { getCurrentUser } from '@nextcloud/auth' + +export class CommentApi { + + url(url) { + url = `dav/comments/deckCard/${url}` + return OC.linkToRemote(url) + } + + listComments(card) { + return axios({ + method: 'REPORT', + url: this.url(`${card.id}`), + data: ` + + ${card.limit} + ${card.offset} + ` + }).then( + (response) => { + return Promise.resolve(response.data) + }, + (err) => { + return Promise.reject(err) + } + ) + .catch((err) => { + return Promise.reject(err) + }) + } + + createComment(commentObj) { + return axios({ + method: 'POST', + url: this.url(`${commentObj.cardId}`), + data: { actorType: 'users', message: `${commentObj.comment}`, verb: 'comment' } + }).then( + (response) => { + let header = response.headers['content-location'] + let headerArray = header.split('/') + let id = headerArray[headerArray.length - 1] + + let ret = { + cardId: (commentObj.cardId).toString(), + id: id, + uId: getCurrentUser().uid, + creationDateTime: (new Date()).toString(), + message: commentObj.comment + } + return Promise.resolve(ret) + }, + (err) => { + return Promise.reject(err) + } + ) + .catch((err) => { + return Promise.reject(err) + }) + } + + updateComment(data) { + return axios({ + method: 'PROPPATCH', + url: this.url(`${data.cardId}/${data.commentId}`), + data: ` + + + + ${data.comment} + + + ` + }).then( + (response) => { + return Promise.resolve(response.data) + }, + (err) => { + return Promise.reject(err) + } + ) + .catch((err) => { + return Promise.reject(err) + }) + } + + deleteComment(data) { + return axios({ + method: 'DELETE', + url: this.url(`${data.cardId}/${data.commentId}`) + }).then( + (response) => { + return Promise.resolve(response.data) + }, + (err) => { + return Promise.reject(err) + } + ) + .catch((err) => { + return Promise.reject(err) + }) + } + +} diff --git a/src/store/comment.js b/src/store/comment.js new file mode 100644 index 000000000..a1c742cef --- /dev/null +++ b/src/store/comment.js @@ -0,0 +1,93 @@ +/* + * @copyright Copyright (c) 2018 Julius Härtl + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +import { CommentApi } from '../services/CommentApi' +import xmlToTagList from '../helpers/xml' +import Vue from 'vue' + +const apiClient = new CommentApi() + +export default { + state: { + comments: {} + }, + mutations: { + addComments(state, commentObj) { + if (state.comments[commentObj.cardId] === undefined) { + Vue.set(state.comments, commentObj.cardId, commentObj.comments) + } else { + // FIXME append comments once incremental fetching is implemented + // state.comments[commentObj.cardId].push(...commentObj.comments) + Vue.set(state.comments, commentObj.cardId, commentObj.comments) + } + }, + createComment(state, newComment) { + if (state.comments[newComment.cardId] === undefined) { + state.comments[newComment.cardId] = [] + } + state.comments[newComment.cardId].push(newComment) + }, + updateComment(state, comment) { + let existingIndex = state.comments[comment.cardId].findIndex(_comment => _comment.id === comment.commentId) + if (existingIndex !== -1) { + state.comments[comment.cardId][existingIndex].message = comment.comment + } + }, + deleteComment(state, comment) { + let existingIndex = state.comments[comment.cardId].findIndex(_comment => _comment.id === comment.commentId) + if (existingIndex !== -1) { + state.comments[comment.cardId].splice(existingIndex, 1) + } + } + }, + actions: { + listComments({ commit }, card) { + apiClient.listComments(card) + .then((comments) => { + const commentsJson = xmlToTagList(comments) + let returnObj = { + cardId: card.id, + comments: commentsJson + } + commit('addComments', returnObj) + }) + }, + createComment({ commit }, newComment) { + apiClient.createComment(newComment) + .then((newComment) => { + commit('createComment', newComment) + }) + }, + deleteComment({ commit }, data) { + apiClient.deleteComment(data) + .then((retVal) => { + commit('deleteComment', data) + }) + }, + updateComment({ commit }, data) { + apiClient.updateComment(data) + .then((retVal) => { + commit('updateComment', data) + }) + } + } +} diff --git a/src/store/main.js b/src/store/main.js index 12770a7e2..63da326a0 100644 --- a/src/store/main.js +++ b/src/store/main.js @@ -28,6 +28,7 @@ import axios from 'nextcloud-axios' import { BoardApi } from './../services/BoardApi' import stack from './stack' import card from './card' +import comment from './comment' Vue.use(Vuex) @@ -44,6 +45,7 @@ export default new Vuex.Store({ modules: { stack, card, + comment, }, strict: debug, state: { @@ -92,8 +94,8 @@ export default new Vuex.Store({ return boards }, currentBoardLabels: state => { - return state.currentBoard.labels - }, + return state.currentBoard ? state.currentBoard.labels : [] + } }, mutations: { toggleShowArchived(state) { From ad069e5e14f28697995edd4a87fab6ed0f2ad3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Sat, 25 Jan 2020 09:52:30 +0100 Subject: [PATCH 2/3] Some comments code cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- package-lock.json | 66 +++++++++--- package.json | 7 +- src/components/ActivityEntry.vue | 2 + src/components/card/CardSidebar.vue | 4 +- src/components/card/CommentItem.vue | 74 +++++++------ src/components/card/CommentsTabSidebar.vue | 118 ++++++++------------- src/helpers/xml.js | 43 ++++---- src/services/CommentApi.js | 18 ++-- src/store/comment.js | 16 +-- src/store/main.js | 2 +- 10 files changed, 187 insertions(+), 163 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6ac9cde21..354169b04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3305,18 +3305,18 @@ } }, "@nextcloud/auth": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-0.3.1.tgz", - "integrity": "sha512-kx5VfB2SWG+BNudoggnjQrmxr559rCDANVLnaDDKmCujToxv0l3kNMTBUUcYhSvv8dyYaD/ZTaXBUON9ZLm9lw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-1.2.1.tgz", + "integrity": "sha512-54g9YPQBFJ+upYMfk5aZhTispuORY/D2R6WdSesJO/hirob7jSpQoUcWuURQj2tssuxADDSgD1rUAiBnbCe1OQ==", "requires": { - "@nextcloud/event-bus": "^0.2.0", - "core-js": "3.2.1" + "@nextcloud/event-bus": "^1.1.2", + "core-js": "3.6.1" }, "dependencies": { "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==" + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.1.tgz", + "integrity": "sha512-186WjSik2iTGfDjfdCZAxv2ormxtKgemjC3SI6PL31qOA0j5LhTDVjHChccoc7brwLvpvLPiMyRlcO88C4l1QQ==" } } }, @@ -3334,6 +3334,30 @@ "core-js": "^3.2.1" }, "dependencies": { + "@nextcloud/auth": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-0.3.1.tgz", + "integrity": "sha512-kx5VfB2SWG+BNudoggnjQrmxr559rCDANVLnaDDKmCujToxv0l3kNMTBUUcYhSvv8dyYaD/ZTaXBUON9ZLm9lw==", + "requires": { + "@nextcloud/event-bus": "^0.2.0", + "core-js": "3.2.1" + }, + "dependencies": { + "core-js": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==" + } + } + }, + "@nextcloud/event-bus": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-0.2.1.tgz", + "integrity": "sha512-yerEPTA5lnJ1JV8qYK6sHMWW8m6fxuMEtptVgv7WnGCy2l5rvxDh9vqwk72qX/Z9i2OrC7Jy382TMYbke8b2Qw==", + "requires": { + "core-js": "^3.1.4" + } + }, "core-js": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.5.0.tgz", @@ -3348,17 +3372,29 @@ "dev": true }, "@nextcloud/event-bus": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-0.2.1.tgz", - "integrity": "sha512-yerEPTA5lnJ1JV8qYK6sHMWW8m6fxuMEtptVgv7WnGCy2l5rvxDh9vqwk72qX/Z9i2OrC7Jy382TMYbke8b2Qw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-1.1.2.tgz", + "integrity": "sha512-E+j71+2LkqEdRjKLrmCKS/fEeI/NxSfthvDH2YkxIK0uH4ZSC+nlzmrNOr0Jby3z0qOgA8PH7+vSLU3D8qdTzw==", "requires": { - "core-js": "^3.1.4" + "@types/semver": "^6.2.0", + "core-js": "^3.6.2", + "semver": "^6.3.0" }, "dependencies": { + "@types/semver": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.0.tgz", + "integrity": "sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA==" + }, "core-js": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.2.tgz", - "integrity": "sha512-S1FfZpeBchkhyoY76YAdFzKS4zz9aOK7EeFaNA2aJlyXyA+sgqz6xdxmLPGXEAf0nF44MVN1kSjrA9Kt3ATDQg==" + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, diff --git a/package.json b/package.json index 52a5a0b3f..b573a7c23 100644 --- a/package.json +++ b/package.json @@ -28,18 +28,19 @@ "dependencies": { "@babel/polyfill": "^7.8.3", "@babel/runtime": "^7.8.3", + "@nextcloud/auth": "^1.2.1", "@nextcloud/l10n": "^1.0.1", "@nextcloud/router": "^1.0.0", "@nextcloud/vue": "^1.2.7", + "fuse.js": "^3.4.5", "nextcloud-axios": "^0.2.1", "nextcloud-server": "^0.15.10", "nextcloud-vue-collections": "^0.7.1", - "url-search-params-polyfill": "^7.0.1", - "vue": "^2.6.11", - "fuse.js": "^3.4.5", "tippy.js": "^4.3.5", "tiptap": "^1.26.3", "tiptap-extensions": "^1.28.3", + "url-search-params-polyfill": "^7.0.1", + "vue": "^2.6.11", "vue-click-outside": "^1.0.7", "vue-color": "^2.7.0", "vue-easymde": "^1.0.1", diff --git a/src/components/ActivityEntry.vue b/src/components/ActivityEntry.vue index ca5017187..84e299056 100644 --- a/src/components/ActivityEntry.vue +++ b/src/components/ActivityEntry.vue @@ -59,6 +59,8 @@ export default { diff --git a/src/components/card/CommentsTabSidebar.vue b/src/components/card/CommentsTabSidebar.vue index 79bf9cc3e..5aa091564 100644 --- a/src/components/card/CommentsTabSidebar.vue +++ b/src/components/card/CommentsTabSidebar.vue @@ -1,28 +1,21 @@ @@ -44,16 +36,20 @@ -

{{ comment.id }}

- -
- - - - +
+
+
+

Keine Kommentare bisher. Beginne die Diskussion!

+
@@ -64,25 +60,21 @@ import { Editor, EditorContent } from 'tiptap' import { Mention } from 'tiptap-extensions' import { mapState } from 'vuex' -import { Avatar } from 'nextcloud-vue' -import { Actions } from 'nextcloud-vue/dist/Components/Actions' -import { ActionButton } from 'nextcloud-vue/dist/Components/ActionButton' +import { Avatar } from '@nextcloud/vue' import CommentItem from './CommentItem' export default { name: 'CommentsTabSidebar', components: { Avatar, - Actions, - ActionButton, CommentItem, - EditorContent + EditorContent, }, props: { card: { type: Object, - default: undefined - } + default: undefined, + }, }, data() { return { @@ -100,7 +92,7 @@ export default { }, // is called when a suggestion starts onEnter: ({ - items, query, range, command, virtualNode + items, query, range, command, virtualNode, }) => { this.query = query this.filteredUsers = items @@ -113,7 +105,7 @@ export default { }, // is called when a suggestion has changed onChange: ({ - items, query, range, virtualNode + items, query, range, virtualNode, }) => { this.query = query this.filteredUsers = items @@ -159,30 +151,30 @@ export default { } const fuse = new Fuse(items, { threshold: 0.2, - keys: ['uid', 'displayname'] + keys: ['uid', 'displayname'], }) return fuse.search(query) - } - }) + }, + }), ], content: '', onUpdate: ({ getHTML }) => { this.newComment = getHTML().replace(/(

|<\/p>)/g, '') - } + }, }), query: null, suggestionRange: null, filteredUsers: [], navigatedUserIndex: 0, insertMention: () => {}, - observer: null + observer: null, } }, computed: { ...mapState({ comments: state => state.comment.comments, - currentBoard: state => state.currentBoard + currentBoard: state => state.currentBoard, }), hasResults() { @@ -190,7 +182,7 @@ export default { }, showSuggestions() { return this.query || this.hasResults - } + }, }, watch: { @@ -198,8 +190,8 @@ export default { immediate: true, handler() { this.loadComments() - } - } + }, + }, }, created() { }, @@ -214,13 +206,14 @@ export default { }) }, createComment() { - let commentObj = { + const commentObj = { cardId: this.card.id, - comment: this.newComment + comment: this.newComment, } this.$store.dispatch('createComment', commentObj) this.loadComments() this.newComment = '' + this.editor.setContent('') }, loadMore() { this.offset = this.offset + this.limit @@ -250,8 +243,8 @@ export default { range: this.suggestionRange, attrs: { id: user.uid, - label: user.displayname - } + label: user.displayname, + }, }) this.editor.focus() }, @@ -268,7 +261,7 @@ export default { placement: 'bottom-start', inertia: true, duration: [400, 200], - showOnInit: true + showOnInit: true, }) // we have to update tippy whenever the DOM is updated if (MutationObserver) { @@ -278,7 +271,7 @@ export default { this.observer.observe(this.$refs.suggestions, { childList: true, subtree: true, - characterData: true + characterData: true, }) } }, @@ -290,30 +283,11 @@ export default { if (this.observer) { this.observer.disconnect() } - } - } + }, + }, } diff --git a/src/helpers/xml.js b/src/helpers/xml.js index de5b0ad99..3c40af3e0 100644 --- a/src/helpers/xml.js +++ b/src/helpers/xml.js @@ -19,7 +19,7 @@ const xmlToJson = (xml) => { obj[nodeName] = xmlToJson(item) } else { if (typeof obj[nodeName].push === 'undefined') { - var old = obj[nodeName] + const old = obj[nodeName] obj[nodeName] = [] obj[nodeName].push(old) } @@ -38,42 +38,41 @@ const parseXml = (xml) => { } return dom } + +const commentToObject = (tag) => { + return { + cardId: tag['d:prop']['oc:objectId']['#text'], + id: tag['d:prop']['oc:id']['#text'], + actorId: tag['d:prop']['oc:actorId']['#text'], + actorDisplayName: tag['d:prop']['oc:actorDisplayName']['#text'], + creationDateTime: tag['d:prop']['oc:creationDateTime']['#text'], + message: tag['d:prop']['oc:message']['#text'], + } +} + +// FIXME: make this generic and not depending on comments const xmlToTagList = (xml) => { - let json = xmlToJson(parseXml(xml)) - let list = json['d:multistatus']['d:response'] + const json = xmlToJson(parseXml(xml)) + const list = json['d:multistatus']['d:response'] // no element if (list === undefined) { return [] } - let result = [] + const result = [] // one element if (Array.isArray(list) === false) { - let tag = list['d:propstat'] - result.push({ - cardId: tag['d:prop']['oc:objectId']['#text'], - id: tag['d:prop']['oc:id']['#text'], - uId: tag['d:prop']['oc:actorId']['#text'], - creationDateTime: tag['d:prop']['oc:creationDateTime']['#text'], - message: tag['d:prop']['oc:message']['#text'] - }) + result.push(commentToObject(list['d:propstat'])) // two or more elements } else { - for (let index in list) { - let tag = list[index]['d:propstat'] - if (tag['d:status']['#text'] !== 'HTTP/1.1 200 OK') { + for (const index in list) { + if (list[index]['d:propstat']['d:status']['#text'] !== 'HTTP/1.1 200 OK') { continue } - result.push({ - cardId: tag['d:prop']['oc:objectId']['#text'], - id: tag['d:prop']['oc:id']['#text'], - uId: tag['d:prop']['oc:actorId']['#text'], - creationDateTime: tag['d:prop']['oc:creationDateTime']['#text'], - message: tag['d:prop']['oc:message']['#text'] - }) + result.push(commentToObject(list[index]['d:propstat'])) } } return result diff --git a/src/services/CommentApi.js b/src/services/CommentApi.js index aaa35b5d3..111fa275e 100644 --- a/src/services/CommentApi.js +++ b/src/services/CommentApi.js @@ -38,7 +38,7 @@ export class CommentApi { ${card.limit} ${card.offset} - ` + `, }).then( (response) => { return Promise.resolve(response.data) @@ -56,19 +56,19 @@ export class CommentApi { return axios({ method: 'POST', url: this.url(`${commentObj.cardId}`), - data: { actorType: 'users', message: `${commentObj.comment}`, verb: 'comment' } + data: { actorType: 'users', message: `${commentObj.comment}`, verb: 'comment' }, }).then( (response) => { - let header = response.headers['content-location'] - let headerArray = header.split('/') - let id = headerArray[headerArray.length - 1] + const header = response.headers['content-location'] + const headerArray = header.split('/') + const id = headerArray[headerArray.length - 1] - let ret = { + const ret = { cardId: (commentObj.cardId).toString(), id: id, uId: getCurrentUser().uid, creationDateTime: (new Date()).toString(), - message: commentObj.comment + message: commentObj.comment, } return Promise.resolve(ret) }, @@ -92,7 +92,7 @@ export class CommentApi { ${data.comment} - ` + `, }).then( (response) => { return Promise.resolve(response.data) @@ -109,7 +109,7 @@ export class CommentApi { deleteComment(data) { return axios({ method: 'DELETE', - url: this.url(`${data.cardId}/${data.commentId}`) + url: this.url(`${data.cardId}/${data.commentId}`), }).then( (response) => { return Promise.resolve(response.data) diff --git a/src/store/comment.js b/src/store/comment.js index a1c742cef..0aac6239e 100644 --- a/src/store/comment.js +++ b/src/store/comment.js @@ -28,7 +28,7 @@ const apiClient = new CommentApi() export default { state: { - comments: {} + comments: {}, }, mutations: { addComments(state, commentObj) { @@ -47,26 +47,26 @@ export default { state.comments[newComment.cardId].push(newComment) }, updateComment(state, comment) { - let existingIndex = state.comments[comment.cardId].findIndex(_comment => _comment.id === comment.commentId) + const existingIndex = state.comments[comment.cardId].findIndex(_comment => _comment.id === comment.commentId) if (existingIndex !== -1) { state.comments[comment.cardId][existingIndex].message = comment.comment } }, deleteComment(state, comment) { - let existingIndex = state.comments[comment.cardId].findIndex(_comment => _comment.id === comment.commentId) + const existingIndex = state.comments[comment.cardId].findIndex(_comment => _comment.id === comment.commentId) if (existingIndex !== -1) { state.comments[comment.cardId].splice(existingIndex, 1) } - } + }, }, actions: { listComments({ commit }, card) { apiClient.listComments(card) .then((comments) => { const commentsJson = xmlToTagList(comments) - let returnObj = { + const returnObj = { cardId: card.id, - comments: commentsJson + comments: commentsJson, } commit('addComments', returnObj) }) @@ -88,6 +88,6 @@ export default { .then((retVal) => { commit('updateComment', data) }) - } - } + }, + }, } diff --git a/src/store/main.js b/src/store/main.js index 63da326a0..fa4fa2168 100644 --- a/src/store/main.js +++ b/src/store/main.js @@ -95,7 +95,7 @@ export default new Vuex.Store({ }, currentBoardLabels: state => { return state.currentBoard ? state.currentBoard.labels : [] - } + }, }, mutations: { toggleShowArchived(state) { From cf67c2e323d97c29bd1745fccfa758b0b662e41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Sat, 25 Jan 2020 10:20:58 +0100 Subject: [PATCH 3/3] Move sidebar tabs to individual components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/components/card/CardSidebar.vue | 88 ++++------------- .../card/CardSidebarTabActivity.vue | 98 +++++++++++++++++++ .../card/CardSidebarTabAttachments.vue | 51 ++++++++++ ...Sidebar.vue => CardSidebarTabComments.vue} | 8 +- src/css/comments.scss | 44 +++++++++ 5 files changed, 214 insertions(+), 75 deletions(-) create mode 100644 src/components/card/CardSidebarTabActivity.vue create mode 100644 src/components/card/CardSidebarTabAttachments.vue rename src/components/card/{CommentsTabSidebar.vue => CardSidebarTabComments.vue} (97%) create mode 100644 src/css/comments.scss diff --git a/src/components/card/CardSidebar.vue b/src/components/card/CardSidebar.vue index ea9069ca2..6cfc5d767 100644 --- a/src/components/card/CardSidebar.vue +++ b/src/components/card/CardSidebar.vue @@ -21,12 +21,11 @@ -->