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", "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",

View File

@ -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",

View File

@ -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

View File

@ -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.",

View File

@ -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>