@windward/core 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/components/Content/Blocks/BlockQuote.vue +51 -47
- package/components/Content/Blocks/GenerateAIQuestionButton.vue +151 -37
- package/components/Content/Blocks/OpenResponse.vue +11 -3
- package/components/Navigation/Items/UserUploadNav.vue +31 -20
- package/components/utils/glossary/CourseGlossary.vue +13 -8
- package/i18n/en-US/components/content/blocks/generate_questions.ts +26 -11
- package/i18n/en-US/shared/content_blocks.ts +1 -1
- package/i18n/en-US/shared/settings.ts +1 -1
- package/i18n/es-ES/components/content/blocks/generate_questions.ts +11 -1
- package/i18n/es-ES/shared/content_blocks.ts +1 -1
- package/i18n/es-ES/shared/settings.ts +1 -2
- package/i18n/sv-SE/components/content/blocks/generate_questions.ts +11 -1
- package/i18n/sv-SE/shared/content_blocks.ts +1 -1
- package/i18n/sv-SE/shared/settings.ts +1 -1
- package/package.json +1 -1
- package/pages/glossary.vue +30 -1
- package/pages/userUpload.vue +69 -46
- package/plugin.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -34,7 +34,9 @@
|
|
|
34
34
|
<v-row>
|
|
35
35
|
<v-col cols="12">
|
|
36
36
|
<p>
|
|
37
|
-
{{
|
|
37
|
+
<span>{{
|
|
38
|
+
citation && source ? citation + ',' : citation
|
|
39
|
+
}}</span>
|
|
38
40
|
<span :class="sourceClass">{{ source }}</span>
|
|
39
41
|
</p>
|
|
40
42
|
</v-col>
|
|
@@ -51,38 +53,10 @@ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
|
|
|
51
53
|
|
|
52
54
|
export default {
|
|
53
55
|
name: 'ContentBlockTab',
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (_.isEmpty(this.block)) {
|
|
57
|
-
this.block = {}
|
|
58
|
-
}
|
|
59
|
-
if (_.isEmpty(this.block.metadata)) {
|
|
60
|
-
this.block.metadata = {}
|
|
61
|
-
}
|
|
62
|
-
if (_.isEmpty(this.block.metadata.config)) {
|
|
63
|
-
this.block.metadata.config = {}
|
|
64
|
-
}
|
|
65
|
-
if (_.isEmpty(this.block.metadata.config.title)) {
|
|
66
|
-
this.block.metadata.config.title = ''
|
|
67
|
-
}
|
|
68
|
-
if (_.isEmpty(this.block.metadata.config.instructions)) {
|
|
69
|
-
this.block.metadata.config.instructions = ''
|
|
70
|
-
}
|
|
71
|
-
if (_.isEmpty(this.block.metadata.config.block_quote)) {
|
|
72
|
-
this.block.metadata.config.block_quote = {
|
|
73
|
-
quote: '',
|
|
74
|
-
author: '',
|
|
75
|
-
author_title: '',
|
|
76
|
-
organization: '',
|
|
77
|
-
source_title: '',
|
|
78
|
-
source_type: '',
|
|
79
|
-
source_url: '',
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
this.block.body = this.$t(
|
|
83
|
-
'windward.core.components.content.blocks.block_quote.body'
|
|
84
|
-
)
|
|
56
|
+
components: {
|
|
57
|
+
TextViewer,
|
|
85
58
|
},
|
|
59
|
+
extends: BaseContentBlock,
|
|
86
60
|
data() {
|
|
87
61
|
return {}
|
|
88
62
|
},
|
|
@@ -101,7 +75,6 @@ export default {
|
|
|
101
75
|
parts.push(value)
|
|
102
76
|
}
|
|
103
77
|
}
|
|
104
|
-
|
|
105
78
|
// If there were parts to return then prepend with a mdash
|
|
106
79
|
if (parts.length > 0) {
|
|
107
80
|
return he.decode('—') + parts.join(', ')
|
|
@@ -113,24 +86,23 @@ export default {
|
|
|
113
86
|
const parts = []
|
|
114
87
|
|
|
115
88
|
const sourceTitle =
|
|
116
|
-
this.block.metadata.config.block_quote
|
|
89
|
+
this.block.metadata.config.block_quote.source_title || ''
|
|
117
90
|
const sourceType =
|
|
118
|
-
this.block.metadata.config.block_quote
|
|
91
|
+
this.block.metadata.config.block_quote.source_type || ''
|
|
119
92
|
|
|
120
|
-
if (
|
|
93
|
+
if (sourceType) {
|
|
121
94
|
switch (sourceType) {
|
|
122
95
|
case 'online_journal':
|
|
123
96
|
// Wrap the sourceTitle for online journals in quotes
|
|
124
|
-
|
|
97
|
+
if (!_.isEmpty(sourceTitle)) {
|
|
98
|
+
parts.push('"' + sourceTitle + '"')
|
|
99
|
+
}
|
|
125
100
|
|
|
126
101
|
// For online journals also add the url if it exists
|
|
127
|
-
if (
|
|
128
|
-
this.block.metadata.config.block_quote['source_url']
|
|
129
|
-
) {
|
|
102
|
+
if (this.block.metadata.config.block_quote.source_url) {
|
|
130
103
|
parts.push(
|
|
131
|
-
this.block.metadata.config.block_quote
|
|
132
|
-
|
|
133
|
-
]
|
|
104
|
+
this.block.metadata.config.block_quote
|
|
105
|
+
.source_url
|
|
134
106
|
)
|
|
135
107
|
}
|
|
136
108
|
break
|
|
@@ -140,7 +112,6 @@ export default {
|
|
|
140
112
|
break
|
|
141
113
|
}
|
|
142
114
|
}
|
|
143
|
-
|
|
144
115
|
// If the citation is empty (aka we only have sources)
|
|
145
116
|
// and there's sources then prepend with a mdash
|
|
146
117
|
if (parts.length > 0 && this.citation === '') {
|
|
@@ -154,14 +125,47 @@ export default {
|
|
|
154
125
|
},
|
|
155
126
|
sourceClass() {
|
|
156
127
|
if (
|
|
157
|
-
this.block.metadata.config.block_quote
|
|
158
|
-
this.block.metadata.config.block_quote
|
|
159
|
-
this.block.metadata.config.block_quote
|
|
128
|
+
this.block.metadata.config.block_quote.source_title &&
|
|
129
|
+
this.block.metadata.config.block_quote.source_type &&
|
|
130
|
+
this.block.metadata.config.block_quote.source_type === 'book'
|
|
160
131
|
) {
|
|
161
132
|
return 'span-title'
|
|
133
|
+
} else {
|
|
134
|
+
return ''
|
|
162
135
|
}
|
|
163
136
|
},
|
|
164
137
|
},
|
|
138
|
+
beforeMount() {
|
|
139
|
+
if (_.isEmpty(this.block)) {
|
|
140
|
+
this.block = {}
|
|
141
|
+
}
|
|
142
|
+
if (_.isEmpty(this.block.metadata)) {
|
|
143
|
+
this.block.metadata = {}
|
|
144
|
+
}
|
|
145
|
+
if (_.isEmpty(this.block.metadata.config)) {
|
|
146
|
+
this.block.metadata.config = {}
|
|
147
|
+
}
|
|
148
|
+
if (_.isEmpty(this.block.metadata.config.title)) {
|
|
149
|
+
this.block.metadata.config.title = ''
|
|
150
|
+
}
|
|
151
|
+
if (_.isEmpty(this.block.metadata.config.instructions)) {
|
|
152
|
+
this.block.metadata.config.instructions = ''
|
|
153
|
+
}
|
|
154
|
+
if (_.isEmpty(this.block.metadata.config.block_quote)) {
|
|
155
|
+
this.block.metadata.config.block_quote = {
|
|
156
|
+
quote: '',
|
|
157
|
+
author: '',
|
|
158
|
+
author_title: '',
|
|
159
|
+
organization: '',
|
|
160
|
+
source_title: '',
|
|
161
|
+
source_type: '',
|
|
162
|
+
source_url: '',
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
this.block.body = this.$t(
|
|
166
|
+
'windward.core.components.content.blocks.block_quote.body'
|
|
167
|
+
)
|
|
168
|
+
},
|
|
165
169
|
mounted() {},
|
|
166
170
|
methods: {},
|
|
167
171
|
}
|
|
@@ -1,7 +1,46 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<v-row>
|
|
4
|
-
<v-col
|
|
3
|
+
<v-row class="container-generate-ai mt-2">
|
|
4
|
+
<v-col>{{
|
|
5
|
+
$t(
|
|
6
|
+
'windward.core.components.content.blocks.generate_questions.ai_assistance'
|
|
7
|
+
)
|
|
8
|
+
}}</v-col>
|
|
9
|
+
<v-col>
|
|
10
|
+
<v-select
|
|
11
|
+
v-model="selectedContent"
|
|
12
|
+
:items="flattenedContent"
|
|
13
|
+
class="btn-selector"
|
|
14
|
+
outlined
|
|
15
|
+
hide-details
|
|
16
|
+
dense
|
|
17
|
+
:label="
|
|
18
|
+
$t(
|
|
19
|
+
'windward.core.components.content.blocks.generate_questions.selected_pages'
|
|
20
|
+
)
|
|
21
|
+
"
|
|
22
|
+
item-text="content.name"
|
|
23
|
+
return-object
|
|
24
|
+
></v-select>
|
|
25
|
+
</v-col>
|
|
26
|
+
<v-col>
|
|
27
|
+
<v-select
|
|
28
|
+
v-model="selectedDifficulty"
|
|
29
|
+
:items="taxonomyLevels"
|
|
30
|
+
item-text="text"
|
|
31
|
+
class="btn-selector"
|
|
32
|
+
outlined
|
|
33
|
+
hide-details
|
|
34
|
+
dense
|
|
35
|
+
:label="
|
|
36
|
+
$t(
|
|
37
|
+
'windward.core.components.content.blocks.generate_questions.blooms.blooms_taxonomy'
|
|
38
|
+
)
|
|
39
|
+
"
|
|
40
|
+
return-object
|
|
41
|
+
></v-select>
|
|
42
|
+
</v-col>
|
|
43
|
+
<v-col>
|
|
5
44
|
<v-btn
|
|
6
45
|
elevation="0"
|
|
7
46
|
color="secondary"
|
|
@@ -10,37 +49,33 @@
|
|
|
10
49
|
:disabled="isLoading"
|
|
11
50
|
@click="generateAIQuestion"
|
|
12
51
|
>
|
|
13
|
-
<v-icon
|
|
14
|
-
|
|
52
|
+
<v-icon v-if="!isLoading" class="pr-1"
|
|
53
|
+
>mdi-magic-staff</v-icon
|
|
54
|
+
>
|
|
55
|
+
{{
|
|
56
|
+
$t(
|
|
57
|
+
'windward.core.components.content.blocks.generate_questions.button_label'
|
|
58
|
+
)
|
|
59
|
+
}}
|
|
15
60
|
<template v-slot:loader>
|
|
16
|
-
<v-progress-circular
|
|
61
|
+
<v-progress-circular
|
|
62
|
+
indeterminate
|
|
63
|
+
size="23"
|
|
64
|
+
></v-progress-circular>
|
|
17
65
|
</template>
|
|
18
66
|
</v-btn>
|
|
19
67
|
</v-col>
|
|
20
|
-
<v-col cols="12" class="d-flex justify-end pt-0">
|
|
21
|
-
<v-select
|
|
22
|
-
v-model="selectedContent"
|
|
23
|
-
:items="flattenedContent"
|
|
24
|
-
class="btn-selector"
|
|
25
|
-
outlined
|
|
26
|
-
hide-details
|
|
27
|
-
dense
|
|
28
|
-
:label="$t('windward.core.components.content.blocks.generate_questions.selected_pages')"
|
|
29
|
-
item-text="content.name"
|
|
30
|
-
return-object
|
|
31
|
-
></v-select>
|
|
32
|
-
</v-col>
|
|
33
68
|
</v-row>
|
|
34
69
|
</div>
|
|
35
70
|
</template>
|
|
36
71
|
|
|
37
72
|
<script>
|
|
73
|
+
import _ from 'lodash'
|
|
74
|
+
import { mapGetters } from 'vuex'
|
|
38
75
|
import AssessmentQuestion from '~/models/AssessmentQuestion'
|
|
39
76
|
import Course from '~/models/Course'
|
|
40
77
|
import Assessment from '~/models/Assessment'
|
|
41
78
|
import Content from '~/models/Content'
|
|
42
|
-
import { mapGetters } from 'vuex'
|
|
43
|
-
import _ from 'lodash'
|
|
44
79
|
import Crypto from '~/helpers/Crypto'
|
|
45
80
|
|
|
46
81
|
export default {
|
|
@@ -55,6 +90,12 @@ export default {
|
|
|
55
90
|
return {
|
|
56
91
|
isLoading: false,
|
|
57
92
|
selectedContent: '',
|
|
93
|
+
selectedDifficulty: {
|
|
94
|
+
value: 'None',
|
|
95
|
+
text: this.$t(
|
|
96
|
+
'windward.core.components.content.blocks.generate_questions.blooms.none'
|
|
97
|
+
),
|
|
98
|
+
},
|
|
58
99
|
}
|
|
59
100
|
},
|
|
60
101
|
computed: {
|
|
@@ -73,6 +114,10 @@ export default {
|
|
|
73
114
|
fullTree.push(content)
|
|
74
115
|
if (content.children.length > 0) {
|
|
75
116
|
fullTree = fullTree.concat(_.flatten(content.children))
|
|
117
|
+
// check if children have children
|
|
118
|
+
content.children.forEach((child) => {
|
|
119
|
+
fullTree = fullTree.concat(_.flatten(child.children))
|
|
120
|
+
})
|
|
76
121
|
}
|
|
77
122
|
})
|
|
78
123
|
//
|
|
@@ -85,17 +130,78 @@ export default {
|
|
|
85
130
|
}
|
|
86
131
|
return fullTree
|
|
87
132
|
},
|
|
133
|
+
taxonomyLevels() {
|
|
134
|
+
let basicBloomTaxonomy = [
|
|
135
|
+
{
|
|
136
|
+
value: 'None',
|
|
137
|
+
text: this.$t(
|
|
138
|
+
'windward.core.components.content.blocks.generate_questions.blooms.none'
|
|
139
|
+
),
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
value: 'Remember',
|
|
143
|
+
text: this.$t(
|
|
144
|
+
'windward.core.components.content.blocks.generate_questions.blooms.remember'
|
|
145
|
+
),
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
value: 'Understand',
|
|
149
|
+
text: this.$t(
|
|
150
|
+
'windward.core.components.content.blocks.generate_questions.blooms.understand'
|
|
151
|
+
),
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
value: 'Apply',
|
|
155
|
+
text: this.$t(
|
|
156
|
+
'windward.core.components.content.blocks.generate_questions.blooms.apply'
|
|
157
|
+
),
|
|
158
|
+
},
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
if (
|
|
162
|
+
this.questionType === 'multi_choice_single_answer' ||
|
|
163
|
+
this.questionType === 'ordering' ||
|
|
164
|
+
this.questionType === 'multi_choice_multi_answer'
|
|
165
|
+
) {
|
|
166
|
+
const multiBlooms = [
|
|
167
|
+
{
|
|
168
|
+
value: 'Analyze',
|
|
169
|
+
text: this.$t(
|
|
170
|
+
'windward.core.components.content.blocks.generate_questions.blooms.analyze'
|
|
171
|
+
),
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
value: 'Evaluate',
|
|
175
|
+
text: this.$t(
|
|
176
|
+
'windward.core.components.content.blocks.generate_questions.blooms.evaluate'
|
|
177
|
+
),
|
|
178
|
+
},
|
|
179
|
+
]
|
|
180
|
+
basicBloomTaxonomy = basicBloomTaxonomy.concat(multiBlooms)
|
|
181
|
+
}
|
|
182
|
+
return basicBloomTaxonomy
|
|
183
|
+
},
|
|
88
184
|
},
|
|
89
185
|
methods: {
|
|
90
186
|
async generateAIQuestion() {
|
|
91
187
|
this.isLoading = true
|
|
188
|
+
let bloomsRequest = ''
|
|
189
|
+
if (
|
|
190
|
+
this.selectedDifficulty.text !==
|
|
191
|
+
this.$t(
|
|
192
|
+
'windward.core.components.content.blocks.generate_questions.blooms.none'
|
|
193
|
+
)
|
|
194
|
+
) {
|
|
195
|
+
// send value to api call so its not changing with language
|
|
196
|
+
bloomsRequest = `?blooms_level=${this.selectedDifficulty.value}`
|
|
197
|
+
}
|
|
92
198
|
try {
|
|
93
199
|
const response = await AssessmentQuestion.custom(
|
|
94
200
|
new Course(this.course),
|
|
95
201
|
new Content(this.selectedContent),
|
|
96
202
|
new Assessment({ id: this.block.id }),
|
|
97
203
|
new AssessmentQuestion(),
|
|
98
|
-
`suggest/${this.questionType}`
|
|
204
|
+
`suggest/${this.questionType}${bloomsRequest}`
|
|
99
205
|
).get()
|
|
100
206
|
|
|
101
207
|
if (response && response.length > 0) {
|
|
@@ -103,27 +209,31 @@ export default {
|
|
|
103
209
|
this.$emit('click:generate', generatedQuestion)
|
|
104
210
|
}
|
|
105
211
|
} catch (error) {
|
|
106
|
-
const errorMessage =
|
|
212
|
+
const errorMessage =
|
|
213
|
+
error.response?.data?.error?.message ||
|
|
214
|
+
'assessment.error.technical'
|
|
107
215
|
const errorType = errorMessage.split('.').pop()
|
|
108
|
-
const basePath =
|
|
216
|
+
const basePath =
|
|
217
|
+
'windward.core.components.content.blocks.generate_questions.error'
|
|
218
|
+
|
|
219
|
+
let errorText =
|
|
220
|
+
this.$t(`${basePath}.${errorType}`) +
|
|
221
|
+
'\n\n' +
|
|
222
|
+
this.$t(`${basePath}.${errorType}_support`)
|
|
109
223
|
|
|
110
|
-
let errorText = this.$t(`${basePath}.${errorType}`) + '\n\n' +
|
|
111
|
-
this.$t(`${basePath}.${errorType}_support`)
|
|
112
|
-
|
|
113
224
|
if (errorType === 'technical') {
|
|
114
|
-
const errorCode =
|
|
225
|
+
const errorCode =
|
|
226
|
+
error.response?.data?.error?.details?.error_type ||
|
|
227
|
+
'UNKNOWN'
|
|
115
228
|
errorText = errorText.replace('[ERROR_CODE]', errorCode)
|
|
116
229
|
}
|
|
117
|
-
|
|
118
|
-
this.$dialog.error(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
type: 'error'
|
|
125
|
-
}
|
|
126
|
-
)
|
|
230
|
+
|
|
231
|
+
this.$dialog.error(errorText, {
|
|
232
|
+
duration: 5000,
|
|
233
|
+
keepOnHover: true,
|
|
234
|
+
singleton: true,
|
|
235
|
+
type: 'error',
|
|
236
|
+
})
|
|
127
237
|
} finally {
|
|
128
238
|
this.isLoading = false
|
|
129
239
|
}
|
|
@@ -136,4 +246,8 @@ export default {
|
|
|
136
246
|
.btn-selector {
|
|
137
247
|
width: 100%;
|
|
138
248
|
}
|
|
249
|
+
.container-generate-ai {
|
|
250
|
+
outline: 1px solid var(--v-secondary-base);
|
|
251
|
+
border-radius: 15px;
|
|
252
|
+
}
|
|
139
253
|
</style>
|
|
@@ -155,7 +155,13 @@ export default {
|
|
|
155
155
|
this.block.metadata.config.starting_text = ''
|
|
156
156
|
}
|
|
157
157
|
},
|
|
158
|
-
watch: {
|
|
158
|
+
watch: {
|
|
159
|
+
render(newVal) {
|
|
160
|
+
if (newVal) {
|
|
161
|
+
this.onAfterSetContentBlockState()
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
},
|
|
159
165
|
mounted() {},
|
|
160
166
|
methods: {
|
|
161
167
|
async onAfterSetContentBlockState() {
|
|
@@ -181,11 +187,13 @@ export default {
|
|
|
181
187
|
}
|
|
182
188
|
|
|
183
189
|
// If after the state is applied the response is still empty then apply the default response
|
|
184
|
-
if (this.response
|
|
190
|
+
if (_.isEmpty(this.response)) {
|
|
185
191
|
this.response = this.block.metadata.config.starting_text
|
|
186
192
|
}
|
|
193
|
+
} else {
|
|
194
|
+
// If we don't have a block_id then we are in the initial setup state
|
|
195
|
+
this.response = this.block.metadata.config.starting_text
|
|
187
196
|
}
|
|
188
|
-
|
|
189
197
|
this.stateLoaded = true
|
|
190
198
|
},
|
|
191
199
|
onSubmit() {
|
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
<v-tooltip right>
|
|
3
|
+
<template #activator="{ on, attrs }">
|
|
4
|
+
<v-list-item
|
|
5
|
+
:to="
|
|
6
|
+
'/course/' +
|
|
7
|
+
course.id +
|
|
8
|
+
'/section/' +
|
|
9
|
+
enrollment.course_section_id +
|
|
10
|
+
'/user-uploads'
|
|
11
|
+
"
|
|
12
|
+
v-bind="attrs"
|
|
13
|
+
v-on="on"
|
|
14
|
+
>
|
|
15
|
+
<v-list-item-action>
|
|
16
|
+
<v-icon>mdi-cloud-upload</v-icon>
|
|
17
|
+
</v-list-item-action>
|
|
18
|
+
<v-list-item-content>
|
|
19
|
+
<v-list-item-title
|
|
20
|
+
>{{
|
|
21
|
+
$t(
|
|
22
|
+
'windward.core.components.navigation.user_upload.title'
|
|
23
|
+
)
|
|
24
|
+
}}
|
|
25
|
+
</v-list-item-title>
|
|
26
|
+
</v-list-item-content>
|
|
27
|
+
</v-list-item>
|
|
28
|
+
</template>
|
|
29
|
+
<span>{{
|
|
30
|
+
$t('windward.core.components.navigation.user_upload.title')
|
|
31
|
+
}}</span>
|
|
32
|
+
</v-tooltip>
|
|
22
33
|
</template>
|
|
23
34
|
|
|
24
35
|
<script>
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-container justify="center">
|
|
2
|
+
<v-container justify="center" class="pa-0">
|
|
3
3
|
<v-row justify="center" align="center">
|
|
4
4
|
<v-col cols="12">
|
|
5
5
|
<v-data-table
|
|
6
6
|
:key="tableKey"
|
|
7
7
|
:headers="headers"
|
|
8
8
|
:items="glossaryTerms"
|
|
9
|
+
:footer-props="{
|
|
10
|
+
'items-per-page-options': [5, -1],
|
|
11
|
+
}"
|
|
9
12
|
:search="search"
|
|
10
13
|
class="elevation-1"
|
|
11
14
|
>
|
|
@@ -35,9 +38,13 @@
|
|
|
35
38
|
>
|
|
36
39
|
<template #title>
|
|
37
40
|
{{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
selectedTerm.id
|
|
42
|
+
? $t(
|
|
43
|
+
'windward.core.pages.glossary.edit_term'
|
|
44
|
+
)
|
|
45
|
+
: $t(
|
|
46
|
+
'windward.core.pages.glossary.add_term'
|
|
47
|
+
)
|
|
41
48
|
}}
|
|
42
49
|
</template>
|
|
43
50
|
<template #trigger>
|
|
@@ -159,18 +166,16 @@
|
|
|
159
166
|
<script>
|
|
160
167
|
import { mapGetters, mapMutations, mapActions } from 'vuex'
|
|
161
168
|
import _ from 'lodash'
|
|
162
|
-
import
|
|
169
|
+
import CourseGlossaryTerm from '../../../models/CourseGlossaryTerm'
|
|
163
170
|
import CourseGlossaryForm from './CourseGlossaryForm'
|
|
164
171
|
import DialogBox from '~/components/Core/DialogBox.vue'
|
|
165
172
|
import Crypto from '~/helpers/Crypto'
|
|
166
173
|
import Course from '~/models/Course'
|
|
167
|
-
import CourseGlossaryTerm from '../../../models/CourseGlossaryTerm'
|
|
168
174
|
import SpeedDial from '~/components/Core/SpeedDial.vue'
|
|
169
|
-
import TextViewer from '~/components/Text/TextViewer.vue'
|
|
170
175
|
|
|
171
176
|
export default {
|
|
172
177
|
name: 'CourseGlossary',
|
|
173
|
-
components: { DialogBox, CourseGlossaryForm, SpeedDial
|
|
178
|
+
components: { DialogBox, CourseGlossaryForm, SpeedDial },
|
|
174
179
|
layout: 'course',
|
|
175
180
|
middleware: ['auth'],
|
|
176
181
|
props: {
|
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
error: {
|
|
3
3
|
default: 'Could not generate question from provided content.',
|
|
4
|
-
default_support:
|
|
5
|
-
|
|
4
|
+
default_support:
|
|
5
|
+
'Please try again or contact support if the issue persists.',
|
|
6
|
+
|
|
6
7
|
insufficient_content: 'More content needed to generate questions.',
|
|
7
|
-
insufficient_content_support:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
insufficient_content_support:
|
|
9
|
+
'Please add more text, examples, or explanations to this section. We recommend at least 50 words of relevant content to generate appropriate questions.',
|
|
10
|
+
|
|
11
|
+
content_mismatch: "Content doesn't match question type.",
|
|
12
|
+
content_mismatch_support:
|
|
13
|
+
"The current content isn't suitable for this type of question. Consider adding more specific examples, numerical data, or comparable items depending on your desired question type.",
|
|
14
|
+
|
|
12
15
|
llm_unavailable: 'Question generation temporarily unavailable.',
|
|
13
|
-
llm_unavailable_support:
|
|
14
|
-
|
|
16
|
+
llm_unavailable_support:
|
|
17
|
+
"We're unable to connect to our AI service at the moment. Please try again in a few minutes or contact support if the issue persists.",
|
|
18
|
+
|
|
15
19
|
technical: 'Unable to process request.',
|
|
16
|
-
technical_support:
|
|
20
|
+
technical_support:
|
|
21
|
+
'Something went wrong on our end. Please try again or contact support if this continues. Reference code: [ERROR_CODE]',
|
|
17
22
|
},
|
|
18
23
|
button_label: 'Generate Question',
|
|
19
|
-
selected_pages: 'Selected Page'
|
|
24
|
+
selected_pages: 'Selected Page',
|
|
25
|
+
ai_assistance: 'AI Assistance',
|
|
26
|
+
blooms: {
|
|
27
|
+
blooms_taxonomy: "Bloom's Taxonomy Level",
|
|
28
|
+
none: 'None selected',
|
|
29
|
+
remember: 'Remember',
|
|
30
|
+
understand: 'Understand',
|
|
31
|
+
apply: 'Apply',
|
|
32
|
+
analyze: 'Analyze',
|
|
33
|
+
evaluate: 'Evaluate',
|
|
34
|
+
},
|
|
20
35
|
}
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
math: 'Math',
|
|
9
9
|
accordion: 'Accordion',
|
|
10
10
|
open_response: 'Open Response',
|
|
11
|
-
open_response_collate: 'Open Response
|
|
11
|
+
open_response_collate: 'Open Response Download',
|
|
12
12
|
image: 'Image',
|
|
13
13
|
user_upload: 'User Upload',
|
|
14
14
|
clickable_icons: 'Clickable Icons',
|
|
@@ -2,7 +2,7 @@ export default {
|
|
|
2
2
|
title: {
|
|
3
3
|
assessment: 'Assessment Settings',
|
|
4
4
|
open_response: 'Open Response Settings',
|
|
5
|
-
open_response_collate: 'Open Response
|
|
5
|
+
open_response_collate: 'Open Response Download Settings',
|
|
6
6
|
image: 'Image Settings',
|
|
7
7
|
user_upload: 'User Upload Settings',
|
|
8
8
|
file_download: 'File Download Settings',
|
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
|
|
13
13
|
content_mismatch: 'El contenido no coincide con el tipo de pregunta.',
|
|
14
14
|
content_mismatch_support:
|
|
15
|
-
'
|
|
15
|
+
'Por favor, añada más texto, ejemplos o explicaciones a esta sección. Recomendamos al menos 50 palabras de contenido relevante para generar preguntas apropiadas.',
|
|
16
16
|
|
|
17
17
|
llm_unavailable:
|
|
18
18
|
'La generación de preguntas no está disponible temporalmente.',
|
|
@@ -25,4 +25,14 @@ export default {
|
|
|
25
25
|
},
|
|
26
26
|
button_label: 'Generar pregunta',
|
|
27
27
|
selected_pages: 'Página seleccionada',
|
|
28
|
+
ai_assistance: 'Asistencia de IA',
|
|
29
|
+
blooms: {
|
|
30
|
+
blooms_taxonomy: 'Nivel de taxonomía de Bloom',
|
|
31
|
+
none: 'Ninguno seleccionado',
|
|
32
|
+
remember: 'Recordar',
|
|
33
|
+
understand: 'Entender',
|
|
34
|
+
apply: 'Aplicar',
|
|
35
|
+
analyze: 'Analizar',
|
|
36
|
+
evaluate: 'Evaluar',
|
|
37
|
+
},
|
|
28
38
|
}
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
math: 'Matemáticas',
|
|
9
9
|
accordion: 'Acordeón',
|
|
10
10
|
open_response: 'Respuesta abierta',
|
|
11
|
-
open_response_collate: '
|
|
11
|
+
open_response_collate: 'Módulo de descarga de respuestas',
|
|
12
12
|
image: 'Imagen',
|
|
13
13
|
user_upload: 'Carga de usuario',
|
|
14
14
|
clickable_icons: 'Iconos en los que se puede hacer clic',
|
|
@@ -2,8 +2,7 @@ export default {
|
|
|
2
2
|
title: {
|
|
3
3
|
assessment: 'Configuración de evaluación',
|
|
4
4
|
open_response: 'Abrir configuración de respuesta',
|
|
5
|
-
open_response_collate:
|
|
6
|
-
'Abrir configuración de clasificación de respuestas',
|
|
5
|
+
open_response_collate: 'Abrir configuración de descarga de respuesta',
|
|
7
6
|
image: 'Configuración de imagen',
|
|
8
7
|
user_upload: 'Configuración de carga del usuario',
|
|
9
8
|
file_download: 'Configuración de descarga de archivos',
|
|
@@ -10,7 +10,7 @@ export default {
|
|
|
10
10
|
|
|
11
11
|
content_mismatch: 'Innehållet matchar inte frågetyp.',
|
|
12
12
|
content_mismatch_support:
|
|
13
|
-
'
|
|
13
|
+
'Vänligen lägg till mer text, exempel eller förklaringar till detta avsnitt. Vi rekommenderar minst 50 ord av relevant innehåll för att generera lämpliga frågor.',
|
|
14
14
|
|
|
15
15
|
llm_unavailable: 'Frågegenerering tillfälligt otillgänglig.',
|
|
16
16
|
llm_unavailable_support:
|
|
@@ -22,4 +22,14 @@ export default {
|
|
|
22
22
|
},
|
|
23
23
|
button_label: 'Generera fråga',
|
|
24
24
|
selected_pages: 'Vald sida',
|
|
25
|
+
ai_assistance: 'AI-hjälp',
|
|
26
|
+
blooms: {
|
|
27
|
+
blooms_taxonomy: 'Blooms taxonominivå',
|
|
28
|
+
none: 'Ingen vald',
|
|
29
|
+
remember: 'Komma ihåg',
|
|
30
|
+
understand: 'Förstå',
|
|
31
|
+
apply: 'Tillämpas',
|
|
32
|
+
analyze: 'Analysera',
|
|
33
|
+
evaluate: 'Utvärdera',
|
|
34
|
+
},
|
|
25
35
|
}
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
math: 'Math',
|
|
9
9
|
accordion: 'Accordion',
|
|
10
10
|
open_response: 'Öppet svar',
|
|
11
|
-
open_response_collate: 'Öppna
|
|
11
|
+
open_response_collate: 'Öppna svar Ladda ner',
|
|
12
12
|
image: 'Bild',
|
|
13
13
|
user_upload: 'User Upload',
|
|
14
14
|
clickable_icons: 'Klickbara ikoner',
|
|
@@ -2,7 +2,7 @@ export default {
|
|
|
2
2
|
title: {
|
|
3
3
|
assessment: 'Bedömningsinställningar',
|
|
4
4
|
open_response: 'Öppna svarsinställningar',
|
|
5
|
-
open_response_collate: 'Öppna inställningar för
|
|
5
|
+
open_response_collate: 'Öppna inställningar för nedladdning av svar',
|
|
6
6
|
image: 'Bildinställningar',
|
|
7
7
|
user_upload: 'Användaruppladdningsinställningar',
|
|
8
8
|
file_download: 'Filnedladdningsinställningar',
|
package/package.json
CHANGED
package/pages/glossary.vue
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-row justify="center" align="center">
|
|
3
|
+
<v-col cols="12">
|
|
4
|
+
<Breadcrumbs :items="breadcrumbPath"></Breadcrumbs>
|
|
5
|
+
</v-col>
|
|
3
6
|
<v-col cols="12">
|
|
4
7
|
<v-alert
|
|
5
8
|
v-if="
|
|
@@ -27,10 +30,12 @@
|
|
|
27
30
|
</template>
|
|
28
31
|
|
|
29
32
|
<script>
|
|
33
|
+
import { mapGetters } from 'vuex'
|
|
30
34
|
import { CourseGlossary } from '../utils/index'
|
|
35
|
+
import Breadcrumbs from '~/components/Core/Breadcrumbs.vue'
|
|
31
36
|
export default {
|
|
32
37
|
name: 'Glossary',
|
|
33
|
-
components: { CourseGlossary },
|
|
38
|
+
components: { CourseGlossary, Breadcrumbs },
|
|
34
39
|
layout: 'course',
|
|
35
40
|
middleware: ['auth', 'privilege'],
|
|
36
41
|
meta: {
|
|
@@ -43,5 +48,29 @@ export default {
|
|
|
43
48
|
},
|
|
44
49
|
},
|
|
45
50
|
},
|
|
51
|
+
computed: {
|
|
52
|
+
...mapGetters({
|
|
53
|
+
course: 'course/get',
|
|
54
|
+
enrollment: 'enrollment/get',
|
|
55
|
+
}),
|
|
56
|
+
breadcrumbPath() {
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
href:
|
|
60
|
+
'/course/' +
|
|
61
|
+
this.course.id +
|
|
62
|
+
'/section/' +
|
|
63
|
+
this.enrollment.course_section_id,
|
|
64
|
+
id: '',
|
|
65
|
+
text: this.course.name,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
href: this.$route.path,
|
|
69
|
+
id: '',
|
|
70
|
+
text: this.$t('windward.core.pages.glossary.title'),
|
|
71
|
+
},
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
},
|
|
46
75
|
}
|
|
47
76
|
</script>
|
package/pages/userUpload.vue
CHANGED
|
@@ -1,48 +1,53 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<v-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
2
|
+
<v-row>
|
|
3
|
+
<v-col cols="12">
|
|
4
|
+
<Breadcrumbs :items="breadcrumbPath"></Breadcrumbs>
|
|
5
|
+
</v-col>
|
|
6
|
+
<v-col cols="12">
|
|
7
|
+
<h2>{{ $t('windward.core.pages.user_upload.title') }}</h2>
|
|
8
|
+
<v-divider class="mt-5 mb-5" />
|
|
9
|
+
<v-data-table
|
|
10
|
+
:headers="headers"
|
|
11
|
+
:items="uploadpages"
|
|
12
|
+
:search="search"
|
|
13
|
+
class="elevation-1"
|
|
14
|
+
>
|
|
15
|
+
<template #top>
|
|
16
|
+
<v-toolbar flat>
|
|
17
|
+
<CourseSectionSwitch
|
|
18
|
+
@change="load($event)"
|
|
19
|
+
></CourseSectionSwitch>
|
|
20
|
+
<v-spacer></v-spacer>
|
|
21
|
+
<v-text-field
|
|
22
|
+
v-model="search"
|
|
23
|
+
class="ml-5 flex-grow-1"
|
|
24
|
+
append-icon="mdi-magnify"
|
|
25
|
+
:label="$t('shared.forms.search')"
|
|
26
|
+
single-line
|
|
27
|
+
hide-details
|
|
28
|
+
></v-text-field>
|
|
29
|
+
</v-toolbar>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<template #item="{ index, item }">
|
|
33
|
+
<tr>
|
|
34
|
+
<td>{{ item.last_name }}</td>
|
|
35
|
+
<td>{{ item.first_name }}</td>
|
|
36
|
+
<td
|
|
37
|
+
v-for="(block, blockIndex) in item.uploadBlocks"
|
|
38
|
+
:key="blockIndex"
|
|
39
|
+
class="grade-column"
|
|
40
|
+
>
|
|
41
|
+
<ManageDataTableUserFiles
|
|
42
|
+
v-model="block.assets"
|
|
43
|
+
:enrollment="block.enrollment"
|
|
44
|
+
></ManageDataTableUserFiles>
|
|
45
|
+
</td>
|
|
46
|
+
</tr>
|
|
47
|
+
</template>
|
|
48
|
+
</v-data-table>
|
|
49
|
+
</v-col>
|
|
50
|
+
</v-row>
|
|
46
51
|
</template>
|
|
47
52
|
|
|
48
53
|
<script>
|
|
@@ -51,14 +56,14 @@ import _ from 'lodash'
|
|
|
51
56
|
import Course from '~/models/Course'
|
|
52
57
|
import CourseSection from '~/models/CourseSection'
|
|
53
58
|
import UserFileAsset from '../models/UserFileAsset'
|
|
54
|
-
|
|
59
|
+
import Breadcrumbs from '~/components/Core/Breadcrumbs.vue'
|
|
55
60
|
import CourseSectionSwitch from '~/components/Course/CourseSectionSwitch.vue'
|
|
56
61
|
import ManageDataTableUserFiles from '../components/Content/Blocks/UserUpload/ManageDataTableUserFiles.vue'
|
|
57
62
|
|
|
58
63
|
export default {
|
|
59
64
|
name: 'PluginUserUploadPage',
|
|
60
65
|
middleware: ['auth', 'privilege'],
|
|
61
|
-
components: { CourseSectionSwitch, ManageDataTableUserFiles },
|
|
66
|
+
components: { CourseSectionSwitch, ManageDataTableUserFiles, Breadcrumbs },
|
|
62
67
|
layout: 'course',
|
|
63
68
|
meta: {
|
|
64
69
|
privilege: {
|
|
@@ -178,6 +183,24 @@ export default {
|
|
|
178
183
|
|
|
179
184
|
return items
|
|
180
185
|
},
|
|
186
|
+
breadcrumbPath() {
|
|
187
|
+
return [
|
|
188
|
+
{
|
|
189
|
+
href:
|
|
190
|
+
'/course/' +
|
|
191
|
+
this.course.id +
|
|
192
|
+
'/section/' +
|
|
193
|
+
this.enrollment.course_section_id,
|
|
194
|
+
id: '',
|
|
195
|
+
text: this.course.name,
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
href: this.$route.path,
|
|
199
|
+
id: '',
|
|
200
|
+
text: this.$t('windward.core.pages.user_upload.title'),
|
|
201
|
+
},
|
|
202
|
+
]
|
|
203
|
+
},
|
|
181
204
|
},
|
|
182
205
|
mounted() {},
|
|
183
206
|
methods: {
|
package/plugin.js
CHANGED
|
@@ -216,7 +216,7 @@ export default {
|
|
|
216
216
|
tag: 'core-open-response-collate',
|
|
217
217
|
template: OpenResponseCollate,
|
|
218
218
|
metadata: {
|
|
219
|
-
icon: 'mdi-
|
|
219
|
+
icon: 'mdi-cloud-download',
|
|
220
220
|
name: 'windward.core.shared.content_blocks.title.open_response_collate',
|
|
221
221
|
grouping: 'components.content.blocks.group.basic',
|
|
222
222
|
},
|