mirror of
https://github.com/filebrowser/filebrowser.git
synced 2026-01-23 02:35:10 +00:00
fix: added column separator select (comma, semicolon and both) in CSV viewer (#5604)
Co-authored-by: Henrique Dias <mail@hacdias.com>
This commit is contained in:
parent
f029c3005e
commit
204a3f0eea
3 changed files with 64 additions and 7 deletions
|
|
@ -25,9 +25,29 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div v-if="data.rows.length > 100" class="csv-info">
|
<div class="csv-footer">
|
||||||
<i class="material-icons">info</i>
|
<div class="csv-info" v-if="data.rows.length > 100">
|
||||||
<span>Showing {{ data.rows.length }} rows</span>
|
<i class="material-icons">info</i>
|
||||||
|
<span>Showing {{ data.rows.length }} rows</span>
|
||||||
|
</div>
|
||||||
|
<div class="column-separator">
|
||||||
|
<label for="columnSeparator">Column Separator</label>
|
||||||
|
<select
|
||||||
|
id="columnSeparator"
|
||||||
|
class="input input--block"
|
||||||
|
v-model="columnSeparator"
|
||||||
|
>
|
||||||
|
<option :value="[',']">
|
||||||
|
{{ $t("available_csv_separators.comma") }}
|
||||||
|
</option>
|
||||||
|
<option :value="[';']">
|
||||||
|
{{ $t("available_csv_separators.semicolon") }}
|
||||||
|
</option>
|
||||||
|
<option :value="[',', ';']">
|
||||||
|
{{ $t("available_csv_separators.both") }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -35,7 +55,7 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { parseCSV, type CsvData } from "@/utils/csv";
|
import { parseCSV, type CsvData } from "@/utils/csv";
|
||||||
import { computed } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
content: string;
|
content: string;
|
||||||
|
|
@ -46,9 +66,11 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
error: "",
|
error: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const columnSeparator = ref([","]);
|
||||||
|
|
||||||
const data = computed<CsvData>(() => {
|
const data = computed<CsvData>(() => {
|
||||||
try {
|
try {
|
||||||
return parseCSV(props.content);
|
return parseCSV(props.content, columnSeparator.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to parse CSV:", e);
|
console.error("Failed to parse CSV:", e);
|
||||||
return { headers: [], rows: [] };
|
return { headers: [], rows: [] };
|
||||||
|
|
@ -181,6 +203,18 @@ const displayError = computed(() => {
|
||||||
transition: background-color 0.15s ease;
|
transition: background-color 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.csv-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-footer > :only-child {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.csv-info {
|
.csv-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -194,6 +228,21 @@ const displayError = computed(() => {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column-separator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-separator > label {
|
||||||
|
font-size: small;
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-separator > select {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.csv-info i {
|
.csv-info i {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
|
|
|
||||||
|
|
@ -272,5 +272,10 @@
|
||||||
"minutes": "Minutes",
|
"minutes": "Minutes",
|
||||||
"seconds": "Seconds",
|
"seconds": "Seconds",
|
||||||
"unit": "Time Unit"
|
"unit": "Time Unit"
|
||||||
|
},
|
||||||
|
"available_csv_separators": {
|
||||||
|
"comma": "Comma (,)",
|
||||||
|
"semicolon": "Semicolon (;)",
|
||||||
|
"both": "Both (,) and (;)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@ export interface CsvData {
|
||||||
* Parse CSV content into headers and rows
|
* Parse CSV content into headers and rows
|
||||||
* Supports quoted fields and handles commas within quotes
|
* Supports quoted fields and handles commas within quotes
|
||||||
*/
|
*/
|
||||||
export function parseCSV(content: string): CsvData {
|
export function parseCSV(
|
||||||
|
content: string,
|
||||||
|
columnSeparator: Array<string>
|
||||||
|
): CsvData {
|
||||||
if (!content || content.trim().length === 0) {
|
if (!content || content.trim().length === 0) {
|
||||||
return { headers: [], rows: [] };
|
return { headers: [], rows: [] };
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +38,7 @@ export function parseCSV(content: string): CsvData {
|
||||||
// Toggle quote state
|
// Toggle quote state
|
||||||
inQuotes = !inQuotes;
|
inQuotes = !inQuotes;
|
||||||
}
|
}
|
||||||
} else if (char === "," && !inQuotes) {
|
} else if (columnSeparator.includes(char) && !inQuotes) {
|
||||||
// Field separator
|
// Field separator
|
||||||
row.push(currentField);
|
row.push(currentField);
|
||||||
currentField = "";
|
currentField = "";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue