@testdracul/media-frontend 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.development +4 -0
- package/.env.example +3 -0
- package/.eslintrc.json +25 -0
- package/babel.config.js +5 -0
- package/dist/dracul-media-frontend.es.js +16238 -0
- package/dist/dracul-media-frontend.umd.js +586 -0
- package/dist/media-frontend.css +1 -0
- package/docs-en.md +45 -0
- package/docs-es.md +45 -0
- package/package.json +56 -0
- package/readme.md +36 -0
- package/src/components/CsvWebViewer/CsvWebViewer.vue +81 -0
- package/src/components/CsvWebViewer/index.ts +4 -0
- package/src/components/FileUpload/FileUpload.vue +94 -0
- package/src/components/FileUpload/index.ts +4 -0
- package/src/components/FileUploadButton/FileUploadButton.vue +127 -0
- package/src/components/FileUploadButton/index.ts +4 -0
- package/src/components/FileUploadExpiration/FileUploadExpiration.vue +274 -0
- package/src/components/FileUploadExpiration/index.ts +4 -0
- package/src/components/FileUploadExpress/FileUploadExpress.vue +208 -0
- package/src/components/FileUploadExpress/index.ts +4 -0
- package/src/components/FileView/FileView.vue +336 -0
- package/src/components/FileView/index.ts +4 -0
- package/src/components/GroupsShow/GroupsShow.vue +40 -0
- package/src/components/GroupsShow/index.ts +4 -0
- package/src/components/MediaField/MediaField.vue +62 -0
- package/src/components/MediaField/index.ts +4 -0
- package/src/components/PdfWebViewer/PdfWebViewer.vue +81 -0
- package/src/components/PdfWebViewer/index.ts +4 -0
- package/src/components/UsersShow/UsersShow.vue +39 -0
- package/src/components/UsersShow/index.ts +4 -0
- package/src/components/XlsxWebViewer/XlsxWebViewer.vue +70 -0
- package/src/components/XlsxWebViewer/index.ts +4 -0
- package/src/helpers/redeableBytes.ts +9 -0
- package/src/i18n/index.ts +22 -0
- package/src/i18n/messages/DocMessages.ts +31 -0
- package/src/i18n/messages/ExtraMessages.ts +29 -0
- package/src/i18n/messages/FileMessages.ts +223 -0
- package/src/i18n/messages/UserStorageMessages.ts +145 -0
- package/src/i18n/permissions/FilePermissionMessages.ts +50 -0
- package/src/i18n/permissions/OldPermissionMessages.ts +59 -0
- package/src/i18n/permissions/UserStoragePermissionMessages.ts +40 -0
- package/src/index.ts +70 -0
- package/src/mixins/readableBytesMixin.ts +9 -0
- package/src/pages/FileManagementPage/FileCreate/FileCreate.vue +108 -0
- package/src/pages/FileManagementPage/FileCreate/index.ts +3 -0
- package/src/pages/FileManagementPage/FileCrud/FileCrud.vue +133 -0
- package/src/pages/FileManagementPage/FileCrud/index.ts +4 -0
- package/src/pages/FileManagementPage/FileDelete/FileDelete.vue +61 -0
- package/src/pages/FileManagementPage/FileDelete/index.ts +3 -0
- package/src/pages/FileManagementPage/FileFilters/FileFilters.vue +150 -0
- package/src/pages/FileManagementPage/FileFilters/index.ts +3 -0
- package/src/pages/FileManagementPage/FileForm/FileForm.vue +184 -0
- package/src/pages/FileManagementPage/FileForm/UserCombobox.vue +66 -0
- package/src/pages/FileManagementPage/FileForm/index.ts +3 -0
- package/src/pages/FileManagementPage/FileList/FileEditButton.vue +410 -0
- package/src/pages/FileManagementPage/FileList/FileList.vue +178 -0
- package/src/pages/FileManagementPage/FileList/index.ts +4 -0
- package/src/pages/FileManagementPage/FileShow/FileShow.vue +23 -0
- package/src/pages/FileManagementPage/FileShow/FileShowData.vue +35 -0
- package/src/pages/FileManagementPage/FileShow/index.ts +3 -0
- package/src/pages/FileManagementPage/FileUpdate/FileUpdate.vue +107 -0
- package/src/pages/FileManagementPage/FileUpdate/index.ts +4 -0
- package/src/pages/FileManagementPage/index.vue +20 -0
- package/src/pages/MediaDocPage/MediaDocCard.vue +35 -0
- package/src/pages/MediaDocPage/MediaDocPage.vue +78 -0
- package/src/pages/UserStoragePage/UserStorage.vue +311 -0
- package/src/pages/UserStoragePage/UserStorageForm/UserStorageForm.vue +172 -0
- package/src/pages/UserStoragePage/UserStorageUpdate/UserStorageUpdate.vue +91 -0
- package/src/pages/UserStoragePage/index.vue +14 -0
- package/src/providers/FileMetricsProvider.ts +47 -0
- package/src/providers/FileProvider.ts +60 -0
- package/src/providers/UploadProvider.ts +32 -0
- package/src/providers/UserStorageProvider.ts +47 -0
- package/src/providers/gql/almacenamientoPorUsuario.graphql +10 -0
- package/src/providers/gql/cantidadArchivosPorUsuario.graphql +10 -0
- package/src/providers/gql/fetchMediaVariables.graphql +6 -0
- package/src/providers/gql/fileCreate.graphql +27 -0
- package/src/providers/gql/fileDelete.graphql +7 -0
- package/src/providers/gql/fileFetch.graphql +29 -0
- package/src/providers/gql/fileFind.graphql +29 -0
- package/src/providers/gql/fileGlobalMetrics.graphql +6 -0
- package/src/providers/gql/filePaginate.graphql +38 -0
- package/src/providers/gql/fileUpdate.graphql +29 -0
- package/src/providers/gql/fileUpload.graphql +29 -0
- package/src/providers/gql/fileUploadAnonymous.graphql +25 -0
- package/src/providers/gql/fileUserMetrics.graphql +9 -0
- package/src/providers/gql/userStorageFetch.graphql +17 -0
- package/src/providers/gql/userStorageFindByUser.graphql +17 -0
- package/src/providers/gql/userStorageUpdate.graphql +31 -0
- package/src/routes/index.ts +32 -0
- package/vite.config.ts +65 -0
- package/vue.config.js +22 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<crud-show v-if="uploadedFile" :open="open" :title="title" @close="$emit('close')">
|
|
4
|
+
<file-view v-if="uploadedFile" :file="uploadedFile"/>
|
|
5
|
+
</crud-show>
|
|
6
|
+
|
|
7
|
+
<crud-create
|
|
8
|
+
v-else
|
|
9
|
+
:open="open"
|
|
10
|
+
:loading="loading"
|
|
11
|
+
:title="title"
|
|
12
|
+
:error-message="errorMessage"
|
|
13
|
+
@close="$emit('close')"
|
|
14
|
+
@create="onCreate"
|
|
15
|
+
:fullscreen="false"
|
|
16
|
+
>
|
|
17
|
+
|
|
18
|
+
<div class="text-center">
|
|
19
|
+
|
|
20
|
+
<file-form
|
|
21
|
+
v-model="form"
|
|
22
|
+
:input-errors="inputErrors"
|
|
23
|
+
ref="formRef"
|
|
24
|
+
@fileSelected="onFileSelected"
|
|
25
|
+
@save="onCreate"
|
|
26
|
+
creating
|
|
27
|
+
/>
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
</crud-create>
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup>
|
|
37
|
+
import { ref } from 'vue'
|
|
38
|
+
import { useI18n } from 'vue-i18n'
|
|
39
|
+
import {CrudCreate, CrudShow, ClientError} from "@testdracul/common-frontend";
|
|
40
|
+
import FileView from "../../../components/FileView/FileView";
|
|
41
|
+
import FileForm from "../FileForm";
|
|
42
|
+
import uploadProvider from "../../../providers/UploadProvider";
|
|
43
|
+
|
|
44
|
+
const props = defineProps({
|
|
45
|
+
open: {type: Boolean, default: true},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const emit = defineEmits(['close', 'itemCreated'])
|
|
49
|
+
|
|
50
|
+
const { t } = useI18n()
|
|
51
|
+
|
|
52
|
+
const title = ref('media.file.creating')
|
|
53
|
+
const errorMessage = ref('')
|
|
54
|
+
const inputErrors = ref({})
|
|
55
|
+
const loading = ref(false)
|
|
56
|
+
const form = ref({
|
|
57
|
+
file: null,
|
|
58
|
+
expirationDate: null,
|
|
59
|
+
isPublic: false,
|
|
60
|
+
description: '',
|
|
61
|
+
tags: [],
|
|
62
|
+
groups: [],
|
|
63
|
+
users: []
|
|
64
|
+
})
|
|
65
|
+
const uploadedFile = ref(null)
|
|
66
|
+
const formRef = ref(null)
|
|
67
|
+
|
|
68
|
+
const onFileSelected = (file) => {
|
|
69
|
+
form.value.file = file
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const onCreate = async () => {
|
|
73
|
+
if (form.value.file) {
|
|
74
|
+
loading.value = true;
|
|
75
|
+
errorMessage.value = '';
|
|
76
|
+
|
|
77
|
+
await uploadProvider.uploadFile(
|
|
78
|
+
form.value.file,
|
|
79
|
+
form.value.expirationDate,
|
|
80
|
+
form.value.isPublic,
|
|
81
|
+
form.value.description,
|
|
82
|
+
form.value.tags,
|
|
83
|
+
form.value.groups,
|
|
84
|
+
form.value.users)
|
|
85
|
+
.then(result => {
|
|
86
|
+
uploadedFile.value = result.data.fileUpload
|
|
87
|
+
emit('itemCreated')
|
|
88
|
+
})
|
|
89
|
+
.catch((error) => {
|
|
90
|
+
const expirationDateError = error.message.includes('Expiration date must be older than current date') ? true : false;
|
|
91
|
+
if(expirationDateError) {
|
|
92
|
+
errorMessage.value = t("media.file.wrongExpirationDate")
|
|
93
|
+
} else {
|
|
94
|
+
let clientError = new ClientError(error)
|
|
95
|
+
inputErrors.value = clientError.inputErrors
|
|
96
|
+
errorMessage.value = clientError.i18nMessage
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
.finally(() => loading.value = false)
|
|
100
|
+
} else {
|
|
101
|
+
errorMessage.value = t("media.file.noFile")
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<style scoped>
|
|
107
|
+
|
|
108
|
+
</style>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<crud-layout
|
|
3
|
+
:title="title"
|
|
4
|
+
:subtitle="subtitle"
|
|
5
|
+
:add-button="topAddButton && hasPermission('FILE_CREATE')"
|
|
6
|
+
@add="create"
|
|
7
|
+
>
|
|
8
|
+
|
|
9
|
+
<template v-slot:list>
|
|
10
|
+
<file-list
|
|
11
|
+
ref="listRef"
|
|
12
|
+
@update="update"
|
|
13
|
+
@delete="remove"
|
|
14
|
+
@show="show"
|
|
15
|
+
@item-updated="onItemUpdated"
|
|
16
|
+
/>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<add-button
|
|
20
|
+
v-if="!topAddButton && hasPermission('FILE_CREATE')"
|
|
21
|
+
@click="create"
|
|
22
|
+
/>
|
|
23
|
+
|
|
24
|
+
<file-create v-if="creating"
|
|
25
|
+
:open="creating"
|
|
26
|
+
@item-created="onItemCreated"
|
|
27
|
+
@close="creating=false"
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
<file-update v-if="updating"
|
|
31
|
+
:open="updating"
|
|
32
|
+
:item="itemToEdit"
|
|
33
|
+
@item-updated="onItemUpdated"
|
|
34
|
+
@close="updating=false"
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
<file-show v-if="showing"
|
|
38
|
+
:open="showing"
|
|
39
|
+
:item="itemToShow"
|
|
40
|
+
@close="showing=false"
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
<file-delete v-if="deleting"
|
|
44
|
+
:open="deleting"
|
|
45
|
+
:item="itemToDelete"
|
|
46
|
+
@item-deleted="onItemDeleted"
|
|
47
|
+
@close="deleting=false"
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
<snackbar v-model="flash"/>
|
|
51
|
+
|
|
52
|
+
</crud-layout>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script setup>
|
|
56
|
+
import { ref, computed, onBeforeMount } from 'vue'
|
|
57
|
+
import { useStore } from 'vuex'
|
|
58
|
+
import { useI18n } from 'vue-i18n'
|
|
59
|
+
import FileUpdate from "../FileUpdate";
|
|
60
|
+
import FileDelete from "../FileDelete";
|
|
61
|
+
import FileShow from "../FileShow";
|
|
62
|
+
import FileList from "../FileList";
|
|
63
|
+
|
|
64
|
+
import {CrudLayout, AddButton, Snackbar} from "@testdracul/common-frontend"
|
|
65
|
+
import FileCreate from "../FileCreate/FileCreate";
|
|
66
|
+
|
|
67
|
+
const props = defineProps({
|
|
68
|
+
topAddButton: Boolean
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const emit = defineEmits([])
|
|
72
|
+
|
|
73
|
+
const { t } = useI18n()
|
|
74
|
+
const store = useStore()
|
|
75
|
+
|
|
76
|
+
const title = ref('media.file.title')
|
|
77
|
+
const subtitle = ref('media.file.subtitle')
|
|
78
|
+
const flash = ref(null)
|
|
79
|
+
const creating = ref(false)
|
|
80
|
+
const updating = ref(false)
|
|
81
|
+
const deleting = ref(false)
|
|
82
|
+
const showing = ref(false)
|
|
83
|
+
const itemToEdit = ref(null)
|
|
84
|
+
const itemToDelete = ref(null)
|
|
85
|
+
const itemToShow = ref(null)
|
|
86
|
+
const timeoutSnackbar = ref(10000)
|
|
87
|
+
const listRef = ref(null)
|
|
88
|
+
|
|
89
|
+
const hasPermission = (permission) => store.getters.hasPermission(permission)
|
|
90
|
+
const getRole = computed(() => store.getters.getRole)
|
|
91
|
+
|
|
92
|
+
onBeforeMount(() => {
|
|
93
|
+
if(getRole.value === "visualizer"){
|
|
94
|
+
subtitle.value = 'media.file.visualizerSubtitle'
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const onItemCreated = () => {
|
|
99
|
+
listRef.value?.fetch()
|
|
100
|
+
flash.value = t("common.created")
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const onItemUpdated = () => {
|
|
104
|
+
listRef.value?.fetch()
|
|
105
|
+
flash.value = t("common.updated")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const onItemDeleted = () => {
|
|
109
|
+
listRef.value?.fetch()
|
|
110
|
+
flash.value = t("common.deleted")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const create = () => {
|
|
114
|
+
creating.value = true
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const update = (item) => {
|
|
118
|
+
updating.value = true
|
|
119
|
+
itemToEdit.value = item
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const show = (item) => {
|
|
123
|
+
showing.value = true
|
|
124
|
+
itemToShow.value = item
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const remove = (item) => {
|
|
128
|
+
deleting.value = true
|
|
129
|
+
itemToDelete.value = item
|
|
130
|
+
}
|
|
131
|
+
</script>
|
|
132
|
+
|
|
133
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<crud-delete :open="open"
|
|
3
|
+
:loading="loading"
|
|
4
|
+
:title="title"
|
|
5
|
+
:error-message="errorMessage"
|
|
6
|
+
@delete="remove"
|
|
7
|
+
@close="$emit('close')"
|
|
8
|
+
>
|
|
9
|
+
|
|
10
|
+
<v-card-text>
|
|
11
|
+
<file-show-data :item="item" />
|
|
12
|
+
</v-card-text>
|
|
13
|
+
|
|
14
|
+
<v-card-text>
|
|
15
|
+
<v-row justify="center">
|
|
16
|
+
<span class="title">{{areYouSure}}</span>
|
|
17
|
+
</v-row>
|
|
18
|
+
</v-card-text>
|
|
19
|
+
|
|
20
|
+
</crud-delete>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
import { ref } from 'vue'
|
|
25
|
+
import { useI18n } from 'vue-i18n'
|
|
26
|
+
import FileProvider from "../../../providers/FileProvider";
|
|
27
|
+
import FileShowData from "../FileShow/FileShowData";
|
|
28
|
+
import {CrudDelete, ClientError} from '@testdracul/common-frontend'
|
|
29
|
+
|
|
30
|
+
const props = defineProps({
|
|
31
|
+
open: {type: Boolean, default: true},
|
|
32
|
+
item: {type: Object, required: true}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const emit = defineEmits(['close', 'itemDeleted'])
|
|
36
|
+
|
|
37
|
+
const { t } = useI18n()
|
|
38
|
+
|
|
39
|
+
const modal = ref(false)
|
|
40
|
+
const title = ref('media.file.deleting')
|
|
41
|
+
const areYouSure = ref(t('common.areYouSureDeleteRecord'))
|
|
42
|
+
const errorMessage = ref('')
|
|
43
|
+
const loading = ref(false)
|
|
44
|
+
|
|
45
|
+
const remove = () => {
|
|
46
|
+
loading.value = true
|
|
47
|
+
FileProvider.deleteFile(props.item.id).then(result => {
|
|
48
|
+
if (result.data.fileDelete.success) {
|
|
49
|
+
emit('itemDeleted', result.data.fileDelete)
|
|
50
|
+
emit('close')
|
|
51
|
+
} else {
|
|
52
|
+
errorMessage.value = 'Error on Delete'
|
|
53
|
+
}
|
|
54
|
+
}).catch(error => {
|
|
55
|
+
let clientError = new ClientError(error)
|
|
56
|
+
errorMessage.value = clientError.showMessage
|
|
57
|
+
}).finally(() => loading.value = false)
|
|
58
|
+
}
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<filter-layout :title="'media.file.filters'" @clear="cleanFilters()" @apply="setFilters()" apply-button>
|
|
3
|
+
<v-col cols="12" sm="6" md="4">
|
|
4
|
+
<date-input
|
|
5
|
+
v-if="filters[0].field == 'dateFrom'"
|
|
6
|
+
v-model="filters[0].value"
|
|
7
|
+
:label="$t('media.file.from')"
|
|
8
|
+
prepend-inner-icon="mdi-calendar"
|
|
9
|
+
color="secondary"
|
|
10
|
+
hide-details
|
|
11
|
+
variant="underlined"
|
|
12
|
+
dense
|
|
13
|
+
/>
|
|
14
|
+
</v-col>
|
|
15
|
+
<v-col cols="12" sm="6" md="4">
|
|
16
|
+
<date-input
|
|
17
|
+
v-model="filters[1].value"
|
|
18
|
+
:label="$t('media.file.until')"
|
|
19
|
+
prepend-inner-icon="mdi-calendar"
|
|
20
|
+
color="secondary"
|
|
21
|
+
hide-details
|
|
22
|
+
variant="underlined"
|
|
23
|
+
dense
|
|
24
|
+
/>
|
|
25
|
+
</v-col>
|
|
26
|
+
<v-col cols="12" md="4" sm="6">
|
|
27
|
+
<v-text-field
|
|
28
|
+
v-model="filters[2].value"
|
|
29
|
+
:label="$t('media.file.filename')"
|
|
30
|
+
prepend-inner-icon="mdi-text"
|
|
31
|
+
color="secondary"
|
|
32
|
+
hide-details
|
|
33
|
+
variant="underlined"
|
|
34
|
+
density="compact"
|
|
35
|
+
/>
|
|
36
|
+
</v-col>
|
|
37
|
+
<v-col cols="12" sm="6" md="3">
|
|
38
|
+
<v-select
|
|
39
|
+
v-model="filters[4].value"
|
|
40
|
+
:label="$t('media.file.type')"
|
|
41
|
+
:items="selectType"
|
|
42
|
+
prepend-inner-icon="mdi-file"
|
|
43
|
+
color="secondary"
|
|
44
|
+
variant="underlined"
|
|
45
|
+
density="compact"
|
|
46
|
+
hide-details
|
|
47
|
+
/>
|
|
48
|
+
</v-col>
|
|
49
|
+
<v-col v-if="isUserAuthorized('FILE_SHOW_OWN')" cols="12" sm="6" md="3">
|
|
50
|
+
<v-select
|
|
51
|
+
prepend-inner-icon="mdi-eye"
|
|
52
|
+
v-model="filters[7].value"
|
|
53
|
+
:items="[{title: 'Público', value: 'true'}, {title: 'Privado', value: 'false'}]"
|
|
54
|
+
:label="$t('media.file.visibility')"
|
|
55
|
+
variant="underlined"
|
|
56
|
+
density="compact"
|
|
57
|
+
hide-details
|
|
58
|
+
></v-select>
|
|
59
|
+
</v-col>
|
|
60
|
+
<v-col cols="12" sm="6" md="3">
|
|
61
|
+
<v-text-field
|
|
62
|
+
v-model="filters[5].value"
|
|
63
|
+
:label="$t('media.file.sizeGt') + ' (MB)'"
|
|
64
|
+
prepend-inner-icon="mdi-arrow-up-bold-circle-outline"
|
|
65
|
+
color="secondary"
|
|
66
|
+
variant="underlined"
|
|
67
|
+
density="compact"
|
|
68
|
+
hide-details
|
|
69
|
+
/>
|
|
70
|
+
</v-col>
|
|
71
|
+
<v-col cols="12" sm="6" md="3">
|
|
72
|
+
<v-text-field
|
|
73
|
+
v-model="filters[6].value"
|
|
74
|
+
:label="$t('media.file.sizeLt') + ' (MB)'"
|
|
75
|
+
prepend-inner-icon="mdi-arrow-down-bold-circle-outline"
|
|
76
|
+
color="secondary"
|
|
77
|
+
variant="underlined"
|
|
78
|
+
density="compact"
|
|
79
|
+
hide-details
|
|
80
|
+
/>
|
|
81
|
+
</v-col>
|
|
82
|
+
<v-col v-if="isUserAuthorized('FILE_SHOW_ALL')" cols="12" md="4" sm="6">
|
|
83
|
+
<user-autocomplete
|
|
84
|
+
v-model="filters[3].value"
|
|
85
|
+
label="media.file.createdBy"
|
|
86
|
+
>
|
|
87
|
+
</user-autocomplete>
|
|
88
|
+
</v-col>
|
|
89
|
+
<v-col v-if="isUserAuthorized('FILE_SHOW_ALL')" cols="12" md="4" sm="6">
|
|
90
|
+
<group-autocomplete
|
|
91
|
+
v-model="filters[8].value"
|
|
92
|
+
label="media.file.group"
|
|
93
|
+
>
|
|
94
|
+
</group-autocomplete>
|
|
95
|
+
</v-col>
|
|
96
|
+
<v-col v-if="isUserAuthorized('FILE_SHOW_ALL')" cols="12" md="4" sm="6">
|
|
97
|
+
<user-autocomplete
|
|
98
|
+
v-model="filters[9].value"
|
|
99
|
+
label="media.file.user"
|
|
100
|
+
>
|
|
101
|
+
</user-autocomplete>
|
|
102
|
+
</v-col>
|
|
103
|
+
</filter-layout>
|
|
104
|
+
</template>
|
|
105
|
+
|
|
106
|
+
<script setup>
|
|
107
|
+
import {computed} from 'vue'
|
|
108
|
+
import {useStore} from 'vuex'
|
|
109
|
+
import {DateInput} from '@testdracul/dayjs-frontend';
|
|
110
|
+
import {GroupAutocomplete, UserAutocomplete} from '@testdracul/user-frontend'
|
|
111
|
+
import {FilterLayout} from '@testdracul/common-frontend'
|
|
112
|
+
|
|
113
|
+
const props = defineProps({
|
|
114
|
+
modelValue: Array
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
const emit = defineEmits(['updateFilters', 'clearFilter', 'update:modelValue'])
|
|
118
|
+
|
|
119
|
+
const store = useStore()
|
|
120
|
+
|
|
121
|
+
const filters = computed({
|
|
122
|
+
get() {
|
|
123
|
+
return props.modelValue
|
|
124
|
+
},
|
|
125
|
+
set(val) {
|
|
126
|
+
emit('update:modelValue', val)
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const me = computed(() => store.getters.me)
|
|
131
|
+
|
|
132
|
+
const selectType = [
|
|
133
|
+
{title: "text", value: "text"},
|
|
134
|
+
{title: "image", value: "image"},
|
|
135
|
+
{title: "application", value: "application"},
|
|
136
|
+
{title: "audio", value: "audio"}
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
const setFilters = () => {
|
|
140
|
+
emit("updateFilters", filters.value);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const cleanFilters = () => {
|
|
144
|
+
emit("clearFilter", filters.value);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const isUserAuthorized = (permission) => {
|
|
148
|
+
return store.getters.hasPermission(permission)
|
|
149
|
+
}
|
|
150
|
+
</script>
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-form ref="formRef" autocomplete="off" @submit.prevent="$emit('save')">
|
|
3
|
+
<v-row class="mt-2">
|
|
4
|
+
|
|
5
|
+
<v-col cols="12" md="6" sm="12">
|
|
6
|
+
<v-card variant="outlined" color="secondary" class="pa-2">
|
|
7
|
+
<date-time-input
|
|
8
|
+
v-model="form.expirationDate"
|
|
9
|
+
:label="$t('media.file.expirationDate')"
|
|
10
|
+
prepend-inner-icon="mdi-calendar-clock"
|
|
11
|
+
persistent-hint
|
|
12
|
+
color="secondary"
|
|
13
|
+
variant="filled"
|
|
14
|
+
density="comfortable"
|
|
15
|
+
:rules="fileExpirationTimeRules"
|
|
16
|
+
/>
|
|
17
|
+
<div class="text-caption mt-1 px-2 text-grey-darken-1">
|
|
18
|
+
La fecha y hora en que el archivo será eliminado automáticamente.
|
|
19
|
+
</div>
|
|
20
|
+
</v-card>
|
|
21
|
+
</v-col>
|
|
22
|
+
|
|
23
|
+
<v-col cols="12" md="6" sm="12">
|
|
24
|
+
<v-select
|
|
25
|
+
prepend-inner-icon="mdi-eye"
|
|
26
|
+
v-model="form.isPublic"
|
|
27
|
+
:items="[{title: 'Público', value: true}, {title: 'Privado', value: false}]"
|
|
28
|
+
:label="$t('media.file.visibility')"
|
|
29
|
+
variant="underlined"
|
|
30
|
+
density="compact"
|
|
31
|
+
></v-select>
|
|
32
|
+
</v-col>
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
<v-col cols="12" sm="12" md="12">
|
|
36
|
+
<v-combobox
|
|
37
|
+
prepend-inner-icon="mdi-tag-multiple"
|
|
38
|
+
v-model="form.tags"
|
|
39
|
+
:label="$t('media.file.tags')"
|
|
40
|
+
chips
|
|
41
|
+
multiple
|
|
42
|
+
color="secondary"
|
|
43
|
+
variant="underlined"
|
|
44
|
+
density="compact"
|
|
45
|
+
></v-combobox>
|
|
46
|
+
</v-col>
|
|
47
|
+
|
|
48
|
+
<v-col cols="12" sm="12">
|
|
49
|
+
<v-text-field
|
|
50
|
+
prepend-inner-icon="mdi-text-box"
|
|
51
|
+
name="filename"
|
|
52
|
+
v-model="form.description"
|
|
53
|
+
:label="$t('media.file.description')"
|
|
54
|
+
:placeholder="$t('media.file.description')"
|
|
55
|
+
color="secondary"
|
|
56
|
+
variant="underlined"
|
|
57
|
+
density="compact"
|
|
58
|
+
></v-text-field>
|
|
59
|
+
</v-col>
|
|
60
|
+
<v-col cols="12">
|
|
61
|
+
<group-autocomplete
|
|
62
|
+
v-model="form.groups"
|
|
63
|
+
multiple
|
|
64
|
+
label="media.file.groups"
|
|
65
|
+
></group-autocomplete>
|
|
66
|
+
</v-col>
|
|
67
|
+
|
|
68
|
+
<v-col cols="12">
|
|
69
|
+
<user-autocomplete
|
|
70
|
+
v-model="form.users"
|
|
71
|
+
multiple
|
|
72
|
+
label="media.file.users"
|
|
73
|
+
></user-autocomplete>
|
|
74
|
+
</v-col>
|
|
75
|
+
|
|
76
|
+
<v-col v-if="creating || updating" cols="12" align-self="center" class="text-center mt-4">
|
|
77
|
+
<v-divider class="mb-4"></v-divider>
|
|
78
|
+
<file-upload-button
|
|
79
|
+
:updating="updating"
|
|
80
|
+
@file-selected="onFileSelected"
|
|
81
|
+
:max-file-size="maxFileSize"
|
|
82
|
+
:loading="loading"
|
|
83
|
+
:old-file-extension="oldFileExtension"
|
|
84
|
+
></file-upload-button>
|
|
85
|
+
</v-col>
|
|
86
|
+
</v-row>
|
|
87
|
+
</v-form>
|
|
88
|
+
</template>
|
|
89
|
+
|
|
90
|
+
<script setup>
|
|
91
|
+
import { ref, computed, onMounted, watch } from 'vue'
|
|
92
|
+
import { useI18n } from 'vue-i18n'
|
|
93
|
+
import { DateTimeInput } from '@testdracul/dayjs-frontend';
|
|
94
|
+
import UserStorageProvider from "../../../providers/UserStorageProvider"
|
|
95
|
+
import FileUploadButton from "../../../components/FileUploadButton";
|
|
96
|
+
import { GroupAutocomplete, UserAutocomplete } from '@testdracul/user-frontend'
|
|
97
|
+
import dayjs from 'dayjs'
|
|
98
|
+
|
|
99
|
+
const props = defineProps({
|
|
100
|
+
modelValue: {type: Object, required: true},
|
|
101
|
+
creating: {type: Boolean, default: false},
|
|
102
|
+
updating: {type: Boolean, default: false},
|
|
103
|
+
loading: {type: Boolean, default: false},
|
|
104
|
+
oldFileExtension: {type: String},
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
const emit = defineEmits(['update:modelValue', 'fileSelected', 'save'])
|
|
108
|
+
|
|
109
|
+
const { t } = useI18n()
|
|
110
|
+
|
|
111
|
+
const maxFileSize = ref(null)
|
|
112
|
+
const fileExpirationTime = ref(null)
|
|
113
|
+
const formRef = ref(null)
|
|
114
|
+
|
|
115
|
+
const form = computed({
|
|
116
|
+
get() {
|
|
117
|
+
return props.modelValue
|
|
118
|
+
},
|
|
119
|
+
set(val) {
|
|
120
|
+
emit('update:modelValue', val)
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// Lógica de validación robusta para el error de RangeError
|
|
125
|
+
const differenceInDays = computed(() => {
|
|
126
|
+
if(form.value.expirationDate){
|
|
127
|
+
const today = dayjs();
|
|
128
|
+
const expirationDate = dayjs(form.value.expirationDate);
|
|
129
|
+
if (!expirationDate.isValid()) return null;
|
|
130
|
+
return expirationDate.diff(today, 'day');
|
|
131
|
+
}
|
|
132
|
+
return null
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const fileExpirationTimeRules = computed(() => [
|
|
136
|
+
() => {
|
|
137
|
+
if (differenceInDays.value === null) return true;
|
|
138
|
+
|
|
139
|
+
if (differenceInDays.value < 0) {
|
|
140
|
+
return t("media.userStorage.fileExpirationTimeOlderThanToday")
|
|
141
|
+
} else if (fileExpirationTime.value && (differenceInDays.value !== null)) {
|
|
142
|
+
return (differenceInDays.value <= fileExpirationTime.value)
|
|
143
|
+
|| `${t("media.userStorage.fileExpirationLimitExceeded")} ${fileExpirationTime.value} ${t("media.file.days")}`
|
|
144
|
+
} else {
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
])
|
|
149
|
+
|
|
150
|
+
const validate = async () => {
|
|
151
|
+
if (formRef.value) {
|
|
152
|
+
const { valid } = await formRef.value.validate()
|
|
153
|
+
return valid
|
|
154
|
+
}
|
|
155
|
+
return false
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const onFileSelected = (file) => {
|
|
159
|
+
emit('fileSelected', file)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const findUserStorage = () => {
|
|
163
|
+
return UserStorageProvider.findUserStorageByUser().then((res) => {
|
|
164
|
+
if (res.data.userStorageFindByUser && res.data.userStorageFindByUser.maxFileSize) {
|
|
165
|
+
maxFileSize.value = res.data.userStorageFindByUser.maxFileSize;
|
|
166
|
+
fileExpirationTime.value = res.data.userStorageFindByUser.fileExpirationTime;
|
|
167
|
+
}
|
|
168
|
+
}).catch(err => console.error(err))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
onMounted(() => {
|
|
172
|
+
findUserStorage()
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
defineExpose({ validate })
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<style scoped>
|
|
179
|
+
/* Espaciado refinado para el formulario */
|
|
180
|
+
.v-row {
|
|
181
|
+
margin-left: -8px;
|
|
182
|
+
margin-right: -8px;
|
|
183
|
+
}
|
|
184
|
+
</style>
|