@windward/core 0.14.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/bitbucket-pipelines.yml +8 -0
  3. package/components/Content/Blocks/BlockQuote.vue +51 -47
  4. package/components/Content/Blocks/GenerateAIQuestionButton.vue +151 -37
  5. package/components/Content/Blocks/OpenResponse.vue +11 -3
  6. package/components/Content/Blocks/UserUpload/ManageDataTableUserFiles.vue +2 -11
  7. package/components/Content/Blocks/Video.vue +1 -1
  8. package/components/Glossary/GlossaryVerification.vue +240 -0
  9. package/components/Navigation/Items/GlossaryNav.vue +8 -2
  10. package/components/Navigation/Items/UserUploadNav.vue +32 -13
  11. package/components/Settings/AccordionSettings.vue +37 -27
  12. package/components/Settings/ClickableIconsSettings.vue +1 -0
  13. package/components/Settings/ImageSettings.vue +5 -12
  14. package/components/Settings/TabSettings.vue +33 -23
  15. package/components/Settings/TextEditorSettings.vue +16 -245
  16. package/components/Settings/VideoSettings.vue +1 -1
  17. package/components/utils/ContentViewer.vue +3 -3
  18. package/components/utils/TinyMCEWrapper.vue +24 -14
  19. package/components/utils/glossary/CourseGlossary.vue +75 -95
  20. package/components/utils/glossary/CourseGlossaryForm.vue +42 -13
  21. package/components/utils/glossary/GlossaryToolTip.vue +7 -11
  22. package/helpers/GlossaryHelper.ts +18 -16
  23. package/i18n/en-US/components/content/blocks/generate_questions.ts +26 -11
  24. package/i18n/en-US/pages/glossary.ts +3 -1
  25. package/i18n/en-US/shared/content_blocks.ts +1 -1
  26. package/i18n/en-US/shared/notification.ts +5 -0
  27. package/i18n/en-US/shared/permission.ts +4 -0
  28. package/i18n/en-US/shared/settings.ts +1 -1
  29. package/i18n/es-ES/components/content/blocks/generate_questions.ts +11 -1
  30. package/i18n/es-ES/pages/glossary.ts +3 -1
  31. package/i18n/es-ES/shared/content_blocks.ts +1 -1
  32. package/i18n/es-ES/shared/notification.ts +5 -0
  33. package/i18n/es-ES/shared/permission.ts +8 -4
  34. package/i18n/es-ES/shared/settings.ts +1 -2
  35. package/i18n/sv-SE/components/content/blocks/generate_questions.ts +11 -1
  36. package/i18n/sv-SE/pages/glossary.ts +3 -1
  37. package/i18n/sv-SE/shared/content_blocks.ts +1 -1
  38. package/i18n/sv-SE/shared/notification.ts +4 -0
  39. package/i18n/sv-SE/shared/permission.ts +8 -4
  40. package/i18n/sv-SE/shared/settings.ts +1 -1
  41. package/jest.config.js +3 -0
  42. package/models/BaseModel.ts +16 -0
  43. package/models/CourseGlossaryTerm.ts +22 -0
  44. package/models/UserFileAsset.ts +1 -0
  45. package/package.json +4 -3
  46. package/pages/glossary.vue +41 -4
  47. package/pages/userUpload.vue +70 -47
  48. package/plugin.js +34 -12
  49. package/store/glossary.js +57 -0
  50. package/test/Components/Content/Blocks/Feedback.spec.js +3 -1
  51. package/test/Components/Content/Blocks/Video.spec.js +2 -2
  52. package/test/Components/Glossary/GlossaryVerification.spec.js +19 -0
  53. package/test/Components/utils/glossary/CourseGlossary.spec.js +19 -0
  54. package/test/Components/utils/glossary/CourseGlossaryForm.spec.js +28 -0
  55. package/test/__mocks__/helpersMock.js +0 -24
  56. package/test/__mocks__/modelMock.js +5 -0
  57. package/test/helpers/GlossaryHelper.spec.js +32 -14
  58. package/test/mocks.js +11 -0
  59. package/test/setup/before.js +15 -0
  60. package/helpers/GlossaryTerm.ts +0 -31
@@ -1,38 +1,33 @@
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
  >
12
15
  <template #top>
13
- <v-toolbar flat>
16
+ <v-toolbar
17
+ v-if="
18
+ $PermissionService.userHasAccessTo(
19
+ 'plugin.windward.core.organization.course.glossary',
20
+ 'writable'
21
+ )
22
+ "
23
+ flat
24
+ >
14
25
  <DialogBox
15
26
  v-model="dialog"
16
27
  color="primary"
17
- max-width="600"
18
- :trigger="
19
- $PermissionService.userHasAccessTo(
20
- 'windward.global.course,windward.organization.course.contentBlock',
21
- 'writable'
22
- )
23
- "
24
- :action-save-new="
25
- $PermissionService.userHasAccessTo(
26
- 'windward.global.course,windward.organization.course.contentBlock',
27
- 'writable'
28
- )
29
- "
30
- :action-save="
31
- $PermissionService.userHasAccessTo(
32
- 'windward.global.course,windward.organization.course.contentBlock',
33
- 'writable'
34
- )
35
- "
28
+ trigger
29
+ action-save-new
30
+ action-save
36
31
  :disabled="disabled"
37
32
  @click:save="save"
38
33
  @click:save-new="saveNew"
@@ -43,9 +38,13 @@
43
38
  >
44
39
  <template #title>
45
40
  {{
46
- $t('shared.forms.add') +
47
- ' ' +
48
- $t('windward.core.pages.glossary.term')
41
+ selectedTerm.id
42
+ ? $t(
43
+ 'windward.core.pages.glossary.edit_term'
44
+ )
45
+ : $t(
46
+ 'windward.core.pages.glossary.add_term'
47
+ )
49
48
  }}
50
49
  </template>
51
50
  <template #trigger>
@@ -53,7 +52,7 @@
53
52
  {{ $t('shared.forms.add') }}
54
53
  </template>
55
54
  <template #form="{ on, attrs }">
56
- <course-glossary-form
55
+ <CourseGlossaryForm
57
56
  v-model="selectedTerm"
58
57
  :glossary="glossaryTerms"
59
58
  :edit-mode="editMode"
@@ -92,16 +91,23 @@
92
91
  </div>
93
92
  </v-row>
94
93
  </td>
95
- <td>{{ item.related_term }}</td>
94
+ <td>
95
+ <v-chip
96
+ v-for="related in item.related_terms"
97
+ :key="related.id"
98
+ >
99
+ {{ related.term }}
100
+ </v-chip>
101
+ </td>
96
102
 
97
103
  <td
98
104
  v-if="
99
105
  $PermissionService.userHasAccessTo(
100
- 'windward.global.course,windward.organization.contentBlock,windward.organization.course.contentBlock',
106
+ 'plugin.windward.core.organization.course.glossary',
101
107
  'writable'
102
- ) &&
108
+ ) ||
103
109
  $PermissionService.userHasAccessTo(
104
- 'windward.organization.current,windward.organization.section,windward.organization.course',
110
+ 'plugin.windward.core.organization.course.glossary',
105
111
  'deletable'
106
112
  )
107
113
  "
@@ -112,16 +118,16 @@
112
118
  :disabled="disabled"
113
119
  >
114
120
  <v-btn
121
+ v-if="
122
+ $PermissionService.userHasAccessTo(
123
+ 'plugin.windward.core.organization.course.glossary',
124
+ 'deletable'
125
+ )
126
+ "
115
127
  color="error"
116
128
  class="outlined"
117
129
  elevation="0"
118
130
  outlined
119
- :disabled="
120
- !$PermissionService.userHasAccessTo(
121
- 'windward.global.course,windward.organization.course.contentBlock',
122
- 'writable'
123
- )
124
- "
125
131
  @click="onDelete(item)"
126
132
  >
127
133
  {{ $t('shared.forms.delete') }}
@@ -130,16 +136,16 @@
130
136
  }}</span>
131
137
  </v-btn>
132
138
  <v-btn
139
+ v-if="
140
+ $PermissionService.userHasAccessTo(
141
+ 'plugin.windward.core.organization.course.glossary',
142
+ 'writable'
143
+ )
144
+ "
133
145
  color="primary"
134
146
  class="outlined"
135
147
  elevation="0"
136
148
  outlined
137
- :disabled="
138
- !$PermissionService.userHasAccessTo(
139
- 'windward.global.course,windward.organization.course.contentBlock',
140
- 'writable'
141
- )
142
- "
143
149
  @click="editTerm(item)"
144
150
  >
145
151
  {{ $t('shared.forms.edit') }}
@@ -158,19 +164,18 @@
158
164
  </template>
159
165
 
160
166
  <script>
161
- import { mapGetters, mapMutations } from 'vuex'
167
+ import { mapGetters, mapMutations, mapActions } from 'vuex'
162
168
  import _ from 'lodash'
163
- import { encode } from 'he'
169
+ import CourseGlossaryTerm from '../../../models/CourseGlossaryTerm'
164
170
  import CourseGlossaryForm from './CourseGlossaryForm'
165
171
  import DialogBox from '~/components/Core/DialogBox.vue'
166
172
  import Crypto from '~/helpers/Crypto'
167
173
  import Course from '~/models/Course'
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: {
@@ -180,22 +185,21 @@ export default {
180
185
  return {
181
186
  dialog: false,
182
187
  editMode: false,
183
- glossaryTerms: [],
184
188
  selectedTerm: {},
185
189
  search: '',
186
190
  tableKey: Crypto.id(),
187
191
  defaultTerm: {
188
192
  term: '',
189
193
  definition: '',
190
- alternate_forms: '',
191
- related_term: '',
194
+ alternate_forms: [],
195
+ related_terms: [],
192
196
  },
193
197
  }
194
198
  },
195
-
196
199
  computed: {
197
200
  ...mapGetters({
198
201
  course: 'course/get',
202
+ glossaryTerms: 'glossary/getTerms',
199
203
  }),
200
204
  ...mapMutations({
201
205
  saveCourse: 'course/set',
@@ -223,19 +227,19 @@ export default {
223
227
  value: 'alternate_forms',
224
228
  },
225
229
  {
226
- text: this.$t('windward.core.pages.glossary.related_term'),
230
+ text: this.$t('windward.core.pages.glossary.related_terms'),
227
231
  align: 'start',
228
232
  sortable: true,
229
- value: 'related_term',
233
+ value: 'related_terms',
230
234
  },
231
235
  ]
232
236
  if (
233
237
  this.$PermissionService.userHasAccessTo(
234
- 'windward.global.course,windward.organization.contentBlock,windward.organization.course.contentBlock',
238
+ 'plugin.windward.core.organization.course.glossary',
235
239
  'writable'
236
- ) &&
240
+ ) ||
237
241
  this.$PermissionService.userHasAccessTo(
238
- 'windward.organization.current,windward.organization.section,windward.organization.course',
242
+ 'plugin.windward.core.organization.course.glossary',
239
243
  'deletable'
240
244
  )
241
245
  ) {
@@ -248,40 +252,19 @@ export default {
248
252
  return headers
249
253
  },
250
254
  },
251
-
252
- beforeMount() {
253
- if (this.course.metadata && _.isArray(this.course.metadata.glossary)) {
254
- this.glossaryTerms = _.cloneDeep(this.course.metadata.glossary)
255
- }
256
- },
257
255
  methods: {
256
+ ...mapActions({
257
+ reloadGlossary: 'glossary/load',
258
+ }),
258
259
  async save() {
259
- let currentGlossaryItemIndex = -1
260
- this.glossaryTerms.filter((item, index) => {
261
- if (item.term === this.selectedTerm.term) {
262
- currentGlossaryItemIndex = index
263
- return item
264
- }
265
- })
266
- if (currentGlossaryItemIndex > -1) {
267
- this.glossaryTerms[currentGlossaryItemIndex] = this.selectedTerm
268
- } else {
269
- this.glossaryTerms.push(this.selectedTerm)
270
- }
271
- const course = new Course(_.cloneDeep(this.course))
272
- if (
273
- !course.hasOwnProperty('metadata') ||
274
- course.metadata === null
275
- ) {
276
- course.metadata = {}
277
- course.metadata.glossary = {}
278
- }
260
+ // Save the term
261
+ await new CourseGlossaryTerm(_.cloneDeep(this.selectedTerm))
262
+ .for(new Course(this.course))
263
+ .save()
264
+
265
+ // And update our local list
266
+ this.reloadGlossary(this.course)
279
267
 
280
- if (course.metadata.glossary !== undefined) {
281
- course.metadata.glossary = this.glossaryTerms
282
- }
283
- const updatedCourse = await course.save()
284
- this.$store.commit('course/set', updatedCourse)
285
268
  this.$toast.success(this.$t('shared.forms.saved'))
286
269
  // force update on datatable
287
270
  this.tableKey = Crypto.id()
@@ -327,16 +310,13 @@ export default {
327
310
  })
328
311
  },
329
312
  async deleteTerm(item) {
330
- const deleteIndex = this.glossaryTerms.indexOf(item)
331
- this.glossaryTerms.splice(deleteIndex, 1)
332
- const course = new Course(this.course)
333
- if (_.isEmpty(course.metadata)) {
334
- course.metadata = {}
335
- course.metadata.glossary = {}
336
- }
337
- course.metadata.glossary = this.glossaryTerms
338
- const updatedCourse = await course.save()
339
- this.$store.commit('course/set', updatedCourse)
313
+ // Delete the term
314
+ await new CourseGlossaryTerm(_.cloneDeep(item))
315
+ .for(new Course(this.course))
316
+ .delete()
317
+
318
+ // And update our local list
319
+ this.reloadGlossary(this.course)
340
320
  this.$toast.success(this.$t('shared.response.deleted'))
341
321
  },
342
322
  close() {
@@ -7,7 +7,7 @@
7
7
  :label="$t('windward.core.pages.glossary.term')"
8
8
  required
9
9
  :rules="validation.termRules"
10
- :disabled="editMode"
10
+ :disabled="editMode || disabled"
11
11
  ></v-text-field>
12
12
  <br />
13
13
  <v-textarea
@@ -16,6 +16,7 @@
16
16
  outlined
17
17
  required
18
18
  :rules="validation.definitionRules"
19
+ :disabled="disabled"
19
20
  ></v-textarea>
20
21
  <br />
21
22
  <v-combobox
@@ -25,12 +26,14 @@
25
26
  :label="$t('windward.core.pages.glossary.alternate_forms')"
26
27
  multiple
27
28
  solo
29
+ :disabled="disabled"
28
30
  >
29
- <template v-slot:selection="{ attrs, item, select, selected }">
31
+ <template #selection="{ attrs, item, select, selected }">
30
32
  <v-chip
31
33
  v-bind="attrs"
32
34
  :input-value="selected"
33
35
  close
36
+ :disabled="disabled"
34
37
  @click:close="removeAlternateForm(item)"
35
38
  >
36
39
  <strong>{{ item }}</strong>
@@ -38,17 +41,22 @@
38
41
  </template>
39
42
  </v-combobox>
40
43
  <br />
41
- <v-select
42
- v-model="selectedTerm.related_term"
44
+ <v-autocomplete
45
+ v-model="selectedTerm.related_terms"
43
46
  :items="termList"
47
+ item-text="term"
48
+ return-object
44
49
  outlined
45
50
  clearable
46
- :label="$t('windward.core.pages.glossary.related_term')"
47
- ></v-select>
51
+ multiple
52
+ :disabled="disabled"
53
+ :label="$t('windward.core.pages.glossary.related_terms')"
54
+ ></v-autocomplete>
48
55
  </v-form>
49
56
  </template>
50
57
 
51
58
  <script>
59
+ import _ from 'lodash'
52
60
  import Form from '~/components/Core/Form'
53
61
  export default {
54
62
  name: 'CourseGlossaryForm',
@@ -57,17 +65,23 @@ export default {
57
65
  value: { type: Object, required: true },
58
66
  glossary: { type: Array, required: true },
59
67
  editMode: { type: Boolean, required: false, default: false },
68
+ disabled: { type: Boolean, required: false, default: false },
60
69
  },
61
70
  data() {
62
71
  return {
63
- selectedTerm: {},
72
+ selectedTerm: {
73
+ term: '',
74
+ definition: '',
75
+ alternate_forms: [],
76
+ related_terms: [],
77
+ },
64
78
  relatedTerm: [],
65
79
  validation: {
66
80
  termRules: [
67
81
  (v) => !!v || this.$t('shared.forms.errors.required'),
68
82
  (v) =>
69
83
  (v && v.length <= 50) ||
70
- this.$t('forms.errors.text_lt', [50]),
84
+ this.$t('shared.forms.errors.text_lt', [50]),
71
85
  (v) =>
72
86
  (v && this.termIsUnique(v)) ||
73
87
  this.$t('shared.forms.errors.field_unique'),
@@ -84,18 +98,33 @@ export default {
84
98
  computed: {
85
99
  termList() {
86
100
  return this.glossary.flatMap((item) => {
87
- if (this.selectedTerm.term !== item.term) return item.term
101
+ if (this.selectedTerm.term !== item.term) return item
88
102
  })
89
103
  },
90
104
  },
91
105
  watch: {
92
- value() {
93
- // Refresh the question model when we open / close the dialog
94
- this.selectedTerm = this.value
106
+ value: {
107
+ deep: true,
108
+ handler(newValue) {
109
+ // Refresh the question model when we open / close the dialog
110
+ this.selectedTerm = _.merge(
111
+ this.selectedTerm,
112
+ _.cloneDeep(newValue)
113
+ )
114
+ },
115
+ },
116
+ selectedTerm: {
117
+ deep: true,
118
+ handler(newValue) {
119
+ if (!_.isEqual(newValue, this.value)) {
120
+ this.$emit('input', newValue)
121
+ }
122
+ },
95
123
  },
96
124
  },
97
125
  mounted() {
98
- this.selectedTerm = this.value
126
+ // Merge to preserve keys in case the value is an empty object for new glossary terms
127
+ this.selectedTerm = _.merge(this.selectedTerm, _.cloneDeep(this.value))
99
128
  },
100
129
  methods: {
101
130
  termIsUnique(term) {
@@ -8,11 +8,7 @@
8
8
  :z-index="20"
9
9
  >
10
10
  <template #activator="{ on }">
11
- <span
12
- tabindex="0"
13
- v-on="on"
14
- @click.stop="show = !show"
15
- >
11
+ <span tabindex="0" v-on="on" @click.stop="show = !show">
16
12
  <slot name="term"></slot>
17
13
  </span>
18
14
  </template>
@@ -34,7 +30,7 @@
34
30
  </p>
35
31
  </div>
36
32
  <div v-if="$slots['alternate_forms']">
37
- <h4 class="text-capitalize">
33
+ <h6 class="text-capitalize">
38
34
  <slot name="term"></slot>
39
35
  {{
40
36
  $t(
@@ -42,19 +38,19 @@
42
38
  )
43
39
  }}
44
40
  :
45
- </h4>
41
+ </h6>
46
42
  <p><slot name="alternate_forms"></slot></p>
47
43
  </div>
48
44
 
49
45
  <div v-if="$slots['related_terms']">
50
- <h4 class="text-capitalize">
46
+ <h6 class="text-capitalize">
51
47
  {{
52
48
  $t(
53
49
  'windward.core.components.utils.tiny_mce_wrapper.related_terms'
54
50
  )
55
51
  }}
56
52
  :
57
- </h4>
53
+ </h6>
58
54
  <p><slot name="related_terms"></slot></p>
59
55
  </div>
60
56
  </v-card-text>
@@ -68,12 +64,12 @@ export default {
68
64
  name: 'GlossaryToolTip',
69
65
  data() {
70
66
  return {
71
- show: false
67
+ show: false,
72
68
  }
73
69
  },
74
70
  beforeDestroy() {
75
71
  this.show = false
76
- }
72
+ },
77
73
  }
78
74
  </script>
79
75
 
@@ -1,28 +1,30 @@
1
1
  import * as _ from 'lodash'
2
2
  import { decode } from 'he'
3
- import GlossaryTerm from '../helpers/GlossaryTerm'
3
+ import CourseGlossaryTerm from '../models/CourseGlossaryTerm'
4
4
 
5
5
  export default class GlossaryHelper {
6
6
  private static glossaryRegex =
7
7
  /<span.*?.class="glossary-word".*?>(.*?)<\/span>/g
8
8
 
9
- public static makeToolTip(term: GlossaryTerm, text: String): string {
9
+ public static makeToolTip(term: CourseGlossaryTerm, text: String): string {
10
10
  const word = _.isString(term.term)
11
11
  ? '<template v-slot:term>' + text + '</template>'
12
12
  : ''
13
13
  const definition = _.isString(term.definition)
14
14
  ? '<template v-slot:definition>' + term.definition + '</template>'
15
15
  : ''
16
- const alternate_forms = _.isString(term.alternate_forms)
17
- ? '<template v-slot:alternate_forms>' +
18
- term.alternate_forms +
19
- '</template>'
20
- : ''
21
- const related_terms = _.isString(term.related_term)
22
- ? '<template v-slot:related_terms>' +
23
- term.related_term +
24
- '</template>'
25
- : ''
16
+ const alternate_forms =
17
+ _.isArray(term.alternate_forms) && term.alternate_forms.length > 0
18
+ ? '<template v-slot:alternate_forms>' +
19
+ term.alternate_forms.join(',') +
20
+ '</template>'
21
+ : ''
22
+ const related_terms =
23
+ _.isArray(term.related_terms) && term.related_terms.length > 0
24
+ ? '<template v-slot:related_terms>' +
25
+ term.related_terms.map((t) => t.term).join(',') +
26
+ '</template>'
27
+ : ''
26
28
  return (
27
29
  '<plugin-core-glossary-tool-tip>' +
28
30
  word +
@@ -47,7 +49,7 @@ export default class GlossaryHelper {
47
49
  const currentGlossary = glossary
48
50
 
49
51
  let match: any
50
- const verifiedTerms: GlossaryTerm[] = []
52
+ const verifiedTerms: CourseGlossaryTerm[] = []
51
53
  while ((match = regex.exec(content)) !== null) {
52
54
  // This is necessary to avoid infinite loops with zero-width matches
53
55
  if (match.index === regex.lastIndex) {
@@ -78,7 +80,7 @@ export default class GlossaryHelper {
78
80
  ))) &&
79
81
  addTerm
80
82
  ) {
81
- verifiedTerms.push(new GlossaryTerm(term))
83
+ verifiedTerms.push(new CourseGlossaryTerm(term))
82
84
  }
83
85
  })
84
86
  }
@@ -97,7 +99,7 @@ export default class GlossaryHelper {
97
99
  content,
98
100
  glossary
99
101
  )
100
- const unVerifiedTerms: GlossaryTerm[] = []
102
+ const unVerifiedTerms: CourseGlossaryTerm[] = []
101
103
  while ((match = regex.exec(content)) !== null) {
102
104
  // This is necessary to avoid infinite loops with zero-width matches
103
105
  if (match.index === regex.lastIndex) {
@@ -134,7 +136,7 @@ export default class GlossaryHelper {
134
136
  })
135
137
  if (inGlossary.length === 0 && !inUnverifiedArray) {
136
138
  unVerifiedTerms.push(
137
- new GlossaryTerm({
139
+ new CourseGlossaryTerm({
138
140
  term: _.trim(match[1]),
139
141
  definition: 'n/a',
140
142
  })
@@ -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
  }
@@ -1,7 +1,9 @@
1
1
  export default {
2
2
  title: 'Course Glossary',
3
3
  term: 'Term',
4
- related_term: 'Related Term',
4
+ add_term: 'Add Term',
5
+ edit_term: 'Edit Term',
6
+ related_terms: 'Related Terms',
5
7
  definition: 'definition',
6
8
  alternate_forms: 'Alternate Forms',
7
9
  }
@@ -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',
@@ -9,5 +9,10 @@ export default {
9
9
  'windward-core-ask-the-expert': 'Course Ask the Expert',
10
10
  'windward-core-contact-support': 'Course Contact Support',
11
11
  },
12
+
13
+ type_recipient_address: {
14
+ 'windward-core-ask-the-expert': '{{courseowner->email}}',
15
+ 'windward-core-contact-support': '',
16
+ },
12
17
  },
13
18
  }
@@ -4,6 +4,8 @@ export default {
4
4
  'Feedback access for the current user',
5
5
  'plugin->windward->core->organization->course->user->userUpload':
6
6
  'User upload block access for the current user',
7
+ 'plugin->windward->core->organization->course->glossary':
8
+ 'Course Glossary',
7
9
  },
8
10
 
9
11
  type_description: {
@@ -11,5 +13,7 @@ export default {
11
13
  'The current users access to the feedback block',
12
14
  'plugin->windward->core->organization->course->user->userUpload':
13
15
  'The current users access to the user upload block',
16
+ 'plugin->windward->core->organization->course->glossary':
17
+ 'Access and manage the course glossary in the current organization for your own courses',
14
18
  },
15
19
  }