✨ Implement importing and exporting of timetables
This commit is contained in:
6
package-lock.json
generated
6
package-lock.json
generated
@ -10,6 +10,7 @@
|
|||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dayjs": "^1.11.3",
|
"dayjs": "^1.11.3",
|
||||||
|
"downloadjs": "^1.4.7",
|
||||||
"lucide-vue-next": "^0.233.0",
|
"lucide-vue-next": "^0.233.0",
|
||||||
"swiper": "^9.3.2",
|
"swiper": "^9.3.2",
|
||||||
"vue": "^3.2.37",
|
"vue": "^3.2.37",
|
||||||
@ -3108,6 +3109,11 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/downloadjs": {
|
||||||
|
"version": "1.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz",
|
||||||
|
"integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q=="
|
||||||
|
},
|
||||||
"node_modules/ejs": {
|
"node_modules/ejs": {
|
||||||
"version": "3.1.9",
|
"version": "3.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dayjs": "^1.11.3",
|
"dayjs": "^1.11.3",
|
||||||
|
"downloadjs": "^1.4.7",
|
||||||
"lucide-vue-next": "^0.233.0",
|
"lucide-vue-next": "^0.233.0",
|
||||||
"swiper": "^9.3.2",
|
"swiper": "^9.3.2",
|
||||||
"vue": "^3.2.37",
|
"vue": "^3.2.37",
|
||||||
|
@ -8,9 +8,10 @@ import {
|
|||||||
AlertCircleIcon,
|
AlertCircleIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
} from "lucide-vue-next";
|
} from "lucide-vue-next";
|
||||||
|
import { DownloadIcon } from "lucide-vue-next";
|
||||||
|
|
||||||
defineProps(["timetable", "editable", "selected"]);
|
defineProps(["timetable", "editable", "selected"]);
|
||||||
defineEmits(["click", "edit", "delete", "copy"]);
|
defineEmits(["click", "edit", "delete", "copy", "export"]);
|
||||||
|
|
||||||
const deleteConfirm = ref(false);
|
const deleteConfirm = ref(false);
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ watch(deleteConfirm, (value) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
<DownloadIcon @click="$emit('export')" />
|
||||||
<Edit2Icon v-if="editable" @click="$emit('edit')" />
|
<Edit2Icon v-if="editable" @click="$emit('edit')" />
|
||||||
<CopyIcon @click="$emit('copy')" />
|
<CopyIcon @click="$emit('copy')" />
|
||||||
<TrashIcon
|
<TrashIcon
|
||||||
|
@ -29,7 +29,8 @@ export const strings = {
|
|||||||
text: {
|
text: {
|
||||||
filtering:
|
filtering:
|
||||||
"Select a class here so the correct timetable is used and only relevant substitutions are shown.",
|
"Select a class here so the correct timetable is used and only relevant substitutions are shown.",
|
||||||
createTimetable: "Create a new Timetable",
|
createTimetable: "Create Timetable",
|
||||||
|
importTimetable: "Import Timetable",
|
||||||
timetableGroups:
|
timetableGroups:
|
||||||
"A timetable group defines, which lesson should be displayed, and which substitution should be shown if there are multiple possibilities for a single lesson within one class.",
|
"A timetable group defines, which lesson should be displayed, and which substitution should be shown if there are multiple possibilities for a single lesson within one class.",
|
||||||
language: "Change the language of all texts in the application.",
|
language: "Change the language of all texts in the application.",
|
||||||
@ -145,7 +146,8 @@ export const strings = {
|
|||||||
text: {
|
text: {
|
||||||
filtering:
|
filtering:
|
||||||
"Wähle hier deine Klasse aus, damit du deinen Stundenplan angezeigt bekommst und du nur relevante Vertretungen siehst.",
|
"Wähle hier deine Klasse aus, damit du deinen Stundenplan angezeigt bekommst und du nur relevante Vertretungen siehst.",
|
||||||
createTimetable: "Neuen Stundenplan erstellen",
|
createTimetable: "Stundenplan erstellen",
|
||||||
|
importTimetable: "Stundenplan importieren",
|
||||||
timetableGroups:
|
timetableGroups:
|
||||||
"Stundenplan-Gruppen legen fest, welche Stundenplan-Daten du angezeigt bekommst, wenn es mehrere Möglichkeiten für eine Stunde gibt.",
|
"Stundenplan-Gruppen legen fest, welche Stundenplan-Daten du angezeigt bekommst, wenn es mehrere Möglichkeiten für eine Stunde gibt.",
|
||||||
language: "Ändere die Sprache aller Texte dieser Anwendung.",
|
language: "Ändere die Sprache aller Texte dieser Anwendung.",
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import TimetableCard from "@/components/settings/timetable-card.vue";
|
import TimetableCard from "@/components/settings/timetable-card.vue";
|
||||||
import { timetables, localTimetables, timetableId } from "@/store";
|
import { timetables, localTimetables, timetableId } from "@/store";
|
||||||
import { PlusIcon } from "lucide-vue-next";
|
import { PlusIcon, PaperclipIcon } from "lucide-vue-next";
|
||||||
import { toRaw } from "vue";
|
import { toRaw, ref } from "vue";
|
||||||
|
import download from "downloadjs";
|
||||||
|
|
||||||
function copyTimetable(timetable) {
|
function copyTimetable(timetable) {
|
||||||
const newTimetable = structuredClone(toRaw(timetable));
|
const newTimetable = structuredClone(toRaw(timetable));
|
||||||
@ -18,6 +19,33 @@ function createTimetable() {
|
|||||||
data: [],
|
data: [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fileInput = ref();
|
||||||
|
function importTimetable(event) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const contents = e.target.result;
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(contents);
|
||||||
|
if (!data.data) throw "Invalid data";
|
||||||
|
localTimetables.value.push(data);
|
||||||
|
} catch (e) {
|
||||||
|
alert("Import failed! Check your timetable file!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportTimetable(timetable) {
|
||||||
|
download(
|
||||||
|
JSON.stringify(timetable),
|
||||||
|
`timetable-${timetable.id}.json`,
|
||||||
|
"application/json"
|
||||||
|
);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -39,10 +67,22 @@ function createTimetable() {
|
|||||||
1
|
1
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
@export="exportTimetable(timetable)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="create" @click="createTimetable">
|
<div class="buttons">
|
||||||
<PlusIcon /> {{ $t("settings.text.createTimetable") }}
|
<div class="create" @click="createTimetable">
|
||||||
|
<PlusIcon /> {{ $t("settings.text.createTimetable") }}
|
||||||
|
</div>
|
||||||
|
<div class="import" @click="fileInput.click()">
|
||||||
|
<PaperclipIcon /> {{ $t("settings.text.importTimetable") }}
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
ref="fileInput"
|
||||||
|
style="display: none"
|
||||||
|
@change="importTimetable"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2>{{ $t("settings.heading.remoteTimetables") }}</h2>
|
<h2>{{ $t("settings.heading.remoteTimetables") }}</h2>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
@ -54,6 +94,7 @@ function createTimetable() {
|
|||||||
:editable="false"
|
:editable="false"
|
||||||
@click="timetableId = timetable.id"
|
@click="timetableId = timetable.id"
|
||||||
@copy="copyTimetable(timetable)"
|
@copy="copyTimetable(timetable)"
|
||||||
|
@export="exportTimetable(timetable)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -74,12 +115,22 @@ p {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.create {
|
.buttons {
|
||||||
display: flex;
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create,
|
||||||
|
.import {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
gap: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Reference in New Issue
Block a user