@windward/integrations 0.0.6 → 0.0.8
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/components/Content/Blocks/ExternalIntegration/LtiConsumer.vue +37 -23
- package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue +12 -14
- package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumers.vue +22 -25
- package/components/ExternalIntegration/Driver/Lti1p1/ManageProvider.vue +53 -19
- package/components/ExternalIntegration/Driver/Lti1p1/ManageProviders.vue +53 -21
- package/components/ExternalIntegration/Driver/ManageLti1p1.vue +2 -2
- package/components/ExternalIntegration/ProviderTargetPicker.vue +218 -0
- package/components/ExternalIntegration/ProviderTargetViewer.vue +50 -0
- package/components/Integration/Driver/ManageBase.vue +3 -1
- package/components/Integration/JobTable.vue +2 -1
- package/components/SecretField.vue +1 -1
- package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +16 -19
- package/i18n/en-US/components/content/blocks/external_integration/lti_consumer.ts +2 -0
- package/i18n/en-US/components/external_integration/driver/lti1p1.ts +0 -20
- package/i18n/en-US/components/external_integration/index.ts +26 -1
- package/i18n/en-US/components/external_integration/provider_target.ts +9 -0
- package/i18n/en-US/pages/login/lti.ts +1 -1
- package/package.json +1 -1
- package/pages/admin/importCourse.vue +3 -0
- package/pages/admin/vendors.vue +2 -1
- package/plugin.js +1 -1
- package/test/Components/ExternalIntegration/ProviderTargetPicker.spec.js +22 -0
- package/test/Components/ExternalIntegration/ProviderTargetViewer.spec.js +22 -0
- package/test/__mocks__/componentsMock.js +12 -0
- package/test/__mocks__/modelMock.js +1 -1
- package/test/mocks.js +1 -0
|
@@ -23,29 +23,44 @@
|
|
|
23
23
|
:items-per-page="10"
|
|
24
24
|
class="elevation-1"
|
|
25
25
|
>
|
|
26
|
-
<template #item.
|
|
26
|
+
<template #[`item.target`]="{ item }">
|
|
27
|
+
<ProviderTargetViewer
|
|
28
|
+
class="field--target text-truncate"
|
|
29
|
+
:target="item.target"
|
|
30
|
+
></ProviderTargetViewer>
|
|
31
|
+
</template>
|
|
32
|
+
<template #[`item.metadata.key`]="{ item }">
|
|
27
33
|
<SecretField v-model="item.metadata.key"></SecretField>
|
|
28
34
|
</template>
|
|
29
|
-
<template #item.metadata.secret="{ item }">
|
|
35
|
+
<template #[`item.metadata.secret`]="{ item }">
|
|
30
36
|
<SecretField v-model="item.metadata.secret"></SecretField>
|
|
31
37
|
</template>
|
|
32
|
-
<template #item.url="{ item }">
|
|
38
|
+
<template #[`item.url`]="{ item }">
|
|
33
39
|
<SecretField v-model="item.url" :hidden="false"></SecretField>
|
|
34
40
|
</template>
|
|
35
41
|
|
|
36
|
-
<template #item.enabled="{ item }">
|
|
42
|
+
<template #[`item.enabled`]="{ item }">
|
|
37
43
|
<v-icon :color="item.enabled ? 'success' : 'error'"
|
|
38
44
|
>{{ item.enabled ? 'mdi-check' : 'mdi-close' }}
|
|
39
45
|
</v-icon>
|
|
40
46
|
<span v-if="!item.enabled" class="sr-only">{{
|
|
47
|
+
$t('shared.forms.enabled')
|
|
48
|
+
}}</span>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<template #[`item.grade_sync`]="{ item }">
|
|
52
|
+
<v-icon :color="item.grade_sync ? 'success' : 'error'"
|
|
53
|
+
>{{ item.grade_sync ? 'mdi-check' : 'mdi-close' }}
|
|
54
|
+
</v-icon>
|
|
55
|
+
<span v-if="!item.grade_sync" class="sr-only">{{
|
|
41
56
|
$t(
|
|
42
|
-
'windward.integrations.components.external_integration.
|
|
57
|
+
'windward.integrations.components.external_integration.grade_sync'
|
|
43
58
|
)
|
|
44
59
|
}}</span>
|
|
45
60
|
</template>
|
|
46
61
|
|
|
47
|
-
<template #item.created_at="{ item }">
|
|
48
|
-
{{ $d(new Date(item.created_at), '
|
|
62
|
+
<template #[`item.created_at`]="{ item }">
|
|
63
|
+
{{ $d(new Date(item.created_at), 'short') }}
|
|
49
64
|
</template>
|
|
50
65
|
<template #[`item.actions`]="{ index, item }">
|
|
51
66
|
<Dialog color="primary" action-save @click:save="onSaved">
|
|
@@ -83,23 +98,24 @@
|
|
|
83
98
|
<script>
|
|
84
99
|
import _ from 'lodash'
|
|
85
100
|
import { mapGetters } from 'vuex'
|
|
86
|
-
import Lti1p1Provider from '../../../../models/ExternalIntegration/Lti1p1Provider'
|
|
87
|
-
import SecretField from '../../../SecretField.vue'
|
|
88
|
-
import ManageProvider from './ManageProvider.vue'
|
|
89
101
|
import Course from '~/models/Course'
|
|
90
102
|
import Organization from '~/models/Organization'
|
|
91
103
|
import Dialog from '~/components/Dialog.vue'
|
|
104
|
+
import Lti1p1Provider from '../../../../models/ExternalIntegration/Lti1p1Provider'
|
|
105
|
+
import SecretField from '../../../SecretField.vue'
|
|
106
|
+
import ProviderTargetViewer from '../../ProviderTargetViewer.vue'
|
|
107
|
+
import ManageProvider from './ManageProvider.vue'
|
|
92
108
|
|
|
93
109
|
export default {
|
|
94
110
|
name: 'ManageLti1p1ProvidersDriver',
|
|
95
|
-
components: { SecretField, Dialog, ManageProvider },
|
|
111
|
+
components: { SecretField, Dialog, ManageProvider, ProviderTargetViewer },
|
|
96
112
|
data() {
|
|
97
113
|
return {
|
|
98
114
|
providers: [],
|
|
99
115
|
headers: [
|
|
100
116
|
{
|
|
101
117
|
text: this.$t(
|
|
102
|
-
'windward.integrations.components.external_integration.
|
|
118
|
+
'windward.integrations.components.external_integration.target'
|
|
103
119
|
),
|
|
104
120
|
value: 'target',
|
|
105
121
|
},
|
|
@@ -117,15 +133,19 @@ export default {
|
|
|
117
133
|
},
|
|
118
134
|
{
|
|
119
135
|
text: this.$t(
|
|
120
|
-
'windward.integrations.components.external_integration.
|
|
136
|
+
'windward.integrations.components.external_integration.launch_url'
|
|
121
137
|
),
|
|
122
138
|
value: 'url',
|
|
123
139
|
},
|
|
140
|
+
{
|
|
141
|
+
text: this.$t('shared.forms.enabled'),
|
|
142
|
+
value: 'enabled',
|
|
143
|
+
},
|
|
124
144
|
{
|
|
125
145
|
text: this.$t(
|
|
126
|
-
'windward.integrations.components.external_integration.
|
|
146
|
+
'windward.integrations.components.external_integration.grade_sync'
|
|
127
147
|
),
|
|
128
|
-
value: '
|
|
148
|
+
value: 'grade_sync',
|
|
129
149
|
},
|
|
130
150
|
{ text: this.$t('shared.forms.created'), value: 'created_at' },
|
|
131
151
|
{
|
|
@@ -151,16 +171,18 @@ export default {
|
|
|
151
171
|
duration: null,
|
|
152
172
|
action: {
|
|
153
173
|
text: this.$t('shared.forms.close'),
|
|
154
|
-
onClick: (
|
|
174
|
+
onClick: (_e, toastObject) => {
|
|
155
175
|
toastObject.goAway(0)
|
|
156
176
|
},
|
|
157
177
|
},
|
|
158
178
|
})
|
|
159
179
|
if (_.isEmpty(this.organization.id) || _.isEmpty(this.course.id)) {
|
|
180
|
+
// eslint-disable-next-line no-console
|
|
160
181
|
console.error(
|
|
161
182
|
'Cannot load external integrations because organization or course is not set!'
|
|
162
183
|
)
|
|
163
184
|
} else {
|
|
185
|
+
// eslint-disable-next-line no-console
|
|
164
186
|
console.error(
|
|
165
187
|
'You do not have access to this external integration!'
|
|
166
188
|
)
|
|
@@ -179,7 +201,7 @@ export default {
|
|
|
179
201
|
}),
|
|
180
202
|
},
|
|
181
203
|
methods: {
|
|
182
|
-
onSaved(
|
|
204
|
+
onSaved() {
|
|
183
205
|
this.loadProviders()
|
|
184
206
|
},
|
|
185
207
|
async loadProviders() {
|
|
@@ -197,14 +219,14 @@ export default {
|
|
|
197
219
|
action: [
|
|
198
220
|
{
|
|
199
221
|
text: this.$t('shared.forms.cancel'),
|
|
200
|
-
onClick: (
|
|
222
|
+
onClick: (_e, toastObject) => {
|
|
201
223
|
toastObject.goAway(0)
|
|
202
224
|
},
|
|
203
225
|
},
|
|
204
226
|
{
|
|
205
227
|
text: this.$t('shared.forms.confirm'),
|
|
206
228
|
// router navigation
|
|
207
|
-
onClick: (
|
|
229
|
+
onClick: (_e, toastObject) => {
|
|
208
230
|
this.deleteProvider(provider)
|
|
209
231
|
toastObject.goAway(0)
|
|
210
232
|
},
|
|
@@ -212,9 +234,19 @@ export default {
|
|
|
212
234
|
],
|
|
213
235
|
})
|
|
214
236
|
},
|
|
215
|
-
deleteProvider(provider) {
|
|
216
|
-
provider.delete()
|
|
237
|
+
async deleteProvider(provider) {
|
|
238
|
+
await provider.delete()
|
|
239
|
+
this.$dialog.success(this.$t('shared.response.deleted'))
|
|
240
|
+
// Reload providers now that we deleted one
|
|
241
|
+
this.loadProviders()
|
|
217
242
|
},
|
|
218
243
|
},
|
|
219
244
|
}
|
|
220
245
|
</script>
|
|
246
|
+
|
|
247
|
+
<style scoped>
|
|
248
|
+
.field--target {
|
|
249
|
+
max-width: 15em;
|
|
250
|
+
display: inline-block;
|
|
251
|
+
}
|
|
252
|
+
</style>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<v-expansion-panel-header>
|
|
6
6
|
{{
|
|
7
7
|
$t(
|
|
8
|
-
'windward.integrations.components.external_integration.
|
|
8
|
+
'windward.integrations.components.external_integration.provider_panel_title'
|
|
9
9
|
)
|
|
10
10
|
}}
|
|
11
11
|
</v-expansion-panel-header>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<v-expansion-panel-header>
|
|
18
18
|
{{
|
|
19
19
|
$t(
|
|
20
|
-
'windward.integrations.components.external_integration.
|
|
20
|
+
'windward.integrations.components.external_integration.consumer_panel_title'
|
|
21
21
|
)
|
|
22
22
|
}}
|
|
23
23
|
</v-expansion-panel-header>
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<v-radio-group
|
|
4
|
+
v-model="provider.target_type"
|
|
5
|
+
row
|
|
6
|
+
@change="onTargetTypeChange"
|
|
7
|
+
>
|
|
8
|
+
<template #label>
|
|
9
|
+
<div>
|
|
10
|
+
{{
|
|
11
|
+
$t(
|
|
12
|
+
'windward.integrations.components.external_integration.provider_target.link_to'
|
|
13
|
+
)
|
|
14
|
+
}}:
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
<v-radio
|
|
18
|
+
:label="
|
|
19
|
+
$t(
|
|
20
|
+
'windward.integrations.components.external_integration.provider_target.whole_course'
|
|
21
|
+
)
|
|
22
|
+
"
|
|
23
|
+
value="course"
|
|
24
|
+
></v-radio>
|
|
25
|
+
<v-radio
|
|
26
|
+
:label="
|
|
27
|
+
$t(
|
|
28
|
+
'windward.integrations.components.external_integration.provider_target.content_with_children'
|
|
29
|
+
)
|
|
30
|
+
"
|
|
31
|
+
value="locked_course_content_children"
|
|
32
|
+
></v-radio>
|
|
33
|
+
<v-radio
|
|
34
|
+
:label="
|
|
35
|
+
$t(
|
|
36
|
+
'windward.integrations.components.external_integration.provider_target.content_no_children'
|
|
37
|
+
)
|
|
38
|
+
"
|
|
39
|
+
value="locked_course_content"
|
|
40
|
+
></v-radio>
|
|
41
|
+
<v-radio
|
|
42
|
+
:label="
|
|
43
|
+
$t(
|
|
44
|
+
'windward.integrations.components.external_integration.provider_target.whole_course_page'
|
|
45
|
+
)
|
|
46
|
+
"
|
|
47
|
+
value="course_content"
|
|
48
|
+
></v-radio>
|
|
49
|
+
</v-radio-group>
|
|
50
|
+
|
|
51
|
+
<div
|
|
52
|
+
v-if="
|
|
53
|
+
provider.target_type === 'course_content' ||
|
|
54
|
+
provider.target_type === 'locked_course_content_children' ||
|
|
55
|
+
provider.target_type === 'locked_course_content'
|
|
56
|
+
"
|
|
57
|
+
class="content-tree secondary"
|
|
58
|
+
>
|
|
59
|
+
<v-treeview
|
|
60
|
+
v-model="selectedTreeviewContent"
|
|
61
|
+
selectable
|
|
62
|
+
selected-color="primary"
|
|
63
|
+
selection-type="independent"
|
|
64
|
+
return-object
|
|
65
|
+
open-all
|
|
66
|
+
:items="contentTree"
|
|
67
|
+
@input="onTreeChange"
|
|
68
|
+
>
|
|
69
|
+
<template #prepend="{ item }">
|
|
70
|
+
<v-chip v-if="isIncludedChild(item)" color="primary">
|
|
71
|
+
{{
|
|
72
|
+
$t(
|
|
73
|
+
'windward.integrations.components.external_integration.provider_target.included'
|
|
74
|
+
)
|
|
75
|
+
}}
|
|
76
|
+
</v-chip>
|
|
77
|
+
</template>
|
|
78
|
+
<template #label="{ item }">
|
|
79
|
+
{{ item.content.name_prefix }}
|
|
80
|
+
{{ item.content.name }}
|
|
81
|
+
</template>
|
|
82
|
+
</v-treeview>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</template>
|
|
86
|
+
|
|
87
|
+
<script>
|
|
88
|
+
import _ from 'lodash'
|
|
89
|
+
import { mapGetters } from 'vuex'
|
|
90
|
+
export default {
|
|
91
|
+
name: 'ExternalIntegrationProviderTargetPicker',
|
|
92
|
+
props: {
|
|
93
|
+
value: { type: Object, required: true },
|
|
94
|
+
},
|
|
95
|
+
data() {
|
|
96
|
+
return {
|
|
97
|
+
selectedContent: null,
|
|
98
|
+
selectedTreeviewContent: [],
|
|
99
|
+
provider: {},
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
computed: {
|
|
103
|
+
...mapGetters({
|
|
104
|
+
contentTree: 'content/getTree',
|
|
105
|
+
course: 'course/get',
|
|
106
|
+
}),
|
|
107
|
+
},
|
|
108
|
+
watch: {
|
|
109
|
+
// Apply any changes coming up
|
|
110
|
+
value: {
|
|
111
|
+
handler(value) {
|
|
112
|
+
this.provider = _.cloneDeep(value)
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
mounted() {
|
|
117
|
+
// Init our local vars
|
|
118
|
+
this.provider = _.cloneDeep(this.value)
|
|
119
|
+
|
|
120
|
+
// Set the target_type key if it doesn't exist
|
|
121
|
+
if (!this.provider.target_type) {
|
|
122
|
+
this.provider.target_type = 'course'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Preset the selected content
|
|
126
|
+
if (this.provider.target) {
|
|
127
|
+
if (!_.isEmpty(this.provider.course_content_id)) {
|
|
128
|
+
this.setSelectedContentById(this.provider.course_content_id)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
this.sync(this.provider.target_type)
|
|
132
|
+
},
|
|
133
|
+
methods: {
|
|
134
|
+
setSelectedContentById(id) {
|
|
135
|
+
this.selectedContent = { id }
|
|
136
|
+
this.selectedTreeviewContent = [{ id }]
|
|
137
|
+
},
|
|
138
|
+
sync(targetType) {
|
|
139
|
+
let url = ''
|
|
140
|
+
|
|
141
|
+
if (
|
|
142
|
+
this.selectedContent &&
|
|
143
|
+
(targetType === 'course_content' ||
|
|
144
|
+
targetType === 'locked_course_content' ||
|
|
145
|
+
targetType === 'locked_course_content_children')
|
|
146
|
+
) {
|
|
147
|
+
url = `/course/${this.course.id}/content/${this.selectedContent.id}`
|
|
148
|
+
this.provider.course_content_id = this.selectedContent.id
|
|
149
|
+
} else if (targetType === 'course') {
|
|
150
|
+
url = `/course/${this.course.id}/`
|
|
151
|
+
this.provider.course_content_id = null
|
|
152
|
+
}
|
|
153
|
+
this.provider.target = url
|
|
154
|
+
// Sync up the changes to the parent component
|
|
155
|
+
this.$emit('input', this.provider)
|
|
156
|
+
},
|
|
157
|
+
onTargetTypeChange(e) {
|
|
158
|
+
// Reset the selected content if you pick by course
|
|
159
|
+
if (e === 'course') {
|
|
160
|
+
this.selectedContent = null
|
|
161
|
+
this.selectedTreeviewContent = []
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.sync(e)
|
|
165
|
+
},
|
|
166
|
+
isIncludedChild(page, children = null) {
|
|
167
|
+
let isIncluded = false
|
|
168
|
+
// If we aren't including children then return hard false
|
|
169
|
+
if (
|
|
170
|
+
this.provider.target_type !== 'locked_course_content_children'
|
|
171
|
+
) {
|
|
172
|
+
return false
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// First run, assign the children from the selected page
|
|
176
|
+
if (this.selectedContent && children === null) {
|
|
177
|
+
children = _.get(this.selectedContent, 'children', [])
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (this.selectedContent && page.parent_id) {
|
|
181
|
+
if (this.selectedContent.id === page.parent_id) {
|
|
182
|
+
return true
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
for (let i = 0; i < children.length; i++) {
|
|
186
|
+
const child = children[i]
|
|
187
|
+
|
|
188
|
+
if (child.id === page.parent_id) {
|
|
189
|
+
return true
|
|
190
|
+
} else if (child.children && child.children.length) {
|
|
191
|
+
isIncluded = this.isIncludedChild(page, child.children)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return isIncluded
|
|
196
|
+
},
|
|
197
|
+
onTreeChange() {
|
|
198
|
+
// Enforce that only 1 item is selected at a time in the treeview
|
|
199
|
+
if (this.selectedTreeviewContent.length > 0) {
|
|
200
|
+
const last = this.selectedTreeviewContent.pop()
|
|
201
|
+
this.selectedTreeviewContent = [last]
|
|
202
|
+
this.selectedContent = last
|
|
203
|
+
} else {
|
|
204
|
+
this.selectedContent = null
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.sync(this.provider.target_type)
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
</script>
|
|
212
|
+
|
|
213
|
+
<style scoped>
|
|
214
|
+
.content-tree {
|
|
215
|
+
height: 230px;
|
|
216
|
+
overflow-y: auto;
|
|
217
|
+
}
|
|
218
|
+
</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span>{{ targetDisplayName }}</span>
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script>
|
|
6
|
+
import _ from 'lodash'
|
|
7
|
+
import { mapGetters } from 'vuex'
|
|
8
|
+
export default {
|
|
9
|
+
name: 'ExternalIntegrationProviderTargetViewer',
|
|
10
|
+
props: {
|
|
11
|
+
target: { type: String, required: true, default: '' },
|
|
12
|
+
},
|
|
13
|
+
computed: {
|
|
14
|
+
...mapGetters({
|
|
15
|
+
organization: 'organization/get',
|
|
16
|
+
course: 'course/get',
|
|
17
|
+
contentTree: 'content/getTree',
|
|
18
|
+
}),
|
|
19
|
+
targetDisplayName() {
|
|
20
|
+
if (_.isEmpty(this.target)) {
|
|
21
|
+
return ''
|
|
22
|
+
}
|
|
23
|
+
const match = this.target.match(
|
|
24
|
+
/\/content\/(?<content_id>[a-zA-Z0-9-]{36})/i
|
|
25
|
+
)
|
|
26
|
+
if (!_.isEmpty(match) && _.get(match, 'groups.content_id', null)) {
|
|
27
|
+
const flatTree = this.$ContentService.flattenTree(
|
|
28
|
+
this.contentTree
|
|
29
|
+
)
|
|
30
|
+
const item = flatTree.find(
|
|
31
|
+
(c) => c.id === _.get(match, 'groups.content_id', null)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if (!_.isEmpty(item)) {
|
|
35
|
+
return (
|
|
36
|
+
_.get(item, 'content.name_prefix', '') +
|
|
37
|
+
' ' +
|
|
38
|
+
_.get(item, 'content.name', '')
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
return this.$t(
|
|
43
|
+
'windward.integrations.components.external_integration.provider_target.whole_course'
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
return ''
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
@@ -38,11 +38,12 @@ export default {
|
|
|
38
38
|
duration: null,
|
|
39
39
|
action: {
|
|
40
40
|
text: this.$t('shared.forms.close'),
|
|
41
|
-
onClick: (
|
|
41
|
+
onClick: (_e, toastObject) => {
|
|
42
42
|
toastObject.goAway(0)
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
45
|
})
|
|
46
|
+
// eslint-disable-next-line no-console
|
|
46
47
|
console.error('You do not have access to this integration!')
|
|
47
48
|
|
|
48
49
|
// Return so we don't even attempt loading
|
|
@@ -129,6 +130,7 @@ export default {
|
|
|
129
130
|
},
|
|
130
131
|
|
|
131
132
|
onIntegrationLoaded() {
|
|
133
|
+
// eslint-disable-next-line no-console
|
|
132
134
|
console.warn(
|
|
133
135
|
'Integration/Driver/ManageBase.vue onIntegrationLoaded called. Not extended!'
|
|
134
136
|
)
|
|
@@ -247,7 +247,7 @@ export default {
|
|
|
247
247
|
connect(channel, event) {
|
|
248
248
|
this.socket.connector.pusher.connection.bind(
|
|
249
249
|
'connected',
|
|
250
|
-
function (
|
|
250
|
+
function (_socket) {
|
|
251
251
|
// Connected to socket id: socket.socket_id
|
|
252
252
|
}
|
|
253
253
|
)
|
|
@@ -266,6 +266,7 @@ export default {
|
|
|
266
266
|
|
|
267
267
|
onSocketJob(data) {
|
|
268
268
|
if (_.isEmpty(data.integrationJob)) {
|
|
269
|
+
// eslint-disable-next-line no-console
|
|
269
270
|
console.error('onSocketJob Missing data', data)
|
|
270
271
|
return false
|
|
271
272
|
}
|
|
@@ -46,10 +46,8 @@
|
|
|
46
46
|
</template>
|
|
47
47
|
|
|
48
48
|
<script>
|
|
49
|
-
import _ from 'lodash'
|
|
50
49
|
import { mapGetters } from 'vuex'
|
|
51
50
|
import BaseContentSettings from '~/components/Content/Tool/BaseContentSettings.js'
|
|
52
|
-
import ManageConsumer from '../../ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue'
|
|
53
51
|
import Course from '~/models/Course'
|
|
54
52
|
import Organization from '~/models/Organization'
|
|
55
53
|
import Lti1p1Consumer from '../../../models/ExternalIntegration/Lti1p1Consumer'
|
|
@@ -57,27 +55,10 @@ import Lti1p1Consumer from '../../../models/ExternalIntegration/Lti1p1Consumer'
|
|
|
57
55
|
export default {
|
|
58
56
|
name: 'ContentBlockExternalIntegrationLti1p1ConsumerSettings',
|
|
59
57
|
extends: BaseContentSettings,
|
|
60
|
-
components: { ManageConsumer },
|
|
61
58
|
props: {
|
|
62
59
|
settings: { type: Object, required: false, default: null },
|
|
63
60
|
context: { type: String, required: false, default: 'block' },
|
|
64
61
|
},
|
|
65
|
-
async fetch() {
|
|
66
|
-
this.consumers = await new Lti1p1Consumer()
|
|
67
|
-
.for(
|
|
68
|
-
new Organization({ id: this.organization.id }),
|
|
69
|
-
new Course({ id: this.course.id })
|
|
70
|
-
)
|
|
71
|
-
.orderBy('name')
|
|
72
|
-
.get()
|
|
73
|
-
},
|
|
74
|
-
computed: {
|
|
75
|
-
...mapGetters({
|
|
76
|
-
organization: 'organization/get',
|
|
77
|
-
course: 'course/get',
|
|
78
|
-
}),
|
|
79
|
-
},
|
|
80
|
-
beforeMount() {},
|
|
81
62
|
data() {
|
|
82
63
|
return {
|
|
83
64
|
consumers: [],
|
|
@@ -97,7 +78,23 @@ export default {
|
|
|
97
78
|
],
|
|
98
79
|
}
|
|
99
80
|
},
|
|
81
|
+
async fetch() {
|
|
82
|
+
this.consumers = await new Lti1p1Consumer()
|
|
83
|
+
.for(
|
|
84
|
+
new Organization({ id: this.organization.id }),
|
|
85
|
+
new Course({ id: this.course.id })
|
|
86
|
+
)
|
|
87
|
+
.orderBy('name')
|
|
88
|
+
.get()
|
|
89
|
+
},
|
|
90
|
+
computed: {
|
|
91
|
+
...mapGetters({
|
|
92
|
+
organization: 'organization/get',
|
|
93
|
+
course: 'course/get',
|
|
94
|
+
}),
|
|
95
|
+
},
|
|
100
96
|
watch: {},
|
|
97
|
+
beforeMount() {},
|
|
101
98
|
mounted() {},
|
|
102
99
|
methods: {
|
|
103
100
|
onSelectLink(consumer) {
|
|
@@ -2,6 +2,8 @@ export default {
|
|
|
2
2
|
launch: 'Launch',
|
|
3
3
|
configure_warning:
|
|
4
4
|
'This block needs to be configured. Please select a LTI tool in the settings panel.',
|
|
5
|
+
no_access:
|
|
6
|
+
'You do not have permissions to launch this link. Please contact your system administrator.',
|
|
5
7
|
missing_tool: 'The tool id {0} is missing',
|
|
6
8
|
unknown_error: 'Something went wrong! Could not launch this link!',
|
|
7
9
|
link_disabled: 'Link disabled',
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export default {
|
|
2
|
-
name: 'Name',
|
|
3
|
-
description: 'Description',
|
|
4
2
|
key: 'Key',
|
|
5
3
|
secret: 'Secret',
|
|
6
4
|
parameter_name: 'Custom Parameter Name',
|
|
@@ -11,24 +9,6 @@ export default {
|
|
|
11
9
|
change_secret: 'Change Secret',
|
|
12
10
|
new_key: 'New Key',
|
|
13
11
|
new_secret: 'New Secret',
|
|
14
|
-
target_url: 'Target Url',
|
|
15
|
-
launch_url: 'Launch Url',
|
|
16
12
|
new: 'New LTI Link',
|
|
17
13
|
edit: 'Edit LTI Link',
|
|
18
|
-
enabled: 'Enabled',
|
|
19
|
-
provider: 'Provider',
|
|
20
|
-
consumer: 'Consumer',
|
|
21
|
-
provider_panel: 'Provider (Students incoming to Windward)',
|
|
22
|
-
consumer_panel: 'Consumer (Students outgoing from Windward)',
|
|
23
|
-
role_map_panel: 'Role map',
|
|
24
|
-
role_in_host: 'Role in Host LMS',
|
|
25
|
-
role_in_local: 'Role in Windward',
|
|
26
|
-
remote_role: 'Remote Role name',
|
|
27
|
-
map_to_role: 'Map to Windward Role',
|
|
28
|
-
delete_role_map_item: 'Delete role map item',
|
|
29
|
-
add_role_map_item: 'Add role map item',
|
|
30
|
-
role_map_instructions:
|
|
31
|
-
'Only add roles to the below map if the host LMS uses different role names that you want to elevated permissions. Eg "Mentor" that you want to elevate to "External Instructor"',
|
|
32
|
-
role_map_warning:
|
|
33
|
-
'Only add roles to the below map if the host LMS uses different role names that you want to elevated permissions. Eg "Mentor" that you want to elevate to "External Instructor"',
|
|
34
14
|
}
|
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import lti1p1 from './driver/lti1p1'
|
|
2
|
-
|
|
2
|
+
import providerTarget from './provider_target'
|
|
3
3
|
export default {
|
|
4
4
|
driver: { lti1p1 },
|
|
5
|
+
provider_target: providerTarget,
|
|
6
|
+
|
|
7
|
+
provider_panel_title: 'Provider (Students incoming to Windward)',
|
|
8
|
+
consumer_panel_title: 'Consumer (Students outgoing from Windward)',
|
|
9
|
+
|
|
10
|
+
target: 'Target',
|
|
11
|
+
target_url: 'Target Url',
|
|
12
|
+
launch_url: 'Launch Url',
|
|
13
|
+
|
|
14
|
+
send_grades: 'Send grades to host LMS',
|
|
15
|
+
grade_sync: 'Grade Sync',
|
|
16
|
+
provider: 'Provider',
|
|
17
|
+
consumer: 'Consumer',
|
|
18
|
+
|
|
19
|
+
role_map_panel: 'Role map',
|
|
20
|
+
role_in_host: 'Role in Host LMS',
|
|
21
|
+
role_in_local: 'Role in Windward',
|
|
22
|
+
remote_role: 'Remote Role name',
|
|
23
|
+
map_to_role: 'Map to Windward Role',
|
|
24
|
+
delete_role_map_item: 'Delete role map item',
|
|
25
|
+
add_role_map_item: 'Add role map item',
|
|
26
|
+
role_map_instructions:
|
|
27
|
+
'Only add roles to the below map if the host LMS uses different role names that you want to elevated permissions. Eg "Mentor" that you want to elevate to "External Instructor"',
|
|
28
|
+
role_map_warning:
|
|
29
|
+
'Only add roles to the below map if the host LMS uses different role names that you want to elevated permissions. Eg "Mentor" that you want to elevate to "External Instructor"',
|
|
5
30
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
name: 'Target Name',
|
|
3
|
+
link_to: 'Link To',
|
|
4
|
+
included: 'Included',
|
|
5
|
+
whole_course: 'Whole Course',
|
|
6
|
+
whole_course_page: 'Whole Course Choose Landing Page',
|
|
7
|
+
content_with_children: 'Content with Child Pages',
|
|
8
|
+
content_no_children: 'Single Content Page',
|
|
9
|
+
}
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
missing_title: 'The below fields are missing:',
|
|
5
5
|
error_title: 'The below errors occurred:',
|
|
6
6
|
error: {
|
|
7
|
-
unknown: 'An unknown error occurred',
|
|
7
|
+
unknown: 'An unknown communication error occurred',
|
|
8
8
|
organization: 'Invalid organization',
|
|
9
9
|
tool: 'Invalid tool id',
|
|
10
10
|
tool_organization: 'This tool does not belong to this organization',
|