@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 CHANGED
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ### Release [0.16.0] created - 2025-04-29
4
+
5
+
3
6
  ### Release [0.15.0] created - 2025-04-09
4
7
 
5
8
 
@@ -34,7 +34,9 @@
34
34
  <v-row>
35
35
  <v-col cols="12">
36
36
  <p>
37
- {{ citation }}
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
- extends: BaseContentBlock,
55
- beforeMount() {
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('&mdash;') + 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['source_title'] || ''
89
+ this.block.metadata.config.block_quote.source_title || ''
117
90
  const sourceType =
118
- this.block.metadata.config.block_quote['source_type'] || ''
91
+ this.block.metadata.config.block_quote.source_type || ''
119
92
 
120
- if (sourceTitle && sourceType) {
93
+ if (sourceType) {
121
94
  switch (sourceType) {
122
95
  case 'online_journal':
123
96
  // Wrap the sourceTitle for online journals in quotes
124
- parts.push('"' + sourceTitle + '"')
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
- 'source_url'
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['source_title'] &&
158
- this.block.metadata.config.block_quote['source_type'] &&
159
- this.block.metadata.config.block_quote['source_type'] === 'book'
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 cols="12" class="d-flex justify-end pb-1">
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 class="pr-1" v-if="!isLoading">mdi-magic-staff</v-icon>
14
- {{ $t('windward.core.components.content.blocks.generate_questions.button_label') }}
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 indeterminate size="23"></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 = error.response?.data?.error?.message || 'assessment.error.technical'
212
+ const errorMessage =
213
+ error.response?.data?.error?.message ||
214
+ 'assessment.error.technical'
107
215
  const errorType = errorMessage.split('.').pop()
108
- const basePath = 'windward.core.components.content.blocks.generate_questions.error'
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 = error.response?.data?.error?.details?.error_type || 'UNKNOWN'
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
- errorText,
120
- {
121
- duration: 5000,
122
- keepOnHover: true,
123
- singleton: true,
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-list-item
3
- :to="
4
- '/course/' +
5
- course.id +
6
- '/section/' +
7
- enrollment.course_section_id +
8
- '/user-uploads'
9
- "
10
- >
11
- <v-list-item-action>
12
- <v-icon>mdi-cloud-upload</v-icon>
13
- </v-list-item-action>
14
- <v-list-item-content>
15
- <v-list-item-title
16
- >{{
17
- $t('windward.core.components.navigation.user_upload.title')
18
- }}
19
- </v-list-item-title>
20
- </v-list-item-content>
21
- </v-list-item>
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
- $t(
39
- 'windward.core.pages.glossary.add_term'
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 { encode } from 'he'
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, TextViewer },
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: 'Please try again or contact support if the issue persists.',
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: 'Please add more text, examples, or explanations to this section. We recommend at least 2-3 paragraphs of content to generate relevant questions.',
8
-
9
- content_mismatch: 'Content doesn\'t match question type.',
10
- content_mismatch_support: '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.',
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: '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.',
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: 'Something went wrong on our end. Please try again or contact support if this continues. Reference code: [ERROR_CODE]'
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 Collate',
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 Collate Settings',
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
- 'El contenido actual no es adecuado para este tipo de pregunta. Considere agregar ejemplos más específicos o elementos comparables.',
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: 'Intercalación de respuesta abierta',
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
- 'Det aktuella innehållet är inte lämpligt för den här typen av frågor. Överväg att lägga till mer specifika exempel eller jämförbara objekt.',
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 svarssortering',
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 svarssortering',
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/core",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Windward UI Core Plugins",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
@@ -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>
@@ -1,48 +1,53 @@
1
1
  <template>
2
- <v-container>
3
- <h2>{{ $t('windward.core.pages.user_upload.title') }}</h2>
4
- <v-divider class="mt-5 mb-5" />
5
- <v-data-table
6
- :headers="headers"
7
- :items="uploadpages"
8
- :search="search"
9
- class="elevation-1"
10
- >
11
- <template #top>
12
- <v-toolbar flat>
13
- <CourseSectionSwitch
14
- @change="load($event)"
15
- ></CourseSectionSwitch>
16
- <v-spacer></v-spacer>
17
- <v-text-field
18
- v-model="search"
19
- class="ml-5 flex-grow-1"
20
- append-icon="mdi-magnify"
21
- :label="$t('shared.forms.search')"
22
- single-line
23
- hide-details
24
- ></v-text-field>
25
- </v-toolbar>
26
- </template>
27
-
28
- <template #item="{ index, item }">
29
- <tr>
30
- <td>{{ item.last_name }}</td>
31
- <td>{{ item.first_name }}</td>
32
- <td
33
- v-for="(block, blockIndex) in item.uploadBlocks"
34
- :key="blockIndex"
35
- class="grade-column"
36
- >
37
- <ManageDataTableUserFiles
38
- v-model="block.assets"
39
- :enrollment="block.enrollment"
40
- ></ManageDataTableUserFiles>
41
- </td>
42
- </tr>
43
- </template>
44
- </v-data-table>
45
- </v-container>
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-text-long',
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
  },