Implement importing and exporting of timetables

This commit is contained in:
2023-06-19 23:58:17 +02:00
parent 9afae9b2cc
commit cd6801d625
5 changed files with 71 additions and 9 deletions

6
package-lock.json generated
View File

@ -10,6 +10,7 @@
"license": "GPL-3.0-or-later",
"dependencies": {
"dayjs": "^1.11.3",
"downloadjs": "^1.4.7",
"lucide-vue-next": "^0.233.0",
"swiper": "^9.3.2",
"vue": "^3.2.37",
@ -3108,6 +3109,11 @@
"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": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",

View File

@ -11,6 +11,7 @@
},
"dependencies": {
"dayjs": "^1.11.3",
"downloadjs": "^1.4.7",
"lucide-vue-next": "^0.233.0",
"swiper": "^9.3.2",
"vue": "^3.2.37",

View File

@ -8,9 +8,10 @@ import {
AlertCircleIcon,
CopyIcon,
} from "lucide-vue-next";
import { DownloadIcon } from "lucide-vue-next";
defineProps(["timetable", "editable", "selected"]);
defineEmits(["click", "edit", "delete", "copy"]);
defineEmits(["click", "edit", "delete", "copy", "export"]);
const deleteConfirm = ref(false);
@ -36,6 +37,7 @@ watch(deleteConfirm, (value) => {
</div>
<div class="buttons">
<DownloadIcon @click="$emit('export')" />
<Edit2Icon v-if="editable" @click="$emit('edit')" />
<CopyIcon @click="$emit('copy')" />
<TrashIcon

View File

@ -29,7 +29,8 @@ export const strings = {
text: {
filtering:
"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:
"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.",
@ -145,7 +146,8 @@ export const strings = {
text: {
filtering:
"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:
"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.",

View File

@ -1,8 +1,9 @@
<script setup>
import TimetableCard from "@/components/settings/timetable-card.vue";
import { timetables, localTimetables, timetableId } from "@/store";
import { PlusIcon } from "lucide-vue-next";
import { toRaw } from "vue";
import { PlusIcon, PaperclipIcon } from "lucide-vue-next";
import { toRaw, ref } from "vue";
import download from "downloadjs";
function copyTimetable(timetable) {
const newTimetable = structuredClone(toRaw(timetable));
@ -18,6 +19,33 @@ function createTimetable() {
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>
<template>
@ -39,10 +67,22 @@ function createTimetable() {
1
)
"
@export="exportTimetable(timetable)"
/>
</div>
<div class="create" @click="createTimetable">
<PlusIcon /> {{ $t("settings.text.createTimetable") }}
<div class="buttons">
<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>
<h2>{{ $t("settings.heading.remoteTimetables") }}</h2>
<div class="list">
@ -54,6 +94,7 @@ function createTimetable() {
:editable="false"
@click="timetableId = timetable.id"
@copy="copyTimetable(timetable)"
@export="exportTimetable(timetable)"
/>
</div>
</div>
@ -74,12 +115,22 @@ p {
gap: 8px;
}
.create {
display: flex;
.buttons {
display: grid;
grid-template-columns: 1fr 1fr;
justify-content: center;
align-items: center;
margin-top: 5px;
user-select: none;
}
.create,
.import {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
gap: 5px;
cursor: pointer;
}
</style>