@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.
- package/CHANGELOG.md +16 -0
- package/components/Content/Blocks/ExternalIntegration/LtiConsumer.vue +3 -3
- package/components/Content/Blocks/ExternalIntegration/ScormConsumer.vue +34 -0
- package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue +10 -8
- package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumers.vue +2 -2
- package/components/ExternalIntegration/Driver/Lti1p1/ManageProvider.vue +8 -5
- package/components/ExternalIntegration/Driver/Lti1p1/ManageProviders.vue +3 -2
- package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumer.vue +8 -6
- package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumers.vue +2 -2
- package/components/ExternalIntegration/Driver/Lti1p3/ManageProvider.vue +27 -5
- package/components/ExternalIntegration/Driver/Lti1p3/ManageProviders.vue +4 -3
- package/components/ExternalIntegration/Driver/Lti1p3/ViewConsumer.vue +6 -5
- package/components/ExternalIntegration/Driver/ManageScorm.vue +45 -0
- package/components/ExternalIntegration/Driver/Scorm/ManageConsumer.vue +76 -0
- package/components/ExternalIntegration/Driver/Scorm/ManageConsumers.vue +233 -0
- package/components/ExternalIntegration/Driver/Scorm/ManageProvider.vue +475 -0
- package/components/ExternalIntegration/Driver/Scorm/ManageProviders.vue +299 -0
- package/components/LLM/GenerateContent/BlockQuestionGenerateButton.vue +34 -3
- package/components/SecretField.vue +57 -34
- package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +2 -2
- package/components/Settings/ExternalIntegration/ManageCourseIntegrationSettings.vue +6 -6
- package/components/Settings/ExternalIntegration/ScormConsumerSettings.vue +42 -0
- package/helpers/ExternalIntegration/ScormHelper.ts +155 -0
- package/i18n/en-US/components/external_integration/driver/lti1p3.ts +4 -1
- package/i18n/en-US/components/external_integration/driver/scorm.ts +14 -0
- package/i18n/en-US/components/external_integration/index.ts +3 -1
- package/i18n/en-US/components/llm/generate_content/generate_questions.ts +7 -0
- package/i18n/en-US/pages/course/external_integration/index.ts +1 -1
- package/i18n/en-US/pages/login/index.ts +2 -0
- package/i18n/en-US/pages/login/lti.ts +2 -0
- package/i18n/en-US/pages/login/scorm.ts +28 -0
- package/i18n/en-US/shared/content_blocks.ts +1 -0
- package/i18n/en-US/shared/settings.ts +1 -0
- package/i18n/es-ES/components/external_integration/driver/lti1p3.ts +4 -1
- package/i18n/es-ES/components/external_integration/driver/scorm.ts +15 -0
- package/i18n/es-ES/components/external_integration/index.ts +3 -1
- package/i18n/es-ES/components/llm/generate_content/generate_questions.ts +7 -0
- package/i18n/es-ES/pages/course/external_integration/index.ts +1 -1
- package/i18n/es-ES/pages/login/index.ts +2 -0
- package/i18n/es-ES/pages/login/lti.ts +2 -0
- package/i18n/es-ES/pages/login/scorm.ts +29 -0
- package/i18n/es-ES/shared/content_blocks.ts +1 -0
- package/i18n/es-ES/shared/settings.ts +1 -0
- package/i18n/sv-SE/components/external_integration/driver/lti1p3.ts +4 -1
- package/i18n/sv-SE/components/external_integration/driver/scorm.ts +14 -0
- package/i18n/sv-SE/components/external_integration/index.ts +3 -1
- package/i18n/sv-SE/components/llm/generate_content/generate_questions.ts +7 -0
- package/i18n/sv-SE/pages/course/external_integration/index.ts +1 -1
- package/i18n/sv-SE/pages/login/index.ts +2 -0
- package/i18n/sv-SE/pages/login/lti.ts +2 -0
- package/i18n/sv-SE/pages/login/scorm.ts +29 -0
- package/i18n/sv-SE/shared/content_blocks.ts +2 -1
- package/i18n/sv-SE/shared/settings.ts +1 -0
- package/models/ExternalIntegration/{LtiConsumer.ts → Consumer.ts} +2 -2
- package/models/ExternalIntegration/{LtiProvider.ts → Provider.ts} +2 -2
- package/package.json +2 -1
- package/pages/course/externalIntegration/index.vue +4 -0
- package/pages/login/scorm/error.vue +102 -0
- package/pages/login/scorm/promptEmail.vue +180 -0
- package/plugin.js +111 -7
- package/test/Components/ExternalIntegration/ManageScorm.spec.js +19 -0
- package/test/Components/ExternalIntegration/Scorm/ManageConsumer.spec.js +19 -0
- package/test/Components/ExternalIntegration/Scorm/ManageConsumers.spec.js +19 -0
- package/test/Components/ExternalIntegration/Scorm/ManageProvider.spec.js +19 -0
- package/test/Components/ExternalIntegration/Scorm/ManageProviders.spec.js +19 -0
- 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
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
<v-icon
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<v-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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: {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
22
|
+
<v-tab>
|
|
23
23
|
{{
|
|
24
24
|
$t(
|
|
25
|
-
'windward.integrations.pages.course.external_integration.
|
|
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
|
|
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
|
-
<
|
|
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>
|