@windward/integrations 0.18.0 → 0.19.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 (66) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/components/Content/Blocks/ExternalIntegration/LtiConsumer.vue +3 -3
  3. package/components/Content/Blocks/ExternalIntegration/ScormConsumer.vue +34 -0
  4. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue +10 -8
  5. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumers.vue +2 -2
  6. package/components/ExternalIntegration/Driver/Lti1p1/ManageProvider.vue +8 -5
  7. package/components/ExternalIntegration/Driver/Lti1p1/ManageProviders.vue +3 -2
  8. package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumer.vue +8 -6
  9. package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumers.vue +2 -2
  10. package/components/ExternalIntegration/Driver/Lti1p3/ManageProvider.vue +27 -5
  11. package/components/ExternalIntegration/Driver/Lti1p3/ManageProviders.vue +4 -3
  12. package/components/ExternalIntegration/Driver/Lti1p3/ViewConsumer.vue +6 -5
  13. package/components/ExternalIntegration/Driver/ManageScorm.vue +45 -0
  14. package/components/ExternalIntegration/Driver/Scorm/ManageConsumer.vue +76 -0
  15. package/components/ExternalIntegration/Driver/Scorm/ManageConsumers.vue +233 -0
  16. package/components/ExternalIntegration/Driver/Scorm/ManageProvider.vue +475 -0
  17. package/components/ExternalIntegration/Driver/Scorm/ManageProviders.vue +299 -0
  18. package/components/LLM/GenerateContent/BlockQuestionGenerateButton.vue +34 -3
  19. package/components/SecretField.vue +57 -34
  20. package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +2 -2
  21. package/components/Settings/ExternalIntegration/ManageCourseIntegrationSettings.vue +6 -6
  22. package/components/Settings/ExternalIntegration/ScormConsumerSettings.vue +42 -0
  23. package/helpers/ExternalIntegration/ScormHelper.ts +155 -0
  24. package/i18n/en-US/components/external_integration/driver/lti1p3.ts +4 -1
  25. package/i18n/en-US/components/external_integration/driver/scorm.ts +14 -0
  26. package/i18n/en-US/components/external_integration/index.ts +3 -1
  27. package/i18n/en-US/components/llm/generate_content/generate_questions.ts +7 -0
  28. package/i18n/en-US/pages/course/external_integration/index.ts +1 -1
  29. package/i18n/en-US/pages/login/index.ts +2 -0
  30. package/i18n/en-US/pages/login/lti.ts +2 -0
  31. package/i18n/en-US/pages/login/scorm.ts +28 -0
  32. package/i18n/en-US/shared/content_blocks.ts +1 -0
  33. package/i18n/en-US/shared/settings.ts +1 -0
  34. package/i18n/es-ES/components/external_integration/driver/lti1p3.ts +4 -1
  35. package/i18n/es-ES/components/external_integration/driver/scorm.ts +15 -0
  36. package/i18n/es-ES/components/external_integration/index.ts +3 -1
  37. package/i18n/es-ES/components/llm/generate_content/generate_questions.ts +7 -0
  38. package/i18n/es-ES/pages/course/external_integration/index.ts +1 -1
  39. package/i18n/es-ES/pages/login/index.ts +2 -0
  40. package/i18n/es-ES/pages/login/lti.ts +2 -0
  41. package/i18n/es-ES/pages/login/scorm.ts +29 -0
  42. package/i18n/es-ES/shared/content_blocks.ts +1 -0
  43. package/i18n/es-ES/shared/settings.ts +1 -0
  44. package/i18n/sv-SE/components/external_integration/driver/lti1p3.ts +4 -1
  45. package/i18n/sv-SE/components/external_integration/driver/scorm.ts +14 -0
  46. package/i18n/sv-SE/components/external_integration/index.ts +3 -1
  47. package/i18n/sv-SE/components/llm/generate_content/generate_questions.ts +7 -0
  48. package/i18n/sv-SE/pages/course/external_integration/index.ts +1 -1
  49. package/i18n/sv-SE/pages/login/index.ts +2 -0
  50. package/i18n/sv-SE/pages/login/lti.ts +2 -0
  51. package/i18n/sv-SE/pages/login/scorm.ts +29 -0
  52. package/i18n/sv-SE/shared/content_blocks.ts +2 -1
  53. package/i18n/sv-SE/shared/settings.ts +1 -0
  54. package/models/ExternalIntegration/{LtiConsumer.ts → Consumer.ts} +2 -2
  55. package/models/ExternalIntegration/{LtiProvider.ts → Provider.ts} +2 -2
  56. package/package.json +2 -1
  57. package/pages/course/externalIntegration/index.vue +4 -0
  58. package/pages/login/scorm/error.vue +102 -0
  59. package/pages/login/scorm/promptEmail.vue +180 -0
  60. package/plugin.js +111 -7
  61. package/test/Components/ExternalIntegration/ManageScorm.spec.js +19 -0
  62. package/test/Components/ExternalIntegration/Scorm/ManageConsumer.spec.js +19 -0
  63. package/test/Components/ExternalIntegration/Scorm/ManageConsumers.spec.js +19 -0
  64. package/test/Components/ExternalIntegration/Scorm/ManageProvider.spec.js +19 -0
  65. package/test/Components/ExternalIntegration/Scorm/ManageProviders.spec.js +19 -0
  66. package/test/mocks.js +12 -0
@@ -0,0 +1,299 @@
1
+ <template>
2
+ <div>
3
+ <DialogBox
4
+ color="primary"
5
+ action-save
6
+ action-save-new
7
+ @click:save="onSaved"
8
+ @click:save-new="onSaved"
9
+ >
10
+ <template #title>{{
11
+ $t(
12
+ 'windward.integrations.components.external_integration.driver.scorm.new'
13
+ )
14
+ }}</template>
15
+ <template #trigger>{{ $t('shared.forms.new') }}</template>
16
+ <template #form="{ on, attrs }"
17
+ ><ManageProvider v-bind="attrs" v-on="on"></ManageProvider
18
+ ></template>
19
+ </DialogBox>
20
+
21
+ <v-data-table
22
+ :headers="headers"
23
+ :items="providers"
24
+ :items-per-page="10"
25
+ class="elevation-1"
26
+ >
27
+ <template #[`item.target`]="{ item }">
28
+ <ProviderTargetViewer
29
+ class="field--target text-truncate"
30
+ :target="item.target"
31
+ ></ProviderTargetViewer>
32
+ </template>
33
+ <template #[`item.download_package`]="{ item }">
34
+ <v-btn
35
+ color="primary"
36
+ :loading="isDownloading"
37
+ @click="onClickDownload(item)"
38
+ >{{
39
+ $t(
40
+ 'windward.integrations.components.external_integration.driver.scorm.download_package'
41
+ )
42
+ }}</v-btn
43
+ >
44
+ </template>
45
+
46
+ <template #[`item.enabled`]="{ item }">
47
+ <v-icon :color="item.enabled ? 'success' : 'error'"
48
+ >{{ item.enabled ? 'mdi-check' : 'mdi-close' }}
49
+ </v-icon>
50
+ <span v-if="!item.enabled" class="sr-only">{{
51
+ $t('shared.forms.enabled')
52
+ }}</span>
53
+ </template>
54
+
55
+ <template #[`item.created_at`]="{ item }">
56
+ {{ $d(new Date(item.created_at), 'short') }}
57
+ </template>
58
+ <template #[`item.actions`]="{ index, item }">
59
+ <SpeedDial
60
+ direction="left"
61
+ color="primary"
62
+ transition="slide-x-reverse-transition"
63
+ >
64
+ <v-btn
65
+ color="error"
66
+ outlined
67
+ elevation="0"
68
+ class="outlined"
69
+ @click="onConfirmDelete(item)"
70
+ >
71
+ {{ $t('shared.forms.delete') }}
72
+ <span class="sr-only">{{
73
+ $t('shared.forms.delete')
74
+ }}</span>
75
+ </v-btn>
76
+ <DialogBox
77
+ color="primary"
78
+ outlined
79
+ :class-prop="'outlined'"
80
+ action-save
81
+ @click:save="onSaved"
82
+ >
83
+ <template #title>{{
84
+ $t(
85
+ 'windward.integrations.components.external_integration.driver.scorm.edit'
86
+ )
87
+ }}</template>
88
+ <template #trigger>
89
+ {{
90
+ $t(
91
+ 'windward.integrations.components.external_integration.driver.scorm.edit_display'
92
+ )
93
+ }}
94
+ <span class="sr-only">{{
95
+ $t(
96
+ 'windward.integrations.components.external_integration.driver.scorm.edit'
97
+ )
98
+ }}</span>
99
+ </template>
100
+ <template #form="{ on, attrs }"
101
+ ><ManageProvider
102
+ v-model="providers[index]"
103
+ v-bind="attrs"
104
+ v-on="on"
105
+ ></ManageProvider
106
+ ></template>
107
+ </DialogBox>
108
+ </SpeedDial>
109
+ </template>
110
+ </v-data-table>
111
+ </div>
112
+ </template>
113
+
114
+ <script>
115
+ import _ from 'lodash'
116
+ import { mapGetters } from 'vuex'
117
+ import Provider from '../../../../models/ExternalIntegration/Provider'
118
+ import SecretField from '../../../SecretField.vue'
119
+ import ProviderTargetViewer from '../../ProviderTargetViewer.vue'
120
+ import ManageProvider from './ManageProvider.vue'
121
+ import DialogBox from '~/components/Core/DialogBox.vue'
122
+ import Organization from '~/models/Organization'
123
+ import Course from '~/models/Course'
124
+ import SpeedDial from '~/components/Core/SpeedDial.vue'
125
+
126
+ export default {
127
+ name: 'ManageScormProvidersDriver',
128
+ components: {
129
+ SecretField,
130
+ DialogBox,
131
+ ManageProvider,
132
+ ProviderTargetViewer,
133
+ SpeedDial,
134
+ },
135
+ data() {
136
+ return {
137
+ providers: [],
138
+ headers: [
139
+ {
140
+ text: this.$t(
141
+ 'windward.integrations.components.external_integration.target'
142
+ ),
143
+ value: 'target',
144
+ },
145
+ {
146
+ text: this.$t(
147
+ 'windward.integrations.components.external_integration.version'
148
+ ),
149
+ value: 'version',
150
+ },
151
+ {
152
+ text: this.$t(
153
+ 'windward.integrations.components.external_integration.driver.scorm.download_package'
154
+ ),
155
+ value: 'download_package',
156
+ },
157
+ {
158
+ text: this.$t('shared.forms.enabled'),
159
+ value: 'enabled',
160
+ },
161
+ { text: this.$t('shared.forms.created'), value: 'created_at' },
162
+ {
163
+ text: this.$t('shared.forms.actions'),
164
+ value: 'actions',
165
+ sortable: false,
166
+ },
167
+ ],
168
+ isDownloading: false,
169
+ }
170
+ },
171
+
172
+ async fetch() {
173
+ if (
174
+ !this.$PermissionService.userHasAccessTo(
175
+ 'plugin.windward.integrations.course.externalIntegration',
176
+ 'readable'
177
+ ) ||
178
+ _.isEmpty(this.organization.id) ||
179
+ _.isEmpty(this.course.id)
180
+ ) {
181
+ // Display an angry error that they can't view this driver
182
+ this.$dialog.error(this.$t('shared.error.description_401'), {
183
+ duration: null,
184
+ action: {
185
+ text: this.$t('shared.forms.close'),
186
+ onClick: (_e, toastObject) => {
187
+ toastObject.goAway(0)
188
+ },
189
+ },
190
+ })
191
+ if (_.isEmpty(this.organization.id) || _.isEmpty(this.course.id)) {
192
+ // eslint-disable-next-line no-console
193
+ console.error(
194
+ 'Cannot load external integrations because organization or course is not set!'
195
+ )
196
+ } else {
197
+ // eslint-disable-next-line no-console
198
+ console.error(
199
+ 'You do not have access to this external integration!'
200
+ )
201
+ }
202
+
203
+ // Return so we don't even attempt loading
204
+ return false
205
+ }
206
+
207
+ await this.loadProviders()
208
+ },
209
+ computed: {
210
+ ...mapGetters({
211
+ organization: 'organization/get',
212
+ course: 'course/get',
213
+ }),
214
+ },
215
+ methods: {
216
+ onSaved() {
217
+ this.loadProviders()
218
+ },
219
+ async loadProviders() {
220
+ this.providers = await new Provider()
221
+ .for(
222
+ new Organization({ id: this.organization.id }),
223
+ new Course({ id: this.course.id })
224
+ )
225
+ .where('type', 'scorm')
226
+ .get()
227
+ },
228
+ onConfirmDelete(provider) {
229
+ this.$dialog.show(this.$t('shared.forms.confirm_delete_text'), {
230
+ icon: 'mdi-help',
231
+ duration: null,
232
+ action: [
233
+ {
234
+ text: this.$t('shared.forms.cancel'),
235
+ onClick: (_e, toastObject) => {
236
+ toastObject.goAway(0)
237
+ },
238
+ },
239
+ {
240
+ text: this.$t('shared.forms.confirm'),
241
+ // router navigation
242
+ onClick: (_e, toastObject) => {
243
+ this.deleteProvider(provider)
244
+ toastObject.goAway(0)
245
+ },
246
+ },
247
+ ],
248
+ })
249
+ },
250
+ async deleteProvider(provider) {
251
+ await provider.delete()
252
+ this.$dialog.success(this.$t('shared.response.deleted'))
253
+ // Reload providers now that we deleted one
254
+ this.loadProviders()
255
+ },
256
+ async onClickDownload(provider) {
257
+ this.isDownloading = true
258
+
259
+ try {
260
+ const result = await Provider.config({
261
+ method: 'GET',
262
+ })
263
+ .custom(
264
+ new Organization(this.organization),
265
+ new Course(this.course),
266
+ new Provider(provider),
267
+ 'download'
268
+ )
269
+ .file()
270
+
271
+ let filename = `${this.organization.name}_${this.course.name}_${provider.type}_${provider.version}_provider_${provider.id}`
272
+ // Replace all non letter/numbers with _
273
+ filename = filename.replaceAll(/[^a-zA-Z0-9\_\-]/gi, '_')
274
+ // Replace all double+ underscores with single
275
+ filename = filename.replaceAll(/_+/gi, '_')
276
+ filename += '.zip'
277
+
278
+ const url = URL.createObjectURL(result)
279
+ const link = document.createElement('a')
280
+ link.href = url
281
+ link.download = filename
282
+ link.click()
283
+ URL.revokeObjectURL(url)
284
+ } catch (e) {
285
+ console.error('Error getting download', e)
286
+ }
287
+
288
+ this.isDownloading = false
289
+ },
290
+ },
291
+ }
292
+ </script>
293
+
294
+ <style scoped>
295
+ .field--target {
296
+ max-width: 15em;
297
+ display: inline-block;
298
+ }
299
+ </style>
@@ -105,7 +105,8 @@ export default {
105
105
  this.value.tag === 'plugin-games-bucket' ||
106
106
  this.value.tag === 'plugin-games-wordjumble-game' ||
107
107
  this.value.tag === 'plugin-games-multiple-choice' ||
108
- this.value.tag === 'plugin-games-seven-strikes-game',
108
+ this.value.tag === 'plugin-games-seven-strikes-game' ||
109
+ this.value.tag === 'plugin-games-crossword-puzzle-game',
109
110
  }
110
111
  },
111
112
  computed: {
@@ -119,7 +120,8 @@ export default {
119
120
  this.isSortingGameType ||
120
121
  this.isWordJumbleType ||
121
122
  this.isMultipleChoiceType ||
122
- this.isSevenStrikesType
123
+ this.isSevenStrikesType ||
124
+ this.isCrosswordType
123
125
  )
124
126
  },
125
127
  isFlashcardType() {
@@ -148,6 +150,9 @@ export default {
148
150
  isMultipleChoiceType() {
149
151
  return this.value.tag === 'plugin-games-multiple-choice'
150
152
  },
153
+ isCrosswordType() {
154
+ return this.value.tag === 'plugin-games-crossword-puzzle-game'
155
+ },
151
156
  replaceExistingLabel() {
152
157
  if (this.isBucketGameType) {
153
158
  return this.$t(
@@ -174,6 +179,11 @@ export default {
174
179
  'windward.integrations.components.llm.generate_content.generate_questions.replace_existing_multiple_choice'
175
180
  )
176
181
  }
182
+ if (this.isCrosswordType) {
183
+ return this.$t(
184
+ 'windward.integrations.components.llm.generate_content.generate_questions.replace_existing_crossword'
185
+ )
186
+ }
177
187
  if (this.isFlashcardType) {
178
188
  return this.$t(
179
189
  'windward.integrations.components.llm.generate_content.generate_questions.replace_existing_flashcard'
@@ -190,11 +200,17 @@ export default {
190
200
  (!this.isFlashcardType &&
191
201
  !this.isBucketGameType &&
192
202
  !this.isMatchingGameType &&
193
- !this.isSevenStrikesType)
203
+ !this.isSevenStrikesType &&
204
+ !this.isWordJumbleType &&
205
+ !this.isCrosswordType &&
206
+ !this.isMultipleChoiceType)
194
207
 
195
208
  return supportsAdvancedTaxonomy
196
209
  },
197
210
  taxonomyLevels() {
211
+ if (this.isCrosswordType) {
212
+ return ['None', 'Remember', 'Understand', 'Apply']
213
+ }
198
214
  // For word jumble games, only show None, Remember, Understand, Apply
199
215
  if (this.isWordJumbleType) {
200
216
  return ['None', 'Remember', 'Understand', 'Apply']
@@ -254,6 +270,10 @@ export default {
254
270
  return this.$t(
255
271
  'windward.integrations.components.llm.generate_content.generate_questions.button_label_multiple_choice'
256
272
  )
273
+ } else if (this.value.tag === 'plugin-games-crossword-puzzle-game') {
274
+ return this.$t(
275
+ 'windward.integrations.components.llm.generate_content.generate_questions.button_label_crossword'
276
+ )
257
277
  } else {
258
278
  return this.$t(
259
279
  'windward.integrations.components.llm.generate_content.generate_questions.button_label'
@@ -422,6 +442,17 @@ export default {
422
442
  this.$t(
423
443
  `${basePath}.content_mismatch_word_jumble_support`
424
444
  )
445
+ } else if (
446
+ (errorMessage === 'activity.error.content_mismatch' ||
447
+ errorType === 'content_mismatch') &&
448
+ this.isCrosswordType
449
+ ) {
450
+ errorText =
451
+ this.$t(`${basePath}.content_mismatch_crossword`) +
452
+ '\n\n' +
453
+ this.$t(
454
+ `${basePath}.content_mismatch_crossword_support`
455
+ )
425
456
  } else if (
426
457
  errorType === 'insufficient_content' &&
427
458
  error.response?.data?.error?.details
@@ -1,39 +1,66 @@
1
1
  <template>
2
- <component
3
- :is="activeComponent"
4
- :id="'secret-field-' + key"
5
- :name="'secret-field-' + key"
6
- :value="value"
7
- :readonly="readonly"
8
- :autocomplete="autocomplete"
9
- :type="fieldType"
10
- :placeholder="placeholder"
11
- :label="label"
12
- :hint="hint"
13
- :append-icon="appendIcon"
14
- :rules="rules"
15
- :rows="rows"
16
- @input="$emit('input', $event)"
17
- >
18
- <template #append>
19
- <v-btn icon elevation="0" @click="toggleClear">
20
- <v-icon>{{ showClear ? 'mdi-eye-off' : 'mdi-eye' }}</v-icon>
21
- </v-btn>
22
- <v-btn v-if="copy" icon elevation="0" @click="copyText(value)">
23
- <v-icon>mdi-content-copy</v-icon>
24
- <span class="sr-only">{{ $t('shared.forms.copy') }}</span>
25
- </v-btn>
26
- </template>
27
- </component>
2
+ <div>
3
+ <v-text-field
4
+ v-show="activeTag === 'v-text-field'"
5
+ :id="'secret-field-' + key"
6
+ :name="'secret-field-' + key"
7
+ :value="value"
8
+ :readonly="readonly"
9
+ :autocomplete="autocomplete"
10
+ :type="fieldType"
11
+ :placeholder="placeholder"
12
+ :label="label"
13
+ :hint="hint"
14
+ :append-icon="appendIcon"
15
+ :rules="rules"
16
+ :rows="rows"
17
+ @input="$emit('input', $event)"
18
+ >
19
+ <template #append>
20
+ <v-btn icon elevation="0" @click="toggleClear">
21
+ <v-icon>{{ showClear ? 'mdi-eye-off' : 'mdi-eye' }}</v-icon>
22
+ </v-btn>
23
+ <v-btn v-if="copy" icon elevation="0" @click="copyText(value)">
24
+ <v-icon>mdi-content-copy</v-icon>
25
+ <span class="sr-only">{{ $t('shared.forms.copy') }}</span>
26
+ </v-btn>
27
+ </template>
28
+ </v-text-field>
29
+ <v-textarea
30
+ v-show="activeTag === 'v-textarea'"
31
+ :id="'secret-field-' + key"
32
+ :name="'secret-field-' + key"
33
+ :value="value"
34
+ :readonly="readonly"
35
+ :autocomplete="autocomplete"
36
+ :type="fieldType"
37
+ :placeholder="placeholder"
38
+ :label="label"
39
+ :hint="hint"
40
+ :append-icon="appendIcon"
41
+ :rules="rules"
42
+ :rows="rows"
43
+ @input="$emit('input', $event)"
44
+ >
45
+ <template #append>
46
+ <v-btn icon elevation="0" @click="toggleClear">
47
+ <v-icon>{{ showClear ? 'mdi-eye-off' : 'mdi-eye' }}</v-icon>
48
+ </v-btn>
49
+ <v-btn v-if="copy" icon elevation="0" @click="copyText(value)">
50
+ <v-icon>mdi-content-copy</v-icon>
51
+ <span class="sr-only">{{ $t('shared.forms.copy') }}</span>
52
+ </v-btn>
53
+ </template>
54
+ </v-textarea>
55
+ </div>
28
56
  </template>
29
57
 
30
58
  <script>
31
59
  import Crypto from '~/helpers/Crypto'
32
- import { VTextarea, VTextField } from 'vuetify/lib'
33
60
 
34
61
  export default {
35
62
  name: 'SecretField',
36
- components: { VTextarea, VTextField },
63
+ components: {},
37
64
  props: {
38
65
  tag: { type: String, required: false, default: 'v-text-field' },
39
66
  value: { type: String, required: false, default: '' },
@@ -81,7 +108,7 @@ export default {
81
108
  }
82
109
  },
83
110
  computed: {
84
- activeComponent() {
111
+ activeTag() {
85
112
  let tag = this.tag
86
113
 
87
114
  // If the field type is password we need to hard-change to textfield since other components don't support password text
@@ -89,11 +116,7 @@ export default {
89
116
  tag = 'v-text-field'
90
117
  }
91
118
 
92
- if (tag === 'v-textarea') {
93
- return VTextarea
94
- } else {
95
- return VTextField
96
- }
119
+ return tag
97
120
  },
98
121
  key() {
99
122
  return Crypto.id()
@@ -74,7 +74,7 @@ import BaseContentSettings from '~/components/Content/Settings/BaseContentSettin
74
74
  import Course from '~/models/Course'
75
75
  import Organization from '~/models/Organization'
76
76
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
77
- import LtiConsumer from '../../../models/ExternalIntegration/LtiConsumer'
77
+ import Consumer from '../../../models/ExternalIntegration/Consumer'
78
78
 
79
79
  export default {
80
80
  name: 'ContentBlockExternalIntegrationLti1p1ConsumerSettings',
@@ -138,7 +138,7 @@ export default {
138
138
  }
139
139
  },
140
140
  async fetch() {
141
- this.consumers = await new LtiConsumer()
141
+ this.consumers = await new Consumer()
142
142
  .for(
143
143
  new Organization({ id: this.organization.id }),
144
144
  new Course({ id: this.course.id })
@@ -19,10 +19,10 @@
19
19
  }}
20
20
  </v-tab>
21
21
 
22
- <v-tab v-if="ltiReady">
22
+ <v-tab>
23
23
  {{
24
24
  $t(
25
- 'windward.integrations.pages.course.external_integration.scorm_1p2'
25
+ 'windward.integrations.pages.course.external_integration.scorm'
26
26
  )
27
27
  }}
28
28
  </v-tab>
@@ -30,13 +30,13 @@
30
30
 
31
31
  <v-tabs-items v-model="tab">
32
32
  <v-tab-item>
33
- <ManageLti1p1></ManageLti1p1>
33
+ <ManageLti1p1 />
34
34
  </v-tab-item>
35
35
  <v-tab-item>
36
36
  <ManageLti1p3 />
37
37
  </v-tab-item>
38
38
  <v-tab-item>
39
- <p class="ma-5">SCORM 1.2 Not yet implemented</p>
39
+ <ManageScorm />
40
40
  </v-tab-item>
41
41
  </v-tabs-items>
42
42
  </div>
@@ -45,13 +45,13 @@
45
45
  <script>
46
46
  import ManageLti1p1 from '../../ExternalIntegration/Driver/ManageLti1p1.vue'
47
47
  import ManageLti1p3 from '../../ExternalIntegration/Driver/ManageLti1p3.vue'
48
+ import ManageScorm from '../../ExternalIntegration/Driver/ManageScorm.vue'
48
49
  export default {
49
50
  name: 'PluginIntegrationsExternalIntegrationManageCourseIntegrationSettings',
50
- components: { ManageLti1p1, ManageLti1p3 },
51
+ components: { ManageLti1p1, ManageLti1p3, ManageScorm },
51
52
  data() {
52
53
  return {
53
54
  tab: 0,
54
- ltiReady: false,
55
55
  }
56
56
  },
57
57
  }
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <v-container>
3
+ <BaseContentBlockSettings
4
+ v-if="false"
5
+ v-model="block.metadata.config"
6
+ :disabled="render"
7
+ ></BaseContentBlockSettings>
8
+ <v-alert type="warning">Not implemented</v-alert>
9
+ </v-container>
10
+ </template>
11
+
12
+ <script>
13
+ import { mapGetters } from 'vuex'
14
+ import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
15
+ import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
16
+
17
+ export default {
18
+ name: 'ContentBlockExternalIntegrationScormConsumerSettings',
19
+ components: {
20
+ BaseContentBlockSettings,
21
+ },
22
+ extends: BaseContentSettings,
23
+ props: {
24
+ settings: { type: Object, required: false, default: null },
25
+ context: { type: String, required: false, default: 'block' },
26
+ },
27
+ data() {
28
+ return {}
29
+ },
30
+ async fetch() {},
31
+ computed: {
32
+ ...mapGetters({
33
+ organization: 'organization/get',
34
+ course: 'course/get',
35
+ }),
36
+ },
37
+ watch: {},
38
+ beforeMount() {},
39
+ mounted() {},
40
+ methods: {},
41
+ }
42
+ </script>