-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
348 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,327 @@ | ||
<script setup lang="ts"> | ||
import { ref, watch, onMounted } from 'vue'; | ||
import { csrfToken } from './api.js'; | ||
class WeekActivity { | ||
/** | ||
Výskyt aktivity v konkrétním týdnu výuky. | ||
*/ | ||
weekActivityId: number; // ID výskytu aktivity v konkrétním týdnu výuky | ||
weekNumber: number; // číslo týdne v semestru | ||
date: string; // datum výskytu aktivity (yyyy-MM-dd) | ||
} | ||
class ConcreteActivity { | ||
/** | ||
Concrete activity in schedule. | ||
*/ | ||
concreteActivityId: number; // ID rozvrhové aktivity | ||
template: string; // activityTemplate např. P, P1, C, C1 ... | ||
order: number; // pořadí concreteActivity v rámci activity template, dohromady s activityTemplate pak dává např. P/01, P/02, P1/01, C/01 ... | ||
subjectVersionId: number; // ID verze předmětu | ||
subjectVersionCompleteCode: string; // kód verze předmětu (včetně čísla předmětu) | ||
subjectId: number; // ID předmětu | ||
subjectAbbrev: string; // zkratka předmětu | ||
subjectTitle: string; // název předmětu | ||
educationTypeId: number; // ID typu výuky (přednáška, cvičení, konzultace) | ||
educationTypeAbbrev: string; // zkratka typu výuky | ||
educationTypeTitle: string; // název typu výuky | ||
semesterId: number; // ID semestru | ||
semesterTypeId: number; // ID typu semestru | ||
semesterTypeAbbrev: string; // zkratka typy semestru | ||
semesterTypeTitle: string; // název typu semestru | ||
academicYearId: number; // ID akademického roku | ||
academicYearTitle: string; // název akademického roku | ||
tutorialCentreId: number; // ID konzultačního střediska | ||
tutorialCentreAbbrev: string; // zkratka konzultačního střediska | ||
tutorialCentreTitle: string; // název konzultačního střediska | ||
educationWeekId: number; // ID typu týdne výuky (každý, lichý, sudý, nepravidelně) | ||
educationWeekTitle: string; // název typu týdne výuky | ||
beginScheduleWindowId: number; // ID počáteční výukové jednotky (rozvrhového okna) | ||
activityDuration: number; // délka výuky - počet výukových jednotek následujících po sobě | ||
beginTime: string; // ($date-time) čas začátku výuky (HH:mm:ss) | ||
endTime: string; // ($date-time) čas konce výuky (HH:mm:ss) | ||
weekDayId: number; // ID dne v týdnu | ||
weekDayAbbrev: string; // zkratka dne v týdnu | ||
weekDayTitle: string; // název dne v týdnu | ||
weekActivities: WeekActivity[]; // seznam výskytů aktivity v konkrétních týdnech výuky (využití při nepravidelné výuce), obsahuje: weekActivityId (Integer), weekNumber (Integer), date (Date) | ||
roomIds: number[]; // seznam ID místností | ||
teacherIds: number[]; // seznam ID vyučujících (osob) | ||
studyGroupIds: number[]; // seznam ID studijních skupin (má význam při rozvrhování na studijní skupiny) | ||
// Default values are defined here, since INBUS API sometimes does not provide there values | ||
// and Python need default values at the end of the definition | ||
roomFullcodes = ''; // optimalizační předpočítávaný atribut z vazby na místnosti | ||
// Emptines may be caused by grouping of activities with other activities. | ||
// Typical situation is a lecture shed by different versions of a subject. | ||
studyGroupCodes = ''; // optimalizační předpočítávaný atribut z vazby na studijní skupiny | ||
teacherFullNames = ''; // optimalizační předpočítávaný atribut z vazby na vyučující | ||
teacherLogins = ''; // optimalizační předpočítávaný atribut z vazby na vyučující | ||
teacherShortNames = ''; // optimalizační předpočítávaný atribut z vazby na vyučující | ||
} | ||
let subject_inbus_selected = ref<InbusSubjectVersion | null>(null); | ||
let subject_kelvin_selected = ref(null); | ||
let semester = ref(null); | ||
let busy = ref<boolean>(false); | ||
let semesters = ref(null); | ||
let semesters_loading = ref<boolean>(true); | ||
let inbus_and_kelvin_subjects_loading = ref<boolean>(true); | ||
let inbus_schedule_loaded = ref<boolean>(false); | ||
let subjects_inbus: InbusSubjectVersion[] | null = null; | ||
let subjects_inbus_filtered: InbusSubjectVersion[] | null = null; | ||
let subjects_kelvin: KelvinSubject[] | null = null; | ||
let subject_inbus_schedule = ref<ConcreteActivity[] | null>(null); | ||
let classes_to_import = ref([]); | ||
let result = ref(null); | ||
let canImport = ref(classes_to_import.value.length && !busy.value); | ||
function assembleRequest(url: string): RequestInfo { | ||
const headers: Headers = new Headers(); | ||
headers.set('Content-Type', 'application/json'); | ||
headers.set('Accept', 'application/json'); | ||
const request: RequestInfo = new Request(url, { | ||
method: 'GET', | ||
headers: headers | ||
}); | ||
return request; | ||
} | ||
function svcc2num(svcc: string): number { | ||
const [dept_code, version]: string[] = svcc.split('/'); | ||
const [dept, code]: string[] = dept_code.split('-'); | ||
const svcc_str = dept + code + version; | ||
const svcc_num = Number(svcc_str); | ||
return svcc_num; | ||
} | ||
class InbusGuarantee { | ||
personId: number; | ||
login: string; | ||
fullName: string; | ||
} | ||
class InbusSubject { | ||
subjectId: number; | ||
code: string; | ||
abbrev: string; | ||
title: string; | ||
guarantee: InbusGuarantee; | ||
} | ||
class InbusSubjectVersion { | ||
subjectVersionId: number; | ||
subject: InbusSubject; | ||
subjectVersionCompleteCode: string; | ||
guarantee: InbusGuarantee; | ||
} | ||
class KelvinSubject { | ||
name: string; | ||
abbr: string; | ||
} | ||
async function loadInbusAndKelvinSubjects() { | ||
const res1 = await fetch('/api/inbus/subject_versions', {}); | ||
const res2 = await fetch('/api/subjects/all', {}); | ||
subjects_inbus = await res1.json(); | ||
const subjects_kelvin_resp = await res2.json(); | ||
subjects_kelvin = subjects_kelvin_resp.subjects; | ||
subjects_kelvin.sort((a, b) => { | ||
const name_a = a.name.toUpperCase(); | ||
const name_b = b.name.toUpperCase(); | ||
if (name_a < name_b) { | ||
return -1; | ||
} | ||
if (name_a > name_b) { | ||
return 1; | ||
} | ||
return 0; | ||
}); | ||
const subject_kelvin_abbrs = subjects_kelvin.map((s) => s.abbr); | ||
subjects_inbus_filtered = subjects_inbus.filter((subject_inbus) => | ||
subject_kelvin_abbrs.includes(subject_inbus.subject.abbrev) | ||
); | ||
subjects_inbus_filtered = subjects_inbus_filtered.sort( | ||
(a, b) => svcc2num(a.subjectVersionCompleteCode) - svcc2num(b.subjectVersionCompleteCode) | ||
); | ||
inbus_and_kelvin_subjects_loading.value = false; | ||
} | ||
class Semester { | ||
pk: number; | ||
year: number; | ||
winter: boolean; | ||
} | ||
function parseSemesters(semesters_data: Semester[]) { | ||
semesters.value = semesters_data.map((sm) => ({ | ||
pk: sm.pk, | ||
year: sm.year, | ||
winter: sm.winter, | ||
display: String(sm.year) + (sm.winter ? 'W' : 'S') | ||
})); | ||
semesters_loading.value = false; | ||
} | ||
async function loadSemesters() { | ||
const request = assembleRequest('/api/semesters'); | ||
const res = await fetch(request, {}); | ||
const semesters_data = await res.json(); | ||
parseSemesters(semesters_data['semesters']); | ||
} | ||
async function loadScheduleForSubjectVersionId(subject_inbus: InbusSubjectVersion) { | ||
const request = assembleRequest( | ||
'/api/inbus/schedule/subject/version/' + subject_inbus.subjectVersionId | ||
); | ||
let res = await fetch(request, {}); | ||
subject_inbus_schedule.value = await res.json(); | ||
inbus_schedule_loaded.value = true; | ||
} | ||
async function importActivities() { | ||
busy.value = true; | ||
const req = { | ||
semester_id: semester.value, | ||
subject: subject_kelvin_selected.value, | ||
activities: classes_to_import.value | ||
}; | ||
//console.log(req); | ||
const res = await fetch('/api/import/activities', { | ||
method: 'POST', | ||
headers: { | ||
Accept: 'application/json', | ||
'Content-Type': 'application/json', | ||
'X-CSRFToken': csrfToken() | ||
}, | ||
body: JSON.stringify(req) | ||
}); | ||
result.value = await res.json(); | ||
busy.value = false; | ||
} | ||
onMounted(() => { | ||
watch(subject_inbus_selected, (newValue, oldValue) => { | ||
//console.log('subject_inbus_selected', 'newvalue: ', newValue, 'oldValue: ', oldValue) | ||
inbus_schedule_loaded.value = false; | ||
loadScheduleForSubjectVersionId(newValue); | ||
}); | ||
watch(classes_to_import, (newValue, oldValue) => { | ||
Check failure on line 234 in frontend/src/AppInbusImport.vue GitHub Actions / test_frontend
|
||
canImport.value = classes_to_import.value.length && !busy.value; | ||
}); | ||
loadSemesters(); | ||
loadInbusAndKelvinSubjects(); | ||
}); | ||
</script> | ||
|
||
<template> | ||
<select v-if="!semesters_loading" v-model="semester"> | ||
<option v-for="item in semesters" :key="item.pk" :value="item.pk">{{ item.display }}</option> | ||
</select> | ||
|
||
<select v-if="!inbus_and_kelvin_subjects_loading" v-model="subject_kelvin_selected"> | ||
<option v-for="item in subjects_kelvin" :key="item.abbr" :value="item"> | ||
{{ item.abbr }} - {{ item.name }} | ||
</option> | ||
</select> | ||
|
||
<select v-if="!inbus_and_kelvin_subjects_loading" v-model="subject_inbus_selected"> | ||
<option v-for="item in subjects_inbus_filtered" :key="item.subjectVersionId" :value="item"> | ||
{{ item.subjectVersionCompleteCode }} - {{ item.subject.abbrev }} - {{ item.subject.title }} | ||
</option> | ||
</select> | ||
|
||
<table v-if="inbus_schedule_loaded" class="table table-hover table-stripped table-sm"> | ||
<tbody> | ||
<tr v-for="ca in subject_inbus_schedule" :key="ca.concreteActivityId"> | ||
<td> | ||
<label> | ||
<input | ||
v-model="classes_to_import" | ||
type="checkbox" | ||
:value="ca.concreteActivityId" | ||
name="classesToImport" | ||
/> | ||
{{ ca.educationTypeAbbrev }} | ||
</label> | ||
</td> | ||
|
||
<td>{{ ca.educationTypeAbbrev }}/{{ ca.order }}, {{ ca.subjectVersionCompleteCode }}</td> | ||
|
||
<td> | ||
{{ ca.teacherFullNames }} | ||
</td> | ||
|
||
<td> | ||
{{ ca.weekDayAbbrev }} | ||
</td> | ||
|
||
<td> | ||
{{ ca.beginTime }} | ||
</td> | ||
|
||
<td> | ||
{{ ca.endTime }} | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
<button | ||
class="btn" | ||
:class="{ 'btn-success': canImport, 'btn-danger': !canImport }" | ||
:disabled="!canImport" | ||
@click="importActivities" | ||
> | ||
<span v-if="busy">Importing...</span> | ||
<span v-else>Import</span> | ||
</button> | ||
|
||
<div> | ||
<div v-if="result"> | ||
<div v-if="result.error" class="alert alert-danger" role="alert"> | ||
{{ result.error }} | ||
</div> | ||
<div v-else> | ||
<table class="table table-sm table-hover table-striped"> | ||
<tbody> | ||
<tr v-for="item in result.users" :key="item.login"> | ||
<td>{{ item.login }}</td> | ||
<td>{{ item.firstname }}</td> | ||
<td>{{ item.lastname }}</td> | ||
<td>{{ item.created }}</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<style scoped></style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{% extends 'web/layout.html' %} | ||
|
||
{% block fullcontent %} | ||
<kelvin-import-inbus></kelvin-import-inbus> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters