@windward/integrations 0.17.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 (80) hide show
  1. package/CHANGELOG.md +25 -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/Integration/Driver/LoginSamlButton.vue +119 -0
  19. package/components/Integration/Driver/ManageSaml.vue +327 -0
  20. package/components/LLM/GenerateContent/BlockQuestionGenerateButton.vue +34 -3
  21. package/components/SecretField.vue +99 -19
  22. package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +2 -2
  23. package/components/Settings/ExternalIntegration/ManageCourseIntegrationSettings.vue +6 -6
  24. package/components/Settings/ExternalIntegration/ScormConsumerSettings.vue +42 -0
  25. package/config/integration.config.js +2 -0
  26. package/helpers/Driver/SamlSso.ts +12 -0
  27. package/helpers/ExternalIntegration/ScormHelper.ts +155 -0
  28. package/i18n/en-US/components/external_integration/driver/lti1p3.ts +4 -1
  29. package/i18n/en-US/components/external_integration/driver/scorm.ts +14 -0
  30. package/i18n/en-US/components/external_integration/index.ts +3 -1
  31. package/i18n/en-US/components/integration/driver.ts +23 -0
  32. package/i18n/en-US/components/llm/generate_content/generate_questions.ts +7 -0
  33. package/i18n/en-US/pages/course/external_integration/index.ts +1 -1
  34. package/i18n/en-US/pages/login/index.ts +4 -0
  35. package/i18n/en-US/pages/login/lti.ts +2 -0
  36. package/i18n/en-US/pages/login/saml.ts +7 -0
  37. package/i18n/en-US/pages/login/scorm.ts +28 -0
  38. package/i18n/en-US/shared/content_blocks.ts +1 -0
  39. package/i18n/en-US/shared/settings.ts +1 -0
  40. package/i18n/es-ES/components/external_integration/driver/lti1p3.ts +4 -1
  41. package/i18n/es-ES/components/external_integration/driver/scorm.ts +15 -0
  42. package/i18n/es-ES/components/external_integration/index.ts +3 -1
  43. package/i18n/es-ES/components/integration/driver.ts +23 -0
  44. package/i18n/es-ES/components/llm/generate_content/generate_questions.ts +7 -0
  45. package/i18n/es-ES/pages/course/external_integration/index.ts +1 -1
  46. package/i18n/es-ES/pages/login/index.ts +4 -0
  47. package/i18n/es-ES/pages/login/lti.ts +2 -0
  48. package/i18n/es-ES/pages/login/saml.ts +7 -0
  49. package/i18n/es-ES/pages/login/scorm.ts +29 -0
  50. package/i18n/es-ES/shared/content_blocks.ts +1 -0
  51. package/i18n/es-ES/shared/settings.ts +1 -0
  52. package/i18n/sv-SE/components/external_integration/driver/lti1p3.ts +4 -1
  53. package/i18n/sv-SE/components/external_integration/driver/scorm.ts +14 -0
  54. package/i18n/sv-SE/components/external_integration/index.ts +3 -1
  55. package/i18n/sv-SE/components/integration/driver.ts +23 -0
  56. package/i18n/sv-SE/components/llm/generate_content/generate_questions.ts +7 -0
  57. package/i18n/sv-SE/pages/course/external_integration/index.ts +1 -1
  58. package/i18n/sv-SE/pages/login/index.ts +4 -0
  59. package/i18n/sv-SE/pages/login/lti.ts +2 -0
  60. package/i18n/sv-SE/pages/login/saml.ts +7 -0
  61. package/i18n/sv-SE/pages/login/scorm.ts +29 -0
  62. package/i18n/sv-SE/shared/content_blocks.ts +2 -1
  63. package/i18n/sv-SE/shared/settings.ts +1 -0
  64. package/jest.config.js +3 -0
  65. package/models/Auth/Saml.ts +21 -0
  66. package/models/ExternalIntegration/{LtiConsumer.ts → Consumer.ts} +2 -2
  67. package/models/ExternalIntegration/{LtiProvider.ts → Provider.ts} +2 -2
  68. package/package.json +2 -1
  69. package/pages/course/externalIntegration/index.vue +4 -0
  70. package/pages/login/scorm/error.vue +102 -0
  71. package/pages/login/scorm/promptEmail.vue +180 -0
  72. package/plugin.js +128 -7
  73. package/test/Components/ExternalIntegration/ManageScorm.spec.js +19 -0
  74. package/test/Components/ExternalIntegration/Scorm/ManageConsumer.spec.js +19 -0
  75. package/test/Components/ExternalIntegration/Scorm/ManageConsumers.spec.js +19 -0
  76. package/test/Components/ExternalIntegration/Scorm/ManageProvider.spec.js +19 -0
  77. package/test/Components/ExternalIntegration/Scorm/ManageProviders.spec.js +19 -0
  78. package/test/__mocks__/componentsMock.js +81 -1
  79. package/test/mocks.js +12 -0
  80. package/test/setup.js +1 -0
@@ -0,0 +1,327 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="!render" class="integration-loading">
4
+ <v-progress-circular size="128" indeterminate />
5
+ </div>
6
+ <div v-if="render">
7
+ <v-row justify="center" align="center" class="mt-5">
8
+ <v-col cols="12">
9
+ <v-switch
10
+ v-model="integration.enabled"
11
+ :label="
12
+ $t(
13
+ 'windward.integrations.components.integration.driver.enabled'
14
+ )
15
+ "
16
+ />
17
+
18
+ <v-text-field
19
+ id="saml-entity-id"
20
+ v-model="integration.metadata.config.idp_entity_id"
21
+ :label="
22
+ $t(
23
+ 'windward.integrations.components.integration.driver.saml_sso.idp_entity_id'
24
+ )
25
+ "
26
+ :hint="
27
+ $t(
28
+ 'windward.integrations.components.integration.driver.saml_sso.idp_entity_id_hint'
29
+ )
30
+ "
31
+ :rules="$Validation.getRule('exists')"
32
+ ></v-text-field>
33
+
34
+ <v-text-field
35
+ id="saml-sso-url"
36
+ v-model="integration.metadata.config.idp_sso_url"
37
+ :label="
38
+ $t(
39
+ 'windward.integrations.components.integration.driver.saml_sso.idp_sso_url'
40
+ )
41
+ "
42
+ :hint="
43
+ $t(
44
+ 'windward.integrations.components.integration.driver.saml_sso.idp_sso_url_hint'
45
+ )
46
+ "
47
+ :rules="$Validation.getRule('url')"
48
+ ></v-text-field>
49
+
50
+ <v-text-field
51
+ id="saml-slo-url"
52
+ v-model="integration.metadata.config.idp_slo_url"
53
+ autocomplete="off"
54
+ :label="
55
+ $t(
56
+ 'windward.integrations.components.integration.driver.saml_sso.idp_slo_url'
57
+ )
58
+ "
59
+ :hint="
60
+ $t(
61
+ 'windward.integrations.components.integration.driver.saml_sso.idp_slo_url_hint'
62
+ )
63
+ "
64
+ :rules="$Validation.getRule('url')"
65
+ ></v-text-field>
66
+
67
+ <SecretField
68
+ id="saml-certificate"
69
+ v-model="integration.metadata.config.idp_x509_cert"
70
+ tag="v-textarea"
71
+ autocomplete="off"
72
+ :label="
73
+ $t(
74
+ 'windward.integrations.components.integration.driver.saml_sso.idp_x509_cert'
75
+ )
76
+ "
77
+ :hint="
78
+ $t(
79
+ 'windward.integrations.components.integration.driver.saml_sso.idp_x509_cert_hint'
80
+ )
81
+ "
82
+ :append-icon="
83
+ showCertificate ? 'mdi-eye' : 'mdi-eye-off'
84
+ "
85
+ rows="4"
86
+ :rules="$Validation.getRule('exists')"
87
+ :readonly="!showCertificate"
88
+ :hidden="!showCertificate"
89
+ :type="showCertificate ? 'text' : 'password'"
90
+ @click:append="showCertificate = !showCertificate"
91
+ ></SecretField>
92
+
93
+ <v-alert
94
+ v-if="integration.metadata.config.idp_x509_cert"
95
+ type="success"
96
+ text
97
+ dense
98
+ class="mt-2"
99
+ >
100
+ <v-icon small left>mdi-lock</v-icon>
101
+ {{
102
+ $t(
103
+ 'windward.integrations.components.integration.driver.saml_sso.cert_stored'
104
+ )
105
+ }}
106
+ </v-alert>
107
+
108
+ <v-divider class="my-4" />
109
+
110
+ <h3 class="mb-3">
111
+ {{
112
+ $t(
113
+ 'windward.integrations.components.integration.driver.saml_sso.button_settings'
114
+ )
115
+ }}
116
+ </h3>
117
+
118
+ <v-text-field
119
+ id="saml-button-label"
120
+ v-model="integration.metadata.config.button_label"
121
+ :label="
122
+ $t(
123
+ 'windward.integrations.components.integration.driver.saml_sso.button_label'
124
+ )
125
+ "
126
+ :hint="
127
+ $t(
128
+ 'windward.integrations.components.integration.driver.saml_sso.button_label_hint'
129
+ )
130
+ "
131
+ :placeholder="
132
+ $t(
133
+ 'windward.integrations.components.integration.driver.saml_sso.button_label_default'
134
+ )
135
+ "
136
+ ></v-text-field>
137
+
138
+ <v-text-field
139
+ id="saml-button-icon"
140
+ v-model="integration.metadata.config.button_icon"
141
+ :label="
142
+ $t(
143
+ 'windward.integrations.components.integration.driver.saml_sso.button_icon'
144
+ )
145
+ "
146
+ :hint="
147
+ $t(
148
+ 'windward.integrations.components.integration.driver.saml_sso.button_icon_hint'
149
+ )
150
+ "
151
+ placeholder="mdi-login"
152
+ >
153
+ <template #prepend>
154
+ <v-icon>{{
155
+ integration.metadata.config.button_icon ||
156
+ 'mdi-login'
157
+ }}</v-icon>
158
+ </template>
159
+ </v-text-field>
160
+
161
+ <v-divider class="my-4" />
162
+
163
+ <v-alert type="info" outlined>
164
+ <div class="font-weight-bold mb-2">
165
+ {{
166
+ $t(
167
+ 'windward.integrations.components.integration.driver.saml_sso.sp_details'
168
+ )
169
+ }}
170
+ </div>
171
+ <div class="text--secondary">
172
+ {{
173
+ $t(
174
+ 'windward.integrations.components.integration.driver.saml_sso.sp_details_description'
175
+ )
176
+ }}
177
+ </div>
178
+ <div class="mt-3">
179
+ <div>
180
+ <strong
181
+ >{{
182
+ $t(
183
+ 'windward.integrations.components.integration.driver.saml_sso.sp_entity_id_label'
184
+ )
185
+ }}:</strong
186
+ >
187
+ {{ spEntityId }}
188
+ </div>
189
+ <div>
190
+ <strong
191
+ >{{
192
+ $t(
193
+ 'windward.integrations.components.integration.driver.saml_sso.acs_url_label'
194
+ )
195
+ }}:</strong
196
+ >
197
+ {{ acsUrl }}
198
+ </div>
199
+ <div>
200
+ <strong
201
+ >{{
202
+ $t(
203
+ 'windward.integrations.components.integration.driver.saml_sso.slo_url_label'
204
+ )
205
+ }}:</strong
206
+ >
207
+ {{ sloUrl }}
208
+ </div>
209
+ </div>
210
+ </v-alert>
211
+
212
+ <TestConnection
213
+ :disabled="
214
+ !integration.metadata.config.idp_entity_id ||
215
+ !integration.metadata.config.idp_sso_url ||
216
+ !integration.metadata.config.idp_slo_url ||
217
+ !integration.metadata.config.idp_x509_cert
218
+ "
219
+ :loading="testConnectionLoading"
220
+ :errors="errorMessage"
221
+ @click="onTestConnection"
222
+ ></TestConnection>
223
+ </v-col>
224
+ </v-row>
225
+ </div>
226
+ </div>
227
+ </template>
228
+
229
+ <script>
230
+ import _ from 'lodash'
231
+ import TestConnection from '../TestConnection.vue'
232
+ import ManageBaseVue from './ManageBase.vue'
233
+ import SecretField from '../../SecretField.vue'
234
+ import Uuid from '~/helpers/Uuid'
235
+
236
+ export default {
237
+ name: 'ManageSamlDriver',
238
+ components: { TestConnection, SecretField },
239
+ extends: ManageBaseVue,
240
+ data() {
241
+ return {
242
+ // formValid: true|false If this form is "complete" and passed validation on THIS component. Defined and watched in ManageBase.vue
243
+ // render: true|false If we should show the form aka when validation has passed. Defined and managed in ManageBase.vue
244
+ // integration: { metadata: {...} } The integration object to write to. Defined and loaded in ManageBase.vue
245
+ showCertificate: false,
246
+ errorMessage: '',
247
+ testConnectionLoading: false,
248
+ }
249
+ },
250
+ computed: {
251
+ spEntityId() {
252
+ return `${process.env.BASE_URL}/saml/metadata`
253
+ },
254
+ acsUrl() {
255
+ return `${process.env.BASE_URL}/saml/acs`
256
+ },
257
+ sloUrl() {
258
+ return `${process.env.BASE_URL}/saml/slo`
259
+ },
260
+ },
261
+ methods: {
262
+ /**
263
+ * Lifecycle event called from ManageBase.vue when async fetch() completes.
264
+ * Once called this.integration will be available containing the integration model (or a new one)
265
+ */
266
+ onIntegrationLoaded() {
267
+ // Initialize SAML config if not exists
268
+ if (!this.integration.metadata.config) {
269
+ this.integration.metadata.config = {
270
+ idp_entity_id: '',
271
+ idp_sso_url: '',
272
+ idp_slo_url: '',
273
+ idp_x509_cert: '',
274
+ button_label: '',
275
+ button_icon: 'mdi-login',
276
+ }
277
+ }
278
+
279
+ // Set defaults for button settings if not present
280
+ if (!this.integration.metadata.config.button_label) {
281
+ this.integration.metadata.config.button_label = ''
282
+ }
283
+ if (!this.integration.metadata.config.button_icon) {
284
+ this.integration.metadata.config.button_icon = 'mdi-login'
285
+ }
286
+
287
+ // Show the certificate by default if this is a new integration without a cert
288
+ this.showCertificate = _.isEmpty(
289
+ _.get(this.integration, 'metadata.config.idp_x509_cert', null)
290
+ )
291
+ },
292
+ async onTestConnection() {
293
+ this.testConnectionLoading = true
294
+ let response = { result: false }
295
+ try {
296
+ response = await this.testConnection(this.integration.metadata)
297
+
298
+ if (response.result) {
299
+ this.errorMessage = ''
300
+ this.$dialog.success(
301
+ this.$t(
302
+ 'windward.integrations.shared.error.connect_success'
303
+ )
304
+ )
305
+ } else {
306
+ this.errorMessage = response.message
307
+ this.$dialog.error(
308
+ this.$t(
309
+ 'windward.integrations.shared.error.connect_fail'
310
+ )
311
+ )
312
+ }
313
+ } catch (e) {
314
+ console.error(e)
315
+ this.$dialog.error(
316
+ this.$t('windward.integrations.shared.error.unknown')
317
+ )
318
+ }
319
+
320
+ // We will indirectly validate the form via connection tests
321
+ // That way we can 100% confirm that the integration is valid
322
+ this.formValid = response.result
323
+ this.testConnectionLoading = false
324
+ },
325
+ },
326
+ }
327
+ </script>
@@ -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,28 +1,68 @@
1
1
  <template>
2
- <v-text-field
3
- id="secret-field"
4
- :value="value"
5
- readonly
6
- :type="fieldType"
7
- :placeholder="placeholder"
8
- :label="label"
9
- >
10
- <template #append>
11
- <v-btn icon elevation="0" @click="toggleClear">
12
- <v-icon>{{ showClear ? 'mdi-eye-off' : 'mdi-eye' }}</v-icon>
13
- </v-btn>
14
- <v-btn v-if="copy" icon elevation="0" @click="copyText(value)">
15
- <v-icon>mdi-content-copy</v-icon>
16
- <span class="sr-only">{{ $t('shared.forms.copy') }}</span>
17
- </v-btn>
18
- </template>
19
- </v-text-field>
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>
20
56
  </template>
21
57
 
22
58
  <script>
59
+ import Crypto from '~/helpers/Crypto'
60
+
23
61
  export default {
24
62
  name: 'SecretField',
63
+ components: {},
25
64
  props: {
65
+ tag: { type: String, required: false, default: 'v-text-field' },
26
66
  value: { type: String, required: false, default: '' },
27
67
  hidden: { type: Boolean, required: false, default: true },
28
68
  copy: { type: Boolean, required: false, default: true },
@@ -34,14 +74,53 @@ export default {
34
74
  type: String,
35
75
  required: false,
36
76
  },
77
+ hint: {
78
+ type: String,
79
+ required: false,
80
+ },
81
+ autocomplete: {
82
+ type: String,
83
+ required: false,
84
+ },
85
+ appendIcon: {
86
+ type: String,
87
+ required: false,
88
+ },
89
+ rules: {
90
+ type: Array,
91
+ required: false,
92
+ default: () => [],
93
+ },
94
+ rows: {
95
+ type: [String, Number],
96
+ required: false,
97
+ default: 5,
98
+ },
99
+ readonly: {
100
+ type: Boolean,
101
+ required: false,
102
+ default: true,
103
+ },
37
104
  },
38
105
  data() {
39
106
  return {
40
107
  showClear: false,
41
108
  }
42
109
  },
43
-
44
110
  computed: {
111
+ activeTag() {
112
+ let tag = this.tag
113
+
114
+ // If the field type is password we need to hard-change to textfield since other components don't support password text
115
+ if (this.fieldType === 'password') {
116
+ tag = 'v-text-field'
117
+ }
118
+
119
+ return tag
120
+ },
121
+ key() {
122
+ return Crypto.id()
123
+ },
45
124
  fieldType() {
46
125
  if (this.showClear) {
47
126
  return 'text'
@@ -56,6 +135,7 @@ export default {
56
135
  methods: {
57
136
  toggleClear() {
58
137
  this.showClear = !this.showClear
138
+ this.$emit('click:append', this.showClear)
59
139
  },
60
140
  copyText(text) {
61
141
  navigator.clipboard.writeText(text || '')
@@ -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>