Merge remote-tracking branch 'origin/master'

pull/4734/head
Angel Fernando Quiroz Campos 1 year ago
commit c21109eb97
  1. 4
      assets/vue/components/basecomponents/BaseButton.vue
  2. 37
      assets/vue/components/basecomponents/BaseCheckbox.vue
  3. 1
      assets/vue/components/basecomponents/BaseMenu.vue
  4. 43
      assets/vue/components/basecomponents/BaseRadioButtons.vue
  5. 39
      assets/vue/composables/notification.js
  6. 24
      assets/vue/composables/upload.js
  7. 2
      assets/vue/router/documents.js
  8. 28
      assets/vue/views/documents/DocumentsList.vue
  9. 143
      assets/vue/views/documents/DocumentsUpload.vue
  10. 157
      assets/vue/views/documents/Upload.vue

@ -94,6 +94,10 @@ const buttonClass = computed(() => {
break;
case "danger":
result += `border-error hover:bg-error text-error hover:text-white ${commonDisabled} `;
break;
case "black":
result += "bg-white text-black hover:bg-gray-90 hover:text-white ";
break;
}
return result;
});

@ -0,0 +1,37 @@
<template>
<div class="flex items-center">
<Checkbox
:model-value="modelValue"
:binary="true"
:name="name"
:input-id="id"
@update:model-value="$emit('update:modelValue', $event)"
/>
<label :for="id" class="ml-2 cursor-pointer">{{ label }}</label>
</div>
</template>
<script setup>
import Checkbox from "primevue/checkbox";
defineProps({
id: {
type: String,
required: true,
},
modelValue: {
type: null,
required: true,
},
name: {
type: String,
required: true,
},
label: {
type: String,
required: true
}
})
defineEmits(['update:modelValue'])
</script>

@ -18,6 +18,7 @@ defineProps({
type: String,
required: true,
},
// https://primevue.org/menu/#api.options.MenuItem
model: {
type: Array,
required: true,

@ -0,0 +1,43 @@
<template>
<div class="flex flex-col">
<div v-for="(option, index) in options" :key="option.value" class="flex items-center mr-2">
<RadioButton
:input-id="name + index"
:model-value="value"
:name="name"
:value="option.value"
@update:model-value="value = $event"
/>
<label :for="name + index" class="ml-2 cursor-pointer">{{ option.label }}</label>
</div>
</div>
</template>
<script setup>
import RadioButton from 'primevue/radiobutton';
import {ref} from "vue";
const props = defineProps({
modelValue: {
type: String,
required: true
},
name: {
type: String,
required: true,
},
// Array with {label: x, value: y} for every option you want to support
options: {
type: Array,
required: true,
},
initialValue: {
type: String,
default: ''
},
})
defineEmits(['update:modelValue'])
const value = ref(props.initialValue)
</script>

@ -0,0 +1,39 @@
import {useToast} from "primevue/usetoast";
// This is the migration from assets/vue/mixins/NotificationMixin.js to composables
// some components still use UploadMixin with options API, this should be use
// when migrating from options API to composition API
export function useNotification() {
const toast = useToast();
const showSuccessNotification = (message) => {
showMessage(message, 'success')
}
const showInfoNotification = (error) => {
showMessage(error, 'info');
}
const showWarningNotification = (message) => {
showMessage(message, 'warning')
}
const showErrorNotification = (error) => {
showMessage(error, 'danger');
}
const showMessage = (message, severity) => {
toast.add({
severity: severity,
detail: message,
life: 3500,
});
}
return {
showSuccessNotification,
showInfoNotification,
showWarningNotification,
showErrorNotification,
}
}

@ -0,0 +1,24 @@
import {useI18n} from "vue-i18n";
import {useNotification} from "./notification";
// This is the migration from assets/vue/mixins/UploadMixin.js to composables
// some components still use UploadMixin with options API, this should be use
// when migrating from options API to composition API
export const useUpload = () => {
const {t} = useI18n();
const notification = useNotification()
const onCreated = (item) => {
notification.showSuccessNotification(t('{resource} created', {'resource': item['resourceNode'].title}))
}
const onError = (message) => {
notification.showErrorNotification(message)
}
return {
onCreated,
onError,
}
}

@ -23,7 +23,7 @@ export default {
{
name: 'DocumentsUploadFile',
path: 'upload',
component: () => import('../views/documents/Upload.vue')
component: () => import('../views/documents/DocumentsUpload.vue')
},
{
name: 'DocumentsUpdate',

@ -281,7 +281,6 @@ import {useCidReq} from '../../composables/cidReq'
import {useDatatableList} from '../../composables/datatableList'
import {useRelativeDatetime} from '../../composables/formatDate'
import axios from 'axios'
import {useToast} from 'primevue/usetoast';
import DocumentEntry from "../../components/documents/DocumentEntry.vue";
import BaseButton from "../../components/basecomponents/BaseButton.vue";
import ButtonToolbar from "../../components/basecomponents/ButtonToolbar.vue";
@ -290,19 +289,16 @@ import BaseDialogConfirmCancel from "../../components/basecomponents/BaseDialogC
import {useFileUtils} from "../../composables/fileUtils";
import BaseDialog from "../../components/basecomponents/BaseDialog.vue";
import BaseChart from "../../components/basecomponents/BaseChart.vue";
import {useNotification} from "../../composables/notification";
const store = useStore()
const route = useRoute()
const router = useRouter()
const {t} = useI18n()
const {filters, options, onUpdateOptions, deleteItem} = useDatatableList('Documents')
const toast = useToast();
const notification = useNotification()
const {cid, sid, gid} = useCidReq()
const {isImage} = useFileUtils()
store.dispatch('course/findCourse', {id: `/api/courses/${cid}`})
@ -414,12 +410,7 @@ function createNewFolder() {
store.dispatch('documents/createWithFormData', item.value)
.then(() => {
toast.add({
severity: 'success',
detail: t('Saved'),
life: 3500,
})
notification.showSuccessNotification(t('Saved'))
onUpdateOptions(options.value)
})
}
@ -440,15 +431,12 @@ function confirmDeleteItem (itemToDelete) {
isDeleteItemDialogVisible.value = true
}
function deleteMultipleItems () {
store.dispatch('documents/delMultiple', selectedItems.value)
.then(() => {
isDeleteMultipleDialogVisible.value = false
unselectAll()
})
async function deleteMultipleItems () {
await store.dispatch('documents/delMultiple', selectedItems.value)
isDeleteMultipleDialogVisible.value = false
notification.showSuccessNotification(t('Deleted'))
unselectAll()
onUpdateOptions(options.value)
//this.$toast.add({severity:'success', summary: 'Successful', detail: 'Products Deleted', life: 3000});*/
}
function unselectAll () {

@ -0,0 +1,143 @@
<template>
<div class="flex flex-col justify-start">
<div class="mb-4">
<Dashboard
:uppy="uppy"
:plugins="['Webcam', 'ImageEditor']"
:props="{
//metaFields: [{id: 'name', name: 'Name', placeholder: 'file name'}],
proudlyDisplayPoweredByUppy: false,
width: '100%',
height: '350px',
}"
/>
</div>
<BaseButton
:label="showAdvancedSettingsLabel"
class="mr-auto mb-4"
type="black"
icon="cog"
@click="advancedSettingsClicked"
/>
<div v-if="showAdvancedSettings">
<div class="flex flex-row mb-2">
<label class="font-semibold w-28">{{ t('Options') }}:</label>
<BaseCheckbox
id="uncompress"
v-model="isUncompressZipEnabled"
:label="t('Uncompres zip')"
name="uncompress"
/>
</div>
<div class="flex flex-row mb-2">
<label class="font-semibold w-28">{{ t('If file exists') }}:</label>
<BaseRadioButtons
v-model="fileExistsOption"
name="file-exists-options"
initial-value="rename"
:options="[
{label: t('Do nothing'), value: 'nothing'},
{label: t('Overwrite the existing file'), value: 'overwrite'},
{label: t('Rename the uploaded file if it exists'), value: 'rename'},
]"
/>
</div>
</div>
</div>
</template>
<script setup>
import {computed, ref} from 'vue'
import '@uppy/core/dist/style.css'
import '@uppy/dashboard/dist/style.css'
import '@uppy/image-editor/dist/style.css'
import Uppy from '@uppy/core'
import Webcam from '@uppy/webcam'
import {Dashboard} from '@uppy/vue'
import {useRoute, useRouter} from "vue-router";
import {RESOURCE_LINK_PUBLISHED} from "../../components/resource_links/visibility";
import {ENTRYPOINT} from "../../config/entrypoint";
import {useCidReq} from "../../composables/cidReq";
import {useUpload} from "../../composables/upload";
import BaseButton from "../../components/basecomponents/BaseButton.vue";
import {useI18n} from "vue-i18n";
import BaseCheckbox from "../../components/basecomponents/BaseCheckbox.vue";
import BaseRadioButtons from "../../components/basecomponents/BaseRadioButtons.vue";
const XHRUpload = require('@uppy/xhr-upload');
const ImageEditor = require('@uppy/image-editor');
const route = useRoute();
const router = useRouter();
const {gid, sid, cid} = useCidReq()
const {onCreated, onError} = useUpload()
const {t} = useI18n()
const parentResourceNodeId = ref(Number(route.params.node))
const resourceLinkList = ref(JSON.stringify([{
gid,
sid,
cid,
visibility: RESOURCE_LINK_PUBLISHED,
}]))
const showAdvancedSettings = ref(false)
const isUncompressZipEnabled = ref(false)
const fileExistsOption = ref('')
const showAdvancedSettingsLabel = computed(() => {
if (showAdvancedSettings.value) {
return t('Hide advanced settings')
} else {
return t('Show advanced settings')
}
})
let uppy = ref();
uppy.value = new Uppy()
.use(Webcam)
.use(ImageEditor, {
cropperOptions: {
viewMode: 1,
background: false,
autoCropArea: 1,
responsive: true
},
actions: {
revert: true,
rotate: true,
granularRotate: true,
flip: true,
zoomIn: true,
zoomOut: true,
cropSquare: true,
cropWidescreen: true,
cropWidescreenVertical: true
}
})
.use(
XHRUpload, {
endpoint: ENTRYPOINT + 'documents',
formData: true,
fieldName: 'uploadFile',
}
)
.on('upload-success', (item, response) => {
onCreated(response.body)
router.back()
})
uppy.value.setMeta({
filetype: 'file',
parentResourceNodeId: parentResourceNodeId.value,
resourceLinkList: resourceLinkList.value,
});
const advancedSettingsClicked = () => {
showAdvancedSettings.value = !showAdvancedSettings.value
}
</script>

@ -1,157 +0,0 @@
<template>
<div>
<dashboard
:uppy="uppy"
:plugins="['Webcam', 'ImageEditor']"
:props="{
//metaFields: [{id: 'name', name: 'Name', placeholder: 'file name'}],
proudlyDisplayPoweredByUppy: false,
width: '100%'
}"
/>
</div>
</template>
<script>
import { mapActions } from 'vuex';
import { createHelpers } from 'vuex-map-fields';
//import FormUpload from '../../components/documents/FormUpload.vue';
import Loading from '../../components/Loading.vue';
import Toolbar from '../../components/Toolbar.vue';
import UploadMixin from '../../mixins/UploadMixin';
import { ref, onMounted } from 'vue'
const servicePrefix = 'Documents';
const { mapFields } = createHelpers({
getterType: 'documents/getField',
mutationType: 'documents/updateField'
});
import '@uppy/core/dist/style.css'
import '@uppy/dashboard/dist/style.css'
import '@uppy/image-editor/dist/style.css'
import Uppy from '@uppy/core'
import Webcam from '@uppy/webcam'
const XHRUpload = require('@uppy/xhr-upload');
import { Dashboard } from '@uppy/vue'
import {useRoute} from "vue-router";
import {RESOURCE_LINK_PUBLISHED} from "../../components/resource_links/visibility";
import {ENTRYPOINT} from "../../config/entrypoint";
const ImageEditor = require('@uppy/image-editor');
export default {
name: 'DocumentsUpload',
servicePrefix,
mixins: [UploadMixin],
components: {
Loading,
Toolbar,
//FormUpload,
Dashboard
},
setup() {
const createForm = ref(null);
const parentResourceNodeId = ref(null);
const resourceLinkList = ref(null);
const route = useRoute();
parentResourceNodeId.value = Number(route.params.node);
resourceLinkList.value = JSON.stringify([{
gid: route.query.gid,
sid: route.query.sid,
cid: route.query.cid,
visibility: RESOURCE_LINK_PUBLISHED,
}]);
let uppy = ref();
uppy.value = new Uppy()
.use(Webcam)
.use(ImageEditor, {
cropperOptions: {
viewMode: 1,
background: false,
autoCropArea: 1,
responsive: true
},
actions: {
revert: true,
rotate: true,
granularRotate: true,
flip: true,
zoomIn: true,
zoomOut: true,
cropSquare: true,
cropWidescreen: true,
cropWidescreenVertical: true
}
})
.use(
XHRUpload, {
endpoint: ENTRYPOINT + 'documents',
formData: true,
fieldName: 'uploadFile'
}
)
;
uppy.value.setMeta({
filetype: 'file',
parentResourceNodeId: parentResourceNodeId.value,
resourceLinkList: resourceLinkList.value,
});
return {
createForm,
uppy
}
},
data() {
return {
files : [],
parentResourceNodeId: 0,
resourceLinkList: '',
};
},
computed: {
...mapFields(['error', 'isLoading', 'created', 'violations'])
},
created() {
console.log('created');
this.parentResourceNodeId = Number(this.$route.params.node);
this.resourceLinkList = JSON.stringify([{
gid: this.$route.query.gid,
sid: this.$route.query.sid,
cid: this.$route.query.cid,
visibility: RESOURCE_LINK_PUBLISHED,
}]);
this.files = [];
},
methods: {
async processFiles(files) {
return new Promise((resolve) => {
for (let i = 0; i < files.length; i++) {
files[i].title = files[i].name;
files[i].parentResourceNodeId = this.parentResourceNodeId;
files[i].resourceLinkList = this.resourceLinkList;
files[i].uploadFile = files[i];
this.createFile(files[i]);
}
resolve(files);
}).then(() => {
this.files = [];
});
},
validate(file) {
if (file) {
return '';
}
return 'error';
},
...mapActions('documents', ['uploadMany', 'createFile'])
}
};
</script>
Loading…
Cancel
Save