@windward/integrations 0.0.12 → 0.1.1

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 (98) hide show
  1. package/components/Content/Blocks/ExternalIntegration/LtiConsumer.vue +136 -20
  2. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue +7 -5
  3. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumers.vue +3 -2
  4. package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumer.vue +284 -0
  5. package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumers.vue +229 -0
  6. package/components/ExternalIntegration/Driver/Lti1p3/ManageProvider.vue +14 -0
  7. package/components/ExternalIntegration/Driver/Lti1p3/ViewConsumer.vue +224 -0
  8. package/components/ExternalIntegration/Driver/ManageLti1p3.vue +3 -3
  9. package/components/Integration/Driver/ManageAtutor.vue +7 -13
  10. package/components/Integration/Driver/ManageBase.vue +0 -7
  11. package/components/Integration/Driver/ManageResourcespace.vue +6 -0
  12. package/components/Integration/JobLog.vue +4 -3
  13. package/components/SecretField.vue +16 -1
  14. package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +72 -30
  15. package/i18n/en-US/components/content/blocks/external_integration/lti_consumer.ts +7 -0
  16. package/i18n/en-US/components/external_integration/driver/lti1p3.ts +4 -0
  17. package/i18n/en-US/components/integration/driver.ts +2 -2
  18. package/i18n/en-US/components/settings/external_integration/lti_consumer.ts +3 -0
  19. package/i18n/es-ES/components/content/blocks/external_integration/index.ts +5 -0
  20. package/i18n/es-ES/components/content/blocks/external_integration/lti_consumer.ts +17 -0
  21. package/i18n/es-ES/components/content/blocks/index.ts +5 -0
  22. package/i18n/es-ES/components/content/index.ts +5 -0
  23. package/i18n/es-ES/components/external_integration/driver/lti1p1.ts +14 -0
  24. package/i18n/es-ES/components/external_integration/driver/lti1p3.ts +23 -0
  25. package/i18n/es-ES/components/external_integration/index.ts +31 -0
  26. package/i18n/es-ES/components/external_integration/provider_target.ts +9 -0
  27. package/i18n/es-ES/components/file_import/index.ts +5 -0
  28. package/i18n/es-ES/components/file_import/resourcespace.ts +4 -0
  29. package/i18n/es-ES/components/index.ts +15 -0
  30. package/i18n/es-ES/components/integration/driver.ts +45 -0
  31. package/i18n/es-ES/components/integration/index.ts +9 -0
  32. package/i18n/es-ES/components/integration/job.ts +23 -0
  33. package/i18n/es-ES/components/integration/job_log.ts +24 -0
  34. package/i18n/es-ES/components/navigation/index.ts +5 -0
  35. package/i18n/es-ES/components/navigation/integrations.ts +8 -0
  36. package/i18n/es-ES/components/settings/external_integration/index.ts +5 -0
  37. package/i18n/es-ES/components/settings/external_integration/lti_consumer.ts +10 -0
  38. package/i18n/es-ES/components/settings/index.ts +5 -0
  39. package/i18n/es-ES/index.ts +16 -0
  40. package/i18n/es-ES/modules/index.ts +5 -0
  41. package/i18n/es-ES/pages/course/external_integration/index.ts +6 -0
  42. package/i18n/es-ES/pages/course/index.ts +5 -0
  43. package/i18n/es-ES/pages/importContent.ts +3 -0
  44. package/i18n/es-ES/pages/importCourse.ts +13 -0
  45. package/i18n/es-ES/pages/index.ts +13 -0
  46. package/i18n/es-ES/pages/login/index.ts +5 -0
  47. package/i18n/es-ES/pages/login/lti.ts +21 -0
  48. package/i18n/es-ES/pages/vendor.ts +11 -0
  49. package/i18n/es-ES/shared/content_blocks.ts +8 -0
  50. package/i18n/es-ES/shared/error.ts +10 -0
  51. package/i18n/es-ES/shared/file.ts +5 -0
  52. package/i18n/es-ES/shared/index.ts +15 -0
  53. package/i18n/es-ES/shared/menu.ts +3 -0
  54. package/i18n/es-ES/shared/permission.ts +31 -0
  55. package/i18n/es-ES/shared/settings.ts +5 -0
  56. package/i18n/index.ts +11 -0
  57. package/i18n/sv-SE/components/content/blocks/external_integration/index.ts +5 -0
  58. package/i18n/sv-SE/components/content/blocks/external_integration/lti_consumer.ts +17 -0
  59. package/i18n/sv-SE/components/content/blocks/index.ts +5 -0
  60. package/i18n/sv-SE/components/content/index.ts +5 -0
  61. package/i18n/sv-SE/components/external_integration/driver/lti1p1.ts +14 -0
  62. package/i18n/sv-SE/components/external_integration/driver/lti1p3.ts +22 -0
  63. package/i18n/sv-SE/components/external_integration/index.ts +31 -0
  64. package/i18n/sv-SE/components/external_integration/provider_target.ts +9 -0
  65. package/i18n/sv-SE/components/file_import/index.ts +5 -0
  66. package/i18n/sv-SE/components/file_import/resourcespace.ts +4 -0
  67. package/i18n/sv-SE/components/index.ts +15 -0
  68. package/i18n/sv-SE/components/integration/driver.ts +44 -0
  69. package/i18n/sv-SE/components/integration/index.ts +9 -0
  70. package/i18n/sv-SE/components/integration/job.ts +23 -0
  71. package/i18n/sv-SE/components/integration/job_log.ts +24 -0
  72. package/i18n/sv-SE/components/navigation/index.ts +5 -0
  73. package/i18n/sv-SE/components/navigation/integrations.ts +8 -0
  74. package/i18n/sv-SE/components/settings/external_integration/index.ts +5 -0
  75. package/i18n/sv-SE/components/settings/external_integration/lti_consumer.ts +10 -0
  76. package/i18n/sv-SE/components/settings/index.ts +5 -0
  77. package/i18n/sv-SE/index.ts +16 -0
  78. package/i18n/sv-SE/modules/index.ts +5 -0
  79. package/i18n/sv-SE/pages/course/external_integration/index.ts +6 -0
  80. package/i18n/sv-SE/pages/course/index.ts +5 -0
  81. package/i18n/sv-SE/pages/importContent.ts +3 -0
  82. package/i18n/sv-SE/pages/importCourse.ts +13 -0
  83. package/i18n/sv-SE/pages/index.ts +13 -0
  84. package/i18n/sv-SE/pages/login/index.ts +5 -0
  85. package/i18n/sv-SE/pages/login/lti.ts +21 -0
  86. package/i18n/sv-SE/pages/vendor.ts +11 -0
  87. package/i18n/sv-SE/shared/content_blocks.ts +8 -0
  88. package/i18n/sv-SE/shared/error.ts +9 -0
  89. package/i18n/sv-SE/shared/file.ts +5 -0
  90. package/i18n/sv-SE/shared/index.ts +15 -0
  91. package/i18n/sv-SE/shared/menu.ts +3 -0
  92. package/i18n/sv-SE/shared/permission.ts +31 -0
  93. package/i18n/sv-SE/shared/settings.ts +5 -0
  94. package/models/ExternalIntegration/{Lti1p1Consumer.ts → LtiConsumer.ts} +1 -1
  95. package/package.json +1 -1
  96. package/plugin.js +3 -4
  97. package/test/Feature/LocaleKeys.spec.js +9 -0
  98. package/test/__mocks__/componentsMock.js +12 -0
@@ -1,23 +1,52 @@
1
1
  <template>
2
2
  <div>
3
3
  <div v-if="!missing && consumer">
4
- <h1>{{ consumer.name }}</h1>
5
- <TextViewer v-model="consumer.description"></TextViewer>
4
+ <h3>{{ block.metadata.config.title }}</h3>
6
5
 
7
- <v-btn
8
- v-if="consumer.enabled"
9
- color="primary"
10
- block
11
- @click="onLaunch"
6
+ <TextViewer
7
+ v-model="block.metadata.config.instructions"
8
+ ></TextViewer>
9
+
10
+ <v-row
11
+ v-if="
12
+ consumer.enabled &&
13
+ block.metadata.config.launch_type !== 'inline'
14
+ "
15
+ class="d-flex justify-center"
12
16
  >
13
- <v-icon>mdi-launch</v-icon>
14
- {{
15
- $t(
16
- 'windward.integrations.components.content.blocks.external_integration.lti_consumer.launch',
17
- [block.metadata.config.tool_id]
18
- )
19
- }}
20
- </v-btn>
17
+ <v-col class="d-flex justify-center col-md-4">
18
+ <v-btn
19
+ v-if="
20
+ block.metadata.config.launch_type === 'new_window'
21
+ "
22
+ color="primary"
23
+ block
24
+ @click="onLaunch"
25
+ >
26
+ {{
27
+ $t(
28
+ 'windward.integrations.components.content.blocks.external_integration.lti_consumer.launch_in_' +
29
+ block.metadata.config.launch_type,
30
+ [consumer.name]
31
+ )
32
+ }}
33
+ </v-btn>
34
+ <v-btn
35
+ v-else
36
+ color="primary"
37
+ block
38
+ @click="setLaunchTimer(100)"
39
+ >
40
+ {{
41
+ $t(
42
+ 'windward.integrations.components.content.blocks.external_integration.lti_consumer.launch_in_' +
43
+ block.metadata.config.launch_type,
44
+ [consumer.name]
45
+ )
46
+ }}
47
+ </v-btn>
48
+ </v-col>
49
+ </v-row>
21
50
 
22
51
  <v-alert v-if="!consumer.enabled" type="error">
23
52
  {{
@@ -33,6 +62,7 @@
33
62
  :target="target"
34
63
  :action="launchData.target || ''"
35
64
  :method="launchData.method || 'POST'"
65
+ @submit.prevent
36
66
  >
37
67
  <input
38
68
  v-for="(value, key) of launchData.payload"
@@ -50,6 +80,35 @@
50
80
  :name="frameId"
51
81
  class="launch-frame"
52
82
  ></iframe>
83
+ <Dialog
84
+ v-if="block.metadata.config.launch_type === 'modal'"
85
+ v-model="openModal"
86
+ :trigger="false"
87
+ persistent
88
+ max-width="1350px"
89
+ @click:close="closeModal"
90
+ >
91
+ <template #title>{{ block.metadata.config.title }}</template>
92
+ <template #trigger>
93
+ <v-icon small>mdi-pencil</v-icon>
94
+ <span class="sr-only">{{
95
+ $t(
96
+ 'windward.integrations.components.external_integration.driver.lti1p1.edit'
97
+ )
98
+ }}</span>
99
+ </template>
100
+ <template #form="{ on, attrs }">
101
+ <iframe
102
+ v-if="launched"
103
+ v-bind="attrs"
104
+ :name="frameId"
105
+ class="launch-frame"
106
+ v-on="on"
107
+ ></iframe>
108
+
109
+ <div v-else></div>
110
+ </template>
111
+ </Dialog>
53
112
  </div>
54
113
 
55
114
  <v-alert v-if="missing" type="error">
@@ -88,17 +147,18 @@
88
147
  <script>
89
148
  import _ from 'lodash'
90
149
  import { mapGetters } from 'vuex'
91
- import Lti1p1Consumer from '../../../../models/ExternalIntegration/Lti1p1Consumer'
150
+ import LtiConsumer from '../../../../models/ExternalIntegration/LtiConsumer'
92
151
  import Crypto from '~/helpers/Crypto'
93
152
  import TextViewer from '~/components/Text/TextViewer.vue'
94
153
  import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
95
154
  import Course from '~/models/Course'
96
155
  import Organization from '~/models/Organization'
97
156
  import Enrollment from '~/models/Enrollment'
157
+ import Dialog from '~/components/Dialog.vue'
98
158
 
99
159
  export default {
100
160
  name: 'ContentBlockExternalIntegrationLti1p1Consumer',
101
- components: { TextViewer },
161
+ components: { TextViewer, Dialog },
102
162
  extends: BaseContentBlock,
103
163
  data() {
104
164
  return {
@@ -109,6 +169,8 @@ export default {
109
169
  frameId: Crypto.id() + '_frame',
110
170
  missing: false,
111
171
  launched: false,
172
+ launchTimeout: {},
173
+ openModal: false,
112
174
  }
113
175
  },
114
176
  async fetch() {
@@ -123,12 +185,27 @@ export default {
123
185
  }),
124
186
  },
125
187
  watch: {
188
+ 'block.metadata.config.launch_type': {
189
+ deep: true,
190
+ handler(newVal, oldVal) {
191
+ // We changed the consumer tool id, reload
192
+ if (
193
+ newVal === 'inline' &&
194
+ this.block.metadata.config.tool_id !== null
195
+ ) {
196
+ this.setLaunchTimer()
197
+ }
198
+ },
199
+ },
126
200
  'block.metadata.config.tool_id': {
127
201
  deep: true,
128
202
  handler(newVal, oldVal) {
129
203
  // We changed the consumer tool id, reload
130
204
  if (newVal !== oldVal) {
131
205
  this.loadConsumer()
206
+ if (this.block.metadata.config.launch_type === 'inline') {
207
+ this.setLaunchTimer()
208
+ }
132
209
  }
133
210
  },
134
211
  },
@@ -140,13 +217,45 @@ export default {
140
217
  if (_.isEmpty(this.block.metadata.config.tool_id)) {
141
218
  this.block.metadata.config.tool_id = null
142
219
  }
220
+ if (_.isEmpty(this.block.metadata.config.title)) {
221
+ this.block.metadata.config.title = this.$t(
222
+ 'windward.integrations.components.content.blocks.external_integration.lti_consumer.title'
223
+ )
224
+ }
225
+ if (_.isEmpty(this.block.metadata.config.instructions)) {
226
+ this.block.metadata.config.instructions = this.$t(
227
+ 'windward.integrations.components.content.blocks.external_integration.lti_consumer.instructions'
228
+ )
229
+ }
230
+ },
231
+ mounted() {
232
+ if (
233
+ this.block.metadata.config.tool_id !== null &&
234
+ this.block.metadata.config.launch_type === 'inline'
235
+ ) {
236
+ this.setLaunchTimer()
237
+ }
238
+ },
239
+
240
+ destroyed() {
241
+ clearTimeout(this.launchTimeout)
143
242
  },
144
- mounted() {},
145
243
  methods: {
244
+ setLaunchTimer(timeout = 1000) {
245
+ clearTimeout(this.launchTimeout)
246
+ this.launchTimeout = setTimeout(this.onLaunch, timeout)
247
+ this.launched = true
248
+ },
249
+ closeModal() {
250
+ this.launchData = {}
251
+ this.target = ''
252
+ this.openModal = false
253
+ this.launched = false
254
+ },
146
255
  async loadConsumer() {
147
256
  try {
148
257
  if (!_.isEmpty(this.block.metadata.config.tool_id)) {
149
- this.consumer = await new Lti1p1Consumer()
258
+ this.consumer = await new LtiConsumer()
150
259
  .for(
151
260
  new Organization({ id: this.organization.id }),
152
261
  new Course({ id: this.course.id })
@@ -168,8 +277,11 @@ export default {
168
277
  // Clear the launch data in-case we're in inline mode
169
278
  // If the iframe isn't destroyed subsequent launches will be new windows instead of the target iframe
170
279
  this.launchData = {}
280
+ if (this.block.metadata.config.launch_type === 'modal') {
281
+ this.openModal = true
282
+ }
171
283
 
172
- this.launchData = await Lti1p1Consumer.custom(
284
+ this.launchData = await LtiConsumer.custom(
173
285
  new Enrollment({ id: this.enrollment.id }),
174
286
  this.consumer,
175
287
  '/launch'
@@ -182,6 +294,9 @@ export default {
182
294
  case 'inline':
183
295
  this.target = this.frameId
184
296
  break
297
+ case 'modal':
298
+ this.target = this.frameId
299
+ break
185
300
  default:
186
301
  this.target = '_blank'
187
302
  }
@@ -216,5 +331,6 @@ export default {
216
331
  .launch-frame {
217
332
  aspect-ratio: 16/9;
218
333
  width: 100%;
334
+ border-style: none;
219
335
  }
220
336
  </style>
@@ -33,6 +33,8 @@
33
33
  <TextEditor
34
34
  id="description"
35
35
  v-model="consumer.description"
36
+ menubar="edit"
37
+ toolbar="undo redo | bold italic underline strikethrough "
36
38
  :height="200"
37
39
  ></TextEditor>
38
40
 
@@ -148,7 +150,7 @@
148
150
  <script>
149
151
  import _ from 'lodash'
150
152
  import { mapGetters } from 'vuex'
151
- import Lti1p1Consumer from '../../../../models/ExternalIntegration/Lti1p1Consumer'
153
+ import LtiConsumer from '../../../../models/ExternalIntegration/LtiConsumer'
152
154
  import Organization from '~/models/Organization'
153
155
  import Course from '~/models/Course'
154
156
  import TextEditor from '~/components/Text/TextEditor.vue'
@@ -160,7 +162,7 @@ export default {
160
162
  extends: FormVue,
161
163
  props: {
162
164
  value: {
163
- type: [Lti1p1Consumer, null],
165
+ type: [LtiConsumer, null],
164
166
  required: false,
165
167
  default: null,
166
168
  },
@@ -220,9 +222,9 @@ export default {
220
222
  },
221
223
  created() {
222
224
  if (_.isEmpty(this.value)) {
223
- this.consumer = new Lti1p1Consumer(this.consumer)
225
+ this.consumer = new LtiConsumer(this.consumer)
224
226
  } else {
225
- this.consumer = new Lti1p1Consumer(_.cloneDeep(this.value))
227
+ this.consumer = new LtiConsumer(_.cloneDeep(this.value))
226
228
  }
227
229
  },
228
230
  mounted() {
@@ -260,7 +262,7 @@ export default {
260
262
  this.consumer.metadata.custom.splice(index, 1)
261
263
  },
262
264
  async save() {
263
- let consumer = new Lti1p1Consumer(this.consumer).for(
265
+ let consumer = new LtiConsumer(this.consumer).for(
264
266
  new Organization({ id: this.organization.id }),
265
267
  new Course({ id: this.course.id })
266
268
  )
@@ -79,7 +79,7 @@
79
79
  <script>
80
80
  import _ from 'lodash'
81
81
  import { mapGetters } from 'vuex'
82
- import Lti1p1Consumer from '../../../../models/ExternalIntegration/Lti1p1Consumer'
82
+ import LtiConsumer from '../../../../models/ExternalIntegration/LtiConsumer'
83
83
  import ManageConsumer from './ManageConsumer.vue'
84
84
  import Course from '~/models/Course'
85
85
  import Organization from '~/models/Organization'
@@ -168,11 +168,12 @@ export default {
168
168
  this.loadConsumers()
169
169
  },
170
170
  async loadConsumers() {
171
- this.consumers = await new Lti1p1Consumer()
171
+ this.consumers = await new LtiConsumer()
172
172
  .for(
173
173
  new Organization({ id: this.organization.id }),
174
174
  new Course({ id: this.course.id })
175
175
  )
176
+ .where('version', '1.1')
176
177
  .get()
177
178
  },
178
179
  onConfirmDelete(consumer) {
@@ -0,0 +1,284 @@
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-form v-model="formValid" @submit.prevent>
8
+ <v-row justify="center" align="center" class="mt-5">
9
+ <v-col cols="12">
10
+ <v-text-field
11
+ v-model="consumer.target"
12
+ :label="
13
+ $t(
14
+ 'windward.integrations.components.external_integration.target_url'
15
+ )
16
+ "
17
+ :hint="
18
+ $t(
19
+ 'windward.integrations.components.external_integration.target_url'
20
+ )
21
+ "
22
+ ></v-text-field>
23
+ <v-text-field
24
+ v-model="consumer.name"
25
+ :placeholder="$t('shared.forms.name')"
26
+ :label="$t('shared.forms.name')"
27
+ :hint="$t('shared.forms.name')"
28
+ ></v-text-field>
29
+
30
+ <label for="description">{{
31
+ $t('shared.forms.description')
32
+ }}</label>
33
+ <TextEditor
34
+ id="description"
35
+ v-model="consumer.description"
36
+ menubar="edit"
37
+ toolbar="undo redo | bold italic underline strikethrough "
38
+ :height="200"
39
+ ></TextEditor>
40
+
41
+ <v-switch
42
+ v-model="consumer.enabled"
43
+ :label="$t('shared.forms.enabled')"
44
+ />
45
+ <v-text-field
46
+ v-model="consumer.metadata.tool_oidc_auth_endpoint"
47
+ :placeholder="
48
+ $t(
49
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_oidc_auth_endpoint'
50
+ )
51
+ "
52
+ :label="
53
+ $t(
54
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_oidc_auth_endpoint'
55
+ )
56
+ "
57
+ ></v-text-field>
58
+ <v-text-field
59
+ v-model="consumer.metadata.tool_public_keyset_url"
60
+ :placeholder="
61
+ $t(
62
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_public_keyset_url'
63
+ )
64
+ "
65
+ :label="
66
+ $t(
67
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_public_keyset_url'
68
+ )
69
+ "
70
+ ></v-text-field>
71
+
72
+ <v-data-table
73
+ :headers="customParameterHeaders"
74
+ :items="consumer.metadata.custom"
75
+ hide-default-footer
76
+ class="elevation-1"
77
+ >
78
+ <template #[`item.key`]="{ index }">
79
+ <v-text-field
80
+ v-model="
81
+ consumer.metadata.custom[index].key
82
+ "
83
+ :label="
84
+ $t(
85
+ 'windward.integrations.components.external_integration.driver.lti1p1.parameter_name'
86
+ )
87
+ "
88
+ />
89
+ </template>
90
+ <template #[`item.value`]="{ index }">
91
+ <v-text-field
92
+ v-model="
93
+ consumer.metadata.custom[index].value
94
+ "
95
+ :label="
96
+ $t(
97
+ 'windward.integrations.components.external_integration.driver.lti1p1.value'
98
+ )
99
+ "
100
+ />
101
+ </template>
102
+ <template #[`item.actions`]="{ index }">
103
+ <v-btn
104
+ text
105
+ color="primary"
106
+ @click="deleteCustomParameter(index)"
107
+ >
108
+ <v-icon small> mdi-delete </v-icon>
109
+ <span class="sr-only">{{
110
+ $t('shared.forms.delete')
111
+ }}</span>
112
+ </v-btn>
113
+ </template>
114
+ <template #footer>
115
+ <div class="text-center">
116
+ <v-btn
117
+ color="primary"
118
+ class="mb-3"
119
+ @click="addCustomParameter"
120
+ >{{ $t('shared.forms.add') }}</v-btn
121
+ >
122
+ </div>
123
+ </template>
124
+ </v-data-table>
125
+ <br />
126
+ <v-select
127
+ v-model="consumer.metadata.security_level"
128
+ :items="securityLevels"
129
+ item-text="name"
130
+ item-value="value"
131
+ label="Security Level"
132
+ outlined
133
+ ></v-select>
134
+ </v-col>
135
+ </v-row>
136
+ </v-form>
137
+ </div>
138
+ </div>
139
+ </template>
140
+
141
+ <script>
142
+ import _ from 'lodash'
143
+ import { mapGetters } from 'vuex'
144
+ import LtiConsumer from '../../../../models/ExternalIntegration/LtiConsumer'
145
+ import Organization from '~/models/Organization'
146
+ import Course from '~/models/Course'
147
+ import TextEditor from '~/components/Text/TextEditor.vue'
148
+ import FormVue from '~/components/Form'
149
+
150
+ export default {
151
+ name: 'ManageLti1p3ConsumerDriver',
152
+ components: { TextEditor },
153
+ extends: FormVue,
154
+ props: {
155
+ value: {
156
+ type: [LtiConsumer, null],
157
+ required: false,
158
+ default: null,
159
+ },
160
+ },
161
+ emits: ['update:consumer'],
162
+ meta: {
163
+ privilege: {
164
+ '': {
165
+ writable: true,
166
+ },
167
+ },
168
+ },
169
+ data() {
170
+ return {
171
+ render: false,
172
+ consumer: {
173
+ version: '1.3',
174
+ metadata: {
175
+ custom: [],
176
+ security_level: '',
177
+ security: [],
178
+ },
179
+ },
180
+ customParameterHeaders: [
181
+ {
182
+ text: this.$t(
183
+ 'windward.integrations.components.external_integration.driver.lti1p1.parameter_name'
184
+ ),
185
+ value: 'key',
186
+ },
187
+ {
188
+ text: this.$t(
189
+ 'windward.integrations.components.external_integration.driver.lti1p1.value'
190
+ ),
191
+ value: 'value',
192
+ },
193
+ {
194
+ text: this.$t('shared.forms.actions'),
195
+ value: 'actions',
196
+ sortable: false,
197
+ },
198
+ ],
199
+ securityLevels: [
200
+ { name: 'Full Access', value: 'full' },
201
+ { name: 'Email Only', value: 'email' },
202
+ { name: 'Name Only', value: 'name' },
203
+ { name: 'Anonymous', value: 'anonymous' },
204
+ // { name: 'Custom', value: 'custom' }, // TODO: When this is selected provide direct access to check off LTI fields
205
+ ],
206
+ }
207
+ },
208
+ computed: {
209
+ ...mapGetters({
210
+ organization: 'organization/get',
211
+ course: 'course/get',
212
+ }),
213
+ },
214
+ created() {
215
+ if (_.isEmpty(this.value)) {
216
+ this.consumer = new LtiConsumer(this.consumer)
217
+ } else {
218
+ this.consumer = new LtiConsumer(_.cloneDeep(this.value))
219
+ }
220
+ },
221
+ mounted() {
222
+ if (
223
+ !this.$PermissionService.userHasAccessTo(
224
+ 'plugin.windward.integrations.course.externalIntegration',
225
+ 'writable'
226
+ )
227
+ ) {
228
+ // Display an angry error that they can't view this driver
229
+ this.$dialog.error(this.$t('shared.error.description_401'), {
230
+ duration: null,
231
+ action: {
232
+ text: this.$t('shared.forms.close'),
233
+ onClick: (_e, toastObject) => {
234
+ toastObject.goAway(0)
235
+ },
236
+ },
237
+ })
238
+
239
+ // eslint-disable-next-line no-console
240
+ console.error('You do not have access to this consumer!')
241
+
242
+ // Return so we don't even attempt loading
243
+ return false
244
+ }
245
+
246
+ this.render = true
247
+ },
248
+ methods: {
249
+ addCustomParameter() {
250
+ this.consumer.metadata.custom.push({ key: '', value: '' })
251
+ },
252
+ deleteCustomParameter(index) {
253
+ this.consumer.metadata.custom.splice(index, 1)
254
+ },
255
+ async save() {
256
+ let consumer = new LtiConsumer(this.consumer).for(
257
+ new Organization({ id: this.organization.id }),
258
+ new Course({ id: this.course.id })
259
+ )
260
+
261
+ try {
262
+ consumer = await consumer.save()
263
+ this.consumer = consumer
264
+
265
+ // Clone and delete the metadata since we don't need to share that around
266
+ // Also include the vendor going back for easier mapping
267
+ const consumerEvent = _.cloneDeep(consumer)
268
+
269
+ this.$dialog.success(this.$t('shared.forms.saved'))
270
+ this.$emit('update:consumer', consumerEvent)
271
+ } catch (e) {
272
+ this.$dialog.error(
273
+ this.$t('windward.integrations.shared.error.save_failed')
274
+ )
275
+ }
276
+ },
277
+ async onSave() {
278
+ if (this.formValid) {
279
+ await this.save()
280
+ }
281
+ },
282
+ },
283
+ }
284
+ </script>