Skip to content
This repository was archived by the owner on Feb 21, 2025. It is now read-only.

Commit a47d3e1

Browse files
committed
subject editor
1 parent 8588815 commit a47d3e1

26 files changed

+763
-892
lines changed

prisma/schema.prisma

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -179,27 +179,15 @@ model Subject {
179179
domainId Int?
180180
parentSubjects Subject[] @relation("SubjectRelation")
181181
childSubjects Subject[] @relation("SubjectRelation")
182-
lectures SubjectLecture[]
183-
}
184-
185-
model SubjectLecture {
186-
subjectId Int
187-
lectureId Int
188-
x Int @default(0)
189-
y Int @default(0)
190-
191-
subject Subject @relation(fields: [subjectId], references: [id], onDelete: Cascade)
192-
lecture Lecture @relation(fields: [lectureId], references: [id], onDelete: Cascade)
193-
194-
@@id([subjectId, lectureId])
182+
lectures Lecture[]
195183
}
196184

197185
model Lecture {
198186
id Int @id @default(autoincrement())
199187
graph Graph @relation(fields: [graphId], references: [id], onDelete: Cascade)
200188
graphId Int
201189
name String @default("")
202-
subjects SubjectLecture[]
190+
subjects Subject[]
203191
}
204192

205193
model GraphLink {

src/lib/components/Dropdown.svelte

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
let header: HTMLButtonElement
5555
let query: string = ''
5656
57-
$: console.log(options)
5857
$: choice = options.find(option => option.value === value)
5958
$: options = options.sort((a, b) => {
6059
if (a.validation.severity === Severity.error) return 1
@@ -73,11 +72,11 @@
7372

7473

7574
<div class="dropdown" bind:this={dropdown}>
76-
<div
77-
class="wrapper"
75+
<div
76+
class="wrapper"
7877
class:visible
79-
use:losefocus={() => visibility(false)}
80-
use:clickoutside={() => visibility(false)}
78+
use:losefocus={() => visibility(false)}
79+
use:clickoutside={() => visibility(false)}
8180
bind:this={wrapper}
8281
>
8382

@@ -176,7 +175,7 @@
176175
width: 100%
177176
height: auto
178177
overflow: hidden
179-
178+
180179
&.visible .header
181180
border-color: $tudelft-blue
182181
border-bottom-color: $gray
@@ -186,7 +185,7 @@
186185
&::after
187186
translate: 0 80%
188187
rotate: -135deg
189-
188+
190189
.header
191190
position: relative
192191
display: block

src/lib/components/Validation.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
3030
$: show_error_icon = has_errors
3131
$: error_disabled = !compact && one_error && !has_warnings
32-
$: error_msg = compact ? '' : warning_disabled ? data.errors[0].short : data.errors.length
32+
$: error_msg = compact ? '' : error_disabled ? data.errors[0].short : data.errors.length
3333
3434
$: one_warning = data.warnings.length === 1
3535
$: has_warnings = data.warnings.length > 0
@@ -43,7 +43,7 @@
4343
: compact ? compact_tooltip
4444
: errors_visible ? 'Hide errors'
4545
: 'Show errors'
46-
46+
4747
$: warning_tooltip = warning_disabled ? ''
4848
: compact ? compact_tooltip
4949
: warnings_visible ? 'Hide warnings'
@@ -224,7 +224,7 @@
224224
225225
&:not(:disabled)
226226
cursor: pointer
227-
227+
228228
img
229229
width: $input-icon-size
230230
height: $input-icon-size
@@ -243,7 +243,7 @@
243243
border-radius: $border-radius
244244
245245
box-shadow: $shadow
246-
246+
247247
.item
248248
display: grid
249249
grid-template: "icon short show" auto "icon long long" auto / $input-icon-size auto 1fr

src/lib/scripts/controllers/CourseController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,10 +330,10 @@ class CourseController {
330330
* @throws `APIError` if the API call fails
331331
*/
332332

333-
async getGraphOptions(): Promise<DropdownOption<GraphController>[]> {
333+
async getGraphOptions(): Promise<DropdownOption<number>[]> {
334334
const graphs = await this.getGraphs()
335335
return graphs.map(graph => ({
336-
value: graph,
336+
value: graph.id,
337337
label: graph.name,
338338
validation: ValidationData.success()
339339
}))

src/lib/scripts/controllers/FieldControllers.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import type {
1717
SerializedGraph,
1818
SerializedDomain,
1919
SerializedSubject,
20-
SerializedLecture
20+
SerializedLecture,
21+
DropdownOption
2122
} from '$scripts/types'
2223

2324
// Exports
@@ -106,7 +107,7 @@ abstract class FieldController {
106107
abstract unassignParent(parent: FieldController, mirror?: boolean): void
107108
abstract unassignChild(child: FieldController, mirror?: boolean): void
108109

109-
abstract matchesQuery(query: string): Promise<boolean>
110+
abstract matchesQuery(query: string): boolean
110111
}
111112

112113
class DomainController extends FieldController {
@@ -407,11 +408,11 @@ class DomainController extends FieldController {
407408
*/
408409

409410
static revive(cache: ControllerCache, data: SerializedDomain): DomainController {
410-
const existing = cache.find(DomainController, data.id)
411-
if (existing) {
412-
if (!existing.represents(data)) {
411+
const domain = cache.find(DomainController, data.id)
412+
if (domain) {
413+
if (!domain.represents(data))
413414
throw new Error(`DomainError: Attempted to revive Domain with ID ${data.id}, but server data is out of sync with cache`)
414-
}
415+
return domain
415416
}
416417

417418
return new DomainController(cache, data.id, data.x, data.y, data.name, data.style, data.graph, data.parents, data.children, data.subjects)
@@ -866,7 +867,7 @@ class DomainController extends FieldController {
866867
* @returns Whether the domain matches the query
867868
*/
868869

869-
async matchesQuery(query: string): Promise<boolean> {
870+
matchesQuery(query: string): boolean {
870871
const query_lower = query.toLowerCase()
871872
const name = this.trimmed_name.toLowerCase()
872873
const style = this.style ? styles[this.style].display_name.toLowerCase() : ''
@@ -966,7 +967,7 @@ class SubjectController extends FieldController {
966967

967968
// Call API to get the graph data
968969
this._pending_graph = this.cache
969-
.fetch(`/api/subject/${this.id}/course`, { method: 'GET' })
970+
.fetch(`/api/subject/${this.id}/graph`, { method: 'GET' })
970971
.then(
971972
async response => {
972973
const data = await response.json() as SerializedGraph
@@ -976,10 +977,10 @@ class SubjectController extends FieldController {
976977
},
977978
error => {
978979
this._pending_graph = undefined
979-
throw new Error(`APIError (/api/subject/${this.id}/course GET): ${error}`)
980+
throw new Error(`APIError (/api/subject/${this.id}/graph GET): ${error}`)
980981
}
981982
)
982-
983+
983984
return await this._pending_graph
984985
}
985986

@@ -1025,6 +1026,17 @@ class SubjectController extends FieldController {
10251026
return await this._pending_domain
10261027
}
10271028

1029+
async getDomainOptions(): Promise<DropdownOption<number>[]> {
1030+
const domains = await this.getGraph()
1031+
.then(graph => graph.getDomains())
1032+
1033+
return domains.map(domain => ({
1034+
value: domain.id,
1035+
label: domain.name,
1036+
validation: ValidationData.success()
1037+
}))
1038+
}
1039+
10281040
/**
10291041
* Get the lectures assigned to this subject, from the cache or the API
10301042
* @returns The lectures assigned to this subject
@@ -1109,7 +1121,7 @@ class SubjectController extends FieldController {
11091121
throw new Error(`APIError (/api/subject/${this.id}/parents GET): ${error}`)
11101122
}
11111123
)
1112-
1124+
11131125
return await this._pending_parents as SubjectController[]
11141126
}
11151127

@@ -1153,7 +1165,7 @@ class SubjectController extends FieldController {
11531165
throw new Error(`APIError (/api/subject/${this.id}/children GET): ${error}`)
11541166
}
11551167
)
1156-
1168+
11571169
return await this._pending_children as SubjectController[]
11581170
}
11591171

@@ -1208,11 +1220,11 @@ class SubjectController extends FieldController {
12081220
*/
12091221

12101222
static revive(cache: ControllerCache, data: SerializedSubject): SubjectController {
1211-
const existing = cache.find(SubjectController, data.id)
1212-
if (existing) {
1213-
if (!existing.represents(data))
1223+
const subject = cache.find(SubjectController, data.id)
1224+
if (subject) {
1225+
if (!subject.represents(data))
12141226
throw new Error(`SubjectError: Attempted to revive Subject with ID ${data.id}, but server data is out of sync with cache`)
1215-
return existing
1227+
return subject
12161228
}
12171229

12181230
return new SubjectController(cache, data.id, data.x, data.y, data.name, data.domain, data.graph, data.parents, data.children, data.lectures)
@@ -1659,11 +1671,16 @@ class SubjectController extends FieldController {
16591671
* @returns Whether the subject matches the query
16601672
*/
16611673

1662-
async matchesQuery(query: string): Promise<boolean> {
1674+
matchesQuery(query: string): boolean {
16631675
const query_lower = query.toLowerCase()
1664-
const name = this.trimmed_name.toLowerCase()
1665-
const domain = await this.getDomain().then(domain => domain?.name.toLowerCase() || '')
1676+
const name_lower = this.trimmed_name.toLowerCase()
1677+
if (this._domain_id === null) {
1678+
return name.includes(query_lower)
1679+
}
1680+
1681+
const domain = this.cache.find(DomainController, this._domain_id)
1682+
const domain_lower = domain ? domain.trimmed_name.toLowerCase() : ''
16661683

1667-
return name.includes(query_lower) || domain.includes(query_lower)
1684+
return name_lower.includes(query_lower) || domain_lower.includes(query_lower)
16681685
}
16691686
}

src/lib/scripts/controllers/GraphController.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ export { GraphController, SortOption }
3333
enum SortOption {
3434
ascending = 0b1000000000,
3535
descending = 0b0100000000,
36-
relations = 0b0010000000,
37-
subjects = 0b0001000000,
38-
domains = 0b0000100000,
36+
relation = 0b0010000000,
37+
subject = 0b0001000000,
38+
domain = 0b0000100000,
3939
index = 0b0000010000,
4040
name = 0b0000001000,
4141
style = 0b0000000100,
42-
parents = 0b0000000010,
43-
children = 0b0000000001
42+
parent = 0b0000000010,
43+
child = 0b0000000001
4444
}
4545

4646

@@ -328,7 +328,7 @@ class GraphController {
328328
lectures.map(async lecture => ({
329329
value: lecture,
330330
label: lecture.trimmed_name,
331-
validation: await lecture.validate()
331+
validation: ValidationData.success()
332332
}))
333333
)
334334
}
@@ -750,13 +750,13 @@ class GraphController {
750750
const [
751751
domains,
752752
domain_relations,
753-
subjects,
753+
subjects,
754754
subject_relations,
755755
lectures
756756
] = await Promise.all([
757-
this.getDomains(),
757+
this.getDomains(),
758758
this.getDomainRelations(),
759-
this.getSubjects(),
759+
this.getSubjects(),
760760
this.getSubjectRelations(),
761761
this.getLectures()
762762
])
@@ -1043,23 +1043,23 @@ class GraphController {
10431043
throw new Error('GraphError: Invalid sort option')
10441044
}
10451045

1046-
if (option & SortOption.relations) {
1047-
if (option & SortOption.domains) {
1046+
if (option & SortOption.relation) {
1047+
if (option & SortOption.domain) {
10481048
if (option & SortOption.index) {
10491049
// Sort domain relations by index
1050-
} else if (option & SortOption.parents) {
1050+
} else if (option & SortOption.parent) {
10511051
// Sort domain relations by parents
1052-
} else if (option & SortOption.children) {
1052+
} else if (option & SortOption.child) {
10531053
// Sort domain relations by children
10541054
} else {
10551055
throw new Error('GraphError: Invalid sort option')
10561056
}
1057-
} else if (option & SortOption.subjects) {
1057+
} else if (option & SortOption.subject) {
10581058
if (option & SortOption.index) {
10591059
// Sort subject relations by index
1060-
} else if (option & SortOption.parents) {
1060+
} else if (option & SortOption.parent) {
10611061
// Sort subject relations by parents
1062-
} else if (option & SortOption.children) {
1062+
} else if (option & SortOption.child) {
10631063
// Sort subject relations by children
10641064
} else {
10651065
throw new Error('GraphError: Invalid sort option')
@@ -1068,7 +1068,7 @@ class GraphController {
10681068
throw new Error('GraphError: Invalid sort option')
10691069
}
10701070
} else {
1071-
if (option & SortOption.subjects) {
1071+
if (option & SortOption.subject) {
10721072
const subjects = await this.getSubjects()
10731073
let comparable: { value: string | number, subject: SubjectController }[]
10741074

@@ -1091,7 +1091,7 @@ class GraphController {
10911091
}
10921092

10931093
// Sort subjects by domain
1094-
else if (option & SortOption.domains) {
1094+
else if (option & SortOption.domain) {
10951095
comparable = await Promise.all(
10961096
subjects.map(async subject => ({
10971097
value: await subject.getDomain().then(domain => domain?.trimmed_name || ''),
@@ -1114,7 +1114,7 @@ class GraphController {
11141114
if (descending) comparable.reverse()
11151115
this._subjects = comparable.map(pair => pair.subject)
11161116

1117-
} else if (option & SortOption.domains) {
1117+
} else if (option & SortOption.domain) {
11181118
const domains = await this.getDomains()
11191119
let comparable: { value: string | number, domain: DomainController }[]
11201120

0 commit comments

Comments
 (0)