Skip to content
Snippets Groups Projects
Commit 3a522127 authored by Tögl, Christina's avatar Tögl, Christina
Browse files

Merge branch 'filehandling-overwrite-dialog' of...

Merge branch 'filehandling-overwrite-dialog' of gitlab.tugraz.at:dbp/web-components/toolkit into filehandling-overwrite-dialog
parents 1116551f 4130766b
No related branches found
No related tags found
1 merge request!1Filehandling overwrite dialog
Pipeline #12627 passed
...@@ -43,6 +43,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -43,6 +43,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
this.uploadFileDirectory = null; this.uploadFileDirectory = null;
this.fileList = []; this.fileList = [];
this.fileNameCounter = 1; this.fileNameCounter = 1;
this.activeDirectoryRights = 'SGDNVCK';
this.activeDirectoryACL = '';
this.forAll = false; this.forAll = false;
} }
...@@ -73,6 +75,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -73,6 +75,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
replaceFilename: { type: String, attribute: false }, replaceFilename: { type: String, attribute: false },
uploadFileObject: { type: Object, attribute: false }, uploadFileObject: { type: Object, attribute: false },
uploadFileDirectory: { type: String, attribute: false }, uploadFileDirectory: { type: String, attribute: false },
activeDirectoryRights: { type: String, attribute: false },
activeDirectoryACL: { type: String, attribute: false },
}; };
} }
...@@ -146,7 +150,9 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -146,7 +150,9 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
const hours = ("0" + timestamp.getHours()).slice(-2); const hours = ("0" + timestamp.getHours()).slice(-2);
const minutes = ("0" + timestamp.getMinutes()).slice(-2); const minutes = ("0" + timestamp.getMinutes()).slice(-2);
return date + "." + month + "." + year + " " + hours + ":" + minutes; return date + "." + month + "." + year + " " + hours + ":" + minutes;
}} }},
{title: "rights", field: "props.permissions"},
{title: "acl", field: "props.acl-list.acl.acl-permissions"}
], ],
initialSort:[ initialSort:[
{column:"basename", dir:"asc"}, {column:"basename", dir:"asc"},
...@@ -165,6 +171,10 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -165,6 +171,10 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
const data = row.getData(); const data = row.getData();
if (this.directoriesOnly) { if (this.directoriesOnly) {
// comment out if you want to navigate through folders with double click
const data = row.getData();
this.directoryClicked(e, data);
this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
} }
else else
{ {
...@@ -186,10 +196,12 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -186,10 +196,12 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
} }
}); });
if (this.tabulatorTable.browserMobile === false)
// Strg + click select mode on desktop
/*if (this.tabulatorTable.browserMobile === false)
{ {
this.tabulatorTable.options.selectableRangeMode = "click"; this.tabulatorTable.options.selectableRangeMode = "click";
} }*/
function checkFileType(data, filterParams) { function checkFileType(data, filterParams) {
// check if file is allowed // check if file is allowed
if (typeof data.mime === 'undefined') { if (typeof data.mime === 'undefined') {
...@@ -240,8 +252,11 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -240,8 +252,11 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
} }
onReceiveWindowMessage(event) { onReceiveWindowMessage(event) {
if (this.webDavClient === null)
{
const data = event.data; const data = event.data;
console.log("data", data); console.log("data", data);
console.log("context", this.directoriesOnly);
if (data.type === "webapppassword") { if (data.type === "webapppassword") {
if(this.loginWindow !== null) { if(this.loginWindow !== null) {
...@@ -259,9 +274,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -259,9 +274,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
password: data.token password: data.token
} }
); );
this.loadDirectory(this.directoryPath); this.loadDirectory(this.directoryPath);
}
} }
} }
...@@ -277,62 +291,82 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -277,62 +291,82 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
this.directoryPath = path; this.directoryPath = path;
// see https://github.com/perry-mitchell/webdav-client#getdirectorycontents // see https://github.com/perry-mitchell/webdav-client#getdirectorycontents
if(this.webDavClient === null)
{
// client is broken reload try to reset & reconnect
this.tabulatorTable.clearData();
this.webDavClient = null;
// TODO Übersetzung
let reloadButton = html`Something went wrong. Please reload <button class="button"
title="${i18n.t('nextcloud-file-picker.refresh-nextcloud-file-picker')}"
@click="${async () => { this.openFilePicker(); } }"><dbp-icon name="reload"></button>`;
this.loading = false;
this.statusText = reloadButton;
}
this.webDavClient this.webDavClient
.getDirectoryContents(path, {details: true}) .getDirectoryContents(path, {details: true, data: "<?xml version=\"1.0\"?>" +
"<d:propfind xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\" xmlns:ocs=\"http://open-collaboration-services.org/ns\">" +
" <d:prop>" +
" <d:getlastmodified />" +
" <d:resourcetype />" +
" <d:getcontenttype />" +
" <d:getcontentlength />" +
" <d:getetag />" +
" <oc:permissions />" +
" <nc:acl-list>" +
" <nc:acl>" +
" <nc:acl-permissions />" +
" </nc:acl>" +
" </nc:acl-list>" +
" </d:prop>" +
"</d:propfind>"})
.then(contents => { .then(contents => {
//console.log("contents", contents);
this.loading = false; this.loading = false;
this.statusText = ""; this.statusText = "";
this.tabulatorTable.setData(contents.data); this.tabulatorTable.setData(contents.data);
console.log("!!!!!!!!!!!!!!!!!!!!!!!!", contents.data)
this.isPickerActive = true; this.isPickerActive = true;
}).catch(error => { }).catch(error => {
console.error(error.message); console.error(error.message);
// on Error: try to reload with home directory // on Error: try to reload with home directory
if (path != "/"){ if (path != "/" && this.webDavClient !== null){
this.loadDirectory("/"); this.loadDirectory("/");
} }
else { else {
this.loading = false; this.loading = false;
this.statusText = error.message; this.statusText = error.message;
this.isPickerActive = false; this.isPickerActive = false;
} this.tabulatorTable.clearData();
// client is broken reload try to reset & reconnect
this.webDavClient = null; this.webDavClient = null;
let reloadButton = html`<button class="button" // TODO Übersetzung
let reloadButton = html`Something went wrong. Please reload <button class="button"
title="${i18n.t('nextcloud-file-picker.refresh-nextcloud-file-picker')}" title="${i18n.t('nextcloud-file-picker.refresh-nextcloud-file-picker')}"
@click="${async () => { this.openFilePicker(); } }"><dbp-icon name="reload"></button>`; @click="${async () => { this.openFilePicker(); } }"><dbp-icon name="reload"></button>`;
this.loading = false; this.loading = false;
this.statusText = reloadButton; this.statusText = reloadButton;
}); }
const contents2 = this.webDavClient.customRequest(path, {
method: "PROPFIND",
headers: {
Accept: "text/plain",
Depth: 0
},
data: "<?xml version=\"1.0\"?>\n" +
"<d:propfind xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">\n" +
" <d:prop>\n" +
" <oc:permissions />\n" +
" <nc:acl-permissions />\n" +
" </d:prop>\n" +
"</d:propfind>",
responseType: "text"
}); // contents => { //console.log("---------", contents)});
});
} }
directoryClicked(event, file) { directoryClicked(event, file) {
// save rights of clicked directory
this.activeDirectoryRights = file.props.permissions;
if(typeof file.props['acl-list'] !== "undefined" &&
typeof file.props['acl-list']['acl']['acl-permissions'] !== "undefined" && file.props['acl-list']['acl']['acl-permissions']) {
this.activeDirectoryACL = file.props['acl-list']['acl']['acl-permissions'];
}
else {
this.activeDirectoryACL = '';
}
this.loadDirectory(file.filename); this.loadDirectory(file.filename);
event.preventDefault(); event.preventDefault();
} }
downloadFiles(files) { downloadFiles(files) {
this.tabulatorTable.deselectRow();
files.forEach((fileData) => this.downloadFile(fileData)); files.forEach((fileData) => this.downloadFile(fileData));
} }
...@@ -364,7 +398,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -364,7 +398,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
} }
sendDirectory(directory) { sendDirectory(directory) {
this.tabulatorTable.deselectRow();
let path; let path;
if(!directory[0]) if(!directory[0])
...@@ -408,8 +442,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -408,8 +442,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
console.error(error.message); console.error(error.message);
//this.loading = false; //this.loading = false;
//this.statusText = error.message; //this.statusText = error.message;
//console.log("--- h-", error.message); console.log("--- h-", error.message);
if(error.message.search("412") !== -1) { if(error.message.search("412") !== -1 || error.message.search("403") !== -1) {
this.generatedFilename = this.getNextFilename(); this.generatedFilename = this.getNextFilename();
this._("#replace-filename").value = this.generatedFilename; this._("#replace-filename").value = this.generatedFilename;
if(this.forAll) { if(this.forAll) {
...@@ -493,12 +527,147 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -493,12 +527,147 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
this.fileNameCounter = 1; this.fileNameCounter = 1;
} }
checkRights(file) {
// Todo check rights after an conflict and return which should be grayed out (the options rename or replace)
// no rename: if you dont have create permissions
// no replace if you dont have write permissions
// nextcloud permissions
let perm = 0;
let active_directory_perm = this.activeDirectoryRights;
let rows = this.tabulatorTable.searchRows("basename", "=", this.replaceFilename);
if(typeof rows[0] !== 'undefined' && rows[0]) {
perm = rows[0].getData().props.permissions;
}
else {
perm = "";
}
console.log("RIGHTS IN THIS FOLDER:", this.activeDirectoryRights);
console.log("RIGHT OF FILE:", perm);
console.log("RIGHTS IN THIS FOLDER:", this.activeDirectoryRights);
console.log("RIGHT OF FILE:", perm);
/* ACL TODO Check if ACL > Permissions
// if I'm in an group or external folder take the acl permissions
if(this.activeDirectoryACL !== '')
{
console.log("ACL SET");
active_directory_perm = "MG";
if(this.activeDirectoryACL & (1 << (3 - 1)))
{
active_directory_perm = "CK";
console.log("ACL CREATE");
}
if(this.activeDirectoryACL & (1 << (2 - 1)))
{
active_directory_perm += "NV";
console.log("ACL WRITE");
}
}
// if file has acl rights take that
if(typeof rows[0].getData().props['acl-list'] !== 'undefined' && rows[0].getData().props['acl-list'] &&
rows[0].getData().props['acl-list']['acl']['acl-permissions'] !== '')
{
console.log("FILE HAS ACL");
perm = "MG";
if(rows[0].getData().props['acl-list']['acl']['acl-permissions'] & (1 << (3 - 1)))
{
perm = "CK";
console.log("FILE ACL CREATE");
}
if(rows[0].getData().props['acl-list']['acl']['acl-permissions'] & (1 << (2 - 1)))
{
perm += "NV";
console.log("FILE ACL WRITE");
}
}
*/
// read only directory
if(active_directory_perm === "MG" || active_directory_perm === "SG" || (active_directory_perm === "RMGD" && perm === ""))
{
console.log("0");
return 0;
}
// read only file
if((perm === 'SG' || perm === 'MG' || perm === 'MG'|| perm === 'RMGD' || perm === 'SGD') && !active_directory_perm.includes("CK") )
{
console.log("0");
return 0;
}
// read only file
if((perm === 'SG' || perm === 'MG'|| perm === 'RMGD' || perm === 'SGD') && active_directory_perm.includes("CK") )
{
console.log("1");
return 1;
}
// only create and no edit
if((active_directory_perm.includes("CK") && !active_directory_perm.includes("NV") && !perm.includes("NV")) || (active_directory_perm.includes("CK") && !perm.includes("NV"))) {
console.log("1");
return 1;
}
// only edit and no create
if(perm.includes("NV") && !active_directory_perm.includes("CK")) {
console.log("2");
return 2;
}
console.log("-1");
return -1;
}
/** /**
* *
*/ */
replaceModalDialog(file, directory) { replaceModalDialog(file, directory) {
this.uploadFileObject = file; this.uploadFileObject = file;
this.uploadFileDirectory = directory; this.uploadFileDirectory = directory;
let rights = this.checkRights(file);
if(rights === 0) {
// TODO Übersetzen
this.loading = false;
this.statusText = "readonly: Du darfst in diesem ordner nichts schreiben";
return;
}
else if(rights === 1) {
this.loading = false;
this.statusText = "Du darfst hier nur erstellen";
this._("#replace-replace").setAttribute("disabled", "true");
this._("#replace-new-name").removeAttribute("disabled");
this._("#replace-replace").checked = false;
this._("#replace-new-name").checked = true;
this.setInputFieldVisibility();
this._("#replace-new-name").focus();
}
else if(rights === 2) {
this.loading = false;
this.statusText = "Du darfst hier nur bearbeiten";
this._("#replace-new-name").setAttribute("disabled", "true");
this._("#replace-replace").removeAttribute("disabled");
this._("#replace-new-name").checked = false;
this._("#replace-replace").checked = true;
this.setInputFieldVisibility();
this._("#replace-replace").focus();
}
else {
this._("#replace-new-name").removeAttribute("disabled");
this._("#replace-replace").removeAttribute("disabled");
this._("#replace-replace").checked = false;
this._("#replace-new-name").checked = true;
this.setInputFieldVisibility();
this._("#replace-new-name").focus();
}
MicroModal.show(this._('#replace-modal')); MicroModal.show(this._('#replace-modal'));
} }
...@@ -564,6 +733,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -564,6 +733,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
* *
*/ */
cancelOverwrite() { cancelOverwrite() {
this.statusText = "";
this.loading = false;
this.fileList = []; this.fileList = [];
} }
...@@ -608,7 +779,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -608,7 +779,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
*/ */
getBreadcrumb() { getBreadcrumb() {
let htmlpath = []; let htmlpath = [];
htmlpath[0] = html`<a @click="${() => { this.loadDirectory("/"); }}" title="${i18n.t('nextcloud-file-picker.folder-home')}"><dbp-icon name="home"></dbp-icon> </a>`; htmlpath[0] = html`<span class="breadcrumb"><a @click="${() => { this.loadDirectory("/"); }}" title="${i18n.t('nextcloud-file-picker.folder-home')}"><dbp-icon name="home"></dbp-icon> </a></span>`;
const directories = this.directoryPath.split('/'); const directories = this.directoryPath.split('/');
if (directories[1] === "") if (directories[1] === "")
{ {
...@@ -623,7 +794,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -623,7 +794,7 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
path += directories[j]; path += directories[j];
} }
htmlpath[i] = html`<a @click="${() => { this.loadDirectory(path); }}" title="${i18n.t('nextcloud-file-picker.load-path-link', {path: directories[i]})}">${directories[i]}</a>`; htmlpath[i] = html`<span class="muted"> › </span><span class="breadcrumb"><a @click="${() => { this.loadDirectory(path); }}" title="${i18n.t('nextcloud-file-picker.load-path-link', {path: directories[i]})}">${directories[i]}</a></span>`;
} }
return htmlpath; return htmlpath;
...@@ -766,14 +937,14 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -766,14 +937,14 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
background-color: white; background-color: white;
} }
.tabulator-row.tabulator-selected:hover, .tabulator-row.tabulator-selected{ .tabulator-row.tabulator-selectable.tabulator-selectable:hover{
background-color: var(--dbp-dark); background-color: var(--dbp-secondary-bg-color);
color: var(--dbp-light); color: var(--dbp-secondary-text-color);
} }
.tabulator-row.tabulator-selectable:hover{ .tabulator-row.tabulator-selectable.tabulator-selected:hover, .tabulator-row.tabulator-selected{
background-color: #eee; background-color: var(--dbp-dark);
color: var(--dbp-dark); color: var(--dbp-light);
} }
.tabulator .tabulator-header .tabulator-col .tabulator-col-content{ .tabulator .tabulator-header .tabulator-col .tabulator-col-content{
...@@ -911,6 +1082,18 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -911,6 +1082,18 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
padding-bottom: 15px; padding-bottom: 15px;
} }
.breadcrumb, .muted{
color: var(--dbp-muted-text);
}
.breadcrumb:last-child{
color: inherit;
}
input:disabled+label{
color: #aaa;
}
@media only screen @media only screen
and (orientation: portrait) and (orientation: portrait)
and (max-device-width: 765px) { and (max-device-width: 765px) {
...@@ -1084,7 +1267,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) { ...@@ -1084,7 +1267,8 @@ export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
</label> </label>
</div> </div>
<div> <div>
<input type="radio" class="radio-btn" name="replacement" value="replace" @click="${() => {this.setInputFieldVisibility();}}"> <input type="radio" id="replace-replace" class="radio-btn" name="replacement" value="replace" @click="${() => {this.setInputFieldVisibility();}}">
<label for="replace">${i18n.t('nextcloud-file-picker.replace-replace')}</label> <label for="replace">${i18n.t('nextcloud-file-picker.replace-replace')}</label>
</div> </div>
<div> <div>
......
...@@ -67,7 +67,14 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { ...@@ -67,7 +67,14 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) {
let zip = new JSZip(); let zip = new JSZip();
let fileNames = []; let fileNames = [];
// add all signed pdf-files // download one file not compressed!
if(this.files.length === 1)
{
FileSaver.saveAs(this.files[0], this.files[0].filename);
return;
}
// download all files compressed
this.files.forEach((file) => { this.files.forEach((file) => {
let fileName = file.name; let fileName = file.name;
...@@ -204,12 +211,12 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { ...@@ -204,12 +211,12 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) {
<div class="source-main ${classMap({"hidden": this.activeDestination !== "local"})}"> <div class="source-main ${classMap({"hidden": this.activeDestination !== "local"})}">
<div id="zip-download-block"> <div id="zip-download-block">
<div class="block"> <div class="block">
${this.text || i18n.t('file-sink.local-intro', {'amount': this.files.length})} ${this.text || i18n.t('file-sink.local-intro', {'count': this.files.length})}
</div> </div>
<button class="button is-primary" <button class="button is-primary"
?disabled="${this.disabled}" ?disabled="${this.disabled}"
@click="${() => { this.downloadCompressedFiles(); }}"> @click="${() => { this.downloadCompressedFiles(); }}">
${this.buttonLabel || i18n.t('file-sink.local-button')} ${this.buttonLabel || i18n.t('file-sink.local-button', {'count': this.files.length})}
</button> </button>
</div> </div>
</div> </div>
......
...@@ -16,8 +16,10 @@ ...@@ -16,8 +16,10 @@
"nav-local": "Lokaler Computer" "nav-local": "Lokaler Computer"
}, },
"file-sink": { "file-sink": {
"local-intro": "{{amount}} Datei(en) als ZIP-Datei herunterladen", "local-intro": "{{count}} Datei herunterladen",
"local-button": "ZIP-Datei herunterladen", "local-intro_plural": "{{count}} Dateien als ZIP-Datei herunterladen",
"local-button": "Datei herunterladen",
"local-button_plural": "ZIP-Datei herunterladen",
"modal-close": "Dialog schließen", "modal-close": "Dialog schließen",
"nav-local": "Lokaler Computer", "nav-local": "Lokaler Computer",
"upload-success-title": "Erfolgreich hochgeladen", "upload-success-title": "Erfolgreich hochgeladen",
......
...@@ -16,8 +16,10 @@ ...@@ -16,8 +16,10 @@
"nav-local": "My device" "nav-local": "My device"
}, },
"file-sink": { "file-sink": {
"local-intro": "Download {{amount}} file(s) as ZIP-file", "local-intro": "Download {{count}} file",
"local-button": "Download ZIP-file", "local-intro_plural": "Download {{count}} files als ZIP",
"local-button": "Download file",
"local-button_plural": "Download ZIP-file",
"modal-close": "Close dialog", "modal-close": "Close dialog",
"nav-local": "My device", "nav-local": "My device",
"upload-success-title": "Successful uploaded", "upload-success-title": "Successful uploaded",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment