Files
raven-client/ayanova/src/components/attachment-control.vue
2020-06-07 17:13:06 +00:00

394 lines
12 KiB
Vue

<template>
<div class="mt-6" v-resize="onResize">
<div>
<v-btn depressed tile @click="revealedClicked">
{{ $ay.t("Attachments")
}}<v-icon v-text="reveal ? 'fa-eye-slash' : 'fa-eye'" right></v-icon
></v-btn>
</div>
<template v-if="reveal">
<div>
<template v-if="readonly">
<!-- Note: this is just a copy of the inner part of read/write version below
with the action taken out -->
<div class="mt-4" :style="cardTextStyle()">
<span v-if="!hasFiles()">{{ $ay.t("NoData") }}</span>
<v-list three-line>
<v-list-item
v-for="item in displayList"
:key="item.id"
:href="item.url"
target="_blank"
>
<v-list-item-avatar>
<v-icon v-text="item.icon"></v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="item.name"></v-list-item-title>
<v-list-item-subtitle
v-text="item.date"
></v-list-item-subtitle>
<v-list-item-subtitle
v-text="item.notes"
></v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
</div>
</template>
<template v-else>
<v-tabs v-model="tab" color="primary">
<v-tabs-slider></v-tabs-slider>
<v-tab key="list"><v-icon>fa-folder</v-icon></v-tab>
<v-tab key="attach"><v-icon>fa-paperclip</v-icon></v-tab>
<v-tabs-items v-model="tab">
<v-tab-item key="list">
<div
v-cloak
@drop.prevent="onDrop"
@dragover.prevent="onDragOver"
@dragleave="onDragEnd"
class="mt-4"
:style="cardTextStyle()"
id="dropDiv"
>
<v-list three-line>
<v-list-item
v-for="item in displayList"
:key="item.id"
:href="item.url"
target="_blank"
>
<v-list-item-avatar>
<v-icon v-text="item.icon"></v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title
v-text="item.name"
></v-list-item-title>
<v-list-item-subtitle
v-text="item.date"
></v-list-item-subtitle>
<v-list-item-subtitle
v-text="item.notes"
></v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-btn large @click="openEditMenu(item, $event)" icon>
<v-icon>fa-edit</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
</div>
<v-btn depressed tile @click="revealedClicked" class="mt-8">
{{ $ay.t("Attachments")
}}<v-icon
v-text="reveal ? 'fa-eye-slash' : 'fa-eye'"
right
></v-icon
></v-btn>
</v-tab-item>
<v-tab-item key="attach">
<div class="mt-8">
<v-file-input
v-model="uploadFiles"
:label="$ay.t('AttachFile')"
prepend-icon="fa-paperclip"
multiple
chips
></v-file-input>
<v-text-field
v-model="notes"
:label="$ay.t('AttachmentNotes')"
></v-text-field>
<v-btn color="primary" text @click="upload">{{
$ay.t("Upload")
}}</v-btn>
</div>
</v-tab-item>
</v-tabs-items>
</v-tabs>
<v-menu
min-width="360"
v-model="editMenu"
:close-on-content-click="false"
offset-y
:position-x="menuX"
:position-y="menuY"
absolute
>
<v-card>
<v-card-title>{{ $ay.t("FileAttachment") }}</v-card-title>
<div class="ma-6">
<v-text-field
v-model="editName"
:label="$ay.t('AttachmentFileName')"
></v-text-field>
<v-text-field
v-model="editNotes"
:label="$ay.t('AttachmentNotes')"
></v-text-field>
</div>
<v-card-actions>
<v-btn @click="remove()" text>
{{ $ay.t("Delete") }}
</v-btn>
<v-spacer></v-spacer>
<v-btn text @click="editMenu = false">{{
$ay.t("Cancel")
}}</v-btn>
<v-btn color="primary" text @click="saveEdit">{{
$ay.t("OK")
}}</v-btn>
</v-card-actions>
</v-card>
</v-menu>
</template>
</div>
</template>
</div>
</template>
<script>
export default {
data() {
return {
reveal: false,
height: 300,
displayList: [],
notes: null,
tab: null,
uploadFiles: [],
editMenu: false,
menuX: 10,
menuY: 10,
editNotes: null,
editName: null,
editId: null
};
},
props: {
ayaType: Number,
ayaId: Number,
readonly: Boolean
},
computed: {},
methods: {
revealedClicked() {
this.reveal = !this.reveal;
if (this.reveal) {
this.getList();
}
},
onResize() {
this.height = window.innerHeight * 0.8;
},
cardTextStyle() {
return "height: " + this.height + "px;overflow-y:auto;";
},
hasFiles() {
if (!this.displayList || this.displayList.length == 0) {
return false;
}
return true;
},
upload() {
//similar code in wiki-control
let vm = this;
let fileData = [];
for (let i = 0; i < vm.uploadFiles.length; i++) {
let f = vm.uploadFiles[i];
fileData.push({ name: f.name, lastModified: f.lastModified });
}
let at = {
ayaId: vm.ayaId,
ayaType: vm.ayaType,
files: vm.uploadFiles,
fileData: JSON.stringify(fileData), //note this is required for an array or it will come to the server as a string [object,object]
notes: vm.notes ? vm.notes : ""
};
window.$gz.api
.uploadAttachment(at)
.then(res => {
if (res.error) {
window.$gz.errorHandler.handleFormError(res.error);
} else {
vm.uploadFiles = [];
vm.updateDisplayList(res.data);
}
})
.catch(function handleUploadError(error) {
window.$gz.errorHandler.handleFormError(error);
});
},
remove() {
let vm = this;
window.$gz.dialog.confirmDelete().then(dialogResult => {
if (dialogResult == true) {
window.$gz.api
.remove("attachment/" + vm.editId)
.then(res => {
if (res.error) {
window.$gz.errorHandler.handleFormError(res.error);
} else {
vm.editMenu = false;
vm.editName = null;
vm.editNotes = null;
vm.editId = null;
vm.getList();
}
})
.catch(function handleUploadError(error) {
window.$gz.errorHandler.handleFormError(error);
});
}
});
},
getList() {
let vm = this;
window.$gz.api
.get("attachment/list?ayatype=" + vm.ayaType + "&ayaid=" + vm.ayaId)
.then(res => {
if (res.error) {
window.$gz.errorHandler.handleFormError(res.error);
} else {
vm.updateDisplayList(res.data);
}
})
.catch(function handleGetListError(error) {
window.$gz.errorHandler.handleFormError(error);
});
},
updateDisplayList(data) {
//{"data":[{"id":1,"concurrency":7733332,"contentType":"image/png","displayFileName":"Screen Shot 2020-01-09 at 10.50.24.png","lastModified":"0001-01-01T00:00:00Z","notes":"Here are notes"},{"id":4,"concurrency":7733354,"contentType":"text/plain","displayFileName":"TNT log file ayanova.txt","lastModified":"0001-01-01T00:00:00Z","notes":"Here are notes"},{"id":2,"concurrency":7733342,"contentType":"text/plain","displayFileName":"stack.txt","lastModified":"0001-01-01T00:00:00Z","notes":"Here are notes"},{"id":3,"concurrency":7733348,"contentType":"image/jpeg","displayFileName":"t2cx6sloffk41.jpg","lastModified":"0001-01-01T00:00:00Z","notes":"Here are notes"}]}
if (!data) {
data = [];
}
let timeZoneName = window.$gz.locale.getBrowserTimeZoneName();
let languageName = window.$gz.locale.getBrowserLanguages();
let hour12 = window.$gz.store.state.locale.hour12;
let ret = [];
for (let i = 0; i < data.length; i++) {
let o = data[i];
//http://localhost:7575/api/v8/attachment/download/100?t=sssss
ret.push({
id: o.id,
concurrency: o.concurrency,
url: window.$gz.api.attachmentDownloadUrl(o.id, o.contentType),
name: o.displayFileName,
date: window.$gz.locale.utcDateToShortDateAndTimeLocalized(
o.lastModified,
timeZoneName,
languageName,
hour12
),
notes: o.notes ? o.notes : "",
icon: window.$gz.util.iconForFile(o.displayFileName, o.contentType)
});
}
this.displayList = ret;
},
openEditMenu(item, e) {
e.preventDefault();
this.editMenu = false;
this.editName = item.name;
this.editNotes = item.notes;
this.editId = item.id;
this.menuX = e.clientX;
this.menuY = e.clientY;
this.$nextTick(() => {
this.editMenu = true;
});
},
saveEdit() {
let vm = this;
if (!vm.editName) {
//todo: some error here, name is required..
return;
}
//check if they differ first
let o = null;
let i = 0;
for (i = 0; i < vm.displayList.length; i++) {
if (vm.displayList[i].id == vm.editId) {
o = vm.displayList[i];
break;
}
}
//any changes?
if (o.name == vm.editName && o.notes == vm.editNotes) {
return;
}
//post to server
/*
public uint Concurrency { get; set; }
[Required]
public string DisplayFileName { get; set; }
public string Notes { get; set; }
*/
let p = {
concurrency: o.concurrency,
displayFileName: vm.editName,
notes: vm.editNotes
};
window.$gz.api
.upsert("attachment/" + vm.editId, p)
.then(res => {
if (res.error) {
window.$gz.errorHandler.handleFormError(res.error);
} else {
vm.editMenu = false;
vm.editName = null;
vm.editNotes = null;
vm.editId = null;
//due to fucking reactivity issues which never seem to resolve no matter what I'm returning a fresh list on update
vm.updateDisplayList(res.data);
}
})
.catch(function handleUploadError(error) {
window.$gz.errorHandler.handleFormError(error);
});
},
onDrop(ev) {
dropDiv.style.border = "none";
dropDiv = null;
//handle file drop
var files = Array.from(ev.dataTransfer.files);
if (files.length > 0) {
this.uploadFiles = files;
this.upload();
}
},
onDragOver(ev) {
if (!dropDiv) {
dropDiv = document.getElementById("dropDiv");
}
dropDiv.style.border = "4px dashed #00ff00";
},
onDragEnd(ev) {
dropDiv.style.border = "none";
dropDiv = null;
}
//-----
}
};
let dropDiv = null;
</script>