diff --git a/package-lock.json b/package-lock.json
index ac1d6c98..f45c8b80 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,18 +1,21 @@
{
"name": "memories",
- "version": "0.0.0",
+ "version": "1.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "memories",
- "version": "0.0.0",
+ "version": "1.0.1",
"license": "agpl",
"dependencies": {
"@nextcloud/l10n": "^1.6.0",
"@nextcloud/vue": "^6.0.0-beta.6",
"path-posix": "^1.0.0",
+ "reflect-metadata": "^0.1.13",
"vue": "^2.7.10",
+ "vue-class-component": "^7.2.6",
+ "vue-property-decorator": "^9.1.2",
"vue-router": "^3.5.4",
"vue-virtual-scroller": "^1.0.10",
"webdav": "^4.11.0"
@@ -22,7 +25,10 @@
"@nextcloud/browserslist-config": "^2.3.0",
"@nextcloud/eslint-config": "^8.1.2",
"@nextcloud/stylelint-config": "^2.2.0",
- "@nextcloud/webpack-vue-config": "^5.3.0"
+ "@nextcloud/webpack-vue-config": "^5.3.0",
+ "@types/url-parse": "^1.4.8",
+ "ts-loader": "^9.3.1",
+ "typescript": "^4.8.3"
},
"engines": {
"node": ">=14.0.0",
@@ -2583,6 +2589,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/url-parse": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.8.tgz",
+ "integrity": "sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw==",
+ "dev": true
+ },
"node_modules/@types/ws": {
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
@@ -3450,7 +3462,6 @@
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
- "peer": true,
"dependencies": {
"fill-range": "^7.0.1"
},
@@ -4706,7 +4717,6 @@
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
"integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
"dev": true,
- "peer": true,
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -5803,7 +5813,6 @@
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
- "peer": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -6283,8 +6292,7 @@
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
- "dev": true,
- "peer": true
+ "dev": true
},
"node_modules/grapheme-splitter": {
"version": "1.0.4",
@@ -7091,7 +7099,6 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
- "peer": true,
"engines": {
"node": ">=0.12.0"
}
@@ -7715,7 +7722,6 @@
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true,
- "peer": true,
"dependencies": {
"braces": "^3.0.2",
"picomatch": "^2.3.1"
@@ -8425,7 +8431,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
- "peer": true,
"engines": {
"node": ">=8.6"
},
@@ -9110,6 +9115,11 @@
"node": ">=8"
}
},
+ "node_modules/reflect-metadata": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+ "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -10490,7 +10500,6 @@
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true,
- "peer": true,
"engines": {
"node": ">=6"
}
@@ -10625,7 +10634,6 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
- "peer": true,
"dependencies": {
"is-number": "^7.0.0"
},
@@ -10663,6 +10671,110 @@
"node": ">=8"
}
},
+ "node_modules/ts-loader": {
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz",
+ "integrity": "sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "enhanced-resolve": "^5.0.0",
+ "micromatch": "^4.0.0",
+ "semver": "^7.3.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "typescript": "*",
+ "webpack": "^5.0.0"
+ }
+ },
+ "node_modules/ts-loader/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/ts-loader/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/ts-loader/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/ts-loader/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/ts-loader/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ts-loader/node_modules/semver": {
+ "version": "7.3.7",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+ "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ts-loader/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -10741,6 +10853,19 @@
"node": ">= 0.6"
}
},
+ "node_modules/typescript": {
+ "version": "4.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
+ "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -10973,6 +11098,14 @@
"csstype": "^3.1.0"
}
},
+ "node_modules/vue-class-component": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-7.2.6.tgz",
+ "integrity": "sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==",
+ "peerDependencies": {
+ "vue": "^2.0.0"
+ }
+ },
"node_modules/vue-color": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/vue-color/-/vue-color-2.8.1.tgz",
@@ -11139,6 +11272,15 @@
"resolved": "https://registry.npmjs.org/vue-observe-visibility/-/vue-observe-visibility-0.4.6.tgz",
"integrity": "sha512-xo0CEVdkjSjhJoDdLSvoZoQrw/H2BlzB5jrCBKGZNXN2zdZgMuZ9BKrxXDjNP2AxlcCoKc8OahI3F3r3JGLv2Q=="
},
+ "node_modules/vue-property-decorator": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz",
+ "integrity": "sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ==",
+ "peerDependencies": {
+ "vue": "*",
+ "vue-class-component": "*"
+ }
+ },
"node_modules/vue-resize": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
@@ -13744,6 +13886,12 @@
"@types/node": "*"
}
},
+ "@types/url-parse": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.8.tgz",
+ "integrity": "sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw==",
+ "dev": true
+ },
"@types/ws": {
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
@@ -14474,7 +14622,6 @@
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
- "peer": true,
"requires": {
"fill-range": "^7.0.1"
}
@@ -15468,7 +15615,6 @@
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
"integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
"dev": true,
- "peer": true,
"requires": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -16299,7 +16445,6 @@
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
- "peer": true,
"requires": {
"to-regex-range": "^5.0.1"
}
@@ -16666,8 +16811,7 @@
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
- "dev": true,
- "peer": true
+ "dev": true
},
"grapheme-splitter": {
"version": "1.0.4",
@@ -17257,8 +17401,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "peer": true
+ "dev": true
},
"is-number-object": {
"version": "1.0.7",
@@ -17739,7 +17882,6 @@
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true,
- "peer": true,
"requires": {
"braces": "^3.0.2",
"picomatch": "^2.3.1"
@@ -18293,8 +18435,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "peer": true
+ "dev": true
},
"pkg-dir": {
"version": "4.2.0",
@@ -18801,6 +18942,11 @@
"strip-indent": "^3.0.0"
}
},
+ "reflect-metadata": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+ "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
+ },
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -19883,8 +20029,7 @@
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
- "dev": true,
- "peer": true
+ "dev": true
},
"terser": {
"version": "5.14.2",
@@ -19977,7 +20122,6 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
- "peer": true,
"requires": {
"is-number": "^7.0.0"
}
@@ -20006,6 +20150,78 @@
"dev": true,
"peer": true
},
+ "ts-loader": {
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz",
+ "integrity": "sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.1.0",
+ "enhanced-resolve": "^5.0.0",
+ "micromatch": "^4.0.0",
+ "semver": "^7.3.4"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.7",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+ "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
"tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -20071,6 +20287,12 @@
"mime-types": "~2.1.24"
}
},
+ "typescript": {
+ "version": "4.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
+ "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==",
+ "dev": true
+ },
"unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -20259,6 +20481,12 @@
"csstype": "^3.1.0"
}
},
+ "vue-class-component": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-7.2.6.tgz",
+ "integrity": "sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==",
+ "requires": {}
+ },
"vue-color": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/vue-color/-/vue-color-2.8.1.tgz",
@@ -20383,6 +20611,12 @@
"resolved": "https://registry.npmjs.org/vue-observe-visibility/-/vue-observe-visibility-0.4.6.tgz",
"integrity": "sha512-xo0CEVdkjSjhJoDdLSvoZoQrw/H2BlzB5jrCBKGZNXN2zdZgMuZ9BKrxXDjNP2AxlcCoKc8OahI3F3r3JGLv2Q=="
},
+ "vue-property-decorator": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz",
+ "integrity": "sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ==",
+ "requires": {}
+ },
"vue-resize": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
diff --git a/package.json b/package.json
index c06f7872..15e922d8 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,10 @@
"@nextcloud/l10n": "^1.6.0",
"@nextcloud/vue": "^6.0.0-beta.6",
"path-posix": "^1.0.0",
+ "reflect-metadata": "^0.1.13",
"vue": "^2.7.10",
+ "vue-class-component": "^7.2.6",
+ "vue-property-decorator": "^9.1.2",
"vue-router": "^3.5.4",
"vue-virtual-scroller": "^1.0.10",
"webdav": "^4.11.0"
@@ -52,6 +55,9 @@
"@nextcloud/browserslist-config": "^2.3.0",
"@nextcloud/eslint-config": "^8.1.2",
"@nextcloud/stylelint-config": "^2.2.0",
- "@nextcloud/webpack-vue-config": "^5.3.0"
+ "@nextcloud/webpack-vue-config": "^5.3.0",
+ "@types/url-parse": "^1.4.8",
+ "ts-loader": "^9.3.1",
+ "typescript": "^4.8.3"
}
}
diff --git a/src/App.vue b/src/App.vue
index 9af5bf43..05d27eaa 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -45,7 +45,7 @@
}
-
diff --git a/src/components/Timeline.vue b/src/components/Timeline.vue
index 6ae06e45..fb2760e9 100644
--- a/src/components/Timeline.vue
+++ b/src/components/Timeline.vue
@@ -91,15 +91,18 @@
-
diff --git a/src/main.js b/src/main.ts
similarity index 87%
rename from src/main.js
rename to src/main.ts
index 87bd84fa..d0a28b24 100644
--- a/src/main.js
+++ b/src/main.ts
@@ -19,12 +19,13 @@
* along with this program. If not, see .
*
*/
+import 'reflect-metadata'
import Vue from 'vue'
import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
-import App from './App'
+import App from './App.vue'
import router from './router'
// Adding translations to the whole app
@@ -42,11 +43,11 @@ Vue.use(VueVirtualScroller)
// original scripts are loaded from
// https://github.com/nextcloud/server/blob/5bf3d1bb384da56adbf205752be8f840aac3b0c5/lib/private/legacy/template.php#L120-L122
window.addEventListener('DOMContentLoaded', () => {
- if (!window.OCA.Files) {
- window.OCA.Files = {}
+ if (!globalThis.OCA.Files) {
+ globalThis.OCA.Files = {}
}
// register unused client for the sidebar to have access to its parser methods
- Object.assign(window.OCA.Files, { App: { fileList: { filesClient: OC.Files.getClient() } } }, window.OCA.Files)
+ Object.assign(globalThis.OCA.Files, { App: { fileList: { filesClient: globalThis.OC.Files.getClient() } } }, globalThis.OCA.Files)
})
export default new Vue({
diff --git a/src/mixins/UserConfig.js b/src/mixins/UserConfig.ts
similarity index 100%
rename from src/mixins/UserConfig.js
rename to src/mixins/UserConfig.ts
diff --git a/src/mixins/constants.js b/src/mixins/constants.ts
similarity index 100%
rename from src/mixins/constants.js
rename to src/mixins/constants.ts
diff --git a/src/router.js b/src/router.ts
similarity index 92%
rename from src/router.js
rename to src/router.ts
index 14820b22..2ab4c4fb 100644
--- a/src/router.js
+++ b/src/router.ts
@@ -21,10 +21,10 @@
*/
import { generateUrl } from '@nextcloud/router'
+ import { translate as t, translatePlural as n } from '@nextcloud/l10n'
import Router from 'vue-router'
import Vue from 'vue'
-
- const Timeline = () => import('./components/Timeline')
+ import Timeline from './components/Timeline.vue';
Vue.use(Router)
@@ -43,7 +43,7 @@
mode: 'history',
// if index.php is in the url AND we got this far, then it's working:
// let's keep using index.php in the url
- base: generateUrl('/apps/memories', ''),
+ base: generateUrl('/apps/memories'),
linkActiveClass: 'active',
routes: [
{
diff --git a/src/services/DavClient.js b/src/services/DavClient.ts
similarity index 89%
rename from src/services/DavClient.js
rename to src/services/DavClient.ts
index a31324c6..37577bcc 100644
--- a/src/services/DavClient.js
+++ b/src/services/DavClient.ts
@@ -27,8 +27,8 @@
// Monkey business
import * as rq from 'webdav/dist/node/request';
- rq.prepareRequestOptionsOld = rq.prepareRequestOptions.bind(rq);
- rq.prepareRequestOptions = (function(requestOptions, context, userOptions) {
+ (rq).prepareRequestOptionsOld = rq.prepareRequestOptions.bind(rq);
+ (rq).prepareRequestOptions = (function(requestOptions, context, userOptions) {
requestOptions.method = userOptions.method || requestOptions.method;
return this.prepareRequestOptionsOld(requestOptions, context, userOptions);
}).bind(rq);
diff --git a/src/services/DavRequests.js b/src/services/DavRequests.ts
similarity index 79%
rename from src/services/DavRequests.js
rename to src/services/DavRequests.ts
index a9e1034c..7cb60520 100644
--- a/src/services/DavRequests.js
+++ b/src/services/DavRequests.ts
@@ -2,6 +2,7 @@ import { getCurrentUser } from '@nextcloud/auth'
import { generateUrl } from '@nextcloud/router'
import { genFileInfo } from './FileUtils'
import client from './DavClient';
+import { IFileInfo } from '../types';
const props = `
@@ -23,11 +24,11 @@ const IMAGE_MIME_TYPES = [
/**
* Get file infos for list of files given Ids
- * @param {number[]} fileIds list of file ids
- * @returns {Promise} list of file infos
+ * @param fileIds list of file ids
+ * @returns list of file infos
*/
-export async function getFiles(fileIds) {
- const prefixPath = `/files/${getCurrentUser().uid}`;
+export async function getFiles(fileIds: number[]): Promise {
+ const prefixPath = `/files/${getCurrentUser()!.uid}`;
// IMPORTANT: if this isn't there, then a blank
// returns EVERYTHING on the server!
@@ -79,20 +80,19 @@ export async function getFiles(fileIds) {
responseType: 'text',
};
- let response = await client.getDirectoryContents('', options);
+ let response: any = await client.getDirectoryContents('', options);
return response.data
- .map(data => genFileInfo(data))
- .map(data => Object.assign({}, data, { filename: data.filename.replace(prefixPath, '') }));
+ .map((data: any) => genFileInfo(data))
+ .map((data: any) => Object.assign({}, data, { filename: data.filename.replace(prefixPath, '') }));
}
/**
* Get file infos for files in folder path
- * @param {string} folderPath Path to folder
- * @param {number} limit Max number of files to return
- * @returns {Promise} list of file infos
+ * @param folderPath Path to folder
+ * @param limit Max number of files to return
*/
-export async function getFolderPreviewFileIds(folderPath, limit) {
- const prefixPath = `/files/${getCurrentUser().uid}`;
+export async function getFolderPreviewFileIds(folderPath: string, limit: number): Promise {
+ const prefixPath = `/files/${getCurrentUser()!.uid}`;
const filter = IMAGE_MIME_TYPES.map(mime => `
@@ -141,10 +141,10 @@ export async function getFolderPreviewFileIds(folderPath, limit) {
responseType: 'text',
};
- let response = await client.getDirectoryContents('', options);
+ let response:any = await client.getDirectoryContents('', options);
return response.data
- .map(data => genFileInfo(data))
- .map(data => Object.assign({}, data, {
+ .map((data: any) => genFileInfo(data))
+ .map((data: any) => Object.assign({}, data, {
filename: data.filename.replace(prefixPath, ''),
etag: data.etag.replace(/"/g, ''), // remove quotes
}));
@@ -153,22 +153,21 @@ export async function getFolderPreviewFileIds(folderPath, limit) {
/**
* Delete a single file
*
- * @param {string} path path to the file
- * @returns {Promise}
+ * @param path path to the file
*/
-export async function deleteFile(path) {
- const prefixPath = `/files/${getCurrentUser().uid}`;
+export async function deleteFile(path: string) {
+ const prefixPath = `/files/${getCurrentUser()!.uid}`;
return await client.deleteFile(`${prefixPath}${path}`);
}
/**
* Delete all files in a given list of Ids
*
- * @param {number[]} fileIds list of file ids
- * @returns {Promise>} list of file ids that were deleted
+ * @param fileIds list of file ids
+ * @returns list of file ids that were deleted
*/
-export async function deleteFilesByIds(fileIds) {
- const delIds = new Set();
+export async function deleteFilesByIds(fileIds: number[]) {
+ const delIds = new Set();
const fileIdsSet = new Set(fileIds);
if (fileIds.length === 0) {
@@ -176,7 +175,7 @@ export async function deleteFilesByIds(fileIds) {
}
// Get files data
- let fileInfos = [];
+ let fileInfos: any[] = [];
try {
fileInfos = await getFiles(fileIds.filter(f => f));
} catch (e) {
@@ -185,7 +184,7 @@ export async function deleteFilesByIds(fileIds) {
}
// Run all promises together
- const promises = [];
+ const promises: Promise[] = [];
// Delete each file
for (const fileInfo of fileInfos) {
@@ -212,10 +211,9 @@ export async function deleteFilesByIds(fileIds) {
/**
* Download a file
*
- * @param {string[]} fileNames - The file's names
- * @returns {Promise}
+ * @param fileNames - The file's names
*/
- export async function downloadFiles(fileNames) {
+ export async function downloadFiles(fileNames: string[]): Promise {
const randomToken = Math.random().toString(36).substring(2)
const params = new URLSearchParams()
@@ -224,7 +222,7 @@ export async function deleteFilesByIds(fileIds) {
const downloadURL = generateUrl(`/apps/files/ajax/download.php?${params}`)
- window.location = `${downloadURL}downloadStartSecret=${randomToken}`
+ window.location.href = `${downloadURL}downloadStartSecret=${randomToken}`
return new Promise((resolve) => {
const waitForCookieInterval = setInterval(
@@ -246,10 +244,9 @@ export async function deleteFilesByIds(fileIds) {
/**
* Download the files given by the fileIds
- * @param {number[]} fileIds
- * @returns {Promise}
+ * @param fileIds list of file ids
*/
-export async function downloadFilesByIds(fileIds) {
+export async function downloadFilesByIds(fileIds: number[]) {
if (fileIds.length === 0) {
return;
}
diff --git a/src/services/FileUtils.js b/src/services/FileUtils.ts
similarity index 95%
rename from src/services/FileUtils.js
rename to src/services/FileUtils.ts
index 78f783d2..e47e1da7 100644
--- a/src/services/FileUtils.js
+++ b/src/services/FileUtils.ts
@@ -94,8 +94,8 @@
// finally sort by name
return asc
- ? fileInfo1[key]?.toString()?.localeCompare(fileInfo2[key].toString(), OC.getLanguage()) || 1
- : -fileInfo1[key]?.toString()?.localeCompare(fileInfo2[key].toString(), OC.getLanguage()) || -1
+ ? fileInfo1[key]?.toString()?.localeCompare(fileInfo2[key].toString(), globalThis.OC.getLanguage()) || 1
+ : -fileInfo1[key]?.toString()?.localeCompare(fileInfo2[key].toString(), globalThis.OC.getLanguage()) || -1
}
const genFileInfo = function(obj) {
@@ -123,7 +123,7 @@
return fileInfo
}
- const getPreviewUrl = function(fileid, etag) {
+ const getPreviewUrl = function(fileid: number, etag: string): string {
return generateUrl(`/core/preview?fileId=${fileid}&c=${etag}&x=250&y=250&forceIcon=0&a=0`);
}
diff --git a/src/services/NumberUtils.js b/src/services/NumberUtils.ts
similarity index 94%
rename from src/services/NumberUtils.js
rename to src/services/NumberUtils.ts
index 5d7e5386..56e90729 100644
--- a/src/services/NumberUtils.js
+++ b/src/services/NumberUtils.ts
@@ -20,7 +20,7 @@
*
*/
- const isNumber = function(num) {
+ const isNumber = function(num: any) {
if (!num) {
return false
}
diff --git a/src/services/Utils.js b/src/services/Utils.ts
similarity index 66%
rename from src/services/Utils.js
rename to src/services/Utils.ts
index 2dda9e94..fb677048 100644
--- a/src/services/Utils.js
+++ b/src/services/Utils.ts
@@ -1,10 +1,10 @@
/** Get JS date object from dayId */
-export function dayIdToDate(dayId){
- return new Date(Number(dayId)*86400*1000);
+export function dayIdToDate(dayId: number){
+ return new Date(dayId*86400*1000);
}
/** Get month name from number */
-export function getMonthName(date) {
+export function getMonthName(date: Date) {
const dateTimeFormat = new Intl.DateTimeFormat('en-US', {
month: 'short',
timeZone: 'UTC',
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 00000000..172ba03a
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,69 @@
+export type IFileInfo = {
+ fileid: number;
+ filename: string;
+ etag: string;
+}
+
+export type IDay = {
+ /** Day ID */
+ dayid: number;
+ /** Number of photos in this day */
+ count: number;
+ /** Set of rows in the day */
+ rows?: Set;
+ /** List of photos for this day */
+ detail?: IPhoto[];
+ /** WebDAV fileInfos, fetched before viewer open */
+ fileInfos?: IFileInfo[];
+ /** Original fileIds from fileInfos */
+ origFileIds?: Set;
+}
+
+export type IPhoto = {
+ /** Nextcloud ID of file */
+ fileid: number;
+ /** Etag from server */
+ etag?: string;
+ /** Bit flags */
+ flag: number;
+ /** Reference to day object */
+ d?: IDay;
+ /** Video flag from server */
+ isvideo?: boolean;
+ /** Favorite flag from server */
+ isfavorite?: boolean;
+}
+
+export type IRow = {
+ /** Vue Recycler identifier */
+ id?: number;
+ /** Day ID */
+ dayId: number;
+ /** Refrence to day object */
+ day: IDay;
+ /** Whether this is a head row */
+ head?: boolean;
+ /** [Head only] Title of the header */
+ name?: string;
+ /** Main list of photo items */
+ photos?: IPhoto[];
+ /** Height in px of the row */
+ size?: number;
+ /** Count of placeholders to create */
+ pct?: number;
+}
+
+export type ITick = {
+ /** Day ID */
+ dayId: number;
+ /** Top row at this */
+ top: number;
+ /** Static distance from top (for headers) */
+ topS: number;
+ /** Count row distance from top (dynamic) */
+ topC: number;
+ /** Text if any (e.g. year) */
+ text?: string | number;
+ /** Whether this tick should be shown */
+ s?: boolean;
+}
\ No newline at end of file
diff --git a/src/vue-shims.d.ts b/src/vue-shims.d.ts
new file mode 100644
index 00000000..98c4f9e4
--- /dev/null
+++ b/src/vue-shims.d.ts
@@ -0,0 +1,10 @@
+declare module "*.vue" {
+ import Vue from "vue"
+ export default Vue
+}
+
+declare module '*.svg' {
+ import Vue, {VueConstructor} from 'vue';
+ const content: VueConstructor;
+ export default content;
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..71d2d0b5
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "compilerOptions": {
+ "lib": ["dom", "es2017"],
+ "target": "ESNext",
+ "module": "es2015",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "allowSyntheticDefaultImports": true,
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true,
+ "jsx": "preserve"
+ }
+}
\ No newline at end of file
diff --git a/webpack.js b/webpack.js
index e5daa927..77df5769 100644
--- a/webpack.js
+++ b/webpack.js
@@ -1,3 +1,19 @@
const webpackConfig = require('@nextcloud/webpack-vue-config')
+const path = require('path')
+
+webpackConfig.module.rules.push({
+ test: /\.ts?$/,
+ loader: 'ts-loader',
+ exclude: /node_modules/,
+ options: {
+ appendTsSuffixTo: [/\.vue$/],
+ },
+});
+webpackConfig.resolve.extensions.push('.ts');
+webpackConfig.resolve.alias = {
+ 'vue$': 'vue/dist/vue.esm.js',
+}
+webpackConfig.entry.main = path.resolve(path.join('src', 'main'));
+delete webpackConfig.optimization.splitChunks;
module.exports = webpackConfig