@windward/games 0.22.0 → 0.23.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.
@@ -82,14 +82,18 @@
82
82
  <v-container class="pa-4 mb-6">
83
83
  <v-row>
84
84
  <v-col cols="12">
85
- <GenerateAIQuestionButton
86
- :course="course"
87
- :content="currentContent"
88
- :block="block"
89
- question-type="sorting_game"
90
- :replace-existing-mode="replaceExisting"
91
- @click:generate="onGeneratedSortingGame"
92
- ></GenerateAIQuestionButton>
85
+ <PluginRef
86
+ target="contentBlockSettingTool"
87
+ :attrs="{
88
+ value: block,
89
+ course: course,
90
+ content: currentContent,
91
+ }"
92
+ :on="{
93
+ input: onPluginSetBlock,
94
+ append: onPluginAppendBlock,
95
+ }"
96
+ ></PluginRef>
93
97
  </v-col>
94
98
  </v-row>
95
99
  </v-container>
@@ -107,16 +111,20 @@
107
111
  <script>
108
112
  import _ from 'lodash'
109
113
  import { mapGetters } from 'vuex'
110
- import { GenerateAIQuestionButton } from '@windward/core/utils'
111
114
  import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
112
115
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
113
116
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
117
+ import PluginRef from '~/components/Core/PluginRef.vue'
114
118
  import Uuid from '~/helpers/Uuid'
115
119
 
116
120
  export default {
117
121
  name: 'SortingGameSettingsManager',
118
122
  extends: BaseContentSettings,
119
- components: { SortableExpansionPanel, BaseContentBlockSettings, GenerateAIQuestionButton },
123
+ components: {
124
+ SortableExpansionPanel,
125
+ BaseContentBlockSettings,
126
+ PluginRef,
127
+ },
120
128
  beforeMount() {
121
129
  if (_.isEmpty(this.block)) {
122
130
  this.block = {}
@@ -202,79 +210,116 @@ export default {
202
210
  return (element.id = startingIndex)
203
211
  })
204
212
  },
205
- onGeneratedSortingGame(activityData, replaceMode) {
213
+ onPluginSetBlock(activityData) {
206
214
  this.loading = true
207
215
  try {
208
216
  // Process the activity data
209
- if (activityData && activityData.metadata &&
217
+ if (
218
+ activityData &&
219
+ activityData.metadata &&
210
220
  activityData.metadata.config &&
211
221
  activityData.metadata.config.answer &&
212
- Array.isArray(activityData.metadata.config.answer)) {
213
-
222
+ Array.isArray(activityData.metadata.config.answer)
223
+ ) {
214
224
  // Save new items
215
225
  const newItems = activityData.metadata.config.answer
216
226
 
217
- if (replaceMode) {
218
- // Replace mode: Clear existing items
219
- this.block.metadata.config.answer.splice(0, this.block.metadata.config.answer.length)
227
+ // Replace mode: Clear existing items
228
+ this.block.metadata.config.answer.splice(
229
+ 0,
230
+ this.block.metadata.config.answer.length
231
+ )
220
232
 
221
- // Add all new items - ensure they have the correct structure
222
- newItems.forEach((item, index) => {
223
- this.block.metadata.config.answer.push({
224
- id: index,
225
- value: item.value || '',
226
- expand: false,
227
- })
233
+ // Add all new items - ensure they have the correct structure
234
+ newItems.forEach((item, index) => {
235
+ this.block.metadata.config.answer.push({
236
+ id: index,
237
+ value: item.value || '',
238
+ expand: false,
228
239
  })
229
- } else {
230
- // Merge mode: Add new items to existing ones
231
- const hasOnlyEmptyAnswer = this.block.metadata.config.answer.length === 1 &&
232
- this.block.metadata.config.answer[0].value === ''
233
-
234
- if (hasOnlyEmptyAnswer) {
235
- // If there's only one empty answer, replace it instead of merging
236
- this.block.metadata.config.answer.splice(0, 1)
237
- }
240
+ })
238
241
 
239
- let currentId = this.block.metadata.config.answer.length
242
+ // Update title and instructions if provided and we're in replace mode
240
243
 
241
- newItems.forEach((item) => {
242
- this.block.metadata.config.answer.push({
243
- id: currentId,
244
- value: item.value || '',
245
- expand: false,
246
- })
247
- currentId += 1
248
- })
244
+ if (activityData.metadata.config.title) {
245
+ this.block.metadata.config.title =
246
+ activityData.metadata.config.title
249
247
  }
250
248
 
251
- // Update title and instructions if provided and we're in replace mode
252
- if (replaceMode) {
253
- if (activityData.metadata.config.title) {
254
- this.block.metadata.config.title = activityData.metadata.config.title
255
- }
249
+ if (activityData.metadata.config.instructions) {
250
+ this.block.metadata.config.instructions =
251
+ activityData.metadata.config.instructions
252
+ }
253
+
254
+ // Update feedback if provided
255
+ if (activityData.metadata.config.feedback_correct) {
256
+ this.block.metadata.config.feedback_correct =
257
+ activityData.metadata.config.feedback_correct
258
+ }
259
+
260
+ this.$toast.success(
261
+ this.$t(
262
+ 'windward.games.components.settings.sorting_game.form.replaced_successfully'
263
+ ),
264
+
265
+ { duration: 3000 }
266
+ )
267
+ } else {
268
+ throw new Error('activity.error.technical')
269
+ }
270
+ } catch (error) {
271
+ // Let the error bubble up to Plugin with proper error type
272
+ throw error
273
+ } finally {
274
+ this.loading = false
275
+ }
276
+ },
277
+ onPluginAppendBlock(activityData) {
278
+ this.loading = true
279
+ try {
280
+ // Process the activity data
281
+ if (
282
+ activityData &&
283
+ activityData.metadata &&
284
+ activityData.metadata.config &&
285
+ activityData.metadata.config.answer &&
286
+ Array.isArray(activityData.metadata.config.answer)
287
+ ) {
288
+ // Save new items
289
+ const newItems = activityData.metadata.config.answer
256
290
 
257
- if (activityData.metadata.config.instructions) {
258
- this.block.metadata.config.instructions = activityData.metadata.config.instructions
259
- }
291
+ // Merge mode: Add new items to existing ones
292
+ const hasOnlyEmptyAnswer =
293
+ this.block.metadata.config.answer.length === 1 &&
294
+ this.block.metadata.config.answer[0].value === ''
260
295
 
261
- // Update feedback if provided
262
- if (activityData.metadata.config.feedback_correct) {
263
- this.block.metadata.config.feedback_correct = activityData.metadata.config.feedback_correct
264
- }
296
+ if (hasOnlyEmptyAnswer) {
297
+ // If there's only one empty answer, replace it instead of merging
298
+ this.block.metadata.config.answer.splice(0, 1)
265
299
  }
266
300
 
301
+ let currentId = this.block.metadata.config.answer.length
302
+
303
+ newItems.forEach((item) => {
304
+ this.block.metadata.config.answer.push({
305
+ id: currentId,
306
+ value: item.value || '',
307
+ expand: false,
308
+ })
309
+ currentId += 1
310
+ })
311
+
267
312
  this.$toast.success(
268
- replaceMode
269
- ? this.$t('windward.games.components.settings.sorting_game.form.replaced_successfully')
270
- : this.$t('windward.games.components.settings.sorting_game.form.added_successfully'),
313
+ this.$t(
314
+ 'windward.games.components.settings.sorting_game.form.added_successfully'
315
+ ),
271
316
  { duration: 3000 }
272
317
  )
273
318
  } else {
274
319
  throw new Error('activity.error.technical')
275
320
  }
276
321
  } catch (error) {
277
- // Let the error bubble up to GenerateAIQuestionButton with proper error type
322
+ // Let the error bubble up to Plugin with proper error type
278
323
  throw error
279
324
  } finally {
280
325
  this.loading = false
@@ -122,14 +122,18 @@
122
122
  <v-container class="pa-4 mb-6">
123
123
  <v-row>
124
124
  <v-col cols="12">
125
- <GenerateAIQuestionButton
126
- :course="course"
127
- :content="currentContent"
128
- :block="block"
129
- question-type="word_jumble"
130
- :replace-existing-mode="replaceExisting"
131
- @click:generate="onGeneratedWordJumble"
132
- ></GenerateAIQuestionButton>
125
+ <PluginRef
126
+ target="contentBlockSettingTool"
127
+ :attrs="{
128
+ value: block,
129
+ course: course,
130
+ content: currentContent,
131
+ }"
132
+ :on="{
133
+ input: onPluginSetBlock,
134
+ append: onPluginAppendBlock,
135
+ }"
136
+ ></PluginRef>
133
137
  </v-col>
134
138
  </v-row>
135
139
  </v-container>
@@ -138,10 +142,10 @@
138
142
  <script>
139
143
  import _ from 'lodash'
140
144
  import { mapGetters } from 'vuex'
141
- import { GenerateAIQuestionButton } from '@windward/core/utils'
142
145
  import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
143
146
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
144
147
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
148
+ import PluginRef from '~/components/Core/PluginRef.vue'
145
149
 
146
150
  export default {
147
151
  name: 'WordJumbleSettings',
@@ -149,7 +153,7 @@ export default {
149
153
  components: {
150
154
  SortableExpansionPanel,
151
155
  BaseContentBlockSettings,
152
- GenerateAIQuestionButton,
156
+ PluginRef,
153
157
  },
154
158
  beforeMount() {
155
159
  if (_.isEmpty(this.block)) {
@@ -194,7 +198,6 @@ export default {
194
198
  }
195
199
  },
196
200
  computed: {
197
-
198
201
  ...mapGetters({
199
202
  course: 'course/get',
200
203
  currentContent: 'content/get',
@@ -251,69 +254,131 @@ export default {
251
254
  this.block.metadata.config.currentWord =
252
255
  this.block.metadata.config.words.length - 1
253
256
  },
254
- onGeneratedWordJumble(activityData, replaceMode) {
257
+ onPluginSetBlock(activityData) {
255
258
  this.loading = true
256
259
  try {
257
260
  // Process the activity data
258
- if (activityData && activityData.metadata &&
261
+ if (
262
+ activityData &&
263
+ activityData.metadata &&
259
264
  activityData.metadata.config &&
260
265
  activityData.metadata.config.words &&
261
- Array.isArray(activityData.metadata.config.words)) {
262
-
266
+ Array.isArray(activityData.metadata.config.words)
267
+ ) {
263
268
  const newWords = activityData.metadata.config.words
264
269
 
265
- if (replaceMode) { this.block.metadata.config.words.splice(0, this.block.metadata.config.words.length)
266
- newWords.forEach(word => {
267
- this.block.metadata.config.words.push({
268
- id: word.id || this.block.metadata.config.words.length + 1,
269
- value: word.value || '',
270
- hint: word.hint || '',
271
- shuffledWord: this.shuffle(word.value || '')
272
- })
273
- })
274
- } else {
275
- newWords.forEach(word => {
276
- this.block.metadata.config.words.push({
277
- id: this.block.metadata.config.words.length + 1,
278
- value: word.value || '',
279
- hint: word.hint || '',
280
- shuffledWord: this.shuffle(word.value || '')
281
- })
270
+ this.block.metadata.config.words.splice(
271
+ 0,
272
+ this.block.metadata.config.words.length
273
+ )
274
+ newWords.forEach((word) => {
275
+ this.block.metadata.config.words.push({
276
+ id:
277
+ word.id ||
278
+ this.block.metadata.config.words.length + 1,
279
+ value: word.value || '',
280
+ hint: word.hint || '',
281
+ shuffledWord: this.shuffle(word.value || ''),
282
282
  })
283
+ })
284
+
285
+ if (activityData.metadata.config.title) {
286
+ this.block.metadata.config.title =
287
+ activityData.metadata.config.title
283
288
  }
284
289
 
285
- if (replaceMode && activityData.metadata.config.title) {
286
- this.block.metadata.config.title = activityData.metadata.config.title
290
+ if (activityData.metadata.config.feedback_correct) {
291
+ this.block.metadata.config.feedback_correct =
292
+ activityData.metadata.config.feedback_correct
287
293
  }
288
294
 
289
- if (replaceMode) {
290
- if (activityData.metadata.config.feedback_correct) {
291
- this.block.metadata.config.feedback_correct = activityData.metadata.config.feedback_correct
292
- }
295
+ if (activityData.metadata.config.feedback_incorrect) {
296
+ this.block.metadata.config.feedback_incorrect =
297
+ activityData.metadata.config.feedback_incorrect
298
+ }
299
+
300
+ this.block.metadata.config.currentWord = 0
293
301
 
294
- if (activityData.metadata.config.feedback_incorrect) {
295
- this.block.metadata.config.feedback_incorrect = activityData.metadata.config.feedback_incorrect
302
+ this.$toast.success(
303
+ this.$t(
304
+ 'windward.games.components.settings.word_jumble.form.replaced_successfully'
305
+ ),
306
+ { duration: 3000 }
307
+ )
308
+ } else {
309
+ this.$toast.error(
310
+ this.$t(
311
+ 'windward.games.components.settings.word_jumble.form.invalid_response'
312
+ ),
313
+ {
314
+ duration: 5000,
296
315
  }
316
+ )
317
+ }
318
+ } catch (error) {
319
+ const errorMessage = error.message || 'Unknown error occurred'
320
+ this.$toast.error(
321
+ `${this.$t(
322
+ 'windward.games.components.settings.word_jumble.form.failed_to_process'
323
+ )}: ${errorMessage}`,
324
+ {
325
+ duration: 5000,
297
326
  }
327
+ )
328
+ } finally {
329
+ this.loading = false
330
+ }
331
+ },
332
+ onPluginAppendBlock(activityData) {
333
+ this.loading = true
334
+ try {
335
+ // Process the activity data
336
+ if (
337
+ activityData &&
338
+ activityData.metadata &&
339
+ activityData.metadata.config &&
340
+ activityData.metadata.config.words &&
341
+ Array.isArray(activityData.metadata.config.words)
342
+ ) {
343
+ const newWords = activityData.metadata.config.words
344
+
345
+ newWords.forEach((word) => {
346
+ this.block.metadata.config.words.push({
347
+ id: this.block.metadata.config.words.length + 1,
348
+ value: word.value || '',
349
+ hint: word.hint || '',
350
+ shuffledWord: this.shuffle(word.value || ''),
351
+ })
352
+ })
298
353
 
299
354
  this.block.metadata.config.currentWord = 0
300
355
 
301
356
  this.$toast.success(
302
- replaceMode
303
- ? this.$t('windward.games.components.settings.word_jumble.form.replaced_successfully')
304
- : this.$t('windward.games.components.settings.word_jumble.form.added_successfully'),
357
+ this.$t(
358
+ 'windward.games.components.settings.word_jumble.form.added_successfully'
359
+ ),
305
360
  { duration: 3000 }
306
361
  )
307
362
  } else {
308
- this.$toast.error(this.$t('windward.games.components.settings.word_jumble.form.invalid_response'), {
309
- duration: 5000
310
- })
363
+ this.$toast.error(
364
+ this.$t(
365
+ 'windward.games.components.settings.word_jumble.form.invalid_response'
366
+ ),
367
+ {
368
+ duration: 5000,
369
+ }
370
+ )
311
371
  }
312
372
  } catch (error) {
313
373
  const errorMessage = error.message || 'Unknown error occurred'
314
- this.$toast.error(`${this.$t('windward.games.components.settings.word_jumble.form.failed_to_process')}: ${errorMessage}`, {
315
- duration: 5000
316
- })
374
+ this.$toast.error(
375
+ `${this.$t(
376
+ 'windward.games.components.settings.word_jumble.form.failed_to_process'
377
+ )}: ${errorMessage}`,
378
+ {
379
+ duration: 5000,
380
+ }
381
+ )
317
382
  } finally {
318
383
  this.loading = false
319
384
  }
@@ -15,4 +15,8 @@ export default {
15
15
  add_answer: 'Add Answer Option',
16
16
  add_question: 'Add Question',
17
17
  answer: 'Answers',
18
+ added_successfully: 'Questions added successfully',
19
+ replaced_successfully: 'Questions replaced successfully',
20
+ invalid_response: 'Could not process AI response for multiple-choice.',
21
+ failed_to_process: 'Failed to process AI response',
18
22
  }
@@ -15,4 +15,8 @@ export default {
15
15
  add_answer: 'Agregar opción de respuesta',
16
16
  add_question: 'Agregar pregunta',
17
17
  answer: 'Respuestas',
18
+ added_successfully: 'Preguntas agregadas correctamente',
19
+ replaced_successfully: 'Preguntas reemplazadas correctamente',
20
+ invalid_response: 'No se pudo procesar la respuesta de IA para opción múltiple.',
21
+ failed_to_process: 'No se pudo procesar la respuesta de IA',
18
22
  }
@@ -14,4 +14,8 @@ export default {
14
14
  add_answer: 'Lägg till svarsalternativ',
15
15
  add_question: 'Lägg till fråga',
16
16
  answer: 'Svar',
17
+ added_successfully: 'Frågor har lagts till',
18
+ replaced_successfully: 'Frågor har ersatts',
19
+ invalid_response: 'Kunde inte bearbeta AI-svar för flervalsfrågor.',
20
+ failed_to_process: 'Misslyckades med att bearbeta AI-svar',
17
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/games",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "Windward UI Plugin Games",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
package/plugin.js CHANGED
@@ -128,7 +128,7 @@ export default {
128
128
  },
129
129
  },
130
130
  ],
131
- settings: [
131
+ contentBlockSetting: [
132
132
  {
133
133
  tag: 'games-flashcard-settings',
134
134
  template: FlashCardSlidesManager,