diff --git a/package-lock.json b/package-lock.json index ccc8970fce64c9e629e256c140a55a7b664c9367..79f7a671d91d3d6e8f17adbabbc5a6d3745ef5ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8628,6 +8628,11 @@ } } }, + "tabulator-tables": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-4.7.0.tgz", + "integrity": "sha512-FOFn13Vxuv0qJXZkwfEVBvT8fjm+VOdpcryclftCvf8i+8P1hJhKftyBfVtOqlPLWM0B0o8pNHZaV+JKY/IJSA==" + }, "tar": { "version": "4.4.13", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", diff --git a/package.json b/package.json index 5247af1fd308598d89d440b03776dac62a28a27f..76bdbb72957bb5e6e058d717a4214a23c630ee8d 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "lit-html": "^1.2.1", "pdfjs-dist": "^2.4.456", "source-sans-pro": "^2.45.0", + "tabulator-tables": "^4.7.0", "universal-router": "^9.0.1", "vpu-app-shell": "file:./vendor/app-shell", "vpu-auth": "file:./vendor/auth", diff --git a/rollup.config.js b/rollup.config.js index 9dcfa435c906683065a9a2a5bf495d507358428d..f9f91a8f4b0db466c7bb15dc6683e3096f6c7f8d 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -272,6 +272,7 @@ Dependencies: {src: 'assets/manifest.json', dest: 'dist', rename: pkg.name + '.manifest.json'}, {src: 'assets/*.metadata.json', dest: 'dist'}, {src: 'node_modules/vpu-common/assets/icons/*.svg', dest: 'dist/local/vpu-common/icons'}, + {src: 'node_modules/tabulator-tables/dist/css', dest: 'dist/local/' + pkg.name + '/tabulator-tables'}, ], }), useBabel && babel({ diff --git a/src/vpu-file-picker.js b/src/vpu-file-picker.js index b1c81f60022ac4c676261e7cdd0d80bb82bc2819..40a17c851e4a4322e3be70a329b7afe4996b4da6 100644 --- a/src/vpu-file-picker.js +++ b/src/vpu-file-picker.js @@ -3,8 +3,12 @@ import {css, html} from 'lit-element'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; import VPULitElement from 'vpu-common/vpu-lit-element'; import {MiniSpinner} from 'vpu-common'; +import * as commonUtils from 'vpu-common/utils'; import * as commonStyles from 'vpu-common/styles'; import { createClient } from "webdav/web"; +import {classMap} from 'lit-html/directives/class-map.js'; +import {humanFileSize} from "vpu-common/i18next"; +import Tabulator from 'tabulator-tables'; const i18n = createI18nInstance(); @@ -18,6 +22,12 @@ export class FilePicker extends ScopedElementsMixin(VPULitElement) { this.authUrl = ''; this.webDavUrl = ''; this.loginWindow = null; + this.isPickerActive = false; + this.statusText = ""; + this.directoryPath = "/"; + this.directoryContents = []; + this.webDavClient = null; + this.tabulatorTable = null; this._onReceiveWindowMessage = this.onReceiveWindowMessage.bind(this); } @@ -36,6 +46,10 @@ export class FilePicker extends ScopedElementsMixin(VPULitElement) { lang: { type: String }, authUrl: { type: String, attribute: "auth-url" }, webDavUrl: { type: String, attribute: "web-dav-url" }, + isPickerActive: { type: Boolean, attribute: false }, + statusText: { type: String, attribute: false }, + directoryPath: { type: String, attribute: false }, + directoryContents: { type: Array, attribute: false }, }; } @@ -62,15 +76,18 @@ export class FilePicker extends ScopedElementsMixin(VPULitElement) { this.updateComplete.then(()=>{ // see: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage window.addEventListener('message', this._onReceiveWindowMessage); + + this.tabulatorTable = new Tabulator(this._("#directory-content-table"), {}); }); } openFilePicker() { + this.statusText = "Auth in progress"; this.loginWindow = window.open(this.authUrl, "Nextcloud Login", "width=400,height=400,menubar=no,scrollbars=no,status=no,titlebar=no,toolbar=no"); } - async onReceiveWindowMessage(event) { + onReceiveWindowMessage(event) { const data = event.data; console.log("data", data); @@ -80,7 +97,8 @@ export class FilePicker extends ScopedElementsMixin(VPULitElement) { const apiUrl = this.webDavUrl + "/" + data.loginName; - const client = createClient( + // https://github.com/perry-mitchell/webdav-client/blob/master/API.md#module_WebDAV.createClient + this.webDavClient = createClient( apiUrl, { username: data.loginName, @@ -88,54 +106,101 @@ export class FilePicker extends ScopedElementsMixin(VPULitElement) { } ); - const directoryItems = await client.getDirectoryContents("/"); - - console.log("directoryItems", directoryItems); - - return; - - fetch(apiUrl, { - method: 'PROPFIND', - headers: { - 'Content-Type': 'text/xml', - 'Authorization': 'Basic ' + btoa(data.loginName + ":" + data.token), - }, - data: "<?xml version=\"1.0\"?>" + - "<a:propfind xmlns:a=\"DAV:\">" + - "<a:prop><a:resourcetype />" + - "</a:prop>" + - "</a:propfind>" - }) - .then(result => { - console.log("result", result); - - if (!result.ok) throw result; - - return result.text(); - }) - .then((xml) => { - console.log("xml", xml); - }).catch(error => { - console.error("error", error); - }); + this.loadDirectory(""); } } + /** + * Loads the directory from WebDAV + * + * @param path + */ + loadDirectory(path) { + this.statusText = "Loading directory from Nextcloud: " + path; + this.directoryPath = path; + this.directoryContents = []; + + // https://github.com/perry-mitchell/webdav-client#getdirectorycontents + this.webDavClient + .getDirectoryContents(path) + .then(contents => { + console.log("contents", contents); + this.statusText = ""; + this.directoryContents = contents; + + this.tabulatorTable.setData(contents); + + this.isPickerActive = true; + }).catch(error => { + console.error(error.message); + this.statusText = error.message; + this.isPickerActive = false; + }); + } + static get styles() { // language=css return css` ${commonStyles.getGeneralCSS()} ${commonStyles.getButtonCSS()} + + .block { + margin-bottom: 10px; + } `; } + /** + * Returns the list of files in a directory + * + * @returns {*[]} + */ + getDirectoryContentsHtml() { + let results = []; + + // this.directoryContents.forEach((content) => { + // results.push(html` + // <tr> + // <td><a href="#" @click="${(e) => { this.fileClicked(content, e); }}">${content.filename}</a></td> + // <td>${content.size}</td> + // </tr> + // `); + // }); + + return results; + } + + fileClicked(file, event) { + this.loadDirectory(this.directoryPath + file.filename); + event.preventDefault(); + } + render() { + commonUtils.initAssetBaseURL('vpu-tabulator-table'); + const tabulatorCss = commonUtils.getAssetURL('local/vpu-signature/tabulator-tables/css/tabulator.min.css'); + console.log("tabulatorCss", tabulatorCss); + return html` - <div> + <link rel="stylesheet" href="${tabulatorCss}"> + <div class="block"> <button class="button" title="${i18n.t('file-picker.open-file-picker')}" @click="${async () => { this.openFilePicker(); } }">${i18n.t('file-picker.open')}</button> </div> + <div class="block ${classMap({hidden: this.statusText === ""})}"> + <vpu-mini-spinner style="font-size: 0.7em"></vpu-mini-spinner> + ${this.statusText} + </div> + <div class="block ${classMap({hidden: !this.isPickerActive})}"> + <h2>${this.directoryPath}</h2> + <table id="directory-content-table"> + <thead> + <th>Filename</th> + <th>Size</th> + </thead> + <tbody>${this.getDirectoryContentsHtml()}</tbody> + </table> + </div> `; } }