Skip to content

Commit 7aad2b5

Browse files
committed
Change fileupload to custom impl
1 parent 3171d4f commit 7aad2b5

File tree

2 files changed

+99
-40
lines changed

2 files changed

+99
-40
lines changed
Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,125 @@
1-
<!-- Waiting for design on variant where a file is uploaded -->
21
<template>
3-
<div class="flex flex-col gap-1">
4-
<label v-if="widget.name" class="text-sm opacity-80">{{
2+
<div class="flex flex-col gap-1 w-full">
3+
<label v-if="widget.name" class="text-xs opacity-80">{{
54
widget.name
65
}}</label>
7-
<FileUpload
8-
v-bind="filteredProps"
9-
:disabled="readonly"
10-
@upload="handleUpload"
11-
@select="handleSelect"
12-
@remove="handleRemove"
13-
@clear="handleClear"
14-
@error="handleError"
15-
/>
6+
<div class="flex flex-col items-center gap-2 w-full">
7+
<!-- TODO: Given file type from node definition, change text here and display differently. -->
8+
<span class="text-xs opacity-60">{{ t('g.dropYourFileOr') }}</span>
9+
<div class="w-full">
10+
<Button
11+
:label="getButtonLabel()"
12+
size="small"
13+
class="w-full text-xs"
14+
:disabled="readonly"
15+
@click="triggerFileInput"
16+
/>
17+
<input
18+
ref="fileInputRef"
19+
type="file"
20+
class="hidden"
21+
:accept="widget.options?.accept"
22+
:multiple="widget.options?.multiple"
23+
:disabled="readonly"
24+
@change="handleFileChange"
25+
/>
26+
</div>
27+
<!-- Display selected files -->
28+
<div v-if="selectedFiles.length > 0" class="w-full text-xs">
29+
<div
30+
v-for="(file, index) in selectedFiles"
31+
:key="index"
32+
class="flex items-center justify-between p-1"
33+
>
34+
<span class="truncate flex-1">{{ file.name }}</span>
35+
<Button
36+
v-if="!readonly"
37+
icon="pi pi-times"
38+
size="small"
39+
text
40+
severity="secondary"
41+
@click="removeFile(index)"
42+
/>
43+
</div>
44+
</div>
45+
</div>
1646
</div>
1747
</template>
1848

1949
<script setup lang="ts">
20-
import FileUpload from 'primevue/fileupload'
21-
import { computed } from 'vue'
50+
import Button from 'primevue/button'
51+
import { computed, ref, watch } from 'vue'
52+
import { useI18n } from 'vue-i18n'
2253
54+
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
2355
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
24-
import {
25-
STANDARD_EXCLUDED_PROPS,
26-
filterWidgetProps
27-
} from '@/utils/widgetPropFilter'
2856
29-
// FileUpload doesn't have a traditional v-model, it handles files through events
57+
const { t } = useI18n()
58+
3059
const props = defineProps<{
3160
widget: SimplifiedWidget<File[] | null>
61+
modelValue: File[] | null
3262
readonly?: boolean
3363
}>()
3464
35-
const filteredProps = computed(() =>
36-
filterWidgetProps(props.widget.options, STANDARD_EXCLUDED_PROPS)
37-
)
65+
const emit = defineEmits<{
66+
'update:modelValue': [value: File[] | null]
67+
}>()
3868
39-
const handleUpload = (event: any) => {
40-
if (!props.readonly && props.widget.callback) {
41-
props.widget.callback(event.files)
42-
}
43-
}
69+
// Use the composable for consistent widget value handling
70+
const { localValue, onChange } = useWidgetValue({
71+
widget: props.widget,
72+
modelValue: props.modelValue,
73+
defaultValue: null,
74+
emit
75+
})
4476
45-
const handleSelect = (event: any) => {
46-
if (!props.readonly && props.widget.callback) {
47-
props.widget.callback(event.files)
77+
const fileInputRef = ref<HTMLInputElement | null>(null)
78+
79+
// Use localValue from composable
80+
const selectedFiles = computed(() => localValue.value || [])
81+
82+
const getButtonLabel = () => {
83+
if (selectedFiles.value.length > 0) {
84+
return `${selectedFiles.value.length} file(s) selected`
4885
}
86+
return props.widget.options?.chooseLabel || t('g.searchbox.browse')
4987
}
5088
51-
const handleRemove = (event: any) => {
52-
if (!props.readonly && props.widget.callback) {
53-
props.widget.callback(event.files)
54-
}
89+
const triggerFileInput = () => {
90+
fileInputRef.value?.click()
5591
}
5692
57-
const handleClear = () => {
58-
if (!props.readonly && props.widget.callback) {
59-
props.widget.callback([])
93+
const handleFileChange = (event: Event) => {
94+
const target = event.target as HTMLInputElement
95+
if (!props.readonly && target.files) {
96+
// Convert FileList to array
97+
const files = Array.from(target.files)
98+
99+
// Use the composable's onChange handler
100+
onChange(files)
101+
102+
// Reset input to allow selecting same file again
103+
target.value = ''
60104
}
61105
}
62106
63-
const handleError = (event: any) => {
64-
// Could be extended to handle error reporting
65-
console.warn('File upload error:', event)
107+
const removeFile = (index: number) => {
108+
const newFiles = [...selectedFiles.value]
109+
newFiles.splice(index, 1)
110+
111+
const filesOrNull = newFiles.length > 0 ? newFiles : null
112+
113+
// Use the composable's onChange handler
114+
onChange(filesOrNull)
66115
}
116+
117+
// Clear file input when value is cleared externally
118+
watch(localValue, (newValue) => {
119+
if (!newValue || newValue.length === 0) {
120+
if (fileInputRef.value) {
121+
fileInputRef.value.value = ''
122+
}
123+
}
124+
})
67125
</script>

src/locales/en/main.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"no": "No",
5050
"cancel": "Cancel",
5151
"close": "Close",
52+
"dropYourFileOr": "Drop your file or",
5253
"back": "Back",
5354
"next": "Next",
5455
"install": "Install",

0 commit comments

Comments
 (0)