@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.
Files changed (26) hide show
  1. package/components/Content/Blocks/ExternalIntegration/LtiConsumer.vue +37 -23
  2. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue +12 -14
  3. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumers.vue +22 -25
  4. package/components/ExternalIntegration/Driver/Lti1p1/ManageProvider.vue +53 -19
  5. package/components/ExternalIntegration/Driver/Lti1p1/ManageProviders.vue +53 -21
  6. package/components/ExternalIntegration/Driver/ManageLti1p1.vue +2 -2
  7. package/components/ExternalIntegration/ProviderTargetPicker.vue +218 -0
  8. package/components/ExternalIntegration/ProviderTargetViewer.vue +50 -0
  9. package/components/Integration/Driver/ManageBase.vue +3 -1
  10. package/components/Integration/JobTable.vue +2 -1
  11. package/components/SecretField.vue +1 -1
  12. package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +16 -19
  13. package/i18n/en-US/components/content/blocks/external_integration/lti_consumer.ts +2 -0
  14. package/i18n/en-US/components/external_integration/driver/lti1p1.ts +0 -20
  15. package/i18n/en-US/components/external_integration/index.ts +26 -1
  16. package/i18n/en-US/components/external_integration/provider_target.ts +9 -0
  17. package/i18n/en-US/pages/login/lti.ts +1 -1
  18. package/package.json +1 -1
  19. package/pages/admin/importCourse.vue +3 -0
  20. package/pages/admin/vendors.vue +2 -1
  21. package/plugin.js +1 -1
  22. package/test/Components/ExternalIntegration/ProviderTargetPicker.spec.js +22 -0
  23. package/test/Components/ExternalIntegration/ProviderTargetViewer.spec.js +22 -0
  24. package/test/__mocks__/componentsMock.js +12 -0
  25. package/test/__mocks__/modelMock.js +1 -1
  26. 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.metadata.key="{ 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.driver.lti1p1.enabled'
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), 'long') }}
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.driver.lti1p1.target_url'
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.driver.lti1p1.launch_url'
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.driver.lti1p1.enabled'
146
+ 'windward.integrations.components.external_integration.grade_sync'
127
147
  ),
128
- value: 'enabled',
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: (e, toastObject) => {
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(e) {
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: (e, toastObject) => {
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: (e, toastObject) => {
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.driver.lti1p1.provider_panel'
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.driver.lti1p1.consumer_panel'
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: (e, toastObject) => {
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 (socket) {
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
  }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <v-text-field :value="value" readonly :type="fieldType">
2
+ <v-text-field id="secret-field" :value="value" readonly :type="fieldType">
3
3
  <template #append>
4
4
  <v-btn icon @click="toggleClear">
5
5
  <v-icon>{{ showClear ? 'mdi-eye-off' : 'mdi-eye' }}</v-icon>
@@ -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',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/integrations",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Windward UI Plugin Integrations for 3rd Party Systems",
5
5
  "main": "plugin.js",
6
6
  "scripts": {