@windward/core 0.15.0 → 0.17.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 +6 -0
- package/components/Content/Blocks/Accordion.vue +39 -38
- package/components/Content/Blocks/BlockQuote.vue +51 -47
- package/components/Content/Blocks/OpenResponse.vue +19 -7
- package/components/Navigation/Items/UserUploadNav.vue +35 -20
- package/components/Settings/TextEditorSettings.vue +1 -0
- package/components/utils/ContentViewer.vue +3 -0
- package/components/utils/FillInBlank/FillInBlankInput.vue +32 -28
- package/components/utils/GenerateAIQuestionButton.vue +345 -0
- package/components/utils/TinyMCEWrapper.vue +14 -57
- package/components/utils/glossary/CourseGlossary.vue +13 -8
- package/helpers/tinymce/WindwardPlugins.ts +36 -3
- 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/models/Activity.ts +9 -0
- package/package.json +1 -1
- package/pages/glossary.vue +30 -1
- package/pages/userUpload.vue +69 -46
- package/plugin.js +1 -1
- package/utils/index.js +1 -1
- package/components/Content/Blocks/GenerateAIQuestionButton.vue +0 -139
|
@@ -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
|
},
|
package/utils/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import TinyMCEWrapper from '../components/utils/TinyMCEWrapper.vue'
|
|
|
7
7
|
import MathExpressionEditor from '../components/utils/MathExpressionEditor'
|
|
8
8
|
import CourseGlossary from '../components/utils/glossary/CourseGlossary.vue'
|
|
9
9
|
import CourseGlossaryForm from '../components/utils/glossary/CourseGlossaryForm.vue'
|
|
10
|
-
import GenerateAIQuestionButton from '../components/
|
|
10
|
+
import GenerateAIQuestionButton from '../components/utils/GenerateAIQuestionButton.vue'
|
|
11
11
|
|
|
12
12
|
export {
|
|
13
13
|
MathHelper,
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<v-row>
|
|
4
|
-
<v-col cols="12" class="d-flex justify-end pb-1">
|
|
5
|
-
<v-btn
|
|
6
|
-
elevation="0"
|
|
7
|
-
color="secondary"
|
|
8
|
-
class="mb-1 btn-selector"
|
|
9
|
-
:loading="isLoading"
|
|
10
|
-
:disabled="isLoading"
|
|
11
|
-
@click="generateAIQuestion"
|
|
12
|
-
>
|
|
13
|
-
<v-icon class="pr-1" v-if="!isLoading">mdi-magic-staff</v-icon>
|
|
14
|
-
{{ $t('windward.core.components.content.blocks.generate_questions.button_label') }}
|
|
15
|
-
<template v-slot:loader>
|
|
16
|
-
<v-progress-circular indeterminate size="23"></v-progress-circular>
|
|
17
|
-
</template>
|
|
18
|
-
</v-btn>
|
|
19
|
-
</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
|
-
</v-row>
|
|
34
|
-
</div>
|
|
35
|
-
</template>
|
|
36
|
-
|
|
37
|
-
<script>
|
|
38
|
-
import AssessmentQuestion from '~/models/AssessmentQuestion'
|
|
39
|
-
import Course from '~/models/Course'
|
|
40
|
-
import Assessment from '~/models/Assessment'
|
|
41
|
-
import Content from '~/models/Content'
|
|
42
|
-
import { mapGetters } from 'vuex'
|
|
43
|
-
import _ from 'lodash'
|
|
44
|
-
import Crypto from '~/helpers/Crypto'
|
|
45
|
-
|
|
46
|
-
export default {
|
|
47
|
-
name: 'GenerateAIQuestionButton',
|
|
48
|
-
props: {
|
|
49
|
-
course: { type: Object, required: true },
|
|
50
|
-
content: { type: Object, required: true },
|
|
51
|
-
block: { type: Object, required: true },
|
|
52
|
-
questionType: { type: String, required: true },
|
|
53
|
-
},
|
|
54
|
-
data() {
|
|
55
|
-
return {
|
|
56
|
-
isLoading: false,
|
|
57
|
-
selectedContent: '',
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
computed: {
|
|
61
|
-
...mapGetters({
|
|
62
|
-
contentTree: 'content/getTree',
|
|
63
|
-
}),
|
|
64
|
-
flattenedContent() {
|
|
65
|
-
let cloneContentTree = _.cloneDeep(this.contentTree)
|
|
66
|
-
const homepage = this.$ContentService.getHomepage()
|
|
67
|
-
if (!_.isEmpty(homepage)) {
|
|
68
|
-
cloneContentTree.unshift(homepage)
|
|
69
|
-
}
|
|
70
|
-
let fullTree = []
|
|
71
|
-
// flatten content tree to get nested children pages
|
|
72
|
-
cloneContentTree.forEach((content) => {
|
|
73
|
-
fullTree.push(content)
|
|
74
|
-
if (content.children.length > 0) {
|
|
75
|
-
fullTree = fullTree.concat(_.flatten(content.children))
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
//
|
|
79
|
-
if (_.isEmpty(this.selectedContent)) {
|
|
80
|
-
// returns array so hold here to pluck out below
|
|
81
|
-
const currentPage = fullTree.filter(
|
|
82
|
-
(contentPage) => contentPage.id === this.content.id
|
|
83
|
-
)
|
|
84
|
-
this.selectedContent = currentPage[0] ? currentPage[0] : ''
|
|
85
|
-
}
|
|
86
|
-
return fullTree
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
methods: {
|
|
90
|
-
async generateAIQuestion() {
|
|
91
|
-
this.isLoading = true
|
|
92
|
-
try {
|
|
93
|
-
const response = await AssessmentQuestion.custom(
|
|
94
|
-
new Course(this.course),
|
|
95
|
-
new Content(this.selectedContent),
|
|
96
|
-
new Assessment({ id: this.block.id }),
|
|
97
|
-
new AssessmentQuestion(),
|
|
98
|
-
`suggest/${this.questionType}`
|
|
99
|
-
).get()
|
|
100
|
-
|
|
101
|
-
if (response && response.length > 0) {
|
|
102
|
-
const generatedQuestion = response[0]
|
|
103
|
-
this.$emit('click:generate', generatedQuestion)
|
|
104
|
-
}
|
|
105
|
-
} catch (error) {
|
|
106
|
-
const errorMessage = error.response?.data?.error?.message || 'assessment.error.technical'
|
|
107
|
-
const errorType = errorMessage.split('.').pop()
|
|
108
|
-
const basePath = 'windward.core.components.content.blocks.generate_questions.error'
|
|
109
|
-
|
|
110
|
-
let errorText = this.$t(`${basePath}.${errorType}`) + '\n\n' +
|
|
111
|
-
this.$t(`${basePath}.${errorType}_support`)
|
|
112
|
-
|
|
113
|
-
if (errorType === 'technical') {
|
|
114
|
-
const errorCode = error.response?.data?.error?.details?.error_type || 'UNKNOWN'
|
|
115
|
-
errorText = errorText.replace('[ERROR_CODE]', errorCode)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
this.$dialog.error(
|
|
119
|
-
errorText,
|
|
120
|
-
{
|
|
121
|
-
duration: 5000,
|
|
122
|
-
keepOnHover: true,
|
|
123
|
-
singleton: true,
|
|
124
|
-
type: 'error'
|
|
125
|
-
}
|
|
126
|
-
)
|
|
127
|
-
} finally {
|
|
128
|
-
this.isLoading = false
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
}
|
|
133
|
-
</script>
|
|
134
|
-
|
|
135
|
-
<style scoped>
|
|
136
|
-
.btn-selector {
|
|
137
|
-
width: 100%;
|
|
138
|
-
}
|
|
139
|
-
</style>
|