@windward/integrations 0.19.1 → 0.21.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 (29) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/components/Content/Blocks/ActionPanel/TransformBlock.vue +776 -0
  3. package/components/LLM/GenerateContent/AssessmentQuestionGenerateButton.vue +180 -9
  4. package/components/LLM/GenerateContent/BlockQuestionGenerateButton.vue +35 -13
  5. package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +18 -12
  6. package/helpers/ExternalIntegration/ScormHelper.ts +1 -1
  7. package/i18n/en-US/components/content/blocks/action_panel/index.ts +5 -0
  8. package/i18n/en-US/components/content/blocks/action_panel/transform_block.ts +9 -0
  9. package/i18n/en-US/components/content/blocks/external_integration/lti_consumer.ts +2 -2
  10. package/i18n/en-US/components/content/blocks/index.ts +2 -0
  11. package/i18n/en-US/components/llm/generate_content/generate_questions.ts +4 -0
  12. package/i18n/en-US/components/llm/generate_content/index.ts +1 -0
  13. package/i18n/en-US/shared/settings.ts +1 -2
  14. package/i18n/es-ES/components/content/blocks/action_panel/index.ts +5 -0
  15. package/i18n/es-ES/components/content/blocks/action_panel/transform_block.ts +9 -0
  16. package/i18n/es-ES/components/content/blocks/external_integration/lti_consumer.ts +2 -2
  17. package/i18n/es-ES/components/content/blocks/index.ts +2 -0
  18. package/i18n/es-ES/components/llm/generate_content/generate_questions.ts +5 -0
  19. package/i18n/es-ES/components/llm/generate_content/index.ts +1 -0
  20. package/i18n/es-ES/shared/settings.ts +1 -2
  21. package/i18n/sv-SE/components/content/blocks/action_panel/index.ts +5 -0
  22. package/i18n/sv-SE/components/content/blocks/action_panel/transform_block.ts +9 -0
  23. package/i18n/sv-SE/components/content/blocks/external_integration/lti_consumer.ts +2 -2
  24. package/i18n/sv-SE/components/content/blocks/index.ts +2 -0
  25. package/i18n/sv-SE/components/llm/generate_content/generate_questions.ts +5 -0
  26. package/i18n/sv-SE/components/llm/generate_content/index.ts +1 -0
  27. package/i18n/sv-SE/shared/settings.ts +1 -2
  28. package/package.json +1 -1
  29. package/plugin.js +21 -5
@@ -17,6 +17,13 @@
17
17
  :disabled="isLoading || disabled"
18
18
  ></BloomTaxonomySelector>
19
19
  </v-col>
20
+ <v-col v-if="questionType !== 'true_false'" cols="12">
21
+ <v-switch
22
+ v-model="keepExisting"
23
+ :disabled="isLoading || disabled"
24
+ :label="$t('windward.integrations.components.llm.generate_content.keep_existing_inputs')"
25
+ ></v-switch>
26
+ </v-col>
20
27
  <v-col cols="12">
21
28
  <v-btn
22
29
  elevation="0"
@@ -84,6 +91,7 @@ export default {
84
91
  showLoadingText: false,
85
92
  selectedContent: null,
86
93
  selectedDifficulty: null,
94
+ keepExisting: true,
87
95
  }
88
96
  },
89
97
  computed: {
@@ -116,6 +124,118 @@ export default {
116
124
  },
117
125
  },
118
126
  methods: {
127
+ buildClearedQuestion() {
128
+ const type = this.questionType
129
+ const cleared = {
130
+ question_type: type,
131
+ assessment_question_type_id: _.get(this.value, 'assessment_question_type_id', null),
132
+ body: '',
133
+ question_metadata: {},
134
+ answer_metadata: {},
135
+ metadata: {},
136
+ }
137
+
138
+ if (type === 'multi_choice_single_answer' || type === 'multi_choice_multi_answer') {
139
+ cleared.question_metadata = { options: [] }
140
+ cleared.answer_metadata = { feedback: {} }
141
+ } else if (type === 'matching_text') {
142
+ cleared.question_metadata = { prompts: [], choices: [] }
143
+ cleared.answer_metadata = { map: [], feedback: {} }
144
+ } else if (type === 'ordering') {
145
+ cleared.question_metadata = { prompts: [] }
146
+ cleared.answer_metadata = { map: [], feedback: {} }
147
+ } else if (type === 'fill_in_the_blank') {
148
+ cleared.question_metadata = _.get(this.value, 'question_metadata', {}) || {}
149
+ cleared.answer_metadata = { correct_answer_options: [], feedback: {} }
150
+ }
151
+
152
+ return cleared
153
+ },
154
+ buildExistingInputs() {
155
+ const q = _.cloneDeep(this.value) || {}
156
+ const type = this.questionType
157
+
158
+ const nonEmpty = (s) => typeof s === 'string' && s.replace(/<[^>]*>/g, '').trim().length > 0
159
+
160
+ const base = { body: q.body || '' }
161
+
162
+ if (type === 'multi_choice_single_answer' || type === 'multi_choice_multi_answer') {
163
+ const options = _.get(q, 'question_metadata.options', [])
164
+ const cleanedOptions = options.map((o, i) => ({ id: o.id || `option_${i}`, body: o.body || '' }))
165
+ const answerMeta = _.get(q, 'answer_metadata', {})
166
+ return {
167
+ ...base,
168
+ question_type: type,
169
+ question_metadata: { options: cleanedOptions },
170
+ answer_metadata: {
171
+ correct_id: answerMeta.correct_id,
172
+ correct_ids: answerMeta.correct_ids,
173
+ feedback: answerMeta.feedback || {},
174
+ },
175
+ }
176
+ }
177
+
178
+ if (type === 'matching_text') {
179
+ const prompts = _.get(q, 'question_metadata.prompts', []).map((p) => ({ id: p.id, body: p.body || '' }))
180
+ const choices = _.get(q, 'question_metadata.choices', []).map((c, i) => ({ id: c.id, letter_id: c.letter_id || String.fromCharCode(65 + i), body: c.body || '' }))
181
+ const map = _.get(q, 'answer_metadata.map', [])
182
+ return {
183
+ ...base,
184
+ question_type: type,
185
+ question_metadata: { prompts, choices },
186
+ answer_metadata: { map, feedback: _.get(q, 'answer_metadata.feedback', {}) },
187
+ }
188
+ }
189
+
190
+ if (type === 'ordering') {
191
+ const prompts = _.get(q, 'question_metadata.prompts', []).map((p) => ({ id: p.id, body: p.body || '' }))
192
+ const map = _.get(q, 'answer_metadata.map', [])
193
+ return {
194
+ ...base,
195
+ question_type: type,
196
+ question_metadata: { prompts },
197
+ answer_metadata: { map, feedback: _.get(q, 'answer_metadata.feedback', {}) },
198
+ }
199
+ }
200
+
201
+ if (type === 'fill_in_the_blank') {
202
+ const corrects = _.get(q, 'answer_metadata.correct_answer_options', [])
203
+ return {
204
+ ...base,
205
+ question_type: type,
206
+ question_metadata: _.get(q, 'question_metadata', {}),
207
+ answer_metadata: {
208
+ correct_id: _.get(q, 'answer_metadata.correct_id'),
209
+ correct_answer_options: corrects.map((c) => ({ id: c.id, answer: c.answer || '' })),
210
+ feedback: _.get(q, 'answer_metadata.feedback', {}),
211
+ },
212
+ }
213
+ }
214
+
215
+ return base
216
+ },
217
+ hasAnyExistingInput(snapshot) {
218
+ if (!snapshot) return false
219
+ if (snapshot.body && snapshot.body.replace(/<[^>]*>/g, '').trim().length > 0) return true
220
+ const qm = snapshot.question_metadata || {}
221
+ if (Array.isArray(qm.options)) {
222
+ return qm.options.some((o) => (o.body || '').replace(/<[^>]*>/g, '').trim().length > 0)
223
+ }
224
+ if (Array.isArray(qm.prompts)) {
225
+ return qm.prompts.some((p) => (p.body || '').replace(/<[^>]*>/g, '').trim().length > 0)
226
+ }
227
+ if (Array.isArray(qm.choices)) {
228
+ return qm.choices.some((c) => (c.body || '').replace(/<[^>]*>/g, '').trim().length > 0)
229
+ }
230
+ const am = snapshot.answer_metadata || {}
231
+ if (Array.isArray(am.correct_answer_options)) {
232
+ return am.correct_answer_options.some((c) => (c.answer || '').trim().length > 0)
233
+ }
234
+ if (am.feedback && typeof am.feedback.question === 'string' && am.feedback.question.trim().length > 0) {
235
+ return true
236
+ }
237
+ return false
238
+ },
119
239
  async generateAIQuestion() {
120
240
  this.isLoading = true
121
241
 
@@ -133,23 +253,64 @@ export default {
133
253
  // ASSESSMENT QUESTION GENERATION
134
254
  const assessment = new Assessment({ id: this.block.id })
135
255
 
136
- const responseBuilder = AssessmentQuestion.custom(
256
+ const endpointBuilder = AssessmentQuestion.custom(
137
257
  course,
138
258
  content,
139
259
  assessment,
140
260
  `suggest-questions`
141
- ).where('question_type', this.questionType)
261
+ )
262
+
263
+ let response
264
+ if (this.keepExisting) {
265
+ const existingInputs = this.buildExistingInputs()
266
+ const hasExisting = this.hasAnyExistingInput(existingInputs)
142
267
 
143
- // Apply blooms level filter if it's not 'None'
144
- if (this.selectedDifficulty !== 'None') {
145
- responseBuilder.where(
146
- 'blooms_level',
147
- this.selectedDifficulty
268
+ if (hasExisting) {
269
+ const payload = {
270
+ filter: {
271
+ question_type: this.questionType,
272
+ // Do not include blooms when preserving existing inputs
273
+ },
274
+ keep_existing_inputs: true,
275
+ existing_inputs: existingInputs,
276
+ }
277
+
278
+ response = await AssessmentQuestion.config({
279
+ method: 'POST',
280
+ data: payload,
281
+ })
282
+ .custom(course, content, assessment, `suggest-questions`)
283
+ .get()
284
+ } else {
285
+ // Treat as replace flow if no existing inputs
286
+ const builder = endpointBuilder.where(
287
+ 'question_type',
288
+ this.questionType
289
+ )
290
+ if (this.selectedDifficulty !== 'None') {
291
+ builder.where('blooms_level', this.selectedDifficulty)
292
+ }
293
+ response = await builder.get()
294
+ }
295
+ } else {
296
+ // Replace flow (legacy behavior)
297
+ // Explicitly clear all existing inputs before generating
298
+ try {
299
+ const cleared = this.buildClearedQuestion()
300
+ this.$emit('input', cleared)
301
+ } catch (e) {
302
+ // no-op if emit fails
303
+ }
304
+ const builder = endpointBuilder.where(
305
+ 'question_type',
306
+ this.questionType
148
307
  )
308
+ if (this.selectedDifficulty !== 'None') {
309
+ builder.where('blooms_level', this.selectedDifficulty)
310
+ }
311
+ response = await builder.get()
149
312
  }
150
313
 
151
- const response = await responseBuilder.get()
152
-
153
314
  if (response && response.length > 0) {
154
315
  const generatedQuestion = response[0]
155
316
 
@@ -196,6 +357,16 @@ export default {
196
357
  'An error occurred while generating content. Try generating again.'
197
358
  ) {
198
359
  errorText = this.$t(`${basePath}.character_limit`)
360
+ } else if (
361
+ (errorMessage === 'assessment.error.content_mismatch' ||
362
+ errorType === 'content_mismatch') &&
363
+ errorSubtype === 'INITIAL_INPUTS_NOT_RELATED'
364
+ ) {
365
+ // Inputs (question/correct answer) are unrelated to the course/page content
366
+ errorText =
367
+ this.$t(`${basePath}.inputs_unrelated`) +
368
+ '\\n\\n' +
369
+ this.$t(`${basePath}.inputs_unrelated_support`)
199
370
  } else if (
200
371
  errorType === 'insufficient_content' &&
201
372
  error.response?.data?.error?.details
@@ -1,35 +1,41 @@
1
1
  <template>
2
2
  <div>
3
3
  <v-row class="container-generate-ai mt-2">
4
- <v-col>{{
4
+ <v-col cols="12" sm="auto" class="d-flex align-center">{{
5
5
  $t('windward.integrations.components.llm.ai_assistance')
6
6
  }}</v-col>
7
- <v-col>
7
+ <v-col cols="12" sm>
8
8
  <ContentSelector
9
9
  v-model="selectedContent"
10
10
  :disabled="isLoading || disabled"
11
11
  ></ContentSelector>
12
12
  </v-col>
13
- <v-col>
13
+ <v-col cols="12" sm class="bloom-taxonomy-col">
14
14
  <BloomTaxonomySelector
15
15
  v-model="selectedDifficulty"
16
16
  :levels="taxonomyLevels"
17
17
  :advanced-levels="isMultipleChoiceType ? false : hasAdvancedBlooms"
18
18
  :disabled="isLoading || disabled"
19
- :hide-details="!isBucketGameType"
19
+ hide-details
20
20
  ></BloomTaxonomySelector>
21
21
 
22
- <div v-if="true || isBucketGameType" class="text-caption mt-1">
23
- {{
24
- $t(
25
- 'windward.integrations.components.llm.generate_content.generate_questions.replaces_content'
26
- )
27
- }}
22
+ <div class="caption-container">
23
+ <div
24
+ class="text-caption mt-1"
25
+ :style="{ visibility: isBucketGameType ? 'visible' : 'hidden' }"
26
+ >
27
+ {{
28
+ $t(
29
+ 'windward.integrations.components.llm.generate_content.generate_questions.replaces_content'
30
+ )
31
+ }}
32
+ </div>
28
33
  </div>
29
34
  </v-col>
30
35
  <v-col
31
36
  v-if="showReplaceExistingToggle"
32
- cols="auto"
37
+ cols="12"
38
+ sm="auto"
33
39
  class="d-flex align-center"
34
40
  >
35
41
  <v-switch
@@ -42,11 +48,11 @@
42
48
  :disabled="isLoading"
43
49
  ></v-switch>
44
50
  </v-col>
45
- <v-col>
51
+ <v-col cols="12" class="button-col">
46
52
  <v-btn
47
53
  elevation="0"
48
54
  color="secondary"
49
- class="mb-1 btn-selector"
55
+ class="btn-selector"
50
56
  :loading="isLoading"
51
57
  :disabled="isLoading"
52
58
  @click="generateAIQuestion"
@@ -542,4 +548,20 @@ export default {
542
548
  outline: 1px solid var(--v-secondary-base);
543
549
  border-radius: $border-radius-root;
544
550
  }
551
+ .bloom-taxonomy-col {
552
+ display: flex;
553
+ flex-direction: column;
554
+ }
555
+ .caption-container {
556
+ min-height: 28px;
557
+ display: flex;
558
+ align-items: flex-start;
559
+ }
560
+ .button-col {
561
+ display: flex;
562
+ align-items: flex-start;
563
+ }
564
+ .switch-col {
565
+ align-self: flex-start !important;
566
+ }
545
567
  </style>
@@ -7,18 +7,6 @@
7
7
  <br />
8
8
  <v-divider class="primary"></v-divider>
9
9
  <br />
10
- <v-select
11
- v-model="block.metadata.config.launch_type"
12
- :label="
13
- $t(
14
- 'windward.integrations.components.settings.external_integration.lti_consumer.launch_type'
15
- )
16
- "
17
- :items="launchTypes"
18
- item-text="name"
19
- item-value="value"
20
- :disabled="render"
21
- ></v-select>
22
10
  {{
23
11
  $t(
24
12
  'windward.integrations.components.settings.external_integration.lti_consumer.link_select'
@@ -65,6 +53,18 @@
65
53
  </v-list-item>
66
54
  </v-list-item-group>
67
55
  </v-list>
56
+ <v-select
57
+ v-model="block.metadata.config.launch_type"
58
+ :label="
59
+ $t(
60
+ 'windward.integrations.components.settings.external_integration.lti_consumer.launch_type'
61
+ )
62
+ "
63
+ :items="launchTypes"
64
+ item-text="name"
65
+ item-value="value"
66
+ :disabled="render"
67
+ ></v-select>
68
68
  </v-container>
69
69
  </template>
70
70
 
@@ -75,6 +75,7 @@ import Course from '~/models/Course'
75
75
  import Organization from '~/models/Organization'
76
76
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
77
77
  import Consumer from '../../../models/ExternalIntegration/Consumer'
78
+ import _ from 'lodash'
78
79
 
79
80
  export default {
80
81
  name: 'ContentBlockExternalIntegrationLti1p1ConsumerSettings',
@@ -161,6 +162,11 @@ export default {
161
162
  if (!_.isBoolean(this.block.metadata.config.display_title)) {
162
163
  this.$set(this.block.metadata.config, 'display_title', true)
163
164
  }
165
+ if (_.isEmpty(this.block.metadata.config.title)) {
166
+ this.block.metadata.config.title = this.$t(
167
+ 'windward.integrations.components.content.blocks.external_integration.lti_consumer.title'
168
+ )
169
+ }
164
170
  },
165
171
  mounted() {},
166
172
  methods: {},
@@ -80,7 +80,7 @@ export default class ScormHelper {
80
80
  return
81
81
  }
82
82
 
83
- const payload = {
83
+ const payload: any = {
84
84
  type: 'update:tracking',
85
85
  launch_config: this.getLaunchConfig(),
86
86
  url: null,
@@ -0,0 +1,5 @@
1
+ import transformBlock from './transform_block'
2
+
3
+ export default {
4
+ transform_block: transformBlock,
5
+ }
@@ -0,0 +1,9 @@
1
+ export default {
2
+ change_block_type: 'Change block type',
3
+ change_block_type_insufficient_paragraphs:
4
+ 'Change block type is available when the text has at least two paragraphs.',
5
+ change_block_type_insufficient_items:
6
+ 'Change block type is available when the block has at least two items.',
7
+ change_block_type_error:
8
+ 'Unable to change block type. Try again or edit manually.',
9
+ }
@@ -1,5 +1,5 @@
1
1
  export default {
2
- title: 'LTI Consumer Block Title',
2
+ title: 'LTI Link',
3
3
  instructions:
4
4
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fringilla ipsum eget ante tempus blandit. Maecenas vel massa\n' +
5
5
  'nec tellus vestibulum porttitor non a enim.',
@@ -8,7 +8,7 @@ export default {
8
8
  launch_in_new_window: 'launch {0} in new tab',
9
9
  launch_in_modal: 'launch {0} in modal',
10
10
  configure_warning:
11
- 'This block needs to be configured. Please select a LTI tool in the settings panel.',
11
+ 'Select an available LTI link to get started. Then, configure the desired launch type.',
12
12
  no_access:
13
13
  'You do not have permissions to launch this link. Please contact your system administrator.',
14
14
  missing_tool: 'The tool id {0} is missing',
@@ -1,5 +1,7 @@
1
+ import actionPanel from './action_panel'
1
2
  import externalIntegration from './external_integration'
2
3
 
3
4
  export default {
4
5
  external_integration: externalIntegration,
6
+ action_panel: actionPanel,
5
7
  }
@@ -51,6 +51,10 @@ export default {
51
51
  content_mismatch_multiple_choice_support:
52
52
  'Consider adding clear expository text with distinct concepts, definitions, or examples that support question and distractor creation.',
53
53
 
54
+ inputs_unrelated: 'Your question or correct answer is unrelated to this page\'s content.',
55
+ inputs_unrelated_support:
56
+ 'Provide a question and/or correct answer that clearly relates to the selected page. Use terms, facts, or examples present on the page so the assistant can complete the remaining inputs.',
57
+
54
58
  character_limit:
55
59
  'An error occurred while generating content. Try generating again.',
56
60
  character_limit_detailed:
@@ -4,4 +4,5 @@ import fakeTextStream from './fake_text_stream'
4
4
  export default {
5
5
  generate_questions: generateQuestions,
6
6
  fake_text_stream: fakeTextStream,
7
+ keep_existing_inputs: 'Keep existing inputs',
7
8
  }
@@ -1,7 +1,6 @@
1
1
  export default {
2
2
  title: {
3
- lti_consumer: 'LTI Consumer',
4
- scorm_consumer: 'SCORM Consumer',
3
+ block_builder: 'Block Builder',
5
4
  ai_chat: 'AI Chat',
6
5
  },
7
6
  errors: {
@@ -0,0 +1,5 @@
1
+ import transformBlock from './transform_block'
2
+
3
+ export default {
4
+ transform_block: transformBlock,
5
+ }
@@ -0,0 +1,9 @@
1
+ export default {
2
+ change_block_type: 'Cambiar tipo de bloque',
3
+ change_block_type_insufficient_paragraphs:
4
+ 'Cambiar el tipo de bloque está disponible cuando el texto tiene al menos dos párrafos.',
5
+ change_block_type_insufficient_items:
6
+ 'Cambiar el tipo de bloque está disponible cuando el bloque tiene al menos dos elementos.',
7
+ change_block_type_error:
8
+ 'No se puede cambiar el tipo de bloque. Inténtalo de nuevo o edítalo manualmente.',
9
+ }
@@ -1,5 +1,5 @@
1
1
  export default {
2
- title: 'LTI Consumer Block Title',
2
+ title: 'Enlace LTI',
3
3
  instructions:
4
4
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fringilla ipsum eget ante tempus blandit. Maecenas vel massa\n' +
5
5
  'nec tellus vestibulum porttitor non a enim.',
@@ -8,7 +8,7 @@ export default {
8
8
  launch_in_new_window: 'lansera {0} i ny flik',
9
9
  launch_in_modal: 'lansera {0} i modal',
10
10
  configure_warning:
11
- 'Detta block måste konfigureras. Välj ett LTI-verktyg i inställningspanelen.',
11
+ 'Seleccione un enlace LTI disponible para comenzar. Luego, configure el tipo de lanzamiento deseado.',
12
12
  no_access:
13
13
  'Du har inte behörighet att starta den här länken. Kontakta din systemadministratör.',
14
14
  missing_tool: 'Verktygs-ID {0} saknas',
@@ -1,5 +1,7 @@
1
+ import actionPanel from './action_panel'
1
2
  import externalIntegration from './external_integration'
2
3
 
3
4
  export default {
4
5
  external_integration: externalIntegration,
6
+ action_panel: actionPanel,
5
7
  }
@@ -54,6 +54,11 @@ export default {
54
54
  content_mismatch_multiple_choice_support:
55
55
  'Considere agregar texto expositivo claro con conceptos, definiciones o ejemplos distintos que respalden la creación de preguntas y distractores.',
56
56
 
57
+ inputs_unrelated:
58
+ 'Tu pregunta o respuesta correcta no está relacionada con el contenido de esta página.',
59
+ inputs_unrelated_support:
60
+ 'Proporciona una pregunta y/o respuesta correcta que se relacione claramente con la página seleccionada. Usa términos, hechos o ejemplos presentes en la página para que el asistente complete el resto de los campos.',
61
+
57
62
  character_limit:
58
63
  'Se produjo un error al generar el contenido. Intenta generar de nuevo.',
59
64
  character_limit_detailed:
@@ -4,4 +4,5 @@ import fakeTextStream from './fake_text_stream'
4
4
  export default {
5
5
  generate_questions: generateQuestions,
6
6
  fake_text_stream: fakeTextStream,
7
+ keep_existing_inputs: 'Mantener entradas existentes',
7
8
  }
@@ -1,7 +1,6 @@
1
1
  export default {
2
2
  title: {
3
- lti_consumer: 'Consumidor LTI',
4
- scorm_consumer: 'Consumidor SCORM',
3
+ block_builder: 'Constructor de bloques',
5
4
  ai_chat: 'Chat de IA',
6
5
  },
7
6
  errors: {
@@ -0,0 +1,5 @@
1
+ import transformBlock from './transform_block'
2
+
3
+ export default {
4
+ transform_block: transformBlock,
5
+ }
@@ -0,0 +1,9 @@
1
+ export default {
2
+ change_block_type: 'Ändra blocktyp',
3
+ change_block_type_insufficient_paragraphs:
4
+ 'Ändra blocktyp är tillgängligt när texten har minst två stycken.',
5
+ change_block_type_insufficient_items:
6
+ 'Ändra blocktyp är tillgängligt när blocket har minst två objekt.',
7
+ change_block_type_error:
8
+ 'Kunde inte byta blocktyp. Försök igen eller ändra manuellt.',
9
+ }
@@ -1,5 +1,5 @@
1
1
  export default {
2
- title: 'LTI Consumer Block Title',
2
+ title: 'LTI-länk',
3
3
  instructions:
4
4
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fringilla ipsum eget ante tempus blandit. Maecenas vel massa\n' +
5
5
  'nec tellus vestibulum porttitor non a enim.',
@@ -8,7 +8,7 @@ export default {
8
8
  launch_in_new_window: 'launch {0} in new tab',
9
9
  launch_in_modal: 'launch {0} in modal',
10
10
  configure_warning:
11
- 'This block needs to be configured. Please select a LTI tool in the settings panel.',
11
+ 'Välj en tillgänglig LTI-länk för att komma igång. Konfigurera sedan önskad starttyp.',
12
12
  no_access:
13
13
  'You do not have permissions to launch this link. Please contact your system administrator.',
14
14
  missing_tool: 'The tool id {0} is missing',
@@ -1,5 +1,7 @@
1
+ import actionPanel from './action_panel'
1
2
  import externalIntegration from './external_integration'
2
3
 
3
4
  export default {
4
5
  external_integration: externalIntegration,
6
+ action_panel: actionPanel,
5
7
  }
@@ -52,6 +52,11 @@ export default {
52
52
  content_mismatch_multiple_choice_support:
53
53
  'Överväg att lägga till tydlig, förklarande text med distinkta koncept, definitioner eller exempel som stödjer skapandet av frågor och distraktorer.',
54
54
 
55
+ inputs_unrelated:
56
+ 'Din fråga eller korrekta svar är inte relaterade till innehållet på denna sida.',
57
+ inputs_unrelated_support:
58
+ 'Ange en fråga och/eller ett korrekt svar som tydligt relaterar till den valda sidan. Använd termer, fakta eller exempel som finns på sidan så att assistenten kan fylla i återstående fält.',
59
+
55
60
  character_limit:
56
61
  'Ett fel uppstod när innehållet genererades. Försök generera igen.',
57
62
  character_limit_detailed:
@@ -4,4 +4,5 @@ import fakeTextStream from './fake_text_stream'
4
4
  export default {
5
5
  generate_questions: generateQuestions,
6
6
  fake_text_stream: fakeTextStream,
7
+ keep_existing_inputs: 'Behåll befintliga indata',
7
8
  }
@@ -1,7 +1,6 @@
1
1
  export default {
2
2
  title: {
3
- lti_consumer: 'LTI konsument',
4
- scorm_consumer: 'SCORM-konsument',
3
+ block_builder: 'Blockbyggare',
5
4
  ai_chat: 'AI-chatt',
6
5
  },
7
6
  errors: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/integrations",
3
- "version": "0.19.1",
3
+ "version": "0.21.0",
4
4
  "description": "Windward UI Plugin Integrations for 3rd Party Systems",
5
5
  "main": "plugin.js",
6
6
  "scripts": {