Vuetify file upload - v-file-input followup

Hello everyone !

I'm opening this topic following the one opened by @nygma2004 :

Vuetify file upload - v-file-input - Dashboard - Node-RED Forum (nodered.org)

An issue of file size was raised in the end and I may have a solution based off of nygma's work : dividing the file in multiple chunks (I set the chunk size to 800Ko) and putting it back together with a join node :

[
    {
        "id": "cc31893de3ea1e48",
        "type": "ui-template",
        "z": "7c89a635677d6c3e",
        "group": "8300798fe75f4399",
        "page": "",
        "ui": "",
        "name": "Binary File Upload",
        "order": 0,
        "width": "0",
        "height": "0",
        "head": "",
        "format": "<template>\n    <v-container>\n        <v-row>\n            <v-col cols=\"24\">\n                <v-file-input label=\"Sélectionner un fichier\" show-size v-model=\"uploadFile\">\n                </v-file-input>\n                <v-spacer></v-spacer>\n                <div style=\"display: flex; align-items: center;\">\n                    <v-btn :disabled=\"loading\" right @click=\"startUpload\">Envoyer le fichier</v-btn>\n                    <div v-if=\"loading\" style=\"margin-left: 20px;\">\n                        <v-progress-circular indeterminate color=\"primary\"></v-progress-circular>\n                    </div>\n                </div>\n            </v-col>\n        </v-row>\n    </v-container>\n</template>\n\n<script>\n    export default {\n        data() {\n            return {\n                uploadFile: null,\n                progress: 0,\n                chunkSize: 1024 * 800, // Size of each chunk (800 Ko in this example)\n                loading: false,\n            }\n        },\n        methods: {\n            startUpload() {\n                if (!this.uploadFile) {\n                    return;\n                } else {\n                    console.log(\"File selected\");\n                    console.log(this.uploadFile);\n                    if (!this.uploadFile) {\n                        console.warn('Aucun fichier sélectionné')\n                        return\n                    }\n                    let fileName = this.uploadFile.name;\n                    const totalChunks = Math.ceil(this.uploadFile.size / this.chunkSize);\n                    this.loading = true;\n                    this.readAndSendChunk(0, totalChunks, fileName);\n                }\n            },\n            readAndSendChunk(i, totalChunks, fileName) {\n                if (i >= totalChunks) {\n                    this.send({complete: true});\n                    return;\n                }\n                const blob = this.uploadFile.slice(i * this.chunkSize, (i + 1) * this.chunkSize);\n                const reader = new FileReader();\n                reader.readAsArrayBuffer(blob);\n                reader.onload = () => {\n                    this.send({topic:\"upload\", payload: reader.result, file:{name: fileName, size: blob.size, type: this.uploadFile.type,\n                    chunk: i, totalChunks: totalChunks } });\n                    this.readAndSendChunk(i + 1, totalChunks, fileName);\n                }\n                reader.onerror = (error) => {\n                    console.error('Error reading file:', error);\n                }\n                reader.onprogress = (data) => {\n                    this.progress = data.loaded + (i * this.chunkSize);\n                }\n            }\n        },\n        mounted() {\n            this.$socket.on(\"msg-input:\" + this.id, (msg) => {\n                if (msg.payload !== undefined) {\n                    this.items = msg.payload;\n                    this.loading = false;\n                }\n            });\n        },\n        unmounted() {\n        }\n    }\n</script>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 290,
        "y": 1940,
        "wires": [
            [
                "9dc3424b123bd04c"
            ]
        ]
    },
    {
        "id": "9dc3424b123bd04c",
        "type": "join",
        "z": "7c89a635677d6c3e",
        "name": "",
        "mode": "custom",
        "build": "buffer",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 450,
        "y": 1940,
        "wires": [
            [
                "5160d4552483e141",
                "cc31893de3ea1e48"
            ]
        ]
    },
    {
        "id": "5160d4552483e141",
        "type": "change",
        "z": "7c89a635677d6c3e",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "filename",
                "pt": "msg",
                "to": "\"C:\\\\Users\\\\username\\\\folder1\\\\folder2\\\\\" & msg.file.name",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 630,
        "y": 1940,
        "wires": [
            [
                "8eb76d737a6ad9a5"
            ]
        ]
    },
    {
        "id": "8eb76d737a6ad9a5",
        "type": "file",
        "z": "7c89a635677d6c3e",
        "name": "",
        "filename": "filename",
        "filenameType": "msg",
        "appendNewline": false,
        "createDir": false,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 800,
        "y": 1940,
        "wires": [
            [
                "c6211b356b869c25"
            ]
        ]
    },
    {
        "id": "c6211b356b869c25",
        "type": "file in",
        "z": "7c89a635677d6c3e",
        "name": "read file",
        "filename": "filename",
        "filenameType": "msg",
        "format": "",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "allProps": false,
        "x": 940,
        "y": 1940,
        "wires": [
            []
        ]
    },
    {
        "id": "8300798fe75f4399",
        "type": "ui-group",
        "name": "DOMOGUARD",
        "page": "444c60306fff8c5c",
        "width": "27",
        "height": "1",
        "order": -1,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "444c60306fff8c5c",
        "type": "ui-page",
        "name": "Produits finis",
        "ui": "f4139e7488bf5f07",
        "path": "/PF",
        "icon": "home",
        "layout": "grid",
        "theme": "684392cc1527bd04",
        "order": 2,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "f4139e7488bf5f07",
        "type": "ui-base",
        "name": "UI Name",
        "path": "/dashboard",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false
    },
    {
        "id": "684392cc1527bd04",
        "type": "ui-theme",
        "name": "Grey",
        "colors": {
            "surface": "#7d7d7d",
            "primary": "#0094ce",
            "bgPage": "#a3a3a3",
            "groupBg": "#dedede",
            "groupOutline": "#dedede"
        },
        "sizes": {
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    }
]

Hopefully this helps :slight_smile:

1 Like

i had the same problem.
You must check apiMaxLength in the settings.js:

For Dashboard 2, there is another setting:

add to the settings.js:

dashboard: {
    maxHttpBufferSize: 1e8 // size in bytes, example: 100 MB
}

and, if you have a reverse proxy, the max body size. In nginx:

3 Likes

This is great detail - I've asked @sumitshinde-84 to add a v-file-input example to the UI Template Examples page too.

Sumit - note the details above that'll be worth including :slight_smile:

2 Likes

Sure thing! I'll make sure to add the v-file-input example to the UI Template Examples page and include the details mentioned above. Thanks for the heads-up @joepavitt !

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.