@windward/integrations 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/components/Content/Blocks/ExternalIntegration/LtiConsumer.vue +3 -3
  3. package/components/Content/Blocks/ExternalIntegration/ScormConsumer.vue +34 -0
  4. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue +10 -8
  5. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumers.vue +2 -2
  6. package/components/ExternalIntegration/Driver/Lti1p1/ManageProvider.vue +8 -5
  7. package/components/ExternalIntegration/Driver/Lti1p1/ManageProviders.vue +3 -2
  8. package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumer.vue +8 -6
  9. package/components/ExternalIntegration/Driver/Lti1p3/ManageConsumers.vue +2 -2
  10. package/components/ExternalIntegration/Driver/Lti1p3/ManageProvider.vue +27 -5
  11. package/components/ExternalIntegration/Driver/Lti1p3/ManageProviders.vue +4 -3
  12. package/components/ExternalIntegration/Driver/Lti1p3/ViewConsumer.vue +6 -5
  13. package/components/ExternalIntegration/Driver/ManageScorm.vue +45 -0
  14. package/components/ExternalIntegration/Driver/Scorm/ManageConsumer.vue +76 -0
  15. package/components/ExternalIntegration/Driver/Scorm/ManageConsumers.vue +233 -0
  16. package/components/ExternalIntegration/Driver/Scorm/ManageProvider.vue +475 -0
  17. package/components/ExternalIntegration/Driver/Scorm/ManageProviders.vue +299 -0
  18. package/components/Integration/Driver/LoginSamlButton.vue +119 -0
  19. package/components/Integration/Driver/ManageSaml.vue +327 -0
  20. package/components/LLM/GenerateContent/BlockQuestionGenerateButton.vue +34 -3
  21. package/components/SecretField.vue +99 -19
  22. package/components/Settings/ExternalIntegration/LtiConsumerSettings.vue +2 -2
  23. package/components/Settings/ExternalIntegration/ManageCourseIntegrationSettings.vue +6 -6
  24. package/components/Settings/ExternalIntegration/ScormConsumerSettings.vue +42 -0
  25. package/config/integration.config.js +2 -0
  26. package/helpers/Driver/SamlSso.ts +12 -0
  27. package/helpers/ExternalIntegration/ScormHelper.ts +155 -0
  28. package/i18n/en-US/components/external_integration/driver/lti1p3.ts +4 -1
  29. package/i18n/en-US/components/external_integration/driver/scorm.ts +14 -0
  30. package/i18n/en-US/components/external_integration/index.ts +3 -1
  31. package/i18n/en-US/components/integration/driver.ts +23 -0
  32. package/i18n/en-US/components/llm/generate_content/generate_questions.ts +7 -0
  33. package/i18n/en-US/pages/course/external_integration/index.ts +1 -1
  34. package/i18n/en-US/pages/login/index.ts +4 -0
  35. package/i18n/en-US/pages/login/lti.ts +2 -0
  36. package/i18n/en-US/pages/login/saml.ts +7 -0
  37. package/i18n/en-US/pages/login/scorm.ts +28 -0
  38. package/i18n/en-US/shared/content_blocks.ts +1 -0
  39. package/i18n/en-US/shared/settings.ts +1 -0
  40. package/i18n/es-ES/components/external_integration/driver/lti1p3.ts +4 -1
  41. package/i18n/es-ES/components/external_integration/driver/scorm.ts +15 -0
  42. package/i18n/es-ES/components/external_integration/index.ts +3 -1
  43. package/i18n/es-ES/components/integration/driver.ts +23 -0
  44. package/i18n/es-ES/components/llm/generate_content/generate_questions.ts +7 -0
  45. package/i18n/es-ES/pages/course/external_integration/index.ts +1 -1
  46. package/i18n/es-ES/pages/login/index.ts +4 -0
  47. package/i18n/es-ES/pages/login/lti.ts +2 -0
  48. package/i18n/es-ES/pages/login/saml.ts +7 -0
  49. package/i18n/es-ES/pages/login/scorm.ts +29 -0
  50. package/i18n/es-ES/shared/content_blocks.ts +1 -0
  51. package/i18n/es-ES/shared/settings.ts +1 -0
  52. package/i18n/sv-SE/components/external_integration/driver/lti1p3.ts +4 -1
  53. package/i18n/sv-SE/components/external_integration/driver/scorm.ts +14 -0
  54. package/i18n/sv-SE/components/external_integration/index.ts +3 -1
  55. package/i18n/sv-SE/components/integration/driver.ts +23 -0
  56. package/i18n/sv-SE/components/llm/generate_content/generate_questions.ts +7 -0
  57. package/i18n/sv-SE/pages/course/external_integration/index.ts +1 -1
  58. package/i18n/sv-SE/pages/login/index.ts +4 -0
  59. package/i18n/sv-SE/pages/login/lti.ts +2 -0
  60. package/i18n/sv-SE/pages/login/saml.ts +7 -0
  61. package/i18n/sv-SE/pages/login/scorm.ts +29 -0
  62. package/i18n/sv-SE/shared/content_blocks.ts +2 -1
  63. package/i18n/sv-SE/shared/settings.ts +1 -0
  64. package/jest.config.js +3 -0
  65. package/models/Auth/Saml.ts +21 -0
  66. package/models/ExternalIntegration/{LtiConsumer.ts → Consumer.ts} +2 -2
  67. package/models/ExternalIntegration/{LtiProvider.ts → Provider.ts} +2 -2
  68. package/package.json +2 -1
  69. package/pages/course/externalIntegration/index.vue +4 -0
  70. package/pages/login/scorm/error.vue +102 -0
  71. package/pages/login/scorm/promptEmail.vue +180 -0
  72. package/plugin.js +128 -7
  73. package/test/Components/ExternalIntegration/ManageScorm.spec.js +19 -0
  74. package/test/Components/ExternalIntegration/Scorm/ManageConsumer.spec.js +19 -0
  75. package/test/Components/ExternalIntegration/Scorm/ManageConsumers.spec.js +19 -0
  76. package/test/Components/ExternalIntegration/Scorm/ManageProvider.spec.js +19 -0
  77. package/test/Components/ExternalIntegration/Scorm/ManageProviders.spec.js +19 -0
  78. package/test/__mocks__/componentsMock.js +81 -1
  79. package/test/mocks.js +12 -0
  80. package/test/setup.js +1 -0
package/plugin.js CHANGED
@@ -1,13 +1,22 @@
1
+ import _ from 'lodash'
1
2
  import locales from './i18n'
2
3
 
3
4
  import AdminVendorsPage from './pages/admin/vendors.vue'
4
5
  import AdminImportCoursePage from './pages/admin/importCourse.vue'
5
6
  import ExternalIntegrationIndexPage from './pages/course/externalIntegration/index.vue'
6
7
  import LoginLtiErrorPage from './pages/login/lti/error.vue'
8
+ import LoginScormErrorPage from './pages/login/scorm/error.vue'
9
+ import LoginScormPromptEmailPage from './pages/login/scorm/promptEmail.vue'
10
+
7
11
  import IntegrationHelper from './helpers/IntegrationHelper'
12
+ import ExternalIntegrationScormHelper from './helpers/ExternalIntegration/ScormHelper'
8
13
 
9
14
  import LtiConsumerBlock from './components/Content/Blocks/ExternalIntegration/LtiConsumer'
10
15
  import LtiConsumerBlockSettings from './components/Settings/ExternalIntegration/LtiConsumerSettings'
16
+
17
+ import ScormConsumerBlock from './components/Content/Blocks/ExternalIntegration/ScormConsumer'
18
+ import ScormConsumerBlockSettings from './components/Settings/ExternalIntegration/ScormConsumerSettings'
19
+
11
20
  import ManageCourseIntegrationSettings from './components/Settings/ExternalIntegration/ManageCourseIntegrationSettings'
12
21
 
13
22
  import FileImportMenu from './components/FileImport/FileImportMenu.vue'
@@ -21,18 +30,81 @@ import ChatWindow from './components/Integration/AiAgentIntegration/ChatWindow.v
21
30
  import AssessmentQuestionGenerateButton from './components/LLM/GenerateContent/AssessmentQuestionGenerateButton.vue'
22
31
  import BlockQuestionGenerateButton from './components/LLM/GenerateContent/BlockQuestionGenerateButton.vue'
23
32
 
33
+ import LoginSamlButton from './components/Integration/Driver/LoginSamlButton.vue'
34
+
24
35
  export default {
25
36
  name: 'windward.integrations.name',
26
37
  version: null,
27
38
  hooks: {
28
- beforeContent: (body) => {
29
- return body
39
+ 'update:enrollment': (app, enrollment = {}) => {
40
+ // If this tracking is for a SCORM enrollment then tell the service to emit the progess back to the host LMS
41
+ if (
42
+ enrollment &&
43
+ _.get(enrollment, 'metadata.integration.type', '') ===
44
+ 'scorm' &&
45
+ _.get(enrollment, 'course_progress.id', null) !== null
46
+ ) {
47
+ try {
48
+ app.$ExternalIntegrationScorm.trackEnrollment(enrollment)
49
+ } catch (e) {
50
+ console.error('Cannot track updated SCORM progress', e)
51
+ }
52
+ } else if (
53
+ enrollment &&
54
+ _.get(enrollment, 'metadata.integration.type', '') ===
55
+ 'scorm' &&
56
+ _.get(enrollment, 'course_progress.id', null) === null
57
+ ) {
58
+ console.error(
59
+ 'Could not push initial data to host LMS. The enrollment is missing progress.'
60
+ )
61
+ }
62
+ },
63
+ 'load:enrollment': (app, enrollment = {}) => {
64
+ // If this tracking is for a SCORM enrollment then tell the service to emit the progess back to the host LMS
65
+ if (
66
+ enrollment &&
67
+ _.get(enrollment, 'metadata.integration.type', '') ===
68
+ 'scorm' &&
69
+ _.get(enrollment, 'course_progress.id', null) !== null
70
+ ) {
71
+ try {
72
+ app.$ExternalIntegrationScorm.trackEnrollment(enrollment)
73
+ } catch (e) {
74
+ console.error('Cannot track SCORM progress', e)
75
+ }
76
+ } else if (
77
+ enrollment &&
78
+ _.get(enrollment, 'metadata.integration.type', '') ===
79
+ 'scorm' &&
80
+ _.get(enrollment, 'course_progress.id', null) === null
81
+ ) {
82
+ console.error(
83
+ 'Could not push initial data to host LMS. The enrollment is missing progress.'
84
+ )
85
+ }
86
+ },
87
+ 'update:tracking': (app, courseUserTracking = {}) => {
88
+ const enrollment = _.get(
89
+ app,
90
+ "store.getters['enrollment/get']",
91
+ null
92
+ )
93
+
94
+ // If this tracking is for a SCORM enrollment then tell the service to emit the progess back to the host LMS
95
+ if (
96
+ enrollment &&
97
+ _.get(enrollment, 'metadata.integration.type', '') === 'scorm'
98
+ ) {
99
+ try {
100
+ app.$ExternalIntegrationScorm.trackProgress(
101
+ courseUserTracking
102
+ )
103
+ } catch (e) {
104
+ console.error('Cannot track SCORM progress', e)
105
+ }
106
+ }
30
107
  },
31
- beforeDestroy: () => {},
32
- beforeNavigate: () => {},
33
- onNavigate: () => {},
34
- onLoad: (_page) => {},
35
- onContent: () => {},
36
108
  },
37
109
  i18n: locales.messages,
38
110
  pages: [
@@ -64,8 +136,37 @@ export default {
64
136
  name: 'PluginIntegrationsLoginLtiErrorPage',
65
137
  template: LoginLtiErrorPage,
66
138
  },
139
+ {
140
+ page: 'scorm-error',
141
+ path: '/login/scorm/error',
142
+ i18n: 'windward.integrations.pages.login.scorm.scorm_error',
143
+ name: 'PluginIntegrationsLoginScormErrorPage',
144
+ template: LoginScormErrorPage,
145
+ },
146
+ {
147
+ page: 'scorm-prompt-email',
148
+ path: '/login/scorm/prompt-email',
149
+ i18n: 'windward.integrations.pages.login.scorm.scorm_prompt_email',
150
+ name: 'PluginIntegrationsLoginScormPromptEmailPage',
151
+ template: LoginScormPromptEmailPage,
152
+ },
67
153
  ],
68
154
  components: {
155
+ userLogin: [
156
+ {
157
+ tag: 'windward-integrations-login-saml',
158
+ template: LoginSamlButton,
159
+ },
160
+ // Future SSO methods can be added here:
161
+ // {
162
+ // tag: 'windward-integrations-login-oauth2',
163
+ // template: LoginOAuth2Button,
164
+ // },
165
+ // {
166
+ // tag: 'windward-integrations-login-google',
167
+ // template: LoginGoogleButton,
168
+ // },
169
+ ],
69
170
  menu: [
70
171
  {
71
172
  ref_page: 'admin',
@@ -178,6 +279,16 @@ export default {
178
279
  'windward.integrations.shared.content_blocks.grouping.integrations',
179
280
  },
180
281
  },
282
+ /*{
283
+ tag: 'windward-integrations-scorm-consumer',
284
+ template: ScormConsumerBlock,
285
+ metadata: {
286
+ icon: 'mdi-shield-link-variant-outline',
287
+ name: 'windward.integrations.shared.content_blocks.title.scorm_consumer',
288
+ grouping:
289
+ 'windward.integrations.shared.content_blocks.grouping.integrations',
290
+ },
291
+ },*/
181
292
  ],
182
293
  contentBlockSetting: [
183
294
  {
@@ -189,6 +300,15 @@ export default {
189
300
  name: 'windward.integrations.shared.settings.title.lti_consumer',
190
301
  },
191
302
  },
303
+ {
304
+ tag: 'windward-integrations-scorm-consumer-settings',
305
+ template: ScormConsumerBlockSettings,
306
+ context: ['block.windward-integrations-scorm-consumer'],
307
+ metadata: {
308
+ icon: 'mdi-cog',
309
+ name: 'windward.integrations.shared.settings.title.scorm_consumer',
310
+ },
311
+ },
192
312
  ],
193
313
  courseSetting: [
194
314
  {
@@ -251,5 +371,6 @@ export default {
251
371
  },
252
372
  services: {
253
373
  Integration: IntegrationHelper,
374
+ ExternalIntegrationScorm: ExternalIntegrationScormHelper,
254
375
  },
255
376
  }
@@ -0,0 +1,19 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+
3
+ import Vue from 'vue'
4
+ import Vuetify from 'vuetify'
5
+ import { defaultMocks } from '@/test/mocks'
6
+
7
+ import ManageScorm from '@/components/ExternalIntegration/Driver/ManageScorm.vue'
8
+
9
+ Vue.use(Vuetify)
10
+
11
+ describe('ManageScorm', () => {
12
+ test('ManageScorm is a Vue instance', () => {
13
+ const wrapper = shallowMount(ManageScorm, {
14
+ vuetify: new Vuetify(),
15
+ mocks: defaultMocks,
16
+ })
17
+ expect(wrapper.vm).toBeTruthy()
18
+ })
19
+ })
@@ -0,0 +1,19 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+
3
+ import Vue from 'vue'
4
+ import Vuetify from 'vuetify'
5
+ import { defaultMocks } from '@/test/mocks'
6
+
7
+ import ManageConsumer from '@/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue'
8
+
9
+ Vue.use(Vuetify)
10
+
11
+ describe('ManageConsumer', () => {
12
+ test('ManageConsumer is a Vue instance', () => {
13
+ const wrapper = shallowMount(ManageConsumer, {
14
+ vuetify: new Vuetify(),
15
+ mocks: defaultMocks,
16
+ })
17
+ expect(wrapper.vm).toBeTruthy()
18
+ })
19
+ })
@@ -0,0 +1,19 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+
3
+ import Vue from 'vue'
4
+ import Vuetify from 'vuetify'
5
+ import { defaultMocks } from '@/test/mocks'
6
+
7
+ import ManageConsumers from '@/components/ExternalIntegration/Driver/Scorm/ManageConsumers.vue'
8
+
9
+ Vue.use(Vuetify)
10
+
11
+ describe('ManageConsumers', () => {
12
+ test('ManageConsumers is a Vue instance', () => {
13
+ const wrapper = shallowMount(ManageConsumers, {
14
+ vuetify: new Vuetify(),
15
+ mocks: defaultMocks,
16
+ })
17
+ expect(wrapper.vm).toBeTruthy()
18
+ })
19
+ })
@@ -0,0 +1,19 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+
3
+ import Vue from 'vue'
4
+ import Vuetify from 'vuetify'
5
+ import { defaultMocks } from '@/test/mocks'
6
+
7
+ import ManageProvider from '@/components/ExternalIntegration/Driver/Scorm/ManageProvider.vue'
8
+
9
+ Vue.use(Vuetify)
10
+
11
+ describe('ManageProvider', () => {
12
+ test('ManageProvider is a Vue instance', () => {
13
+ const wrapper = shallowMount(ManageProvider, {
14
+ vuetify: new Vuetify(),
15
+ mocks: defaultMocks,
16
+ })
17
+ expect(wrapper.vm).toBeTruthy()
18
+ })
19
+ })
@@ -0,0 +1,19 @@
1
+ import { shallowMount } from '@vue/test-utils'
2
+
3
+ import Vue from 'vue'
4
+ import Vuetify from 'vuetify'
5
+ import { defaultMocks } from '@/test/mocks'
6
+
7
+ import ManageProviders from '@/components/ExternalIntegration/Driver/Scorm/ManageProviders.vue'
8
+
9
+ Vue.use(Vuetify)
10
+
11
+ describe('ManageProviders', () => {
12
+ test('ManageProviders is a Vue instance', () => {
13
+ const wrapper = shallowMount(ManageProviders, {
14
+ vuetify: new Vuetify(),
15
+ mocks: defaultMocks,
16
+ })
17
+ expect(wrapper.vm).toBeTruthy()
18
+ })
19
+ })
@@ -1 +1,81 @@
1
- // Mock components from other repos
1
+ import Vue from 'vue'
2
+
3
+ Vue.component('SearchField', {
4
+ name: 'SearchField',
5
+ template: '<div>SearchField</div>',
6
+ })
7
+
8
+ Vue.component('v-expansion-panels', {
9
+ name: 'v-expansion-panels',
10
+ template: '<div>v-expansion-panels</div>',
11
+ })
12
+
13
+ Vue.component('v-expansion-panel', {
14
+ name: 'v-expansion-panel',
15
+ template: '<div>v-expansion-panel</div>',
16
+ })
17
+
18
+ Vue.component('v-expansion-panel-header', {
19
+ name: 'v-expansion-panel-header',
20
+ template: '<div>v-expansion-panel-header</div>',
21
+ })
22
+
23
+ Vue.component('v-expansion-panel-content', {
24
+ name: 'v-expansion-panel-content',
25
+ template: '<div>v-expansion-panel-content</div>',
26
+ })
27
+
28
+ Vue.component('v-tabs', {
29
+ name: 'v-tabs',
30
+ template: '<div>v-tabs</div>',
31
+ })
32
+
33
+ Vue.component('v-tabs-slider', {
34
+ name: 'v-tabs-slider',
35
+ template: '<div>v-tabs-slider</div>',
36
+ })
37
+
38
+ Vue.component('v-tab', {
39
+ name: 'v-tab',
40
+ template: '<div>v-tab</div>',
41
+ })
42
+
43
+ Vue.component('v-tabs-items', {
44
+ name: 'v-tabs-items',
45
+ template: '<div>v-tabs-items</div>',
46
+ })
47
+
48
+ Vue.component('v-tab-item', {
49
+ name: 'v-tab-item',
50
+ template: '<div>v-tab-item</div>',
51
+ })
52
+
53
+ Vue.component('v-select', {
54
+ name: 'v-select',
55
+ template: '<div>v-select</div>',
56
+ })
57
+
58
+ Vue.component('v-autocomplete', {
59
+ name: 'v-autocomplete',
60
+ template: '<div>v-autocomplete</div>',
61
+ })
62
+
63
+ Vue.component('v-switch', {
64
+ name: 'v-switch',
65
+ template: '<div>v-switch</div>',
66
+ })
67
+
68
+ Vue.component('v-divider', {
69
+ name: 'v-divider',
70
+ template: '<div>v-divider</div>',
71
+ })
72
+
73
+ Vue.component('v-progress-circular', {
74
+ name: 'v-progress-circular',
75
+ template: '<div>v-progress-circular</div>',
76
+ })
77
+
78
+ Vue.component('v-treeview', {
79
+ name: 'v-treeview',
80
+ template: '<div>v-treeview</div>',
81
+ })
package/test/mocks.js CHANGED
@@ -28,5 +28,17 @@ mocks.$Integration = {
28
28
  },
29
29
  }
30
30
  mocks.$PermissionService = { userHasAccessTo: () => true }
31
+ mocks.$Validation = {
32
+ getRule() {
33
+ return []
34
+ },
35
+ getLimit() {
36
+ return 0
37
+ },
38
+ addLimit() {},
39
+ addRule() {},
40
+ addLimits() {},
41
+ addRules() {},
42
+ }
31
43
 
32
44
  export const defaultMocks = mocks
package/test/setup.js ADDED
@@ -0,0 +1 @@
1
+ // This file is intentionally left blank.