From ddc797a9dcca36ee1c05f57ab8e1276dfbf0a7b8 Mon Sep 17 00:00:00 2001 From: Daniel Wiehl Date: Tue, 20 Nov 2018 23:57:37 +0100 Subject: [PATCH] feat: contribute 'Workbench Application Platform' to allow integrating content from multiple web applications SCION Workbench Application Platform is an extension to SCION Workbench and allows for integrating content from multiple web applications in a coherent way, thus enabling a micro frontend architecture for allowing different front-end frameworks to co-exist and autonomous delivery. It provides the concept of an application manifest with every application declaring its capabilities and intents to allow for loosely coupled inter-application navigation. Integration into the platform is as lean as possible, consequently, any web application can be integrated without the need for adaptation. closes #80 --- .travis.yml | 344 ++- README.md | 3 +- angular.json | 589 +++- package-lock.json | 492 ++- package.json | 93 +- .../common/ng-package.json | 8 + .../common/package.json | 35 + .../common/src/lib/_common.scss | 197 ++ .../lib/accordion/accordion-item.directive.ts | 69 + .../lib/accordion/accordion.component.html | 21 + .../lib/accordion/accordion.component.scss | 79 + .../src/lib/accordion/accordion.component.ts | 83 + .../src/lib/accordion/accordion.module.ts | 37 + .../src/lib/custom-extension/metadata.ts | 23 + .../filter-field/filter-field.component.html | 2 + .../filter-field/filter-field.component.scss | 26 + .../filter-field/filter-field.component.ts | 99 + .../lib/filter-field/filter-field.module.ts | 32 + .../src/lib/list/list-item.directive.ts | 51 + .../list/list-item/list-item.component.html | 16 + .../list/list-item/list-item.component.scss | 45 + .../lib/list/list-item/list-item.component.ts | 50 + .../common/src/lib/list/list.component.html | 21 + .../common/src/lib/list/list.component.scss | 35 + .../common/src/lib/list/list.component.ts | 153 + .../common/src/lib/list/list.module.ts | 42 + .../common/src/lib/list/metadata.ts | 14 + .../params-enter/params-enter.component.html | 20 + .../params-enter/params-enter.component.scss | 34 + .../params-enter/params-enter.component.ts | 76 + .../lib/params-enter/params-enter.module.ts | 32 + .../popup-shell-button.directive.ts | 54 + .../popup-shell-content.directive.ts | 33 + .../popup-shell-title.directive.ts | 33 + .../popup-shell/popup-shell.component.html | 20 + .../popup-shell/popup-shell.component.scss | 36 + .../lib/popup-shell/popup-shell.component.ts | 82 + .../src/lib/popup-shell/popup-shell.module.ts | 41 + .../src/lib/property/property.component.html | 4 + .../src/lib/property/property.component.scss | 17 + .../src/lib/property/property.component.ts | 53 + .../src/lib/property/property.module.ts | 30 + .../common/src/lib/sash/sash.directive.ts | 109 + .../common/src/lib/sash/sash.module.ts | 30 + .../session-storage/session-storage.module.ts | 21 + .../session-storage.service.ts | 83 + .../common/src/lib/uuid/uuid.util.ts | 34 + .../common/src/public_api.ts | 73 + .../common/tsconfig.lib.json | 28 + .../common/tslint.json | 21 + .../communication-app/browserslist | 11 + .../src/app/app-routing.module.ts | 23 + .../src/app/app.component.html | 3 + .../src/app/app.component.scss | 13 + .../src/app/app.component.ts | 19 + .../communication-app/src/app/app.module.ts | 35 + ...ation-accordion-item-header.component.html | 10 + ...ation-accordion-item-header.component.scss | 18 + ...ication-accordion-item-header.component.ts | 23 + .../communication-new-popup.component.html | 28 + .../communication-new-popup.component.scss | 29 + .../communication-new-popup.component.ts | 81 + .../communication-routing.module.ts | 26 + .../communication-view.component.html | 10 + .../communication-view.component.scss | 17 + .../communication-view.component.ts | 48 + .../app/communication/communication.model.ts | 18 + .../app/communication/communication.module.ts | 41 + .../communication/communication.service.ts | 64 + .../communication-app/src/assets/.gitkeep | 0 .../src/assets/manifest.json | 45 + .../src/environments/environment.now.ts | 13 + .../src/environments/environment.ts | 26 + .../communication-app/src/index.html | 13 + .../communication-app/src/main.ts | 22 + .../communication-app/src/now.json | 5 + .../communication-app/src/polyfills.ts | 89 + .../communication-app/src/styles.scss | 3 + .../communication-app/tsconfig.app.json | 7 + .../communication-app/tslint.json | 17 + .../contact-app/browserslist | 11 + .../contact-app/src/app/app-routing.module.ts | 23 + .../contact-app/src/app/app.component.html | 3 + .../contact-app/src/app/app.component.scss | 13 + .../contact-app/src/app/app.component.ts | 19 + .../contact-app/src/app/app.module.ts | 37 + .../contact-activity.component.html | 19 + .../contact-activity.component.scss | 10 + .../contact-activity.component.ts | 54 + .../contact-new-popup.component.html | 27 + .../contact-new-popup.component.scss | 19 + .../contact-new-popup.component.ts | 84 + .../src/app/contact/contact-routing.module.ts | 30 + .../contact-view/contact-view.component.html | 46 + .../contact-view/contact-view.component.scss | 48 + .../contact-view/contact-view.component.ts | 175 ++ .../src/app/contact/contact.model.ts | 20 + .../src/app/contact/contact.module.ts | 50 + .../src/app/contact/contact.service.ts | 126 + .../related-contact-add-popup.component.html | 16 + .../related-contact-add-popup.component.scss | 12 + .../related-contact-add-popup.component.ts | 69 + .../contact-app/src/assets/.gitkeep | 0 .../contact-app/src/assets/contact.data.json | 2740 +++++++++++++++++ .../contact-app/src/assets/manifest.json | 78 + .../src/environments/environment.now.ts | 13 + .../src/environments/environment.ts | 26 + .../contact-app/src/index.html | 12 + .../contact-app/src/main.ts | 12 + .../contact-app/src/now.json | 5 + .../contact-app/src/polyfills.ts | 89 + .../contact-app/src/styles.scss | 3 + .../contact-app/tsconfig.app.json | 7 + .../contact-app/tslint.json | 17 + .../dev-tools-app/browserslist | 11 + .../src/app/app-routing.module.ts | 23 + .../dev-tools-app/src/app/app.component.html | 3 + .../dev-tools-app/src/app/app.component.scss | 13 + .../dev-tools-app/src/app/app.component.ts | 19 + .../dev-tools-app/src/app/app.module.ts | 37 + .../application-list-item.component.html | 8 + .../application-list-item.component.scss | 40 + .../application-list-item.component.ts | 32 + .../application-list.component.html | 5 + .../application-list.component.scss | 10 + .../application-list.component.ts | 58 + .../application-view.component.html | 66 + .../application-view.component.scss | 134 + .../application-view.component.ts | 126 + .../capability-accordion-item.component.html | 16 + .../capability-accordion-item.component.scss | 28 + .../capability-accordion-item.component.ts | 79 + .../capability-accordion-panel.component.html | 21 + .../capability-accordion-panel.component.scss | 44 + .../capability-accordion-panel.component.ts | 40 + .../app/dev-tools/dev-tools-routing.module.ts | 29 + .../src/app/dev-tools/dev-tools.module.ts | 58 + .../intent-accordion-item.component.html | 5 + .../intent-accordion-item.component.scss | 26 + .../intent-accordion-item.component.ts | 39 + .../intent-accordion-panel.component.html | 12 + .../intent-accordion-panel.component.scss | 30 + .../intent-accordion-panel.component.ts | 38 + ...utlet-capability-exec-popup.component.html | 13 + ...utlet-capability-exec-popup.component.scss | 21 + .../outlet-capability-exec-popup.component.ts | 130 + .../qualifier-chip-list.component.html | 9 + .../qualifier-chip-list.component.scss | 54 + .../qualifier-chip-list.component.ts | 41 + .../dev-tools-app/src/assets/.gitkeep | 0 .../dev-tools-app/src/assets/manifest.json | 97 + .../src/environments/environment.now.ts | 13 + .../src/environments/environment.ts | 26 + .../dev-tools-app/src/index.html | 12 + .../dev-tools-app/src/main.ts | 12 + .../dev-tools-app/src/now.json | 5 + .../dev-tools-app/src/polyfills.ts | 89 + .../dev-tools-app/src/styles.scss | 3 + .../dev-tools-app/tsconfig.app.json | 7 + .../dev-tools-app/tslint.json | 17 + .../host-app/browserslist | 11 + .../host-app/src/app/app.component.html | 1 + .../host-app/src/app/app.component.ts | 18 + .../host-app/src/app/app.module.ts | 68 + .../custom-extension.module.ts | 60 + ...notify-activity-action-provider.service.ts | 21 + ...stom-notify-activity-action.component.html | 7 + ...stom-notify-activity-action.component.scss | 12 + ...custom-notify-activity-action.component.ts | 34 + .../list-messagebox.component.html | 4 + .../list-messagebox.component.scss | 5 + .../list-messagebox.component.ts | 23 + .../list-notification.component.html | 4 + .../list-notification.component.scss | 5 + .../list-notification.component.ts | 23 + .../host-app/src/assets/.gitkeep | 0 .../src/assets/angular-io-manifest.json | 30 + .../host-app/src/assets/fonts/wb-icon.eot | Bin 0 -> 1616 bytes .../host-app/src/assets/fonts/wb-icon.svg | 14 + .../host-app/src/assets/fonts/wb-icon.ttf | Bin 0 -> 1452 bytes .../host-app/src/assets/fonts/wb-icon.woff | Bin 0 -> 1528 bytes .../src/environments/environment.now.ts | 17 + .../host-app/src/environments/environment.ts | 30 + .../host-app/src/favicon.ico | Bin 0 -> 34494 bytes .../host-app/src/index.html | 13 + .../host-app/src/main.ts | 12 + .../host-app/src/now.json | 5 + .../host-app/src/polyfills.ts | 88 + .../host-app/src/styles.scss | 5 + .../host-app/tsconfig.app.json | 7 + .../host-app/tslint.json | 17 + .../test-runner/protractor.conf.js | 35 + .../test-runner/src/activity.e2e-spec.ts | 1115 +++++++ .../test-runner/src/message-box.e2e-spec.ts | 207 ++ .../src/notifcation-box.e2e-spec.ts | 185 ++ .../page-object/activity-actions-panel.po.ts | 39 + .../activity-interaction-panel.po.ts | 58 + .../src/page-object/host-app.po.ts | 455 +++ .../src/page-object/message-box-panel.po.ts | 101 + .../src/page-object/notification-panel.po.ts | 94 + .../popup-open-activity-action-panel.po.ts | 82 + .../src/page-object/popup-panel.po.ts | 69 + .../src/page-object/sci-accordion-p.o.ts | 35 + .../src/page-object/sci-params-enter.po.ts | 29 + .../src/page-object/sci-property.po.ts | 36 + .../page-object/testcase-159913ad-popup.po.ts | 34 + .../testcase-28f32b51-activity.po.ts | 23 + .../page-object/testcase-28f32b51-view.po.ts | 23 + .../page-object/testcase-45dc693f-popup.po.ts | 34 + .../testcase-4a3a8984-activity-po.ts | 22 + .../page-object/testcase-56657ad1-view.po.ts | 34 + .../testcase-5782ab19-activity.po.ts | 36 + .../page-object/testcase-5782ab19-popup.po.ts | 36 + .../page-object/testcase-5782ab19-view.po.ts | 36 + .../testcase-61097bad-msgbox.po.ts | 31 + .../testcase-61097bad-notification.po.ts | 31 + .../page-object/testcase-68f302b4-view-po.ts | 41 + .../page-object/testcase-8a468258-popup.po.ts | 34 + .../page-object/testcase-9c5319f7-popup.po.ts | 34 + .../page-object/testcase-a686d615-view.po.ts | 34 + .../page-object/testcase-b6a8fe23-view.po.ts | 34 + .../page-object/testcase-c8e40918-view.po.ts | 34 + .../page-object/testcase-cc977da9-view.po.ts | 34 + .../page-object/testcase-f4286ac4-popup.po.ts | 34 + .../page-object/testcase-fc077b32-popup.po.ts | 40 + .../page-object/testcase-ffd6a78f-view.po.ts | 34 + .../src/page-object/testing-activity.po.ts | 68 + .../src/page-object/testing-popup.po.ts | 61 + .../src/page-object/testing-view.po.ts | 65 + .../page-object/view-interaction-panel.po.ts | 61 + .../page-object/view-navigation-panel.po.ts | 58 + .../view-open-activity-action-panel.po.ts | 77 + .../test-runner/src/popup.e2e-spec.ts | 481 +++ .../test-runner/src/util/testing.util.ts | 147 + .../test-runner/src/view.e2e-spec.ts | 837 +++++ .../test-runner/tsconfig.e2e.json | 13 + .../testing-app/browserslist | 11 + .../testing-app/src/app/app-routing.module.ts | 23 + .../testing-app/src/app/app.component.html | 3 + .../testing-app/src/app/app.component.scss | 13 + .../testing-app/src/app/app.component.ts | 19 + .../testing-app/src/app/app.module.ts | 37 + .../activity-28f32b51.component.html | 1 + .../activity-28f32b51.component.scss | 6 + .../activity-28f32b51.component.ts | 35 + .../activity-4a3a8984.component.html | 3 + .../activity-4a3a8984.component.scss | 19 + .../activity-4a3a8984.component.ts | 26 + .../activity-5782ab19.component.html | 5 + .../activity-5782ab19.component.scss | 15 + .../activity-5782ab19.component.ts | 23 + .../activity-6d806bea.component.ts | 22 + .../activity-actions-panel.component.html | 20 + .../activity-actions-panel.component.scss | 10 + .../activity-actions-panel.component.ts | 36 + ...custom-notify-activity-action.directive.ts | 67 + .../activity-interation-panel.component.html | 19 + .../activity-interation-panel.component.scss | 19 + .../activity-interation-panel.component.ts | 32 + .../src/app/testing/app-instance.service.ts | 8 + .../src/app/testing/custom-validators.ts | 37 + .../message-box-panel.component.html | 46 + .../message-box-panel.component.scss | 45 + .../message-box-panel.component.ts | 82 + .../notification-panel.component.html | 42 + .../notification-panel.component.scss | 33 + .../notification-panel.component.ts | 72 + .../popup-159913ad.component.html | 9 + .../popup-159913ad.component.scss | 23 + .../popup-159913ad.component.ts | 33 + .../popup-1a90c8d2.component.ts | 22 + .../popup-45dc693f.component.html | 9 + .../popup-45dc693f.component.scss | 23 + .../popup-45dc693f.component.ts | 33 + .../popup-5782ab19.component.html | 5 + .../popup-5782ab19.component.scss | 15 + .../popup-5782ab19.component.ts | 23 + .../popup-7330f506.component.ts | 22 + .../popup-8a468258.component.html | 9 + .../popup-8a468258.component.scss | 23 + .../popup-8a468258.component.ts | 33 + .../popup-9c5319f7.component.html | 9 + .../popup-9c5319f7.component.scss | 23 + .../popup-9c5319f7.component.ts | 33 + .../popup-f4286ac4.component.html | 9 + .../popup-f4286ac4.component.scss | 23 + .../popup-f4286ac4.component.ts | 33 + .../popup-fc077b32.component.html | 1 + .../popup-fc077b32.component.scss | 6 + .../popup-fc077b32.component.ts | 30 + ...-open-activity-action-panel.component.html | 30 + ...-open-activity-action-panel.component.scss | 46 + ...up-open-activity-action-panel.component.ts | 84 + .../popup-panel/popup-panel.component.html | 38 + .../popup-panel/popup-panel.component.scss | 36 + .../popup-panel/popup-panel.component.ts | 75 + .../testing-activity.component.html | 47 + .../testing-activity.component.scss | 31 + .../testing-activity.component.ts | 33 + .../testing-popup.component.html | 25 + .../testing-popup.component.scss | 57 + .../testing-popup/testing-popup.component.ts | 48 + .../src/app/testing/testing-routing.module.ts | 91 + .../testing-view/testing-view.component.html | 56 + .../testing-view/testing-view.component.scss | 31 + .../testing-view/testing-view.component.ts | 33 + .../src/app/testing/testing.module.ts | 124 + .../view-0c4fe9e3/view-0c4fe9e3.component.ts | 38 + .../view-28f32b51.component.html | 1 + .../view-28f32b51.component.scss | 6 + .../view-28f32b51/view-28f32b51.component.ts | 35 + .../view-354aa6da/view-354aa6da.component.ts | 22 + .../view-4a4e6970/view-4a4e6970.component.ts | 22 + .../view-56657ad1.component.html | 9 + .../view-56657ad1.component.scss | 23 + .../view-56657ad1/view-56657ad1.component.ts | 33 + .../view-5782ab19.component.html | 5 + .../view-5782ab19.component.scss | 15 + .../view-5782ab19/view-5782ab19.component.ts | 23 + .../view-608aa47c/view-608aa47c.component.ts | 22 + .../view-68f302b4.component.html | 16 + .../view-68f302b4.component.scss | 28 + .../view-68f302b4/view-68f302b4.component.ts | 36 + .../view-85dde646/view-85dde646.component.ts | 20 + .../view-a686d615.component.html | 9 + .../view-a686d615.component.scss | 23 + .../view-a686d615/view-a686d615.component.ts | 33 + .../view-b1dd152a/view-b1dd152a.component.ts | 22 + .../view-b6a8fe23.component.html | 9 + .../view-b6a8fe23.component.scss | 23 + .../view-b6a8fe23/view-b6a8fe23.component.ts | 33 + .../view-be587bd6/view-be587bd6.component.ts | 22 + .../view-c8e40918.component.html | 9 + .../view-c8e40918.component.scss | 23 + .../view-c8e40918/view-c8e40918.component.ts | 33 + .../view-c91805e8/view-c91805e8.component.ts | 22 + .../view-cc977da9.component.html | 9 + .../view-cc977da9.component.scss | 23 + .../view-cc977da9/view-cc977da9.component.ts | 33 + .../view-f389a9d5/view-f389a9d5.component.ts | 22 + .../view-ffd6a78f.component.html | 9 + .../view-ffd6a78f.component.scss | 23 + .../view-ffd6a78f/view-ffd6a78f.component.ts | 33 + .../view-interation-panel.component.html | 24 + .../view-interation-panel.component.scss | 33 + .../view-interation-panel.component.ts | 32 + .../view-navigation-panel.component.html | 19 + .../view-navigation-panel.component.scss | 24 + .../view-navigation-panel.component.ts | 63 + ...-open-activity-action-panel.component.html | 24 + ...-open-activity-action-panel.component.scss | 24 + ...ew-open-activity-action-panel.component.ts | 78 + .../testing-app/src/assets/.gitkeep | 0 .../testing-app/src/assets/manifest.json | 703 +++++ .../src/environments/environment.now.ts | 13 + .../src/environments/environment.ts | 26 + .../testing-app/src/index.html | 12 + .../testing-app/src/main.ts | 12 + .../testing-app/src/polyfills.ts | 90 + .../testing-app/src/styles.scss | 3 + .../testing-app/tsconfig.app.json | 7 + .../testing-app/tslint.json | 17 + .../ng-package.json | 7 + .../package.json | 35 + .../src/lib/activity.model.ts | 334 ++ .../src/lib/core.model.ts | 310 ++ .../src/lib/manifest-registry.model.ts | 127 + .../src/lib/messagebox.model.ts | 73 + .../src/lib/notification.model.ts | 65 + .../src/lib/popup.model.ts | 120 + .../src/lib/view.model.ts | 214 ++ .../src/public_api.ts | 20 + .../tsconfig.lib.json | 28 + .../tslint.json | 5 + .../karma.conf.js | 42 + .../ng-package.json | 11 + .../package.json | 44 + .../activity-capability.module.ts | 60 + .../activity-outlet.component.html | 3 + .../activity-outlet.component.scss | 11 + .../activity-outlet.component.ts | 141 + .../activity-registrator.service.ts | 76 + .../src/lib/activity-capability/metadata.ts | 63 + ...p-open-activity-action-provider.service.ts | 24 + .../popup-open-activity-action.component.html | 6 + .../popup-open-activity-action.component.scss | 12 + .../popup-open-activity-action.component.ts | 55 + ...l-open-activity-action-provider.service.ts | 24 + .../url-open-activity-action.component.html | 6 + .../url-open-activity-action.component.scss | 12 + .../url-open-activity-action.component.ts | 27 + ...w-open-activity-action-provider.service.ts | 24 + .../view-open-activity-action.component.html | 6 + .../view-open-activity-action.component.scss | 12 + .../view-open-activity-action.component.ts | 47 + .../src/lib/core/app-outlet.directive.ts | 147 + .../lib/core/application-registry.service.ts | 92 + .../src/lib/core/array.util.ts | 28 + .../src/lib/core/core.module.ts | 56 + .../lib/core/default-error-handler.service.ts | 36 + .../src/lib/core/defined.util.ts | 32 + .../intent-handler-registrator.service.ts | 75 + .../src/lib/core/logger.service.ts | 46 + .../lib/core/manifest-collector.service.ts | 82 + .../src/lib/core/manifest-registry.service.ts | 175 ++ .../src/lib/core/message-bus.service.ts | 194 ++ .../src/lib/core/metadata.ts | 198 ++ ...odule-application-config-loader.service.ts | 33 + .../lib/core/null-error-handler.service.ts | 29 + .../src/lib/core/qualifier-tester.ts | 37 + .../src/lib/core/url.util.ts | 117 + .../src/lib/core/uuid.util.ts | 34 + .../src/lib/for-root-guard.service.ts | 15 + .../manifest-capability.module.ts | 30 + ...anifest-registry-intent-handler.service.ts | 159 + .../message-box-capability.module.ts | 39 + .../message-box-intent-handler.service.ts | 75 + .../notification-capability.module.ts | 39 + .../notification-intent-handler.service.ts | 70 + .../popup-capability.module.ts | 39 + .../popup-intent-handler.service.ts | 123 + .../popup-outlet.component.html | 7 + .../popup-outlet.component.scss | 11 + .../popup-outlet.component.ts | 90 + .../src/lib/spec/application-registry.spec.ts | 201 ++ .../src/lib/spec/manifest-collector.spec.ts | 100 + .../src/lib/spec/manifest-registry.spec.ts | 242 ++ .../src/lib/spec/message-bus.spec.ts | 475 +++ .../src/lib/spec/message-envelope.spec.ts | 38 + .../src/lib/spec/qualifier.spec.ts | 71 + .../src/lib/spec/url.util.spec.ts | 288 ++ ...kbench-application-platform.module.spec.ts | 49 + .../src/lib/view-capability/metadata.ts | 18 + .../view-capability/view-capability.module.ts | 41 + .../view-intent-handler.service.ts | 136 + .../view-outlet.component.html | 3 + .../view-outlet.component.scss | 11 + .../view-capability/view-outlet.component.ts | 157 + .../workbench-application-platform.config.ts | 41 + ...orkbench-application-platform.constants.ts | 16 + .../workbench-application-platform.module.ts | 73 + .../src/public_api.ts | 25 + .../src/test.ts | 29 + .../tsconfig.lib.json | 32 + .../tsconfig.spec.json | 17 + .../tslint.json | 21 + .../karma.conf.js | 42 + .../ng-package.json | 8 + .../package.json | 40 + .../src/lib/activator.service.ts | 117 + .../src/lib/defined.util.ts | 32 + .../src/lib/for-root-guard.service.ts | 15 + .../src/lib/spec/application-registry.spec.ts | 16 + .../src/lib/workbench-activity.ts | 196 ++ .../src/lib/workbench-application.config.ts | 54 + .../src/lib/workbench-application.module.ts | 122 + ...ch-popup-open-activity-action.directive.ts | 126 + .../src/lib/workbench-popup.ts | 83 + .../lib/workbench-router-link.directive.ts | 69 + .../src/lib/workbench-router.service.ts | 76 + ...ench-url-open-activity-action.directive.ts | 88 + ...nch-view-open-activity-action.directive.ts | 118 + .../src/lib/workbench-view.ts | 214 ++ .../src/public_api.ts | 22 + .../workbench-application.angular/src/test.ts | 29 + .../tsconfig.lib.json | 32 + .../tsconfig.spec.json | 17 + .../workbench-application.angular/tslint.json | 21 + .../workbench-application.core/karma.conf.js | 42 + .../ng-package.json | 8 + .../workbench-application.core/package.json | 38 + .../src/lib/activity.service.ts | 116 + .../src/lib/manifest-registryService.ts | 129 + .../src/lib/message-box-service.ts | 44 + .../src/lib/message-bus-service.ts | 130 + .../src/lib/metadata.ts | 32 + .../src/lib/notification-service.ts | 41 + .../src/lib/platform-activator.ts | 53 + .../src/lib/platform-event-bus-service.ts | 79 + .../src/lib/platform.ts | 54 + .../src/lib/popup-service.ts | 104 + .../src/lib/router.service.ts | 87 + .../src/lib/spec/application-registry.spec.ts | 16 + .../src/lib/uuid.util.ts | 34 + .../src/lib/view.service.ts | 142 + .../src/public_api.ts | 27 + .../workbench-application.core/src/test.ts | 29 + .../tsconfig.lib.json | 32 + .../tsconfig.spec.json | 17 + .../workbench-application.core/tslint.json | 5 + projects/scion/workbench/package.json | 7 +- .../message-box/message-box.component.scss | 1 - .../lib/message-box/message-box.service.ts | 2 + .../notification-list.component.ts | 6 +- .../remote-site/remote-site.component.html | 3 +- .../remote-site/remote-site.component.scss | 2 + .../lib/remote-site/remote-site.component.ts | 69 +- .../lib/routing/wb-router-link.directive.ts | 3 + .../view-tab/view-tab.component.html | 8 +- .../workbench/src/lib/workbench.service.ts | 2 +- travis-scripts/cd.sh | 7 + travis-scripts/deploy-now.sh | 14 + tsconfig.json | 90 + 503 files changed, 28677 insertions(+), 230 deletions(-) create mode 100644 projects/e2e/workbench-application-platform/common/ng-package.json create mode 100644 projects/e2e/workbench-application-platform/common/package.json create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/_common.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion-item.directive.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.html create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/custom-extension/metadata.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.html create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list-item.directive.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.html create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list.component.html create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list.component.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list.component.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/list.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/list/metadata.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.html create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell-button.directive.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell-content.directive.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell-title.directive.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.html create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/property/property.component.html create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/property/property.component.scss create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/property/property.component.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/property/property.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/sash/sash.directive.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/sash/sash.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.module.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.service.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/lib/uuid/uuid.util.ts create mode 100644 projects/e2e/workbench-application-platform/common/src/public_api.ts create mode 100644 projects/e2e/workbench-application-platform/common/tsconfig.lib.json create mode 100644 projects/e2e/workbench-application-platform/common/tslint.json create mode 100644 projects/e2e/workbench-application-platform/communication-app/browserslist create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/app-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/app.component.html create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/app.component.scss create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/app.component.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/app.module.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.html create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.scss create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.html create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.scss create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.html create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.scss create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.model.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.module.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.service.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/assets/.gitkeep create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/assets/manifest.json create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/environments/environment.now.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/environments/environment.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/index.html create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/main.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/now.json create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/polyfills.ts create mode 100644 projects/e2e/workbench-application-platform/communication-app/src/styles.scss create mode 100644 projects/e2e/workbench-application-platform/communication-app/tsconfig.app.json create mode 100644 projects/e2e/workbench-application-platform/communication-app/tslint.json create mode 100644 projects/e2e/workbench-application-platform/contact-app/browserslist create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/app-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/app.component.html create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/app.component.scss create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/app.component.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/app.module.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.html create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.scss create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.html create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.scss create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.html create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.scss create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.model.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.module.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.service.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.html create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.scss create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/assets/.gitkeep create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/assets/contact.data.json create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/assets/manifest.json create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/environments/environment.now.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/environments/environment.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/index.html create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/main.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/now.json create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/polyfills.ts create mode 100644 projects/e2e/workbench-application-platform/contact-app/src/styles.scss create mode 100644 projects/e2e/workbench-application-platform/contact-app/tsconfig.app.json create mode 100644 projects/e2e/workbench-application-platform/contact-app/tslint.json create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/browserslist create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/app-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.module.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools.module.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/assets/.gitkeep create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/assets/manifest.json create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.now.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/index.html create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/main.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/now.json create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/polyfills.ts create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/src/styles.scss create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/tsconfig.app.json create mode 100644 projects/e2e/workbench-application-platform/dev-tools-app/tslint.json create mode 100644 projects/e2e/workbench-application-platform/host-app/browserslist create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/app.component.html create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/app.component.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/app.module.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-extension.module.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action-provider.service.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.html create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.scss create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.html create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.scss create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.html create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.scss create mode 100644 projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/assets/.gitkeep create mode 100644 projects/e2e/workbench-application-platform/host-app/src/assets/angular-io-manifest.json create mode 100644 projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.eot create mode 100644 projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.svg create mode 100644 projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.ttf create mode 100644 projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.woff create mode 100644 projects/e2e/workbench-application-platform/host-app/src/environments/environment.now.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/environments/environment.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/favicon.ico create mode 100644 projects/e2e/workbench-application-platform/host-app/src/index.html create mode 100644 projects/e2e/workbench-application-platform/host-app/src/main.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/now.json create mode 100644 projects/e2e/workbench-application-platform/host-app/src/polyfills.ts create mode 100644 projects/e2e/workbench-application-platform/host-app/src/styles.scss create mode 100644 projects/e2e/workbench-application-platform/host-app/tsconfig.app.json create mode 100644 projects/e2e/workbench-application-platform/host-app/tslint.json create mode 100644 projects/e2e/workbench-application-platform/test-runner/protractor.conf.js create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/activity.e2e-spec.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/message-box.e2e-spec.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/notifcation-box.e2e-spec.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-actions-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-interaction-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/host-app.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/message-box-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/notification-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-open-activity-action-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-accordion-p.o.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-params-enter.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-property.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-159913ad-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-activity.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-45dc693f-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-4a3a8984-activity-po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-56657ad1-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-activity.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-msgbox.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-notification.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-68f302b4-view-po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-8a468258-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-9c5319f7-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-a686d615-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-b6a8fe23-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-c8e40918-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-cc977da9-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-f4286ac4-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-fc077b32-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-ffd6a78f-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-activity.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-popup.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-view.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/view-interaction-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/view-navigation-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/page-object/view-open-activity-action-panel.po.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/popup.e2e-spec.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/util/testing.util.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/src/view.e2e-spec.ts create mode 100644 projects/e2e/workbench-application-platform/test-runner/tsconfig.e2e.json create mode 100644 projects/e2e/workbench-application-platform/testing-app/browserslist create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/app-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/app.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/app.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/app.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/app.module.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-28f32b51/activity-28f32b51.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-28f32b51/activity-28f32b51.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-28f32b51/activity-28f32b51.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-4a3a8984/activity-4a3a8984.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-4a3a8984/activity-4a3a8984.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-4a3a8984/activity-4a3a8984.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-5782ab19/activity-5782ab19.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-5782ab19/activity-5782ab19.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-5782ab19/activity-5782ab19.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-6d806bea/activity-6d806bea.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-actions-panel/activity-actions-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-actions-panel/activity-actions-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-actions-panel/activity-actions-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-actions-panel/custom-notify-activity-action.directive.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-interaction-panel/activity-interation-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-interaction-panel/activity-interation-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/activity-interaction-panel/activity-interation-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/app-instance.service.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/custom-validators.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/message-box-panel/message-box-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/message-box-panel/message-box-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/message-box-panel/message-box-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/notification-panel/notification-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/notification-panel/notification-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/notification-panel/notification-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-159913ad/popup-159913ad.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-159913ad/popup-159913ad.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-159913ad/popup-159913ad.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-1a90c8d2/popup-1a90c8d2.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-45dc693f/popup-45dc693f.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-45dc693f/popup-45dc693f.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-45dc693f/popup-45dc693f.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-5782ab19/popup-5782ab19.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-5782ab19/popup-5782ab19.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-5782ab19/popup-5782ab19.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-7330f506/popup-7330f506.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-8a468258/popup-8a468258.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-8a468258/popup-8a468258.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-8a468258/popup-8a468258.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-9c5319f7/popup-9c5319f7.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-9c5319f7/popup-9c5319f7.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-9c5319f7/popup-9c5319f7.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-f4286ac4/popup-f4286ac4.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-f4286ac4/popup-f4286ac4.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-f4286ac4/popup-f4286ac4.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-fc077b32/popup-fc077b32.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-fc077b32/popup-fc077b32.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-fc077b32/popup-fc077b32.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-open-activity-action-panel/popup-open-activity-action-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-open-activity-action-panel/popup-open-activity-action-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-open-activity-action-panel/popup-open-activity-action-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-panel/popup-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-panel/popup-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/popup-panel/popup-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-activity/testing-activity.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-activity/testing-activity.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-activity/testing-activity.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-popup/testing-popup.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-popup/testing-popup.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-popup/testing-popup.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-routing.module.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-view/testing-view.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-view/testing-view.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing-view/testing-view.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/testing.module.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-0c4fe9e3/view-0c4fe9e3.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-28f32b51/view-28f32b51.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-28f32b51/view-28f32b51.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-28f32b51/view-28f32b51.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-354aa6da/view-354aa6da.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-4a4e6970/view-4a4e6970.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-56657ad1/view-56657ad1.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-56657ad1/view-56657ad1.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-56657ad1/view-56657ad1.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-5782ab19/view-5782ab19.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-5782ab19/view-5782ab19.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-5782ab19/view-5782ab19.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-608aa47c/view-608aa47c.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-68f302b4/view-68f302b4.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-68f302b4/view-68f302b4.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-68f302b4/view-68f302b4.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-85dde646/view-85dde646.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-a686d615/view-a686d615.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-a686d615/view-a686d615.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-a686d615/view-a686d615.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-b1dd152a/view-b1dd152a.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-b6a8fe23/view-b6a8fe23.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-b6a8fe23/view-b6a8fe23.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-b6a8fe23/view-b6a8fe23.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-be587bd6/view-be587bd6.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-c8e40918/view-c8e40918.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-c8e40918/view-c8e40918.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-c8e40918/view-c8e40918.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-c91805e8/view-c91805e8.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-cc977da9/view-cc977da9.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-cc977da9/view-cc977da9.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-cc977da9/view-cc977da9.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-f389a9d5/view-f389a9d5.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-ffd6a78f/view-ffd6a78f.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-ffd6a78f/view-ffd6a78f.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-ffd6a78f/view-ffd6a78f.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-interaction-panel/view-interation-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-interaction-panel/view-interation-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-interaction-panel/view-interation-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-navigation-panel/view-navigation-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-navigation-panel/view-navigation-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-navigation-panel/view-navigation-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-open-activity-action-panel/view-open-activity-action-panel.component.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-open-activity-action-panel/view-open-activity-action-panel.component.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/app/testing/view-open-activity-action-panel/view-open-activity-action-panel.component.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/assets/.gitkeep create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/assets/manifest.json create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/environments/environment.now.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/environments/environment.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/index.html create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/main.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/polyfills.ts create mode 100644 projects/e2e/workbench-application-platform/testing-app/src/styles.scss create mode 100644 projects/e2e/workbench-application-platform/testing-app/tsconfig.app.json create mode 100644 projects/e2e/workbench-application-platform/testing-app/tslint.json create mode 100644 projects/scion/workbench-application-platform.api/ng-package.json create mode 100644 projects/scion/workbench-application-platform.api/package.json create mode 100644 projects/scion/workbench-application-platform.api/src/lib/activity.model.ts create mode 100644 projects/scion/workbench-application-platform.api/src/lib/core.model.ts create mode 100644 projects/scion/workbench-application-platform.api/src/lib/manifest-registry.model.ts create mode 100644 projects/scion/workbench-application-platform.api/src/lib/messagebox.model.ts create mode 100644 projects/scion/workbench-application-platform.api/src/lib/notification.model.ts create mode 100644 projects/scion/workbench-application-platform.api/src/lib/popup.model.ts create mode 100644 projects/scion/workbench-application-platform.api/src/lib/view.model.ts create mode 100644 projects/scion/workbench-application-platform.api/src/public_api.ts create mode 100644 projects/scion/workbench-application-platform.api/tsconfig.lib.json create mode 100644 projects/scion/workbench-application-platform.api/tslint.json create mode 100644 projects/scion/workbench-application-platform/karma.conf.js create mode 100644 projects/scion/workbench-application-platform/ng-package.json create mode 100644 projects/scion/workbench-application-platform/package.json create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/activity-capability.module.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/activity-outlet.component.html create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/activity-outlet.component.scss create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/activity-outlet.component.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/activity-registrator.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/metadata.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/popup-open-action/popup-open-activity-action-provider.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/popup-open-action/popup-open-activity-action.component.html create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/popup-open-action/popup-open-activity-action.component.scss create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/popup-open-action/popup-open-activity-action.component.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/url-open-action/url-open-activity-action-provider.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/url-open-action/url-open-activity-action.component.html create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/url-open-action/url-open-activity-action.component.scss create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/url-open-action/url-open-activity-action.component.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/view-open-action/view-open-activity-action-provider.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/view-open-action/view-open-activity-action.component.html create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/view-open-action/view-open-activity-action.component.scss create mode 100644 projects/scion/workbench-application-platform/src/lib/activity-capability/view-open-action/view-open-activity-action.component.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/app-outlet.directive.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/application-registry.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/array.util.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/core.module.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/default-error-handler.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/defined.util.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/intent-handler-registrator.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/logger.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/manifest-collector.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/manifest-registry.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/message-bus.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/metadata.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/module-application-config-loader.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/null-error-handler.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/qualifier-tester.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/url.util.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/core/uuid.util.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/for-root-guard.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/manifest-capability/manifest-capability.module.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/manifest-capability/manifest-registry-intent-handler.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/messagebox-capability/message-box-capability.module.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/messagebox-capability/message-box-intent-handler.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/notification-capability/notification-capability.module.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/notification-capability/notification-intent-handler.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/popup-capability/popup-capability.module.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/popup-capability/popup-intent-handler.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/popup-capability/popup-outlet.component.html create mode 100644 projects/scion/workbench-application-platform/src/lib/popup-capability/popup-outlet.component.scss create mode 100644 projects/scion/workbench-application-platform/src/lib/popup-capability/popup-outlet.component.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/application-registry.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/manifest-collector.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/manifest-registry.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/message-bus.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/message-envelope.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/qualifier.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/url.util.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/spec/workbench-application-platform.module.spec.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/view-capability/metadata.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/view-capability/view-capability.module.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/view-capability/view-intent-handler.service.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/view-capability/view-outlet.component.html create mode 100644 projects/scion/workbench-application-platform/src/lib/view-capability/view-outlet.component.scss create mode 100644 projects/scion/workbench-application-platform/src/lib/view-capability/view-outlet.component.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/workbench-application-platform.config.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/workbench-application-platform.constants.ts create mode 100644 projects/scion/workbench-application-platform/src/lib/workbench-application-platform.module.ts create mode 100644 projects/scion/workbench-application-platform/src/public_api.ts create mode 100644 projects/scion/workbench-application-platform/src/test.ts create mode 100644 projects/scion/workbench-application-platform/tsconfig.lib.json create mode 100644 projects/scion/workbench-application-platform/tsconfig.spec.json create mode 100644 projects/scion/workbench-application-platform/tslint.json create mode 100644 projects/scion/workbench-application.angular/karma.conf.js create mode 100644 projects/scion/workbench-application.angular/ng-package.json create mode 100644 projects/scion/workbench-application.angular/package.json create mode 100644 projects/scion/workbench-application.angular/src/lib/activator.service.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/defined.util.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/for-root-guard.service.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/spec/application-registry.spec.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-activity.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-application.config.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-application.module.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-popup-open-activity-action.directive.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-popup.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-router-link.directive.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-router.service.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-url-open-activity-action.directive.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-view-open-activity-action.directive.ts create mode 100644 projects/scion/workbench-application.angular/src/lib/workbench-view.ts create mode 100644 projects/scion/workbench-application.angular/src/public_api.ts create mode 100644 projects/scion/workbench-application.angular/src/test.ts create mode 100644 projects/scion/workbench-application.angular/tsconfig.lib.json create mode 100644 projects/scion/workbench-application.angular/tsconfig.spec.json create mode 100644 projects/scion/workbench-application.angular/tslint.json create mode 100644 projects/scion/workbench-application.core/karma.conf.js create mode 100644 projects/scion/workbench-application.core/ng-package.json create mode 100644 projects/scion/workbench-application.core/package.json create mode 100644 projects/scion/workbench-application.core/src/lib/activity.service.ts create mode 100644 projects/scion/workbench-application.core/src/lib/manifest-registryService.ts create mode 100644 projects/scion/workbench-application.core/src/lib/message-box-service.ts create mode 100644 projects/scion/workbench-application.core/src/lib/message-bus-service.ts create mode 100644 projects/scion/workbench-application.core/src/lib/metadata.ts create mode 100644 projects/scion/workbench-application.core/src/lib/notification-service.ts create mode 100644 projects/scion/workbench-application.core/src/lib/platform-activator.ts create mode 100644 projects/scion/workbench-application.core/src/lib/platform-event-bus-service.ts create mode 100644 projects/scion/workbench-application.core/src/lib/platform.ts create mode 100644 projects/scion/workbench-application.core/src/lib/popup-service.ts create mode 100644 projects/scion/workbench-application.core/src/lib/router.service.ts create mode 100644 projects/scion/workbench-application.core/src/lib/spec/application-registry.spec.ts create mode 100644 projects/scion/workbench-application.core/src/lib/uuid.util.ts create mode 100644 projects/scion/workbench-application.core/src/lib/view.service.ts create mode 100644 projects/scion/workbench-application.core/src/public_api.ts create mode 100644 projects/scion/workbench-application.core/src/test.ts create mode 100644 projects/scion/workbench-application.core/tsconfig.lib.json create mode 100644 projects/scion/workbench-application.core/tsconfig.spec.json create mode 100644 projects/scion/workbench-application.core/tslint.json create mode 100644 travis-scripts/cd.sh create mode 100644 travis-scripts/deploy-now.sh diff --git a/.travis.yml b/.travis.yml index 6609ead81..3e9dfaf35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,110 +5,256 @@ dist: trusty language: node_js node_js: - '8' +env: + global: + - NPM_EMAIL="scion.collaborator@gmail.com" + - NPM_TOKEN="FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" + - secure: "W2MbFhPYKn4nBzW9uV5GlRBU7Bsml3CA2sGapskwHouAW/5KApc8OPirhlu37LdUKaPmJwacWOugK9SPU5Fh2kBEad4ktlyVpbwIbzt3R29EpdolnaeUX2cpGfqUWxSN3EA02mlKyExfTQL7AYJlrysgVc+5D1FyvZQ/Ej4sw8NvbUbuRxUXiOCP9FpZ3GYa3Tprl3cfQpgHPUqxO64kvym1kZZAYXkrLiidGA5riiWyY8b4waBv7cg+tpYzsqkPCSdlnTaisy1Lo5vMaAXsKroWnJHRH6ONPJr8qw1YmffSslpXYeENDKJQNKPdd9i5M56Vq7sV2jHb9vWP8CdOUxO9298pC6ymQ28EJFttEG/0CrLCZdkDbf9HcKy6ZygOyrow/FDOaOCJSilNzecfeNJmF5Av+tt7tg4zSLVK33mKFJSrrPvalG44iIHIgHHWd8LOGAy7k4pzquW1zbTVMqcqctYxUWYTy8s2r/7Nxy/f0bdb5XHwj91TOnp8+mSR1FI8UGgvmc8Y8BuXSwz9cdihX6nM7u+gVpEwgRpelej05dathtmUtuSTAZBdETBspFrCCjzSy7J/9M5/nVXArf875qzqWfj4/KNqqAeg/YNWdI2wlW90JQgt5msOe1awwuWttFVyO3mdT6gvkaPrkpxbDW/yHgr8pXiGIHm1iAE=" # $NOW_TOKEN install: - npm install -script: -- npm run build jobs: include: - - stage: lint and test all packages + - stage: "Lint" + name: "lint Workbench & Workbench Application Platform" + script: + - npm run lint + - + name: "lint E2E-App (Workbench Application Platform)" + script: + - npm run e2e:workbench-application-platform:lint + - stage: "Build, Test, Deploy, Publish" + name: "build, test, deploy E2E-App (if branch=master) to 'https://zeit.co/scion', publish Workbench & Workbench Application Platform to NPM (if branch=master AND if release tag)" script: - npm run build - - npm run lint - npm run test - - stage: release mouse-dispatcher package - if: tag IS present - before_deploy: - - cd dist/scion/mouse-dispatcher - after_deploy: - - cd ../../.. - deploy: - - provider: npm - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) - - provider: npm - tag: next - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) - - stage: release dimension package - if: tag IS present - before_deploy: - - cd dist/scion/dimension - after_deploy: - - cd ../../.. - deploy: - - provider: npm - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) - - provider: npm - tag: next - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) - - stage: release viewport package - if: tag IS present - before_deploy: - - cd dist/scion/viewport - after_deploy: - - cd ../../.. - deploy: - - provider: npm - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) - - provider: npm - tag: next - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) - - stage: release workbench package - if: tag IS present - before_deploy: - - cd dist/scion/workbench - after_deploy: - - cd ../../.. + - npm run e2e:workbench-application-platform:build-now + - npm run e2e:workbench-application-platform:e2e deploy: - - provider: npm - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) - - provider: npm - tag: next - email: scion.collaborator@gmail.com - api_key: - secure: "FbNdERSRydcm38qnM9XV2HRSYhh7yi33JJe5FUSITDwQh8PAHjmxC5yCvyHHg2WBq5bLBS54oeR8NwomcTQXFL0s8d4Pte32sHBVgNnZ34U1IJDQ6Eufy01dZZjtZNfyv+3CeWOKgHWB963aBbCnfTisN2C66FBLQ4cK1cUO7UaMPZ6ux1wjhtFtd/Isih4TYNCmMRYGYZO1cNO+Ua84dm0j3ko8Hwx68Er3Ce3isQKqHKtXA5d0bX4/bYZuiXwWZwM/QQ2YMCALy8XOSBoE8ObBqOUiutO9LCsGEcPP5LiuWp0D1uqSvajdRhlmoTL3TI3/qDoLtkphww70JYzgRI8HJRekzGvg/gNqJrCDDxz51LpHVrH95TFS+pb9yw/OeEnT6HTpk3C0wc1KUx04EP90bJg36do+eixir3bqQsVJnFMZaBCPGOEyNHsHEqJ5tyKtqVW7UQeyynZGpNXhK1QRS+SQmisLP8nlo6QFheSn965Ke7kYoGB2olasUo7YKJko70bK4kCJOCPdbFyRQUBWGxjdFaAk29a9ekSj6RrkhazjqlxtZAUK72FSlj8UzloJKLugsBfhWEGPqorprbhyeK3qZUUj3ammiu4VW057A2FASAsE9Y80yzrO+0dJeIsTjHC6zNIaQj3KxR7jJBLGe0pKMpql75Adne+ThZM=" - skip_cleanup: true - on: - tags: true - condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + - provider: script + script: bash ./travis-scripts/deploy-now.sh $TRAVIS_BUILD_DIR dist/e2e/workbench-application-platform/host-app $NOW_TOKEN + skip_cleanup: true + on: + branch: workbench-application-platform + - provider: script + script: bash ./travis-scripts/deploy-now.sh $TRAVIS_BUILD_DIR dist/e2e/workbench-application-platform/contact-app $NOW_TOKEN + skip_cleanup: true + on: + branch: workbench-application-platform + - provider: script + script: bash ./travis-scripts/deploy-now.sh $TRAVIS_BUILD_DIR dist/e2e/workbench-application-platform/communication-app $NOW_TOKEN + skip_cleanup: true + on: + branch: workbench-application-platform + - provider: script + script: bash ./travis-scripts/deploy-now.sh $TRAVIS_BUILD_DIR dist/e2e/workbench-application-platform/dev-tools-app $NOW_TOKEN + skip_cleanup: true + on: + branch: workbench-application-platform + # Publish @scion/mouse-dispatcher + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/mouse-dispatcher + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + # Publish @scion/dimension + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/dimension + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + # Publish @scion/viewport + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/viewport + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + # Publish @scion/workbench + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/workbench + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + # Publish @scion/workbench-application-platform.api + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/workbench-application-platform.api + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + # Publish @scion/workbench-application-platform + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/workbench-application-platform + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + # Publish @scion/workbench-application.core + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/workbench-application.core + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) + # Publish @scion/workbench-application.angular + - provider: script + script: bash ./travis-scripts/cd.sh $TRAVIS_BUILD_DIR dist/scion/workbench-application.angular + skip_cleanup: true + on: + branch: master + tags: true + - provider: npm + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+$" # Matches 'stable' versions x.x.x (npm tag: latest) + - provider: npm + tag: next + email: $NPM_EMAIL + api_key: + secure: $NPM_TOKEN + skip_cleanup: true + on: + branch: master + tags: true + condition: "$TRAVIS_TAG =~ ^[0-9]+.[0-9]+.[0-9]+-" # Matches 'next' versions x.x.x-beta and x.x.x-rc (npm tag: next) diff --git a/README.md b/README.md index 5137d709d..1301ff1ac 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,14 @@ # Overview -SCION Workbench helps to build multi-view web applications and integrates separate micro frontends into a consistent rich web application. Views are shown within tabs which can be flexible arranged and dragged around by the user. +SCION Workbench helps to build multi-view web applications and integrates separate micro frontends into a consistent rich web application. Views are shown within tabs which can be flexibly arranged and dragged around by the user. ![SCION Workbench](/resources/site/pics/workbench-small.png) The Workbench provides core features of a modern rich web application. - Tabbed, movable and stackable views - Activity panel as application entry point +- Popups - Global notifications - Global or view-local message boxes - URL encoded navigational state diff --git a/angular.json b/angular.json index 54f657367..8263147d9 100644 --- a/angular.json +++ b/angular.json @@ -16,8 +16,7 @@ "project": "projects/scion/workbench/ng-package.json" }, "configurations": { - "production": { - } + "production": {} } }, "test": { @@ -42,6 +41,149 @@ } } }, + "@scion/workbench-application-platform": { + "root": "projects/scion/workbench-application-platform", + "sourceRoot": "projects/scion/workbench-application-platform/src", + "projectType": "library", + "prefix": "wap", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/scion/workbench-application-platform/tsconfig.lib.json", + "project": "projects/scion/workbench-application-platform/ng-package.json" + }, + "configurations": { + "production": {} + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/scion/workbench-application-platform/src/test.ts", + "tsConfig": "projects/scion/workbench-application-platform/tsconfig.spec.json", + "karmaConfig": "projects/scion/workbench-application-platform/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/scion/workbench-application-platform/tsconfig.lib.json", + "projects/scion/workbench-application-platform/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "@scion/workbench-application-platform.api": { + "root": "projects/scion/workbench-application-platform.api", + "sourceRoot": "projects/scion/workbench-application-platform.api/src", + "projectType": "library", + "prefix": "", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/scion/workbench-application-platform.api/tsconfig.lib.json", + "project": "projects/scion/workbench-application-platform.api/ng-package.json" + }, + "configurations": { + "production": {} + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/scion/workbench-application-platform.api/tsconfig.lib.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "@scion/workbench-application.core": { + "root": "projects/scion/workbench-application.core", + "sourceRoot": "projects/scion/workbench-application.core/src", + "projectType": "library", + "prefix": "", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/scion/workbench-application.core/tsconfig.lib.json", + "project": "projects/scion/workbench-application.core/ng-package.json" + }, + "configurations": { + "production": {} + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/scion/workbench-application.core/src/test.ts", + "tsConfig": "projects/scion/workbench-application.core/tsconfig.spec.json", + "karmaConfig": "projects/scion/workbench-application.core/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/scion/workbench-application.core/tsconfig.lib.json", + "projects/scion/workbench-application.core/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "@scion/workbench-application.angular": { + "root": "projects/scion/workbench-application.angular", + "sourceRoot": "projects/scion/workbench-application.angular/src", + "projectType": "library", + "prefix": "wb", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/scion/workbench-application.angular/tsconfig.lib.json", + "project": "projects/scion/workbench-application.angular/ng-package.json" + }, + "configurations": { + "production": {} + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/scion/workbench-application.angular/src/test.ts", + "tsConfig": "projects/scion/workbench-application.angular/tsconfig.spec.json", + "karmaConfig": "projects/scion/workbench-application.angular/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/scion/workbench-application.angular/tsconfig.lib.json", + "projects/scion/workbench-application.angular/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, "@scion/mouse-dispatcher": { "root": "projects/scion/mouse-dispatcher", "sourceRoot": "projects/scion/mouse-dispatcher/src", @@ -55,8 +197,7 @@ "project": "projects/scion/mouse-dispatcher/ng-package.json" }, "configurations": { - "production": { - } + "production": {} } }, "test": { @@ -156,6 +297,446 @@ } } } + }, + "e2e/workbench-application-platform/test-runner": { + "root": "projects/e2e/workbench-application-platform/test-runner/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "projects/e2e/workbench-application-platform/test-runner/protractor.conf.js" + }, + "configurations": { + "now": { + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "projects/e2e/workbench-application-platform/test-runner/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "e2e/workbench-application-platform/host-app": { + "root": "projects/e2e/workbench-application-platform/host-app", + "sourceRoot": "projects/e2e/workbench-application-platform/host-app/src", + "projectType": "application", + "prefix": "app", + "schematics": { + "@schematics/angular:component": { + "styleext": "scss" + } + }, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/e2e/workbench-application-platform/host-app", + "index": "projects/e2e/workbench-application-platform/host-app/src/index.html", + "main": "projects/e2e/workbench-application-platform/host-app/src/main.ts", + "polyfills": "projects/e2e/workbench-application-platform/host-app/src/polyfills.ts", + "tsConfig": "projects/e2e/workbench-application-platform/host-app/tsconfig.app.json", + "assets": [ + "projects/e2e/workbench-application-platform/host-app/src/assets", + "projects/e2e/workbench-application-platform/host-app/src/now.json", + "projects/e2e/workbench-application-platform/host-app/src/favicon.ico" + ], + "styles": [ + "projects/e2e/workbench-application-platform/host-app/src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "projects/e2e/workbench-application-platform/common/src/lib" + ] + }, + "scripts": [] + }, + "configurations": { + "now": { + "fileReplacements": [ + { + "replace": "projects/e2e/workbench-application-platform/host-app/src/environments/environment.ts", + "with": "projects/e2e/workbench-application-platform/host-app/src/environments/environment.now.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "e2e/workbench-application-platform/host-app:build" + }, + "configurations": { + "now": { + "browserTarget": "e2e/workbench-application-platform/host-app:build:now" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/e2e/workbench-application-platform/host-app/tsconfig.app.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "e2e/workbench-application-platform/contact-app": { + "root": "projects/e2e/workbench-application-platform/contact-app", + "sourceRoot": "projects/e2e/workbench-application-platform/contact-app/src", + "projectType": "application", + "prefix": "app", + "schematics": { + "@schematics/angular:component": { + "styleext": "scss" + } + }, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/e2e/workbench-application-platform/contact-app", + "index": "projects/e2e/workbench-application-platform/contact-app/src/index.html", + "main": "projects/e2e/workbench-application-platform/contact-app/src/main.ts", + "polyfills": "projects/e2e/workbench-application-platform/contact-app/src/polyfills.ts", + "tsConfig": "projects/e2e/workbench-application-platform/contact-app/tsconfig.app.json", + "assets": [ + "projects/e2e/workbench-application-platform/contact-app/src/assets", + "projects/e2e/workbench-application-platform/contact-app/src/now.json" + ], + "styles": [ + "projects/e2e/workbench-application-platform/contact-app/src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "projects/e2e/workbench-application-platform/common/src/lib" + ] + }, + "scripts": [] + }, + "configurations": { + "now": { + "fileReplacements": [ + { + "replace": "projects/e2e/workbench-application-platform/contact-app/src/environments/environment.ts", + "with": "projects/e2e/workbench-application-platform/contact-app/src/environments/environment.now.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "e2e/workbench-application-platform/contact-app:build" + }, + "configurations": { + "now": { + "browserTarget": "e2e/workbench-application-platform/contact-app:build:now" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/e2e/workbench-application-platform/contact-app/tsconfig.app.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "e2e/workbench-application-platform/communication-app": { + "root": "projects/e2e/workbench-application-platform/communication-app", + "sourceRoot": "projects/e2e/workbench-application-platform/communication-app/src", + "projectType": "application", + "prefix": "app", + "schematics": { + "@schematics/angular:component": { + "styleext": "scss" + } + }, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/e2e/workbench-application-platform/communication-app", + "index": "projects/e2e/workbench-application-platform/communication-app/src/index.html", + "main": "projects/e2e/workbench-application-platform/communication-app/src/main.ts", + "polyfills": "projects/e2e/workbench-application-platform/communication-app/src/polyfills.ts", + "tsConfig": "projects/e2e/workbench-application-platform/communication-app/tsconfig.app.json", + "assets": [ + "projects/e2e/workbench-application-platform/communication-app/src/assets", + "projects/e2e/workbench-application-platform/communication-app/src/now.json" + ], + "styles": [ + "projects/e2e/workbench-application-platform/communication-app/src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "projects/e2e/workbench-application-platform/common/src/lib" + ] + }, + "scripts": [] + }, + "configurations": { + "now": { + "fileReplacements": [ + { + "replace": "projects/e2e/workbench-application-platform/communication-app/src/environments/environment.ts", + "with": "projects/e2e/workbench-application-platform/communication-app/src/environments/environment.now.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "e2e/workbench-application-platform/communication-app:build" + }, + "configurations": { + "now": { + "browserTarget": "e2e/workbench-application-platform/communication-app:build:now" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/e2e/workbench-application-platform/communication-app/tsconfig.app.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "e2e/workbench-application-platform/dev-tools-app": { + "root": "projects/e2e/workbench-application-platform/dev-tools-app", + "sourceRoot": "projects/e2e/workbench-application-platform/dev-tools-app/src", + "projectType": "application", + "prefix": "app", + "schematics": { + "@schematics/angular:component": { + "styleext": "scss" + } + }, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/e2e/workbench-application-platform/dev-tools-app", + "index": "projects/e2e/workbench-application-platform/dev-tools-app/src/index.html", + "main": "projects/e2e/workbench-application-platform/dev-tools-app/src/main.ts", + "polyfills": "projects/e2e/workbench-application-platform/dev-tools-app/src/polyfills.ts", + "tsConfig": "projects/e2e/workbench-application-platform/dev-tools-app/tsconfig.app.json", + "assets": [ + "projects/e2e/workbench-application-platform/dev-tools-app/src/assets", + "projects/e2e/workbench-application-platform/dev-tools-app/src/now.json" + ], + "styles": [ + "projects/e2e/workbench-application-platform/dev-tools-app/src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "projects/e2e/workbench-application-platform/common/src/lib" + ] + }, + "scripts": [] + }, + "configurations": { + "now": { + "fileReplacements": [ + { + "replace": "projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.ts", + "with": "projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.now.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "e2e/workbench-application-platform/dev-tools-app:build" + }, + "configurations": { + "now": { + "browserTarget": "e2e/workbench-application-platform/dev-tools-app:build:now" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/e2e/workbench-application-platform/dev-tools-app/tsconfig.app.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "e2e/workbench-application-platform/testing-app": { + "root": "projects/e2e/workbench-application-platform/testing-app", + "sourceRoot": "projects/e2e/workbench-application-platform/testing-app/src", + "projectType": "application", + "prefix": "app", + "schematics": { + "@schematics/angular:component": { + "styleext": "scss" + } + }, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/e2e/workbench-application-platform/testing-app", + "index": "projects/e2e/workbench-application-platform/testing-app/src/index.html", + "main": "projects/e2e/workbench-application-platform/testing-app/src/main.ts", + "polyfills": "projects/e2e/workbench-application-platform/testing-app/src/polyfills.ts", + "tsConfig": "projects/e2e/workbench-application-platform/testing-app/tsconfig.app.json", + "assets": [ + "projects/e2e/workbench-application-platform/testing-app/src/assets" + ], + "styles": [ + "projects/e2e/workbench-application-platform/testing-app/src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "projects/e2e/workbench-application-platform/common/src/lib" + ] + }, + "scripts": [] + }, + "configurations": { + "now": { + "fileReplacements": [ + { + "replace": "projects/e2e/workbench-application-platform/testing-app/src/environments/environment.ts", + "with": "projects/e2e/workbench-application-platform/testing-app/src/environments/environment.now.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "e2e/workbench-application-platform/testing-app:build" + }, + "configurations": { + "now": { + "browserTarget": "e2e/workbench-application-platform/testing-app:build:now" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/e2e/workbench-application-platform/testing-app/tsconfig.app.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "e2e/workbench-application-platform/common": { + "root": "projects/e2e/workbench-application-platform/common", + "sourceRoot": "projects/e2e/workbench-application-platform/common/src", + "projectType": "library", + "prefix": "sci", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/e2e/workbench-application-platform/common/tsconfig.lib.json", + "project": "projects/e2e/workbench-application-platform/common/ng-package.json" + }, + "configurations": { + "now": {} + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/e2e/workbench-application-platform/common/tsconfig.lib.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } } }, "defaultProject": "@scion/workbench" diff --git a/package-lock.json b/package-lock.json index 51c692e74..1895ff455 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "scion", - "version": "1.0.0", + "version": "0.0.0-beta.12", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -586,12 +586,12 @@ } }, "@babel/generator": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.6.tgz", - "integrity": "sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.2.0.tgz", + "integrity": "sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==", "dev": true, "requires": { - "@babel/types": "^7.1.6", + "@babel/types": "^7.2.0", "jsesc": "^2.5.1", "lodash": "^4.17.10", "source-map": "^0.5.0", @@ -661,9 +661,9 @@ } }, "@babel/parser": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.6.tgz", - "integrity": "sha512-dWP6LJm9nKT6ALaa+bnL247GHHMWir3vSlZ2+IHgHgktZQx0L3Uvq2uAWcuzIe+fujRsYWBW2q622C5UvGK9iQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-M74+GvK4hn1eejD9lZ7967qAwvqTZayQa3g10ag4s9uewgR7TKjeaT0YMyoq+gVfKYABiWZ4MQD701/t5e1Jhg==", "dev": true }, "@babel/template": { @@ -718,9 +718,9 @@ } }, "@babel/types": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.6.tgz", - "integrity": "sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.0.tgz", + "integrity": "sha512-b4v7dyfApuKDvmPb+O488UlGuR1WbwMXFsO/cyqMrnfvRAChZKJAYeeglWTjUO1b9UghKKgepAQM5tsvBJca6A==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -1133,9 +1133,9 @@ } }, "ansi-colors": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.1.tgz", - "integrity": "sha512-Xt+zb6nqgvV9SWAVp0EG3lRsHcbq5DDgqjPPz6pwgtj6RKz65zGXMNa82oJfOSBA/to6GmRP7Dr+6o+kbApTzQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", "dev": true }, "ansi-escapes": { @@ -1233,6 +1233,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -1240,9 +1246,21 @@ "dev": true }, "array-flatten": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", - "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", "dev": true }, "array-slice": { @@ -2061,9 +2079,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000910", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000910.tgz", - "integrity": "sha512-u/nxtHGAzCGZzIxt3dA/tpSPOcirBZFWKwz1EPz4aaupnBI2XR0Rbr74g0zc6Hzy41OEM4uMoZ38k56TpYAWjQ==", + "version": "1.0.30000916", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000916.tgz", + "integrity": "sha512-D6J9jloPm2MPkg0PXcODLMQAJKkeixKO9xhqTUMvtd44MtTYMyyDXPQ2Lk9IgBq5FH0frwiPa/N/w8ncQf7kIQ==", "dev": true }, "canonical-path": { @@ -2829,6 +2847,15 @@ } } }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -3082,9 +3109,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.84", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.84.tgz", - "integrity": "sha512-IYhbzJYOopiTaNWMBp7RjbecUBsbnbDneOP86f3qvS0G0xfzwNSvMJpTrvi5/Y1gU7tg2NAgeg8a8rCYvW9Whw==", + "version": "1.3.88", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.88.tgz", + "integrity": "sha512-UPV4NuQMKeUh1S0OWRvwg0PI8ASHN9kBC8yDTk1ROXLC85W5GnhTRu/MZu3Teqx3JjlQYuckuHYXSUSgtb3J+A==", "dev": true }, "elliptic": { @@ -3226,6 +3253,30 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", @@ -3438,7 +3489,7 @@ }, "expand-range": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", "dev": true, "requires": { @@ -3497,7 +3548,7 @@ }, "expand-range": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { @@ -3586,7 +3637,7 @@ "dependencies": { "array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", "dev": true } @@ -4543,6 +4594,12 @@ "rimraf": "2" } }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -4789,9 +4846,9 @@ }, "dependencies": { "ajv": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", - "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz", + "integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -4802,6 +4859,15 @@ } } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -4840,6 +4906,12 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -4889,9 +4961,9 @@ } }, "hash.js": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", - "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -4909,6 +4981,12 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoek": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", + "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==", + "dev": true + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -5360,6 +5438,12 @@ "builtin-modules": "^1.0.0" } }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, "is-ci": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", @@ -5389,6 +5473,12 @@ } } }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -5573,6 +5663,15 @@ "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", "dev": true }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", @@ -5585,6 +5684,15 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -5624,6 +5732,15 @@ "buffer-alloc": "^1.2.0" } }, + "isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "dev": true, + "requires": { + "punycode": "2.x.x" + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5933,12 +6050,28 @@ "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", "dev": true }, + "joi": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz", + "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==", + "dev": true, + "requires": { + "hoek": "5.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + }, "js-base64": { "version": "2.4.9", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.9.tgz", "integrity": "sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ==", "dev": true }, + "js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -6020,6 +6153,12 @@ "graceful-fs": "^4.1.6" } }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -6079,7 +6218,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } @@ -6121,9 +6260,9 @@ }, "dependencies": { "mime": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", - "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", "dev": true }, "source-map": { @@ -6437,13 +6576,13 @@ "dev": true }, "lru-cache": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.4.tgz", - "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "^1.0.2", - "yallist": "^3.0.2" + "yallist": "^2.1.2" } }, "magic-string": { @@ -6550,6 +6689,12 @@ "readable-stream": "^2.0.1" } }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, "meow": { "version": "3.7.0", "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -6866,28 +7011,28 @@ }, "dependencies": { "autoprefixer": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.3.1.tgz", - "integrity": "sha512-DY9gOh8z3tnCbJ13JIWaeQsoYncTGdsrgCceBaQSIL4nvdrLxgbRSBPevg2XbX7u4QCSfLheSJEEIUUSlkbx6Q==", + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.2.tgz", + "integrity": "sha512-tYQYJvZvqlJCzF+BLC//uAcdT/Yy4ik9bwZRXr/EehUJ/bjjpTthsWTy8dpowdoIE1sLCDf1ch4Eb2cOSzZC9w==", "dev": true, "requires": { - "browserslist": "^4.3.3", - "caniuse-lite": "^1.0.30000898", + "browserslist": "^4.3.5", + "caniuse-lite": "^1.0.30000914", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", - "postcss": "^7.0.5", + "postcss": "^7.0.6", "postcss-value-parser": "^3.3.1" } }, "browserslist": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.4.tgz", - "integrity": "sha512-u5iz+ijIMUlmV8blX82VGFrB9ecnUg5qEt55CMZ/YJEhha+d8qpBfOFuutJ6F/VKRXjZoD33b6uvarpPxcl3RA==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.5.tgz", + "integrity": "sha512-z9ZhGc3d9e/sJ9dIx5NFXkKoaiQTnrvrMsN3R1fGb1tkWWNSz12UewJn9TNxGo1l7J23h0MRaPmk7jfeTZYs1w==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000899", - "electron-to-chromium": "^1.3.82", - "node-releases": "^1.0.1" + "caniuse-lite": "^1.0.30000912", + "electron-to-chromium": "^1.3.86", + "node-releases": "^1.0.5" } }, "find-up": { @@ -7081,9 +7226,9 @@ } }, "node-releases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.4.tgz", - "integrity": "sha512-GqRV9GcHw8JCRDaP/JoeNMNzEGzHAknMvIHqMb2VeTOmg1Cf9+ej8bkV12tHfzWHQMCkQ5zUFgwFUkfraynNCw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.0.tgz", + "integrity": "sha512-+qV91QMDBvARuPxUEfI/mRF/BY+UAkTIn3pvmvM2iOLIRvv6RNYklFXBgrkky6P1wXUqQW1P3qKlWxxy4JZbfg==", "dev": true, "requires": { "semver": "^5.3.0" @@ -7217,7 +7362,7 @@ }, "tough-cookie": { "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "resolved": "http://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "dev": true, "requires": { @@ -7271,6 +7416,12 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, + "now": { + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/now/-/now-13.0.4.tgz", + "integrity": "sha512-o7uS6JEdlslP021/zC/5VzrXuCLfFak43AbjSq3l4QcRlyUyXq40hZiLcSsk6m+oZeFY7RpDHWg0vEMYrYLQZQ==", + "dev": true + }, "npm-package-arg": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", @@ -7303,6 +7454,77 @@ "ssri": "^5.2.4" } }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -7391,6 +7613,12 @@ } } }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -7617,9 +7845,9 @@ } }, "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.7.tgz", + "integrity": "sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ==", "dev": true }, "parallel-transform": { @@ -7722,7 +7950,7 @@ }, "path-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, @@ -7802,6 +8030,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "pidtree": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", + "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", + "dev": true + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -7928,9 +8162,9 @@ }, "dependencies": { "mime": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", - "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", "dev": true }, "postcss": { @@ -7989,9 +8223,9 @@ "dev": true }, "progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "promise": { @@ -8243,9 +8477,9 @@ } }, "mime": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", - "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", "dev": true }, "ms": { @@ -8545,7 +8779,7 @@ }, "regexpu-core": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { @@ -8581,7 +8815,7 @@ }, "regjsparser": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "resolved": "http://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { @@ -8677,7 +8911,7 @@ }, "resolve": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, @@ -8939,6 +9173,12 @@ "aproba": "^1.1.1" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", + "dev": true + }, "rxjs": { "version": "6.3.3", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", @@ -9271,6 +9511,18 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" + } + }, "shelljs": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", @@ -9617,9 +9869,9 @@ "dev": true }, "spdx-correct": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", - "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -9851,9 +10103,20 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.padend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", + "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" + } + }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -9987,9 +10250,9 @@ "dev": true }, "tapable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz", - "integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz", + "integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==", "dev": true }, "tar": { @@ -10041,9 +10304,9 @@ } }, "terser": { - "version": "3.10.12", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.10.12.tgz", - "integrity": "sha512-3ODPC1eVt25EVNb04s/PkHxOmzKBQUF6bwwuR6h2DbEF8/j265Y1UkwNtOk9am/pRxfJ5HPapOlUlO6c16mKQQ==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.11.0.tgz", + "integrity": "sha512-5iLMdhEPIq3zFWskpmbzmKwMQixKmTYwY3Ox9pjtSklBLnHiuQ0GKJLhL1HSYtyffHM3/lDIFBnb82m9D7ewwQ==", "dev": true, "requires": { "commander": "~2.17.1", @@ -10311,6 +10574,23 @@ "repeat-string": "^1.6.1" } }, + "topo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", + "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", + "dev": true, + "requires": { + "hoek": "6.x.x" + }, + "dependencies": { + "hoek": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.2.tgz", + "integrity": "sha512-6qhh/wahGYZHFSFw12tBbJw5fsAhhwrrG/y3Cs0YMTv2WzMnL0oLPnQJjv1QJvEfylRSOFuP+xCu+tdx0tD16Q==", + "dev": true + } + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -10446,7 +10726,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -10861,7 +11141,7 @@ }, "vm-browserify": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "dev": true, "requires": { @@ -10874,6 +11154,27 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, + "wait-on": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.2.0.tgz", + "integrity": "sha512-QUGNKlKLDyY6W/qHdxaRlXUAgLPe+3mLL/tRByHpRNcHs/c7dZXbu+OnJWGNux6tU1WFh/Z8aEwvbuzSAu79Zg==", + "dev": true, + "requires": { + "core-js": "^2.5.7", + "joi": "^13.0.0", + "minimist": "^1.2.0", + "request": "^2.88.0", + "rx": "^4.1.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -10894,6 +11195,11 @@ "minimalistic-assert": "^1.0.0" } }, + "web-animations-js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.1.tgz", + "integrity": "sha1-Om2bwVGWN3qQ+OKAP6UmIWWwRRA=" + }, "webdriver-js-extender": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", @@ -10990,9 +11296,9 @@ }, "dependencies": { "mime": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", - "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", "dev": true } } @@ -11126,9 +11432,9 @@ } }, "mime": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", - "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", "dev": true }, "ms": { @@ -11496,9 +11802,9 @@ "dev": true }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { diff --git a/package.json b/package.json index f3f0980da..0218c8dba 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "scion", "version": "0.0.0-beta.12", - "description": "SCION Workbench helps to build multi-view web applications and integrates separate micro frontends into a consistent rich web application. Views are shown within tabs which can be flexible arranged and dragged around by the user.", + "description": "SCION Workbench helps to build multi-view web applications and integrates separate micro frontends into a consistent rich web application.", "license": "EPL-2.0", "homepage": "https://github.com/SchweizerischeBundesbahnen/scion-workbench", "bugs": { @@ -12,35 +12,85 @@ "url": "https://github.com/SchweizerischeBundesbahnen/scion-workbench" }, "scripts": { - "ng": "ng", - "build": "npm run build-mouse-dispatcher && npm run build-dimension && npm run build-viewport && npm run build-workbench", - "build-workbench": "ng build --prod @scion/workbench && cp -r projects/scion/workbench/src/theme/** dist/scion/workbench", - "build-mouse-dispatcher": "ng build --prod @scion/mouse-dispatcher", - "build-dimension": "ng build --prod @scion/dimension", - "build-viewport": "ng build --prod @scion/viewport", - "test": "npm run test-workbench && npm run test-viewport", - "test-workbench": "ng test @scion/workbench --watch=false", - "test-viewport": "ng test @scion/viewport --watch=false", - "lint": "npm run lint-workbench && npm run lint-mouse-dispatcher && npm run lint-dimension && npm run lint-viewport", - "lint-workbench": "ng lint @scion/workbench", - "lint-mouse-dispatcher": "ng lint @scion/mouse-dispatcher", - "lint-dimension": "ng lint @scion/dimension", - "lint-viewport": "ng lint @scion/viewport", - "e2e": "ng e2e" + "build": "run-s build:*", + "build:mouse-dispatcher": "ng build --prod @scion/mouse-dispatcher", + "build:dimension": "ng build --prod @scion/dimension", + "build:viewport": "ng build --prod @scion/viewport", + "build:workbench": "ng build --prod @scion/workbench && cp -r projects/scion/workbench/src/theme/** dist/scion/workbench", + "build:workbench-application-platform.api": "ng build --prod @scion/workbench-application-platform.api", + "build:workbench-application-platform": "ng build --prod @scion/workbench-application-platform", + "build:workbench-application.core": "ng build --prod @scion/workbench-application.core", + "build:workbench-application.angular": "ng build --prod @scion/workbench-application.angular", + + "test": "run-s test:*", + "test:workbench": "ng test @scion/workbench --watch=false", + "test:workbench-application-platform": "ng test @scion/workbench-application-platform --watch=false", + "test:workbench-application.core": "ng test @scion/workbench-application.core --watch=false", + "test:workbench-application.angular": "ng test @scion/workbench-application.angular --watch=false", + "test:viewport": "ng test @scion/viewport --watch=false", + + "lint": "run-p lint:*", + "lint:workbench": "ng lint @scion/workbench", + "lint:workbench-application-platform.api": "ng lint @scion/workbench-application-platform.api", + "lint:workbench-application-platform": "ng lint @scion/workbench-application-platform", + "lint:workbench-application.core": "ng lint @scion/workbench-application.core", + "lint:workbench-application.angular": "ng lint @scion/workbench-application.angular", + "lint:mouse-dispatcher": "ng lint @scion/mouse-dispatcher", + "lint:dimension": "ng lint @scion/dimension", + "lint:viewport": "ng lint @scion/viewport", + + "e2e:workbench-application-platform:e2e": "run-p -r e2e:workbench-application-platform:serve e2e:workbench-application-platform:await-then-exec", + "e2e:workbench-application-platform:await-then-exec": "run-s e2e:workbench-application-platform:await e2e:workbench-application-platform:exec:test-runner", + "e2e:workbench-application-platform:build-now": "run-s e2e:workbench-application-platform:build-now:*", + "e2e:workbench-application-platform:lint": "run-p e2e:workbench-application-platform:lint:*", + "e2e:workbench-application-platform:serve": "run-p -r e2e:workbench-application-platform:serve:*", + "e2e:workbench-application-platform:await": "run-s e2e:workbench-application-platform:await:*", + + "e2e:workbench-application-platform:lint:test-runner": "ng lint e2e/workbench-application-platform/test-runner", + "e2e:workbench-application-platform:exec:test-runner": "ng e2e e2e/workbench-application-platform/test-runner --baseUrl http://localhost:5000", + + "e2e:workbench-application-platform:build-now:common": "ng build --configuration=now e2e/workbench-application-platform/common", + "e2e:workbench-application-platform:lint:common": "ng lint e2e/workbench-application-platform/common", + + "e2e:workbench-application-platform:build-now:host-app": "ng build --configuration=now e2e/workbench-application-platform/host-app", + "e2e:workbench-application-platform:lint:host-app": "ng lint e2e/workbench-application-platform/host-app", + "e2e:workbench-application-platform:serve:host-app": "ng serve e2e/workbench-application-platform/host-app --aot --port 5000", + "e2e:workbench-application-platform:await:host-app": "wait-on http-get://localhost:5000", + + "e2e:workbench-application-platform:build-now:contact-app": "ng build --configuration=now e2e/workbench-application-platform/contact-app", + "e2e:workbench-application-platform:lint:contact-app": "ng lint e2e/workbench-application-platform/contact-app", + "e2e:workbench-application-platform:serve:contact-app": "ng serve e2e/workbench-application-platform/contact-app --aot --port 5001", + "e2e:workbench-application-platform:await:contact-app": "wait-on http-get://localhost:5001", + + "e2e:workbench-application-platform:build-now:communication-app": "ng build --configuration=now e2e/workbench-application-platform/communication-app", + "e2e:workbench-application-platform:lint:communication-app": "ng lint e2e/workbench-application-platform/communication-app", + "e2e:workbench-application-platform:serve:communication-app": "ng serve e2e/workbench-application-platform/communication-app --aot --port 5002", + "e2e:workbench-application-platform:await:communication-app": "wait-on http-get://localhost:5002", + + "e2e:workbench-application-platform:build-now:dev-tools-app": "ng build --configuration=now e2e/workbench-application-platform/dev-tools-app", + "e2e:workbench-application-platform:lint:dev-tools-app": "ng lint e2e/workbench-application-platform/dev-tools-app", + "e2e:workbench-application-platform:serve:dev-tools-app": "ng serve e2e/workbench-application-platform/dev-tools-app --aot --port 5003", + "e2e:workbench-application-platform:await:dev-tools-app": "wait-on http-get://localhost:5003", + + "e2e:workbench-application-platform:lint:testing-app": "ng lint e2e/workbench-application-platform/testing-app", + "e2e:workbench-application-platform:serve:testing-app": "ng serve e2e/workbench-application-platform/testing-app --aot --port 5004", + "e2e:workbench-application-platform:await:testing-app": "wait-on http-get://localhost:5004" }, "private": true, "dependencies": { - "@angular/core": "7.0.0", - "@angular/common": "7.0.0", + "@angular/animations": "7.0.0", "@angular/cdk": "7.0.1", + "@angular/common": "7.0.0", "@angular/compiler": "7.0.0", - "@angular/animations": "7.0.0", + "@angular/core": "7.0.0", "@angular/forms": "7.0.0", "@angular/platform-browser": "7.0.0", "@angular/platform-browser-dynamic": "7.0.0", "@angular/router": "7.0.0", "core-js": "2.5.7", + "js-sha256": "0.9.0", "rxjs": "6.3.3", + "web-animations-js": "2.3.1", "zone.js": "0.8.26" }, "devDependencies": { @@ -61,6 +111,8 @@ "karma-jasmine": "1.1.2", "karma-jasmine-html-reporter": "1.3.1", "ng-packagr": "4.4.0", + "now": "13.0.4", + "npm-run-all": "4.1.5", "protractor": "5.4.1", "puppeteer": "1.10.0", "rxjs-tslint": "0.1.5", @@ -68,7 +120,8 @@ "tsickle": "0.33.0", "tslib": "1.9.3", "tslint": "5.11.0", - "typescript": "3.1.3" + "typescript": "3.1.3", + "wait-on": "3.2.0" }, "repository": { "type": "git", diff --git a/projects/e2e/workbench-application-platform/common/ng-package.json b/projects/e2e/workbench-application-platform/common/ng-package.json new file mode 100644 index 000000000..264a67984 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/ng-package.json @@ -0,0 +1,8 @@ +{ + "$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../../../dist/scion/e2e/common", + "lib": { + "entryFile": "src/public_api.ts" + }, + "whitelistedNonPeerDependencies": ["@scion"] +} diff --git a/projects/e2e/workbench-application-platform/common/package.json b/projects/e2e/workbench-application-platform/common/package.json new file mode 100644 index 000000000..23765c793 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/package.json @@ -0,0 +1,35 @@ +{ + "name": "@scion/e2e/common", + "version": "0.0.0-beta.12", + "description": "Contains a collection of UI components, styles and services used by E2E application.", + "license": "EPL-2.0", + "private": true, + "publishConfig": { + "access": "private" + }, + "homepage": "https://github.com/SchweizerischeBundesbahnen/scion-workbench", + "bugs": { + "url": "https://github.com/SchweizerischeBundesbahnen/scion-workbench/issues" + }, + "author": { + "name": "SCION Workbench contributors", + "url": "https://github.com/SchweizerischeBundesbahnen/scion-workbench" + }, + "dependencies": { + }, + "peerDependencies": { + "@angular/common": "^6.0.0-rc.0 || ^6.0.0 || ^7.0.0-rc.0 || ^7.0.0", + "@angular/core": "^6.0.0-rc.0 || ^6.0.0 || ^7.0.0-rc.0 || ^7.0.0", + "@angular/cdk": "^6.0.0-rc.0 || ^6.0.0 || ^7.0.0-rc.0 || ^7.0.0", + "@scion/viewport": "0.0.0-beta.12", + "@scion/dimension": "0.0.0-beta.12", + "@scion/workbench-application-platform.api": "0.0.0-beta.12", + "rxjs": "^6.0.0" + }, + "keywords": [ + ], + "repository": { + "type": "git", + "url": "git+https://github.com/SchweizerischeBundesbahnen/scion-workbench.git" + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/_common.scss b/projects/e2e/workbench-application-platform/common/src/lib/_common.scss new file mode 100644 index 000000000..c2ff7db87 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/_common.scss @@ -0,0 +1,197 @@ +@function primaryColor($opacity: 1) { + @return rgba(55, 95, 156, $opacity); +} + +@function accentColor($opacity: 1) { + @return rgba(85, 85, 85, $opacity); +} + +@function errorColor($opacity: 1) { + @return rgba(255, 55, 55, $opacity); +} + +/** + * IE does not support align-items on grid containers. Therefore, we use align-self on child elements instead. + */ +@mixin grid-container-align-items($align) { + > * { + align-self: $align; + } +} + +/** + * Installs the application theme. + */ +@mixin app-theme() { + @import url('https://fonts.googleapis.com/css?family=Roboto:normal,bold,italic,bolditalic|Roboto+Mono'); + @import url('https://fonts.googleapis.com/icon?family=Material+Icons'); + + body { + font-family: Roboto, Arial, sans-serif; + font-size: .9em; + box-sizing: border-box; + + input, textarea, select { + @include input-field; + } + + a { + @include link; + } + + button.material-icons { + @include mat-icon-button; + } + + button:not(.material-icons) { + @include button; + } + } +} + +@function app-padding() { + @return 1em; +} + +@mixin position($position, $top, $right, $bottom, $left) { + position: $position; + top: $top; + right: $right; + bottom: $bottom; + left: $left; +} + +/** + * Provides the styling for a panel with HTML button elements. + */ +@mixin button-bar() { + display: flex; + justify-content: flex-end; + border-top: 1px solid rgba(50, 50, 50, .3); + background-color: rgba(50, 50, 50, .075); + margin-top: 1em; + padding: .5em 1em; + + > button { + @include button(); + + &:not(:first-child) { + margin-left: .2em; + } + + &:not(:last-child) { + margin-right: .2em; + } + } +} + +/** + * Provides the styling for a Material icon button. + */ +@mixin mat-icon-button() { + background-color: transparent; + border: none; + cursor: pointer; + outline: none; + color: inherit; + padding: 0 0 0 .25em; + user-select: none; + + &:focus, &:hover { + color: primaryColor(); + } +} + +/** + * Provides the styling for a button. + */ +@mixin button() { + cursor: pointer; + padding: .5em 1.5em; + font-family: inherit; + color: rgba(51, 51, 51, .8); + border: 1px solid rgba(51, 51, 51, .5); + border-radius: 3px; + background-color: rgb(255, 255, 255); + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + + &:focus, &:active { + border-color: primaryColor(); + color: primaryColor(); + outline: 0; + box-shadow: 0 0 8px 0 primaryColor(.35); + } + + &:disabled { + color: rgba(51, 51, 51, .5); + border-style: dotted; + cursor: auto; + } +} + +/** + * Provides the styling for an input field. + */ +@mixin input-field($radius: 2px) { + border: 1px solid accentColor(.25); + border-radius: $radius; + padding: .5em; + outline: 0; + font-family: inherit; + font-size: inherit; + + &:focus-within { + border-color: primaryColor(); + box-shadow: 0 0 6px 0 primaryColor(.35); + } + + &.inline-editable:not(.ng-invalid) { + &:not(:focus-within):not(:hover):not(:active) { + border: 1px solid transparent; + } + + &:hover:not(:active):not(:focus-within) { + cursor: pointer; + } + } + + &.ng-invalid.ng-touched { + border-color: errorColor(1); + box-shadow: 0 0 6px 0 errorColor(.35); + } + + &[readonly] { + color: accentColor(.5); + } + + &[type="checkbox"] { + margin: .75em 0; + } +} + +@mixin chip($border-color, $background-color, $color, $borderStyle: solid) { + border: 1px $borderStyle $border-color; + background-color: $background-color; + color: $color; + border-radius: 3px; + padding: .25em .5em; + font-size: smaller; + user-select: none; + margin-bottom: .25em; + &:not(:last-child) { + margin-right: .25em; + } +} + +/** + * Provides the styling for a link. + */ +@mixin link($radius: 2px) { + color: rgb(55, 95, 156); + text-decoration: none; + outline: none; + + &:hover, &:focus { + text-decoration: underline; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion-item.directive.ts b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion-item.directive.ts new file mode 100644 index 000000000..4dd80a954 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion-item.directive.ts @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Directive, Input, OnInit, TemplateRef } from '@angular/core'; + +/** + * Use this directive to model an accordion item for {SciAccordionComponent}. + * The host element of this modelling directive must be a . + * + * --- + * Example usage: + * + * + * + * + * + * ... + * + * + * + * + * ... + * + * + * + */ +@Directive({selector: 'ng-template[sciAccordionItem]'}) +export class SciAccordionItemDirective implements OnInit { + + /** + * Optional key to identify this item and is used as key for the {TrackBy} function. + */ + @Input() + public key: string; + + /** + * Provide template(s) to be rendered as actions of this list item. + */ + @Input() + public panel: TemplateRef; + + /** + * Indicates whether to expand this item. + */ + @Input() + public expanded: boolean; + + /** + * Specifies CSS class(es) added to the
and elements, e.g. used for e2e testing. + */ + @Input() + public cssClass: string | string[]; + + constructor(public readonly template: TemplateRef) { + } + + public ngOnInit(): void { + if (!this.panel) { + throw Error('[NullPanelError] No panel template specified for `sciAccordionItem`'); + } + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.html b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.html new file mode 100644 index 000000000..6a5222c05 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.html @@ -0,0 +1,21 @@ + +
+
+
+
+ +
+ {{cdkAccordionItem.expanded ? 'expand_less' : 'expand_more'}} +
+
+ +
+
+
+
diff --git a/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.scss b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.scss new file mode 100644 index 000000000..61d866a08 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.scss @@ -0,0 +1,79 @@ +@import '../common'; + +$diamond-height: 8; +$border-color: accentColor(.2); +$background-color: rgb(249, 249, 249); + +:host { + display: flex; + + > sci-viewport { + flex: auto; + border: 1px solid accentColor(.25); + border-radius: 5px; + + section.accordion-item { + flex: none; + padding: 1em; + + &:not(:first-child) { + border-top: 1px solid accentColor(.25); + } + + &:last-child { + border-bottom: 1px solid accentColor(.25); + } + + > header { + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + + > div { + flex: auto; + } + + > span.toggle { + flex: none; + margin-left: .5em; + user-select: none; + } + } + + > section { + position: relative; // positioning anchor for the diamond + + background-color: $background-color; + border-radius: 5px; + border: 1px solid $border-color; + padding: 1em; + margin: 1em -.5em -.5em -.5em; + + //::before is used as diamond-border + //::after is used as diamond-content + &::before, &::after { + content: ''; + display: inline-block; + position: absolute; + border: #{$diamond-height}px solid transparent; + } + + &::before { + top: -#{$diamond-height}px; + left: calc(50px - #{$diamond-height}px); + border-top-width: 0; + border-bottom-color: $border-color; + } + + &::after { + top: -#{$diamond-height - 1}px; + left: calc(50px - #{$diamond-height}px); + border-top-width: 0; + border-bottom-color: $background-color; + } + } + } + } +} + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.ts b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.ts new file mode 100644 index 000000000..0ae7da1e6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.component.ts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, ContentChildren, Input, QueryList, TrackByFunction, ViewChild } from '@angular/core'; +import { animate, AnimationMetadata, style, transition, trigger } from '@angular/animations'; +import { SciAccordionItemDirective } from './accordion-item.directive'; +import { SciViewportComponent } from '@scion/viewport'; +import { CdkAccordionItem } from '@angular/cdk/accordion'; + +/** + * Component that shows items in an accordion. + * + * An accordion item is contributed as content child in the form of a `` decorated with `sciAccordionItem` directive, + * and its panel modelled in the form of a `` and given as input to its `sciAccordionItem` directive. + * + * --- + * Example of a simple list: + * + * + * + * + * + * ... + * + * + * + * + * ... + * + * + * + */ +@Component({ + selector: 'sci-accordion', + templateUrl: './accordion.component.html', + styleUrls: ['./accordion.component.scss'], + animations: [ + trigger('enter', SciAccordionComponent.provideEnterAnimation()), + ] +}) +export class SciAccordionComponent { + + @ViewChild(SciViewportComponent) + private _viewport: SciViewportComponent; + + @ContentChildren(SciAccordionItemDirective) + public items: QueryList; + + /** + * Whether the accordion should allow multiple expanded accordion items simultaneously. + */ + @Input() + public multi: boolean; + + public trackByFn: TrackByFunction = (index: number, item: SciAccordionItemDirective): any => { + return item.key || item; + }; + + public onToggle(item: CdkAccordionItem, section: HTMLElement): void { + item.toggle(); + item.expanded && setTimeout(() => this._viewport.scrollIntoView(section)); + } + + /** + * Returns animation metadata to expand accordion panel. + */ + private static provideEnterAnimation(): AnimationMetadata[] { + return [ + transition(':enter', [ + style({opacity: 0, height: 0, overflow: 'hidden'}), + animate('125ms ease-out', style({opacity: 1, height: '*'})) + ]), + ]; + } +} + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.module.ts new file mode 100644 index 000000000..350bfed7f --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/accordion/accordion.module.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciViewportModule } from '@scion/viewport'; +import { SciAccordionComponent } from './accordion.component'; +import { SciAccordionItemDirective } from './accordion-item.directive'; +import { CdkAccordionModule } from '@angular/cdk/accordion'; + +/** + * Provides an accordion component. + */ +@NgModule({ + declarations: [ + SciAccordionComponent, + SciAccordionItemDirective, + ], + imports: [ + CommonModule, + SciViewportModule, + CdkAccordionModule, + ], + exports: [ + SciAccordionComponent, + SciAccordionItemDirective, + ], +}) +export class SciAccordionModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/custom-extension/metadata.ts b/projects/e2e/workbench-application-platform/common/src/lib/custom-extension/metadata.ts new file mode 100644 index 000000000..1dae5d159 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/custom-extension/metadata.ts @@ -0,0 +1,23 @@ +import { ActivityAction } from '@scion/workbench-application-platform.api'; + +/** + * Custom types for activity actions. + */ +export enum CustomActivityActionTypes { + /** + * Action button to show a notification to the user. + */ + CustomNotify = 'custom', +} + +/** + * Shows an activity button to show a notification to the user. + */ +export interface CustomNotifyActivityAction extends ActivityAction { + type: CustomActivityActionTypes.CustomNotify; + properties: { + text: string; + title: string; + cssClass: string | string[]; + }; +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.html b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.html new file mode 100644 index 000000000..285df41c7 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.html @@ -0,0 +1,2 @@ + + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.scss b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.scss new file mode 100644 index 000000000..96fbc4d90 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.scss @@ -0,0 +1,26 @@ +@import '../common'; + +:host { + display: inline-flex; + flex-direction: row; + @include input-field(5px); + padding: .25em .5em; + + > input#search { + border: none; + box-shadow: none; + outline: none; + padding: 0; + flex: auto; + width: 0; // allows the input to shrink past UA minimal width + } + + > label.filter-icon { + flex: none; + user-select: none; + } + + &:focus-within > label.filter-icon { + color: primaryColor(); + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.ts b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.ts new file mode 100644 index 000000000..93b35db66 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.component.ts @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, Output, ViewChild } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; + +/** + * Provides a simple filter control. + */ +@Component({ + selector: 'sci-filter-field', + templateUrl: './filter-field.component.html', + styleUrls: ['./filter-field.component.scss'] +}) +export class SciFilterFieldComponent implements OnDestroy { + + private _destroy$ = new Subject(); + + /** + * Sets focus order in sequential keyboard navigation. + * If not specified, the focus order is according to the position in the document (tabindex=0). + */ + @Input() + public tabindex = 0; + + /** + * Emits on filter change. + */ + @Output() + public filter = new EventEmitter(); + + @ViewChild('input') + private _inputElement: ElementRef; + + @HostBinding('attr.tabindex') + public componentTabindex = -1; // component is not focusable in sequential keyboard navigation, but tabindex (if any) is installed on input field + + public formControl: FormControl; + + constructor() { + this.formControl = new FormControl('', {updateOn: 'change'}); + this.formControl.valueChanges + .pipe(takeUntil(this._destroy$)) + .subscribe(this.filter); + } + + @HostListener('focus') + public focus(): void { + this._inputElement.nativeElement.focus(); + } + + /** + * Invoke to propagate keyboard events to the filter field. + * + * If the keyboard event represents an alphanumeric character, filter text is cleared and the cursor set into the filter field. + * This allows to start filtering without having to focus the filter field, e.g. if another element has the focus. + */ + public onKeydown(event: KeyboardEvent): void { + if (event.ctrlKey || event.altKey || event.shiftKey) { + return; + } + if (!isAlphanumeric(event)) { + return; + } + this.formControl.setValue(''); + this._inputElement.nativeElement.focus(); + event.stopPropagation(); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} + +function isAlphanumeric(event: KeyboardEvent): boolean { + return (/^[a-z0-9]$/i.test(event.key)); +} + +/** + * Creates a regular expression of the given filter text. + */ +export function toFilterRegExp(filterText: string): RegExp | null { + if (!filterText) { + return null; + } + + // Escape the user filter input and add wildcard support + const escapedString = filterText.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); + return new RegExp(escapedString, 'i'); +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.module.ts new file mode 100644 index 000000000..edc45e9d6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/filter-field/filter-field.module.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciFilterFieldComponent } from './filter-field.component'; +import { ReactiveFormsModule } from '@angular/forms'; + +/** + * Provides a simple filter field. + */ +@NgModule({ + declarations: [ + SciFilterFieldComponent, + ], + imports: [ + CommonModule, + ReactiveFormsModule, + ], + exports: [ + SciFilterFieldComponent, + ], +}) +export class SciFilterFieldModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list-item.directive.ts b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item.directive.ts new file mode 100644 index 000000000..9d793d325 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item.directive.ts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Directive, Input, TemplateRef } from '@angular/core'; + +/** + * Use this directive to model a list item for {SciListComponent}. + * The host element of this modelling directive must be a . + * + * --- + * Example usage: + * + * + * + * + * + * + */ +@Directive({selector: 'ng-template[sciListItem]'}) +export class SciListItemDirective { + + private _actionTemplates: TemplateRef[] = []; + + /** + * Optional key to identify this item and is used to emit selection and internally as key for the {TrackBy} function. + */ + @Input() + public key: string; + + /** + * Provide template(s) to be rendered as actions of this list item. + */ + @Input() + public set actions(actions: TemplateRef | TemplateRef[]) { + this._actionTemplates = (Array.isArray(actions) ? actions : actions && [actions] || []); + } + + constructor(public readonly template: TemplateRef) { + } + + public get actionTemplates(): TemplateRef[] { + return this._actionTemplates; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.html b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.html new file mode 100644 index 000000000..48cb5cc3d --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.html @@ -0,0 +1,16 @@ + + + {{active ? 'radio_button_checked' : 'radio_button_unchecked'}} + + + +
+ +
+ + +
    +
  • + +
  • +
diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.scss b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.scss new file mode 100644 index 000000000..ee45d3152 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.scss @@ -0,0 +1,45 @@ +@import '../../common'; + +:host { + display: flex; + align-items: center; + outline: none; + padding: 1em; + + > span.option { + flex: none; + margin-right: .5em; + user-select: none; + } + + > div.item { + flex: auto; + text-overflow: ellipsis; + overflow: hidden; + } + + > ul.actions { + flex: none; + display: flex; + list-style: none; + margin: 0; + padding: 0; + visibility: hidden; + } + + &:hover, &:focus-within { + > ul.actions { + visibility: visible; + } + } + + &.active { + > div.main, > span.option { + color: primaryColor(); + } + } + + &.option { + cursor: pointer; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.ts b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.ts new file mode 100644 index 000000000..88e60e7c2 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list-item/list-item.component.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, ElementRef, HostBinding, Input } from '@angular/core'; +import { FocusableOption, FocusOrigin } from '@angular/cdk/a11y'; +import { SciListItemDirective } from '../list-item.directive'; +import { SciListStyle } from '../metadata'; + +@Component({ + selector: 'sci-list-item', + templateUrl: './list-item.component.html', + styleUrls: ['./list-item.component.scss'], +}) +export class SciListItemComponent implements FocusableOption { + + @Input() + public listItem: SciListItemDirective; + + @HostBinding('class.active') + @Input() + public active: boolean; + + @Input() + public style: SciListStyle; + + @HostBinding('attr.disabled') + public disabled: boolean; + + @HostBinding('attr.tabindex') + public tabindex = -1; + + constructor(private _host: ElementRef) { + } + + public focus(origin?: FocusOrigin): void { + this._host.nativeElement.focus(); + } + + @HostBinding('class.option') + public get optionStyle(): boolean { + return this.style === 'option-item'; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.html b/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.html new file mode 100644 index 000000000..f1bccfeba --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.html @@ -0,0 +1,21 @@ + + + + + +
+ + +
+
+ + + + + + + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.scss b/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.scss new file mode 100644 index 000000000..1141c0e94 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.scss @@ -0,0 +1,35 @@ +@import '../common'; + +:host { + display: flex; + flex-direction: column; + outline: none; + + > sci-filter-field { + flex: none; + + &.top { + margin-bottom: .3em; + } + + &.bottom { + margin-top: .3em; + } + } + + > sci-viewport { + flex: auto; + border: 1px solid accentColor(.25); + border-radius: 5px; + padding: .5em; + + sci-list-item { + &:not(:first-child) { + border-top: 1px solid accentColor(.25); + } + &:last-child { + border-bottom: 1px solid accentColor(.25); + } + } + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.ts b/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.ts new file mode 100644 index 000000000..6668c344a --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list.component.ts @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { AfterViewInit, Component, ContentChildren, EventEmitter, HostBinding, HostListener, Input, OnDestroy, Output, QueryList, TrackByFunction, ViewChild, ViewChildren } from '@angular/core'; +import { FocusKeyManager } from '@angular/cdk/a11y'; +import { SciListItemDirective } from './list-item.directive'; +import { SciListItemComponent } from './list-item/list-item.component'; +import { SciFilterFieldComponent } from '../filter-field/filter-field.component'; +import { Subject } from 'rxjs'; +import { filter, map, takeUntil } from 'rxjs/operators'; +import { SciListStyle } from './metadata'; + +/** + * Component that contains a list of items or options which can be filtered and associated with actions. + * + * List items are contributed as content children in the form of a `` decorated with `sciListItem` directive. + * Actions are modelled in the form of a `` and are inputs for respective `sciListItem` directive. + * + * --- + * Example of a simple list: + * + * + * + * ... + * + * + * + * + * --- + * Example of a list with actions: + * + * + * + * + * + * ... + * + * + * + * + * + * + * + * + */ +@Component({ + selector: 'sci-list', + templateUrl: './list.component.html', + styleUrls: ['./list.component.scss'], +}) +export class SciListComponent implements AfterViewInit, OnDestroy { + + private _focusKeyManager: FocusKeyManager; + private _destroy$ = new Subject(); + + /** + * Specifies where to position the filter field. + */ + @Input() + public filterPosition: 'top' | 'bottom' = 'top'; + + /** + * Specifies whether to render list items or option items. + */ + @Input() + public style: SciListStyle = 'list-item'; + + /** + * Sets focus order in sequential keyboard navigation. + * If not specified, the focus order is according to the position in the document (tabindex=0). + */ + @Input() + public tabindex = 0; + + /** + * Emits filter text on filter change. + */ + @Output() + public filter = new EventEmitter(); + + /** + * Emits selected item key on selection change. + */ + @Output() + public selection = new EventEmitter(); + + @ContentChildren(SciListItemDirective) + public listItems: QueryList; + + @ViewChildren(SciListItemComponent) + private _listItemComponents: QueryList; + + @ViewChild(SciFilterFieldComponent) + private _filterField: SciFilterFieldComponent; + + @HostBinding('attr.tabindex') + public componentTabindex = -1; // component itself is not focusable in sequential keyboard navigation, but tabindex (if any) set to filter field + + @HostListener('keydown', ['$event']) + public onKeydown(event: KeyboardEvent): void { + this._focusKeyManager.onKeydown(event); + } + + @HostListener('focus') + public focus(): void { + this._filterField.focus(); + } + + public ngAfterViewInit(): void { + this._focusKeyManager = new FocusKeyManager(this._listItemComponents); + this._focusKeyManager.change + .pipe( + map(index => this.listItems.toArray()[index]), + filter(Boolean), + takeUntil(this._destroy$) + ) + .subscribe((listItem: SciListItemDirective) => { + this.selection.emit(listItem.key); + }); + } + + public onItemClick(item: SciListItemComponent): void { + this._focusKeyManager.setActiveItem(item); + } + + public onFilter(filterText: string): void { + this._focusKeyManager.setActiveItem(-1); + this.filter.emit(filterText); + } + + public onAnyKey(event: KeyboardEvent): void { + this._filterField.onKeydown(event); + } + + public get activeItem(): SciListItemComponent { + return this._focusKeyManager && this._focusKeyManager.activeItem; + } + + public trackByFn: TrackByFunction = (index: number, item: SciListItemDirective): any => { + return item.key || item; + }; + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/list.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/list/list.module.ts new file mode 100644 index 000000000..fcfcab8cc --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/list.module.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { SciListComponent } from './list.component'; +import { A11yModule } from '@angular/cdk/a11y'; +import { SciFilterFieldModule } from '../filter-field/filter-field.module'; +import { SciListItemComponent } from './list-item/list-item.component'; +import { SciListItemDirective } from './list-item.directive'; +import { SciViewportModule } from '@scion/viewport'; +import { CommonModule } from '@angular/common'; + +/** + * Provides a list component to render a list of items which can be filtered. + */ +@NgModule({ + declarations: [ + SciListComponent, + SciListItemComponent, + SciListItemDirective, + ], + exports: [ + SciListComponent, + SciListItemComponent, + SciListItemDirective, + ], + imports: [ + CommonModule, + SciViewportModule, + SciFilterFieldModule, + A11yModule, + ] +}) +export class SciListModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/list/metadata.ts b/projects/e2e/workbench-application-platform/common/src/lib/list/metadata.ts new file mode 100644 index 000000000..dce6f37be --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/list/metadata.ts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/** + * Styles for ``. + */ +export declare type SciListStyle = 'list-item' | 'option-item'; diff --git a/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.html b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.html new file mode 100644 index 000000000..2dc5b8050 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.html @@ -0,0 +1,20 @@ +

{{title}}

+ + + + + + + + + + + + + + + + + + + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.scss b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.scss new file mode 100644 index 000000000..b633f45dd --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.scss @@ -0,0 +1,34 @@ +@import '../common'; + +:host { + display: grid; + outline: none; + + grid-template-columns: 100px auto; // 2 columns + grid-column-gap: 1em; + grid-row-gap: .5em; + grid-template-rows: auto; + @include grid-container-align-items(center); + + border: 1px solid accentColor(.25); + border-radius: 5px; + padding: 1em; + + &.addable, &.removable { + grid-template-columns: 100px auto 25px; // 3 columns + } + + > h2 { + font-size: 1em; + font-weight: bold; + margin-top: 0; + + grid-column: 1/3; + grid-row: 1/2; + } + + > button.add { + grid-column: 3/4; + grid-row: 1/2; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.ts b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.ts new file mode 100644 index 000000000..5625beff8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.component.ts @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, ElementRef, HostBinding, Input } from '@angular/core'; +import { FormArray, FormBuilder } from '@angular/forms'; + +export const PARAM_NAME = 'paramName'; +export const PARAM_VALUE = 'paramValue'; + +/** + * Allows to enter parameters. + */ +@Component({ + selector: 'sci-params-enter', + templateUrl: './params-enter.component.html', + styleUrls: ['./params-enter.component.scss'], +}) +export class SciParamsEnterComponent { + + public readonly PARAM_NAME = PARAM_NAME; + public readonly PARAM_VALUE = PARAM_VALUE; + + @Input() + public title: string; + + @Input() + public paramsFormArray: FormArray; + + @Input() + @HostBinding('class.removable') + public removable: boolean; + + @Input() + @HostBinding('class.addable') + public addable: boolean; + + @HostBinding('attr.tabindex') + public tabindex = -1; + + constructor(private _formBuilder: FormBuilder, private _host: ElementRef) { + } + + public onRemove(index: number): void { + this.paramsFormArray.removeAt(index); + + // Focus the component to not loose the focus when the remove button is removed from the DOM. + // Otherwise, if used in a popup, the popup would be closed because no element is focused anymore. + this._host.nativeElement.focus({preventScroll: true}); + } + + public onAdd(): void { + this.paramsFormArray.push(this._formBuilder.group({ + [PARAM_NAME]: this._formBuilder.control(''), + [PARAM_VALUE]: this._formBuilder.control(''), + })); + } + + /** + * Creates a dictionary from the form controls in the given `FormArray`. + */ + public static toParams(formArray: FormArray): { [key: string]: any } { + const params: { [key: string]: any } = {}; + formArray.controls.forEach(formGroup => { + const paramName = formGroup.get(PARAM_NAME).value; + params[paramName] = formGroup.get(PARAM_VALUE).value; + }); + return params; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.module.ts new file mode 100644 index 000000000..28f50953a --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/params-enter/params-enter.module.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciParamsEnterComponent } from './params-enter.component'; +import { ReactiveFormsModule } from '@angular/forms'; + +/** + * Allows to enter parameters. + */ +@NgModule({ + declarations: [ + SciParamsEnterComponent + ], + exports: [ + SciParamsEnterComponent, + ], + imports: [ + CommonModule, + ReactiveFormsModule, + ] +}) +export class SciParamsEnterModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell-button.directive.ts b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell-button.directive.ts new file mode 100644 index 000000000..ef3788026 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell-button.directive.ts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Directive, EventEmitter, Input, Output, TemplateRef } from '@angular/core'; + +/** + * Use this directive to model a button for {SciPopupComponent}. + * The host element of this modelling directive must be a . + * + * --- + * Example usage: + * + * + * Title + * + * + * ... + * + * OK + * + */ +@Directive({selector: 'ng-template[sciPopupShellButton]'}) +export class SciPopupShellButtonDirective { + + /** + * Specifies if this is the default button, meaning it is enabled only if valid + * and clicked upon enter keystroke. + */ + @Input() + public defaultButton = true; + + /** + * Specifies CSS class(es) added to the + + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.scss b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.scss new file mode 100644 index 000000000..b8905ffa6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.scss @@ -0,0 +1,36 @@ +@import '../common'; + +:host { + display: flex; + position: relative; // positioned anchor for close button + flex-direction: column; + padding-top: app-padding(); + + > header { + flex: none; + margin: 0 app-padding() 2em app-padding(); + font-size: 1.1em; + font-weight: bold; + } + + > sci-viewport { + flex: auto; + + div.content { + margin: 0 app-padding(); + display: grid; + } + } + + > div.button-bar { + flex: none; + @include button-bar(); + } + + > button.close { + position: absolute; + top: 5px; + right: 5px; + @include mat-icon-button; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.ts b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.ts new file mode 100644 index 000000000..ac60946f3 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.component.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { AfterViewInit, Component, ContentChild, ContentChildren, HostListener, Input, QueryList } from '@angular/core'; +import { WorkbenchPopup } from '@scion/workbench-application.angular'; +import { SciPopupShellTitleDirective } from './popup-shell-title.directive'; +import { SciPopupShellContentDirective } from './popup-shell-content.directive'; +import { SciPopupShellButtonDirective } from './popup-shell-button.directive'; + +/** + * Component that provides the shell for a popup. + * + * The shell consists of the following elements: + * - close button in the top-right corner + * - title at the top + * - button panel at the bottom with an 'OK' button (enabled if valid) + * + * This component can be used only in a workbench popup context. + * + * Title and content are contributed as content children in the form of a `` decorated with `sciPopupShellTitle` + * directive and `sciPopupShellContent`, respectively. + * + * Content is added to a CSS grid container with a single column. + * + * --- + * Example: + * + * + * Title + * + * + * ... + * + * + */ +@Component({ + selector: 'sci-popup-shell', + templateUrl: './popup-shell.component.html', + styleUrls: ['./popup-shell.component.scss'], +}) +export class SciPopupShellComponent implements AfterViewInit { + + @Input() + public valid: boolean; + + @ContentChild(SciPopupShellTitleDirective) + public title: SciPopupShellTitleDirective; + + @ContentChild(SciPopupShellContentDirective) + public content: SciPopupShellContentDirective; + + @ContentChildren(SciPopupShellButtonDirective) + public buttons: QueryList; + + constructor(private _popup: WorkbenchPopup) { + } + + @HostListener('keydown.enter', ['$event']) + public onEnter(event: Event): void { + this.valid && this.buttons.forEach(button => button.defaultButton && button.onClick(event)); + } + + public onClose(): void { + this._popup.close(); + } + + public ngAfterViewInit(): void { + if (!this.title) { + throw Error('[NullTitleError] No title template decorated with `sciPopupShellTitle` directive modelled as content child of \u02C2sci-popup-shell\u02C3'); + } + if (!this.content) { + throw Error('[NullContentError] No content template decorated with `sciPopupShellContent` directive modelled as content child of \u02C2sci-popup-shell\u02C3'); + } + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.module.ts new file mode 100644 index 000000000..9f5f72490 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/popup-shell/popup-shell.module.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciPopupShellComponent } from './popup-shell.component'; +import { SciPopupShellTitleDirective } from './popup-shell-title.directive'; +import { SciPopupShellContentDirective } from './popup-shell-content.directive'; +import { SciPopupShellButtonDirective } from './popup-shell-button.directive'; +import { SciViewportModule } from '@scion/viewport'; + +/** + * Provides the shell for a popup. + */ +@NgModule({ + declarations: [ + SciPopupShellComponent, + SciPopupShellTitleDirective, + SciPopupShellContentDirective, + SciPopupShellButtonDirective, + ], + imports: [ + CommonModule, + SciViewportModule, + ], + exports: [ + SciPopupShellComponent, + SciPopupShellTitleDirective, + SciPopupShellContentDirective, + SciPopupShellButtonDirective, + ], +}) +export class SciPopupShellModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.html b/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.html new file mode 100644 index 000000000..dbe7eaf1a --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.html @@ -0,0 +1,4 @@ + + {{property.key}}: + {{property.value}} + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.scss b/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.scss new file mode 100644 index 000000000..519c3690e --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.scss @@ -0,0 +1,17 @@ +:host { + display: grid; + grid-template-columns: max-content 3fr; + grid-column-gap: 1em; + grid-row-gap: .5em; + grid-template-rows: auto; + + > span.key { + overflow: hidden; + text-overflow: ellipsis; + } + + > span.value { + overflow: hidden; + text-overflow: ellipsis; + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.ts b/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.ts new file mode 100644 index 000000000..194a05a02 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/property/property.component.ts @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { KeyValue } from '@angular/common'; + +/** + * Show the properties of an object. + */ +@Component({ + selector: 'sci-property', + templateUrl: './property.component.html', + styleUrls: ['./property.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SciPropertyComponent { + + public flattenedProperties: { [key: string]: any }; + private _keys: string[]; + + @Input() + public set properties(properties: any) { + this.flattenedProperties = this.flattenObject(properties || {}); + this._keys = Object.keys(this.flattenedProperties || {}); + } + + /** + * Compares qualifier entries by their position in the object. + */ + public keyCompareFn = (a: KeyValue, b: KeyValue): number => { + return this._keys.indexOf(a.key) - this._keys.indexOf(b.key); + }; + + private flattenObject(property: any, path: string[] = []): { [key: string]: any } { + return Object.keys(property).reduce((acc, key) => { + const value = property[key]; + if (typeof value === 'object') { + return {...acc, ...this.flattenObject(value, [...path, key])}; + } + else { + const propName = [...path, key].join('.'); + return {...acc, ...{[propName]: value}}; + } + }, {}); + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/property/property.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/property/property.module.ts new file mode 100644 index 000000000..1cf628e26 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/property/property.module.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciPropertyComponent } from './property.component'; + +/** + * Allows to show the properties of an object. + */ +@NgModule({ + declarations: [ + SciPropertyComponent, + ], + exports: [ + SciPropertyComponent, + ], + imports: [ + CommonModule, + ] +}) +export class SciPropertyModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/sash/sash.directive.ts b/projects/e2e/workbench-application-platform/common/src/lib/sash/sash.directive.ts new file mode 100644 index 000000000..a0d2e1453 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/sash/sash.directive.ts @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Directive, EventEmitter, HostBinding, HostListener, Inject, Input, OnChanges, OnDestroy, Output, SimpleChanges } from '@angular/core'; +import { fromEvent, Subject } from 'rxjs'; +import { DOCUMENT } from '@angular/common'; +import { first, takeUntil } from 'rxjs/operators'; + +/** + * Allows the host element to be used as splitter in a sash box. + * + * Emits delta pixels when the host element is moved. + * + */ +@Directive({ + selector: '[sciSash]' +}) +export class SciSashDirective implements OnDestroy, OnChanges { + + private _destroy$ = new Subject(); + private _mousePosition: number; + + @Input('sciSash') // tslint:disable-line:no-input-rename + public direction: 'vertical' | 'horizontal'; + + @Output('sciSashStart') // tslint:disable-line:no-output-rename + public sashStart = new EventEmitter(); + + @Output('sciSashChange') // tslint:disable-line:no-output-rename + public sashChange = new EventEmitter(); + + @Output('sciSashEnd') // tslint:disable-line:no-output-rename + public sashEnd = new EventEmitter(); + + @Output('sciSashReset') // tslint:disable-line:no-output-rename + public sashReset = new EventEmitter(); + + @HostBinding('style.cursor') + public cursor: string; + + constructor(@Inject(DOCUMENT) private _document: any) { + } + + public ngOnChanges(changes: SimpleChanges): void { + this.cursor = this.direction === 'vertical' ? 'ew-resize' : 'ns-resize'; + } + + @HostListener('dblclick') + public onDoubleClick(): void { + this.sashReset.emit(); + } + + @HostListener('mousedown', ['$event']) + public onMouseDown(event: MouseEvent): void { + if (event.button !== 0) { + return; + } + + event.preventDefault(); + this._mousePosition = this.extractMousePosition(event); + + // Apply cursor on document level to prevent flickering while sashing + const oldCursor = this._document.body.style.cursor; + this._document.body.style.cursor = this.cursor; + + // Listen for 'mousemove' events + const mousemoveListener = fromEvent(this._document, 'mousemove') + .pipe( + takeUntil(this._destroy$) + ) + .subscribe((mousemoveEvent: MouseEvent) => { + mousemoveEvent.preventDefault(); + const mousePosition = this.extractMousePosition(mousemoveEvent); + const delta = mousePosition - this._mousePosition; + this._mousePosition = mousePosition; + this.sashChange.emit(delta); + }); + + // Listen for 'mouseup' events + fromEvent(this._document, 'mouseup') + .pipe( + first(), + takeUntil(this._destroy$) + ) + .subscribe(() => { + mousemoveListener.unsubscribe(); + this._mousePosition = null; + this._document.body.style.cursor = oldCursor; + this.sashEnd.next(); + }); + + this.sashStart.next(); + } + + public extractMousePosition(event: MouseEvent): number { + return this.direction === 'vertical' ? event.pageX : event.pageY; + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/sash/sash.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/sash/sash.module.ts new file mode 100644 index 000000000..77f18b5fb --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/sash/sash.module.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciSashDirective } from './sash.directive'; + +/** + * Allows the host element to be used as splitter in a sash box. + */ +@NgModule({ + declarations: [ + SciSashDirective, + ], + imports: [ + CommonModule, + ], + exports: [ + SciSashDirective, + ], +}) +export class SciSashModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.module.ts b/projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.module.ts new file mode 100644 index 000000000..344d01dd9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.module.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; + +/** + * Provides {SciSessionStorageService} to interact with session storage. + * + * Session storage maintains a separate storage area per origin that is available for the duration of the page session + * (as long as the browser is open, including page reloads and restores). + */ +@NgModule({}) +export class SciSessionStorageModule { +} diff --git a/projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.service.ts b/projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.service.ts new file mode 100644 index 000000000..269866383 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/session-storage/session-storage.service.ts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Injectable } from '@angular/core'; +import { fromEvent, merge, NEVER, Observable, of, Subject } from 'rxjs'; +import { filter, map, startWith, switchMap, tap } from 'rxjs/operators'; + +/** + * Indicates data being loaded. + */ +const LOADING_HINT = 'LOADING_HINT [SessionStorageService]'; + +/** + * Allows to interact with session storage. + * + * Session storage maintains a separate storage area per origin that is available for the duration of the page session + * (as long as the browser is open, including page reloads and restores). + */ +@Injectable({providedIn: 'root'}) +export class SciSessionStorageService { + + private _currentDocumentChange$ = new Subject(); + + /** + * Puts data into session storage. + */ + public put(key: string, value: any): void { + if (value === LOADING_HINT) { + throw Error(`[IllegalValueError] Reserved value used by \`SessionStorageService\` [value=${LOADING_HINT}]`); + } + + sessionStorage.setItem(key, JSON.stringify(value)); + this._currentDocumentChange$.next(key); + } + + /** + * Returns data of given key from session storage. + * + * Upon subscription, it emits latest data, if any, and then continuously emits when data change. It never completes. + * + * Optionally, you can provide a supplier to put data into session storage if missing. + */ + public observe$(key: string, supplierIfAbsentFn$?: () => Observable): Observable { + const otherDocumentChange$ = fromEvent(window, 'storage') + .pipe( + filter(event => event.storageArea === sessionStorage), + map(event => event.key), + ); + + return merge(this._currentDocumentChange$, otherDocumentChange$) + .pipe( + filter(itemKey => itemKey === key), + startWith(key), + map(itemKey => sessionStorage.getItem(itemKey)), + filter(item => !item || item !== LOADING_HINT), + map(item => item && JSON.parse(item)), + switchMap((item: T | undefined): Observable => { + if (item) { + return of(item); + } + + if (!supplierIfAbsentFn$) { + return NEVER; + } + + sessionStorage.setItem(key, LOADING_HINT); + return supplierIfAbsentFn$() + .pipe( + tap(it => this.put(key, it)), + switchMap(it => of(it)) + ); + }) + ); + } +} + diff --git a/projects/e2e/workbench-application-platform/common/src/lib/uuid/uuid.util.ts b/projects/e2e/workbench-application-platform/common/src/lib/uuid/uuid.util.ts new file mode 100644 index 000000000..0477a61d3 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/lib/uuid/uuid.util.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/** + * Utility for random numbers. + */ +export class UUID { + + private constructor() { + } + + /** + * Generates a 'pseudo-random' identifier. + */ + public static randomUUID(): string { + let now = Date.now(); + if (window.performance && typeof window.performance.now === 'function') { + now += performance.now(); // use high-precision timer if available + } + + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, char => { + const random = (now + Math.random() * 16) % 16 | 0; // tslint:disable-line:no-bitwise + now = Math.floor(now / 16); + return (char === 'x' ? random : (random & 0x3 | 0x8)).toString(16); // tslint:disable-line:no-bitwise + }); + } +} diff --git a/projects/e2e/workbench-application-platform/common/src/public_api.ts b/projects/e2e/workbench-application-platform/common/src/public_api.ts new file mode 100644 index 000000000..efd8612f5 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/src/public_api.ts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/** + * Public API of `SciAccordionModule` + */ +export { SciAccordionModule } from './lib/accordion/accordion.module'; +export { SciAccordionComponent } from './lib/accordion/accordion.component'; +export { SciAccordionItemDirective } from './lib/accordion/accordion-item.directive'; + +/** + * Public API of `SciPopupShellModule` + */ +export { SciPopupShellModule } from './lib/popup-shell/popup-shell.module'; +export { SciPopupShellComponent } from './lib/popup-shell/popup-shell.component'; +export { SciPopupShellTitleDirective } from './lib/popup-shell/popup-shell-title.directive'; +export { SciPopupShellContentDirective } from './lib/popup-shell/popup-shell-content.directive'; +export { SciPopupShellButtonDirective } from './lib/popup-shell/popup-shell-button.directive'; + +/** + * Public API of `SciSessionStorageModule` + */ +export { SciSessionStorageModule } from './lib/session-storage/session-storage.module'; +export { SciSessionStorageService } from './lib/session-storage/session-storage.service'; + +/** + * Public API of `SciFilterFieldModule` + */ +export { SciFilterFieldModule } from './lib/filter-field/filter-field.module'; +export { SciFilterFieldComponent, toFilterRegExp } from './lib/filter-field/filter-field.component'; + +/** + * Public API of `uuid` + */ +export { UUID } from './lib/uuid/uuid.util'; + +/** + * Public API of `SciListModule` + */ +export { SciListModule } from './lib/list/list.module'; +export { SciListComponent } from './lib/list/list.component'; +export { SciListItemDirective } from './lib/list/list-item.directive'; +export { SciListStyle } from './lib/list/metadata'; + +/** + * Public API of `SciSashModule` + */ +export { SciSashModule } from './lib/sash/sash.module'; +export { SciSashDirective } from './lib/sash/sash.directive'; + +/** + * Public API of `SciParamsEnterModule` + */ +export { SciParamsEnterModule } from './lib/params-enter/params-enter.module'; +export { SciParamsEnterComponent, PARAM_VALUE, PARAM_NAME } from './lib/params-enter/params-enter.component'; + +/** + * Public API of `SciPropertyModule` + */ +export { SciPropertyModule } from './lib/property/property.module'; +export { SciPropertyComponent } from './lib/property/property.component'; + +/** + * Public API of `custom-extension` + */ +export * from './lib/custom-extension/metadata'; diff --git a/projects/e2e/workbench-application-platform/common/tsconfig.lib.json b/projects/e2e/workbench-application-platform/common/tsconfig.lib.json new file mode 100644 index 000000000..3d57476f9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/tsconfig.lib.json @@ -0,0 +1,28 @@ +{ + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../../../out-tsc/lib", + "target": "es2015", + "module": "es2015", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "inlineSources": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true + } +} diff --git a/projects/e2e/workbench-application-platform/common/tslint.json b/projects/e2e/workbench-application-platform/common/tslint.json new file mode 100644 index 000000000..b5ac9f50b --- /dev/null +++ b/projects/e2e/workbench-application-platform/common/tslint.json @@ -0,0 +1,21 @@ +{ + "extends": "../../../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + [ + "sci" + ], + "camelCase" + ], + "component-selector": [ + true, + "element", + [ + "sci" + ], + "kebab-case" + ] + } +} diff --git a/projects/e2e/workbench-application-platform/communication-app/browserslist b/projects/e2e/workbench-application-platform/communication-app/browserslist new file mode 100644 index 000000000..37371cb04 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/app-routing.module.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/app-routing.module.ts new file mode 100644 index 000000000..793ca848c --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/app-routing.module.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + {path: 'communication', loadChildren: './communication/communication.module#CommunicationModule'}, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes, {useHash: true})], + exports: [RouterModule] +}) +export class AppRoutingModule { +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.html b/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.html new file mode 100644 index 000000000..8fe45de6e --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.html @@ -0,0 +1,3 @@ + + + diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.scss b/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.scss new file mode 100644 index 000000000..e1f2859cf --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.scss @@ -0,0 +1,13 @@ +@import 'common'; + +:host { + @include position(absolute, 0, 0, 0, 0); + + > sci-viewport { + @include position(absolute, 0, 0, 0, 0); + + router-outlet { + position: absolute; // take router outlet out of the document flow + } + } +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.ts new file mode 100644 index 000000000..15f0590f2 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/app.component.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent { +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/app.module.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/app.module.ts new file mode 100644 index 000000000..511d6e1d8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/app.module.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; +import { SciViewportModule } from '@scion/viewport'; +import { AppRoutingModule } from './app-routing.module'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { WorkbenchApplicationModule } from '@scion/workbench-application.angular'; + +@NgModule({ + declarations: [ + AppComponent, + ], + imports: [ + BrowserModule, + WorkbenchApplicationModule.forRoot(), + SciViewportModule, + AppRoutingModule, + BrowserAnimationsModule, + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.html b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.html new file mode 100644 index 000000000..c48515498 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.html @@ -0,0 +1,10 @@ + + + + + + + + +{{communication.subject}} +{{communication.date | date:'d. MMM yyyy'}} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.scss b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.scss new file mode 100644 index 000000000..53bbd0cd4 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.scss @@ -0,0 +1,18 @@ +:host { + display: flex; + + > span.icon { + flex: none; + width: 30px; + font-size: 20px; + } + + > span.subject { + flex: auto; + } + + > span.date { + flex: none; + font-size: .8em; + } +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.ts new file mode 100644 index 000000000..e3857e54a --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-accordion-item-header/communication-accordion-item-header.component.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, Input } from '@angular/core'; +import { Communication } from '../communication.model'; + +@Component({ + selector: 'app-communication-accordion-item-header', + templateUrl: './communication-accordion-item-header.component.html', + styleUrls: ['./communication-accordion-item-header.component.scss'] +}) +export class CommunicationAccordionItemHeaderComponent { + + @Input() + public communication: Communication; +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.html b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.html new file mode 100644 index 000000000..d724f601f --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.html @@ -0,0 +1,28 @@ + + New communication + + +
+ + + + + + + + + + + +
+
+ + OK +
diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.scss b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.scss new file mode 100644 index 000000000..0de4616d1 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.scss @@ -0,0 +1,29 @@ +@import 'common'; + +:host { + display: flex; + flex-direction: column; + + > sci-popup-shell { + flex: auto; + + form { + flex: auto; + display: grid; + grid-template-columns: 100px auto; + grid-column-gap: 1em; + grid-row-gap: .5em; + grid-template-rows: auto; + @include grid-container-align-items(center); + + > label[for="message"] { + align-self: start; + } + + > textarea#message { + height: 16em; + resize: none; + } + } + } +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.ts new file mode 100644 index 000000000..faed42549 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-new-popup/communication-new-popup.component.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, OnDestroy } from '@angular/core'; +import { provideWorkbenchPopup, WorkbenchPopup } from '@scion/workbench-application.angular'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { noop, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { Communication } from '../communication.model'; +import { CommunicationService } from '../communication.service'; +import { ActivatedRoute } from '@angular/router'; +import { UUID } from '@scion/e2e/common'; + +const CHANNEL = 'channel'; +const DATE = 'date'; +const SUBJECT = 'subject'; +const MESSAGE = 'message'; + +@Component({ + selector: 'app-communication-new-popup', + templateUrl: './communication-new-popup.component.html', + styleUrls: ['./communication-new-popup.component.scss'], + providers: [ + provideWorkbenchPopup(CommunicationNewPopupComponent) + ] +}) +export class CommunicationNewPopupComponent implements OnDestroy { + + public readonly CHANNEL = CHANNEL; + public readonly DATE = DATE; + public readonly SUBJECT = SUBJECT; + public readonly MESSAGE = MESSAGE; + + private _destroy$ = new Subject(); + public form: FormGroup; + + constructor(private _popup: WorkbenchPopup, + private _communicationService: CommunicationService, + private _route: ActivatedRoute, + formBuilder: FormBuilder) { + this.form = formBuilder.group({ + [CHANNEL]: formBuilder.control('email', Validators.required), + [DATE]: formBuilder.control(nowAsIsoString(), Validators.required), + [SUBJECT]: formBuilder.control('', Validators.required), + [MESSAGE]: formBuilder.control('', Validators.required), + }); + } + + public onOk(): void { + const contactId = this._route.snapshot.params['contactId']; + + const communication: Communication = { + id: UUID.randomUUID(), + contactId: contactId, + channel: this.form.get(CHANNEL).value, + date: this.form.get(DATE).value, + subject: this.form.get(SUBJECT).value, + message: this.form.get(MESSAGE).value + }; + + this._communicationService.create$(communication) + .pipe(takeUntil(this._destroy$)) + .subscribe(noop, noop, () => this._popup.close()); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} + +function nowAsIsoString(): string { + const now = /(\d{4})-(\d{2})-(\d{2})/.exec(new Date().toISOString()); + return `${now[1]}-${now[2]}-${now[3]}`; +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-routing.module.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-routing.module.ts new file mode 100644 index 000000000..5b2e32a0d --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-routing.module.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { CommunicationViewComponent } from './communication-view/communication-view.component'; +import { CommunicationNewPopupComponent } from './communication-new-popup/communication-new-popup.component'; + +const routes: Routes = [ + {path: '', component: CommunicationViewComponent}, + {path: 'new', component: CommunicationNewPopupComponent}, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class CommunicationRoutingModule { +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.html b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.html new file mode 100644 index 000000000..7b6ae1fc2 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.html @@ -0,0 +1,10 @@ + + + + + + +
{{communication.message}}
+
+
+
diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.scss b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.scss new file mode 100644 index 000000000..b7a710cf3 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.scss @@ -0,0 +1,17 @@ +@import 'common'; + +:host { + display: flex; + padding: app-padding(); + + > sci-accordion { + flex: auto; + + div.message { + font-size: .8em; + text-overflow: ellipsis; + overflow: hidden; + } + } +} + diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.ts new file mode 100644 index 000000000..2dba37da0 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication-view/communication-view.component.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, TrackByFunction } from '@angular/core'; +import { Communication } from '../communication.model'; +import { Observable } from 'rxjs'; +import { CommunicationService } from '../communication.service'; +import { ActivatedRoute } from '@angular/router'; +import { distinctUntilChanged, map, switchMap } from 'rxjs/operators'; +import { provideWorkbenchView, WorkbenchView } from '@scion/workbench-application.angular'; + +@Component({ + selector: 'app-communication-view', + templateUrl: './communication-view.component.html', + styleUrls: ['./communication-view.component.scss'], + providers: [ + provideWorkbenchView(CommunicationViewComponent) + ] +}) +export class CommunicationViewComponent { + + public communications$: Observable; + + constructor(communicationService: CommunicationService, + route: ActivatedRoute, + view: WorkbenchView) { + view.heading = 'Communications'; + view.title = route.snapshot.params['contactFullName']; + + this.communications$ = route.params + .pipe( + map(params => params['contactId']), + distinctUntilChanged(), + switchMap(contactId => communicationService.communicationsByContactId$(contactId)), + ); + } + + public trackByFn: TrackByFunction = (index: number, communication: Communication): any => { + return communication.id; + }; +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.model.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.model.ts new file mode 100644 index 000000000..c9d6a852b --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.model.ts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +export interface Communication { + id: string; + contactId: string; + channel: 'email' | 'letter' | 'phone' | 'sms' | 'facebook' | 'twitter'; + date: string; + subject: string; + message: string; +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.module.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.module.ts new file mode 100644 index 000000000..0211d66c9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.module.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciViewportModule } from '@scion/viewport'; +import { SciAccordionModule, SciPopupShellModule, SciSessionStorageModule } from '@scion/e2e/common'; +import { CommunicationViewComponent } from './communication-view/communication-view.component'; +import { CommunicationAccordionItemHeaderComponent } from './communication-accordion-item-header/communication-accordion-item-header.component'; +import { CommunicationRoutingModule } from './communication-routing.module'; +import { CommunicationNewPopupComponent } from './communication-new-popup/communication-new-popup.component'; +import { ReactiveFormsModule } from '@angular/forms'; +import { WorkbenchApplicationModule } from '@scion/workbench-application.angular'; + +@NgModule({ + declarations: [ + CommunicationViewComponent, + CommunicationNewPopupComponent, + CommunicationAccordionItemHeaderComponent, + ], + imports: [ + CommonModule, + SciViewportModule, + CommunicationRoutingModule, + SciAccordionModule, + SciPopupShellModule, + SciSessionStorageModule, + ReactiveFormsModule, + WorkbenchApplicationModule.forChild(), + ], + exports: [], +}) +export class CommunicationModule { +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.service.ts b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.service.ts new file mode 100644 index 000000000..158b01039 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/app/communication/communication.service.ts @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Injectable, OnDestroy } from '@angular/core'; +import { map, mergeMapTo, take, tap } from 'rxjs/operators'; +import { EMPTY, MonoTypeOperatorFunction, Observable, of, OperatorFunction, Subject } from 'rxjs'; +import { SciSessionStorageService } from '@scion/e2e/common'; +import { Communication } from './communication.model'; + +const COMMUNICATIONS_STORAGE_KEY = 'communication.data'; + +@Injectable({providedIn: 'root'}) +export class CommunicationService implements OnDestroy { + + private _destroy$ = new Subject(); + private _communications$: Observable; + + constructor(private _storage: SciSessionStorageService) { + this._communications$ = this._storage.observe$(COMMUNICATIONS_STORAGE_KEY, () => of([])); + } + + public communicationsByContactId$(contactId: string): Observable { + return this._communications$.pipe(filterByContactId(contactId)); + } + + public create$(communication: Communication): Observable { + return this._communications$ + .pipe( + once(), + addCommunication(this._storage, communication), + mergeMapTo(EMPTY), + ); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} + +function filterByContactId(contactId: string): OperatorFunction { + return map((communications: Communication[]): Communication[] => { + return communications + .filter(communication => communication.contactId === contactId) + .sort((c1, c2) => c1.date.localeCompare(c2.date)); + }); +} + +function addCommunication(storage: SciSessionStorageService, communication: Communication): MonoTypeOperatorFunction { + return tap((communications: Communication[]): void => { + communications.push(communication); + storage.put(COMMUNICATIONS_STORAGE_KEY, communications); + }); +} + +function once(): MonoTypeOperatorFunction { + return take(1); +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/assets/.gitkeep b/projects/e2e/workbench-application-platform/communication-app/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/projects/e2e/workbench-application-platform/communication-app/src/assets/manifest.json b/projects/e2e/workbench-application-platform/communication-app/src/assets/manifest.json new file mode 100644 index 000000000..4a2afca2e --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/assets/manifest.json @@ -0,0 +1,45 @@ +{ + "name": "Communication Application", + "baseUrl": "#", + "capabilities": [ + { + "type": "view", + "qualifier": { + "entity": "communication", + "presentation": "list", + "contactId": "*" + }, + "private": false, + "description": "Lists all communications of a contact.", + "properties": { + "path": "communication", + "matrixParams": { + "contactId": ":contactId" + }, + "title": "Communications", + "cssClass": "e2e-communication-list" + } + }, + { + "type": "popup", + "qualifier": { + "entity": "communication", + "action": "create", + "contactId": "*" + }, + "private": false, + "description": "Allows to create a new communication for a contact.", + "properties": { + "path": "communication/new", + "matrixParams": { + "contactId": ":contactId" + }, + "width": "500px", + "height": "520px", + "cssClass": "e2e-communication-create" + } + } + ], + "intents": [ + ] +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/environments/environment.now.ts b/projects/e2e/workbench-application-platform/communication-app/src/environments/environment.now.ts new file mode 100644 index 000000000..dc39aca58 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/environments/environment.now.ts @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +export const environment = { + production: true +}; diff --git a/projects/e2e/workbench-application-platform/communication-app/src/environments/environment.ts b/projects/e2e/workbench-application-platform/communication-app/src/environments/environment.ts new file mode 100644 index 000000000..2a785475f --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/environments/environment.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --configuration=now` replaces `environment.ts` with `environment.now.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/projects/e2e/workbench-application-platform/communication-app/src/index.html b/projects/e2e/workbench-application-platform/communication-app/src/index.html new file mode 100644 index 000000000..344beb469 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/index.html @@ -0,0 +1,13 @@ + + + + + Communication Application + + + + + + + + diff --git a/projects/e2e/workbench-application-platform/communication-app/src/main.ts b/projects/e2e/workbench-application-platform/communication-app/src/main.ts new file mode 100644 index 000000000..87c3f3d9a --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/main.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/projects/e2e/workbench-application-platform/communication-app/src/now.json b/projects/e2e/workbench-application-platform/communication-app/src/now.json new file mode 100644 index 000000000..dc73c6b63 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/now.json @@ -0,0 +1,5 @@ +{ + "version": 2, + "name": "scion-workbench-application-platform-communication", + "alias": "scion-workbench-application-platform-communication" +} diff --git a/projects/e2e/workbench-application-platform/communication-app/src/polyfills.ts b/projects/e2e/workbench-application-platform/communication-app/src/polyfills.ts new file mode 100644 index 000000000..f56cc3de6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/polyfills.ts @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/number'; +import 'core-js/es6/math'; +import 'core-js/es6/string'; +import 'core-js/es6/date'; +import 'core-js/es6/array'; +import 'core-js/es6/regexp'; +import 'core-js/es6/map'; +import 'core-js/es6/weak-map'; +import 'core-js/es6/set'; +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + + // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + + /* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/projects/e2e/workbench-application-platform/communication-app/src/styles.scss b/projects/e2e/workbench-application-platform/communication-app/src/styles.scss new file mode 100644 index 000000000..1506f1627 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/src/styles.scss @@ -0,0 +1,3 @@ +@import 'common'; + +@include app-theme(); diff --git a/projects/e2e/workbench-application-platform/communication-app/tsconfig.app.json b/projects/e2e/workbench-application-platform/communication-app/tsconfig.app.json new file mode 100644 index 000000000..27e4b91c8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/tsconfig.app.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../../../out-tsc/communication-app", + "types": [] + } +} diff --git a/projects/e2e/workbench-application-platform/communication-app/tslint.json b/projects/e2e/workbench-application-platform/communication-app/tslint.json new file mode 100644 index 000000000..78a62a0db --- /dev/null +++ b/projects/e2e/workbench-application-platform/communication-app/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/browserslist b/projects/e2e/workbench-application-platform/contact-app/browserslist new file mode 100644 index 000000000..37371cb04 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/app-routing.module.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/app-routing.module.ts new file mode 100644 index 000000000..f32749bea --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/app-routing.module.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + {path: 'contact', loadChildren: './contact/contact.module#ContactModule'}, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes, {useHash: true})], + exports: [RouterModule] +}) +export class AppRoutingModule { +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.html b/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.html new file mode 100644 index 000000000..8fe45de6e --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.html @@ -0,0 +1,3 @@ + + + diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.scss b/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.scss new file mode 100644 index 000000000..e1f2859cf --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.scss @@ -0,0 +1,13 @@ +@import 'common'; + +:host { + @include position(absolute, 0, 0, 0, 0); + + > sci-viewport { + @include position(absolute, 0, 0, 0, 0); + + router-outlet { + position: absolute; // take router outlet out of the document flow + } + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.ts new file mode 100644 index 000000000..15f0590f2 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/app.component.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent { +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/app.module.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/app.module.ts new file mode 100644 index 000000000..49f5b608e --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/app.module.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; +import { WorkbenchApplicationModule } from '@scion/workbench-application.angular'; +import { SciViewportModule } from '@scion/viewport'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { AppRoutingModule } from './app-routing.module'; + +@NgModule({ + declarations: [ + AppComponent, + ], + imports: [ + BrowserModule, + WorkbenchApplicationModule.forRoot(), + SciViewportModule, + AppRoutingModule, + BrowserAnimationsModule, + ], + providers: [], + bootstrap: [ + AppComponent, + ] +}) +export class AppModule { +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.html b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.html new file mode 100644 index 000000000..d7b21f351 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.html @@ -0,0 +1,19 @@ + + + + + {{contact.firstname}} {{contact.lastname}}, {{contact.city}} + + + + + + + + + + diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.scss b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.scss new file mode 100644 index 000000000..57bda86d3 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.scss @@ -0,0 +1,10 @@ +@import 'common'; + +:host { + display: flex; + padding: app-padding(); + + > sci-list { + flex: auto; + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.ts new file mode 100644 index 000000000..5f43adbda --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-activity/contact-activity.component.ts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, OnDestroy, TrackByFunction } from '@angular/core'; +import { provideWorkbenchActivity } from '@scion/workbench-application.angular'; +import { takeUntil } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs'; +import { ContactService, filterContacts } from '../contact.service'; +import { Contact } from '../contact.model'; + +@Component({ + selector: 'app-contact-activity', + templateUrl: './contact-activity.component.html', + styleUrls: ['./contact-activity.component.scss'], + providers: [ + provideWorkbenchActivity(ContactActivityComponent) + ] +}) +export class ContactActivityComponent implements OnDestroy { + + private _destroy$ = new Subject(); + private _filter$ = new BehaviorSubject(null); + + public contacts$: Observable; + + constructor(private _contactService: ContactService) { + this.contacts$ = combineLatest(this._filter$, this._contactService.contacts$()).pipe(filterContacts()); + } + + public onDelete(contactId: string): void { + this._contactService.delete$(contactId) + .pipe(takeUntil(this._destroy$)) + .subscribe(); + } + + public onFilter(filterText: string): void { + this._filter$.next(filterText); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } + + public trackByFn: TrackByFunction = (index: number, contact: Contact): any => { + return contact.id; + }; +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.html b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.html new file mode 100644 index 000000000..76dd1208f --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.html @@ -0,0 +1,27 @@ + + New contact + + +
+ + + + + + + + + + + + + + + + + +
+
+ + OK +
diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.scss b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.scss new file mode 100644 index 000000000..f4d4e72c1 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.scss @@ -0,0 +1,19 @@ +@import 'common'; + +:host { + display: flex; + flex-direction: column; + + > sci-popup-shell { + flex: auto; + + form { + flex: auto; + display: grid; + grid-template-columns: 100px auto; + grid-column-gap: 1em; + grid-row-gap: .5em; + @include grid-container-align-items(center); + } + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.ts new file mode 100644 index 000000000..bfe85e0a3 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-new-popup/contact-new-popup.component.ts @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, OnDestroy } from '@angular/core'; +import { provideWorkbenchPopup, WorkbenchPopup, WorkbenchRouter } from '@scion/workbench-application.angular'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { ContactService } from '../contact.service'; +import { UUID } from '@scion/e2e/common'; +import { noop, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { Contact } from '../contact.model'; + +const FIRSTNAME = 'firstname'; +const LASTNAME = 'lastname'; +const STREET = 'street'; +const CITY = 'city'; +const EMAIL = 'email'; +const PHONE = 'phone'; + +@Component({ + selector: 'app-contact-new-popup', + templateUrl: './contact-new-popup.component.html', + styleUrls: ['./contact-new-popup.component.scss'], + providers: [ + provideWorkbenchPopup(ContactNewPopupComponent) + ] +}) +export class ContactNewPopupComponent implements OnDestroy { + + public readonly FIRSTNAME = FIRSTNAME; + public readonly LASTNAME = LASTNAME; + public readonly STREET = STREET; + public readonly CITY = CITY; + public readonly EMAIL = EMAIL; + public readonly PHONE = PHONE; + + private _destroy$ = new Subject(); + public form: FormGroup; + + constructor(private _popup: WorkbenchPopup, + private _contactService: ContactService, + private _router: WorkbenchRouter, + formBuilder: FormBuilder) { + this.form = formBuilder.group({ + [FIRSTNAME]: formBuilder.control('', Validators.required), + [LASTNAME]: formBuilder.control('', Validators.required), + [STREET]: formBuilder.control('', Validators.required), + [CITY]: formBuilder.control('', Validators.required), + [EMAIL]: formBuilder.control('', Validators.email), + [PHONE]: formBuilder.control(''), + }); + } + + public onOk(): void { + const contact: Contact = { + id: UUID.randomUUID(), + firstname: this.form.get(FIRSTNAME).value, + lastname: this.form.get(LASTNAME).value, + street: this.form.get(STREET).value, + city: this.form.get(CITY).value, + email: this.form.get(EMAIL).value, + phone: this.form.get(PHONE).value, + relatedContactIds: [], + }; + + this._contactService.create$(contact) + .pipe(takeUntil(this._destroy$)) + .subscribe(noop, noop, () => { + this._router.navigate({'entity': 'contact', 'id': contact.id}); + this._popup.close(); + }); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-routing.module.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-routing.module.ts new file mode 100644 index 000000000..a0bbce730 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-routing.module.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ContactActivityComponent } from './contact-activity/contact-activity.component'; +import { ContactNewPopupComponent } from './contact-new-popup/contact-new-popup.component'; +import { ContactViewComponent } from './contact-view/contact-view.component'; +import { RelatedContactAddPopupComponent } from './related-contact-add-popup/related-contact-add-popup.component'; + +const routes: Routes = [ + {path: 'list', component: ContactActivityComponent}, + {path: 'new', component: ContactNewPopupComponent}, + {path: ':id', component: ContactViewComponent}, + {path: ':id/add-related-contact', component: RelatedContactAddPopupComponent}, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ContactRoutingModule { +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.html b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.html new file mode 100644 index 000000000..7a7fef52f --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.html @@ -0,0 +1,46 @@ +
+ + + + + + + + + + + + + + + + + + + +
+ +
+

Related contacts

+ +
+ + + + + + {{relatedContact.firstname}} {{relatedContact.lastname}}, {{relatedContact.city}} + + + + + + + diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.scss b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.scss new file mode 100644 index 000000000..76b6ce118 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.scss @@ -0,0 +1,48 @@ +@import 'common'; + +:host { + display: flex; + flex-direction: column; + padding: app-padding(); + + > form { + flex: none; + display: grid; + grid-template-columns: minmax(80px, 120px) auto; + grid-column-gap: 1em; + grid-row-gap: .5em; + grid-template-rows: auto; + + border: 1px solid accentColor(.25); + border-radius: 5px; + padding: 1em; + @include grid-container-align-items(center); + + > nav.communications { + grid-column: 1/3; + display: flex; + flex-direction: column; + align-items: flex-start; + + > * { + margin: 0.5em 0; + } + } + } + + > header { + flex: none; + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 2em; + + > h2 { + font-size: 1.1em; + } + } + + > sci-list.related-contacts { + flex: auto; + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.ts new file mode 100644 index 000000000..fb8f5b477 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact-view/contact-view.component.ts @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, OnDestroy, TrackByFunction } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; +import { ContactService, filterContacts } from '../contact.service'; +import { provideWorkbenchView, WorkbenchRouter, WorkbenchView } from '@scion/workbench-application.angular'; +import { Popup, PopupService } from '@scion/workbench-application.core'; +import { Contact } from '../contact.model'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +const FIRSTNAME = 'firstname'; +const LASTNAME = 'lastname'; +const STREET = 'street'; +const CITY = 'city'; +const EMAIL = 'email'; +const PHONE = 'phone'; +const RELATED_PERSON_IDS = 'related-contact-ids'; + +@Component({ + selector: 'app-contact-view', + templateUrl: './contact-view.component.html', + styleUrls: ['./contact-view.component.scss'], + providers: [ + provideWorkbenchView(ContactViewComponent) + ] +}) +export class ContactViewComponent implements OnDestroy { + + public readonly FIRSTNAME = FIRSTNAME; + public readonly LASTNAME = LASTNAME; + public readonly STREET = STREET; + public readonly CITY = CITY; + public readonly EMAIL = EMAIL; + public readonly PHONE = PHONE; + + private _destroy$ = new Subject(); + private _relatedContactFilter$ = new BehaviorSubject(null); + + public form: FormGroup; + public contact: Contact; + public relatedContacts$: Observable; + + constructor(route: ActivatedRoute, + private _contactService: ContactService, + private _view: WorkbenchView, + private _router: WorkbenchRouter, + formBuilder: FormBuilder, + private _popupService: PopupService) { + this._view.heading = 'Contact'; + this.form = new FormGroup({ + [FIRSTNAME]: formBuilder.control('', Validators.required), + [LASTNAME]: formBuilder.control('', Validators.required), + [STREET]: formBuilder.control('', Validators.required), + [CITY]: formBuilder.control('', Validators.required), + [EMAIL]: formBuilder.control('', Validators.email), + [PHONE]: formBuilder.control(''), + [RELATED_PERSON_IDS]: formBuilder.control([]), + }); + + route.params + .pipe( + map(params => params['id']), + distinctUntilChanged(), + switchMap(id => this.load$(id)), + takeUntil(this._destroy$), + ) + .subscribe(); + + this.form.statusChanges + .pipe( + filter(() => this.form.valid), + switchMap(() => this.store$()), + takeUntil(this._destroy$), + ) + .subscribe(); + } + + private load$(contactId: string): Observable { + return this._contactService.contact$(contactId).pipe(tap((contact: Contact) => { + this.contact = contact; + this._view.title = `${this.contact.firstname} ${this.contact.lastname}`; + this.form.controls[FIRSTNAME].setValue(contact.firstname, {emitEvent: false}); + this.form.controls[LASTNAME].setValue(contact.lastname, {emitEvent: false}); + this.form.controls[STREET].setValue(contact.street, {emitEvent: false}); + this.form.controls[CITY].setValue(contact.city, {emitEvent: false}); + this.form.controls[EMAIL].setValue(contact.email, {emitEvent: false}); + this.form.controls[PHONE].setValue(contact.phone, {emitEvent: false}); + this.form.controls[RELATED_PERSON_IDS].setValue(contact.relatedContactIds, {emitEvent: false}); + this.relatedContacts$ = combineLatest(this._relatedContactFilter$, this._contactService.contacts$(contact.relatedContactIds)).pipe(filterContacts()); + }) + ); + } + + private store$(): Observable { + return this._contactService.update$({ + id: this.contact.id, + firstname: this.form.controls[FIRSTNAME].value, + lastname: this.form.controls[LASTNAME].value, + street: this.form.controls[STREET].value, + city: this.form.controls[CITY].value, + email: this.form.controls[EMAIL].value, + phone: this.form.controls[PHONE].value, + relatedContactIds: this.form.controls[RELATED_PERSON_IDS].value, + }); + } + + public onRelatedContactsFilter(filterText: string): void { + this._relatedContactFilter$.next(filterText); + } + + public onRelatedContactAdd(event: MouseEvent): void { + event.preventDefault(); + const popup: Popup = { + position: 'west', + anchor: event.target as Element, + }; + this._popupService.open(popup, { + 'entity': 'contact', + 'id': this.contact.id, + 'action': 'add-related-contact', + }); + } + + public onCommunicationsOpen(event: MouseEvent): void { + event.preventDefault(); + + this._router.navigate({ + entity: 'communication', + presentation: 'list', + contactId: this.contact.id + }, + { + matrixParams: { + contactFullName: `${this.contact.firstname} ${this.contact.lastname}` + } + } + ); + } + + public onCommunicationAdd(event: MouseEvent): void { + event.preventDefault(); + const popup: Popup = { + position: 'east', + anchor: event.target as Element, + }; + this._popupService.open(popup, { + entity: 'communication', + action: 'create', + contactId: this.contact.id + }); + } + + public onRelatedContactRemove(relatedContactId: string): void { + const relatedContactIds: string[] = this.form.controls[RELATED_PERSON_IDS].value; + this.form.controls[RELATED_PERSON_IDS].setValue(relatedContactIds.filter(it => it !== relatedContactId)); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } + + public contactTrackByFn: TrackByFunction = (index: number, contact: Contact): any => { + return contact.id; + }; +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.model.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.model.ts new file mode 100644 index 000000000..3da0f124f --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.model.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +export interface Contact { + id: string; + firstname: string; + lastname: string; + email: string; + phone: string; + street: string; + city: string; + relatedContactIds: string[]; +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.module.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.module.ts new file mode 100644 index 000000000..7b45f4b75 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.module.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciViewportModule } from '@scion/viewport'; +import { ContactRoutingModule } from './contact-routing.module'; +import { ReactiveFormsModule } from '@angular/forms'; +import { WorkbenchApplicationModule } from '@scion/workbench-application.angular'; +import { HttpClientModule } from '@angular/common/http'; +import { ContactActivityComponent } from './contact-activity/contact-activity.component'; +import { ContactViewComponent } from './contact-view/contact-view.component'; +import { ContactNewPopupComponent } from './contact-new-popup/contact-new-popup.component'; +import { RelatedContactAddPopupComponent } from './related-contact-add-popup/related-contact-add-popup.component'; +import { SciFilterFieldModule, SciListModule, SciPopupShellModule, SciSessionStorageModule } from '@scion/e2e/common'; +import { ContactService } from './contact.service'; + +@NgModule({ + declarations: [ + ContactActivityComponent, + ContactViewComponent, + ContactNewPopupComponent, + RelatedContactAddPopupComponent, + ], + imports: [ + CommonModule, + SciViewportModule, + ContactRoutingModule, + SciPopupShellModule, + SciSessionStorageModule, + SciFilterFieldModule, + SciListModule, + ReactiveFormsModule, + HttpClientModule, + WorkbenchApplicationModule.forChild(), + ], + exports: [], + providers: [ + ContactService + ] +}) +export class ContactModule { +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.service.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.service.ts new file mode 100644 index 000000000..cd1f78b04 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/contact.service.ts @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Injectable, OnDestroy } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { filter, map, mergeMapTo, take, tap } from 'rxjs/operators'; +import { EMPTY, MonoTypeOperatorFunction, Observable, OperatorFunction, Subject } from 'rxjs'; +import { SciSessionStorageService, toFilterRegExp } from '@scion/e2e/common'; +import { Contact } from './contact.model'; +import { WorkbenchRouter } from '@scion/workbench-application.angular'; + +const PERSONS_STORAGE_KEY = 'contact.data'; + +@Injectable() +export class ContactService implements OnDestroy { + + private _destroy$ = new Subject(); + private _contacts$: Observable; + + constructor(httpClient: HttpClient, private _storage: SciSessionStorageService, private _router: WorkbenchRouter) { + this._contacts$ = this._storage.observe$(PERSONS_STORAGE_KEY, () => { + return httpClient.get('assets/contact.data.json').pipe(mapToContactDictionary()); + }); + } + + public contact$(id: string, options?: {once: boolean}): Observable { + return this._contacts$ + .pipe( + options && options.once ? take(1) : tap(), + map(dictionary => dictionary[id]), + filter(Boolean) + ); + } + + public contacts$(ids?: string[]): Observable { + return this._contacts$.pipe(mapToFilteredContactArray(ids)); + } + + public create$(contact: Contact): Observable { + return this._contacts$ + .pipe( + once(), + putContact(this._storage, contact), + mergeMapTo(EMPTY), + ); + } + + public update$(contact: Contact): Observable { + return this._contacts$ + .pipe( + once(), + putContact(this._storage, contact), + mergeMapTo(EMPTY), + ); + } + + public delete$(id: string): Observable { + return this._contacts$ + .pipe( + once(), + deleteContact(this._storage, id), + tap(() => this._router.navigate({entity: 'contact', id}, {closeIfPresent: true})), + mergeMapTo(EMPTY), + ); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} + +interface ContactDictionary { + [key: string]: any; +} + +function mapToContactDictionary(): OperatorFunction { + return map((contacts: Contact[]): ContactDictionary => { + return contacts.reduce((acc, contact) => ({...acc, ...{[contact.id]: contact}}), {}); + }); +} + +function mapToFilteredContactArray(ids: string[]): OperatorFunction { + return map((dictionary: ContactDictionary): Contact[] => { + return (ids || Object.keys(dictionary)) + .map(id => dictionary[id]) + .filter(Boolean) + .reduce((acc, contact) => [...acc, contact], [] as Contact[]) + .sort((p1, p2) => p1.firstname.localeCompare(p2.firstname)); + }); +} + +function putContact(storage: SciSessionStorageService, contact: Contact): MonoTypeOperatorFunction { + return tap((dictionary: ContactDictionary): void => { + dictionary[contact.id] = contact; + storage.put(PERSONS_STORAGE_KEY, dictionary); + }); +} + +function deleteContact(storage: SciSessionStorageService, id: string): MonoTypeOperatorFunction { + return tap((dictionary: ContactDictionary): void => { + delete dictionary[id]; + storage.put(PERSONS_STORAGE_KEY, dictionary); + }); +} + +function once(): MonoTypeOperatorFunction { + return take(1); +} + +export function filterContacts(): OperatorFunction<[string, Contact[]], Contact[]> { + return map(([filterText, contacts]: [string, Contact[]]): Contact[] => { + if (!filterText) { + return contacts; + } + + const filterRegExp = toFilterRegExp(filterText); + return contacts.filter(contact => filterRegExp.test(contact.firstname) || filterRegExp.test(contact.lastname) || filterRegExp.test(contact.city)); + }); +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.html b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.html new file mode 100644 index 000000000..dfda0e800 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.html @@ -0,0 +1,16 @@ + + Add related contact + + + + + {{contact.firstname}} {{contact.lastname}}
+ {{contact.city}} +
+
+
+ + OK +
diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.scss b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.scss new file mode 100644 index 000000000..b5bef06d6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.scss @@ -0,0 +1,12 @@ +:host { + display: flex; + flex-direction: column; + + > sci-popup-shell { + flex: auto; + + sci-list { + flex: auto; + } + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.ts b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.ts new file mode 100644 index 000000000..6fb5829f1 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/app/contact/related-contact-add-popup/related-contact-add-popup.component.ts @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, OnDestroy, TrackByFunction } from '@angular/core'; +import { provideWorkbenchPopup, WorkbenchPopup } from '@scion/workbench-application.angular'; +import { ContactService, filterContacts } from '../contact.service'; +import { BehaviorSubject, combineLatest, noop, Observable, Subject } from 'rxjs'; +import { ActivatedRoute } from '@angular/router'; +import { switchMap, takeUntil } from 'rxjs/operators'; +import { Contact } from '../contact.model'; + +@Component({ + selector: 'app-related-contact-add-popup', + templateUrl: './related-contact-add-popup.component.html', + styleUrls: ['./related-contact-add-popup.component.scss'], + providers: [ + provideWorkbenchPopup(RelatedContactAddPopupComponent) + ] +}) +export class RelatedContactAddPopupComponent implements OnDestroy { + + private _destroy$ = new Subject(); + private _relatedContactId: string; + private _filter$ = new BehaviorSubject(null); + + public contacts$: Observable; + + constructor(private _route: ActivatedRoute, + private _popup: WorkbenchPopup, + private _contactService: ContactService) { + this.contacts$ = combineLatest(this._filter$, this._contactService.contacts$()).pipe(filterContacts()); + } + + public onOption(relatedContactId: string): void { + this._relatedContactId = relatedContactId; + } + + public onOk(): void { + this._contactService.contact$(this._route.snapshot.params['id'], {once: true}) + .pipe( + switchMap(contact => this._contactService.update$({...contact, relatedContactIds: [...contact.relatedContactIds, this._relatedContactId]})), + takeUntil(this._destroy$), + ) + .subscribe(noop, noop, () => this._popup.close()); + } + + public onFilter(filterText: string): void { + this._filter$.next(filterText); + } + + public get valid(): boolean { + return !!this._relatedContactId; + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } + + public trackByFn: TrackByFunction = (index: number, contact: Contact): any => { + return contact.id; + }; +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/assets/.gitkeep b/projects/e2e/workbench-application-platform/contact-app/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/projects/e2e/workbench-application-platform/contact-app/src/assets/contact.data.json b/projects/e2e/workbench-application-platform/contact-app/src/assets/contact.data.json new file mode 100644 index 000000000..586c4df12 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/assets/contact.data.json @@ -0,0 +1,2740 @@ +[ + { + "id": "1", + "firstname": "Marley", + "lastname": "Chidzoy", + "email": "mchidzoy0@oracle.com", + "phone": "424-561-5508", + "street": "08 Monterey Court", + "city": "New York", + "relatedContactIds": [ + "17", + "1", + "13", + "5", + "91", + "57", + "44", + "32", + "4", + "16", + "86", + "43", + "40", + "67", + "13", + "65", + "22", + "86", + "11", + "27", + "94", + "82", + "91", + "84", + "80", + "61", + "80", + "11", + "5" + ] + }, + { + "id": "2", + "firstname": "Arlen", + "lastname": "Bossel", + "email": "abossel1@bandcamp.com", + "phone": "205-853-0895", + "street": "1 Moulton Terrace", + "city": "Los Angeles", + "relatedContactIds": [ + "48", + "26", + "43", + "92", + "70", + "25", + "78", + "30" + ] + }, + { + "id": "3", + "firstname": "Sigismond", + "lastname": "Mulqueeny", + "email": "smulqueeny2@oaic.gov.au", + "phone": "737-861-1860", + "street": "15 Hintze Point", + "city": "Chicago", + "relatedContactIds": [ + "33", + "97", + "82", + "88", + "76", + "99", + "16", + "39", + "18", + "75", + "38", + "11", + "52", + "79" + ] + }, + { + "id": "4", + "firstname": "Brooke", + "lastname": "Hulmes", + "email": "bhulmes3@1und1.de", + "phone": "667-900-2300", + "street": "5 Moland Lane", + "city": "Houston", + "relatedContactIds": [ + "82", + "7", + "95", + "63", + "16", + "47", + "14", + "37", + "14", + "72", + "53", + "11" + ] + }, + { + "id": "5", + "firstname": "Robbie", + "lastname": "Bannon", + "email": "rbannon4@ebay.co.uk", + "phone": "127-927-7189", + "street": "685 Hansons Pass", + "city": "Philadelphia", + "relatedContactIds": [ + "30", + "96", + "93", + "6", + "100", + "85", + "100", + "95", + "11", + "75", + "88", + "35", + "26", + "49", + "96", + "36", + "21", + "87", + "18", + "53" + ] + }, + { + "id": "6", + "firstname": "Chastity", + "lastname": "Schumacher", + "email": "cschumacher5@youtube.com", + "phone": "627-896-4939", + "street": "2 Badeau Center", + "city": "Phoenix", + "relatedContactIds": [ + "45", + "99", + "90", + "35", + "58", + "49", + "35", + "45", + "14", + "88", + "33", + "89", + "54", + "11", + "35", + "98", + "40", + "22", + "51", + "52", + "33" + ] + }, + { + "id": "7", + "firstname": "Ric", + "lastname": "Spelsbury", + "email": "rspelsbury6@over-blog.com", + "phone": "120-113-6252", + "street": "52558 Del Sol Road", + "city": "San Antonio", + "relatedContactIds": [ + "27", + "67", + "13", + "31", + "60", + "10", + "82", + "56", + "72", + "1", + "27", + "53", + "88", + "8", + "52", + "36", + "72", + "15", + "56", + "58", + "26", + "13", + "65", + "40", + "35", + "75", + "2", + "18" + ] + }, + { + "id": "8", + "firstname": "Sherilyn", + "lastname": "Baselio", + "email": "sbaselio7@dion.ne.jp", + "phone": "336-625-1423", + "street": "19 Carey Point", + "city": "San Diego", + "relatedContactIds": [ + "79", + "60", + "89", + "43", + "4", + "37", + "82", + "39", + "54", + "58", + "45", + "9", + "20", + "51", + "42", + "3", + "57", + "93", + "97", + "4", + "81" + ] + }, + { + "id": "9", + "firstname": "Allianora", + "lastname": "Boldt", + "email": "aboldt8@cpanel.net", + "phone": "308-983-4275", + "street": "41 Blaine Road", + "city": "Dallas", + "relatedContactIds": [ + "4", + "66", + "84", + "1", + "83", + "84", + "70", + "45", + "21", + "33", + "69", + "49", + "72", + "19", + "30", + "47", + "6", + "86", + "60", + "67", + "7", + "82", + "6", + "81", + "99", + "11" + ] + }, + { + "id": "10", + "firstname": "Priscilla", + "lastname": "Duffitt", + "email": "pduffitt9@economist.com", + "phone": "919-470-6524", + "street": "967 Blaine Center", + "city": "10", + "relatedContactIds": [ + "8", + "50", + "57", + "11", + "25", + "43", + "39", + "13", + "5", + "20", + "19", + "57" + ] + }, + { + "id": "11", + "firstname": "Darcy", + "lastname": "Hammelberg", + "email": "dhammelberga@thetimes.co.uk", + "phone": "944-291-7076", + "street": "21621 Merry Trail", + "city": "New York", + "relatedContactIds": [ + "1", + "53", + "53", + "3", + "88", + "56", + "49", + "47", + "38", + "39", + "64", + "51", + "15", + "27", + "35", + "97" + ] + }, + { + "id": "12", + "firstname": "Kennie", + "lastname": "Klessmann", + "email": "kklessmannb@pagesperso-orange.fr", + "phone": "199-728-6721", + "street": "17 Garrison Circle", + "city": "New York", + "relatedContactIds": [ + "35" + ] + }, + { + "id": "13", + "firstname": "Zorana", + "lastname": "Jankovic", + "email": "zjankovicc@paypal.com", + "phone": "760-147-5671", + "street": "311 Del Mar Park", + "city": "New York", + "relatedContactIds": [ + "57", + "73", + "79", + "5", + "45", + "22", + "99", + "39", + "19", + "23", + "68", + "47", + "8", + "51", + "12", + "49", + "19" + ] + }, + { + "id": "14", + "firstname": "Cheryl", + "lastname": "Mattea", + "email": "cmattead@webs.com", + "phone": "356-935-1878", + "street": "7774 Crescent Oaks Road", + "city": "New York", + "relatedContactIds": [ + "3", + "12", + "24", + "96", + "64", + "2", + "94", + "35", + "93", + "93", + "46", + "74", + "82", + "48", + "18", + "6", + "28", + "17", + "16" + ] + }, + { + "id": "15", + "firstname": "Clarke", + "lastname": "Noden", + "email": "cnodene@google.ru", + "phone": "839-291-9187", + "street": "37 Anhalt Street", + "city": "New York", + "relatedContactIds": [ + "6", + "97", + "66", + "61", + "36", + "74", + "38", + "76", + "86", + "25", + "37", + "42", + "90", + "91", + "27" + ] + }, + { + "id": "16", + "firstname": "Giralda", + "lastname": "Fackrell", + "email": "gfackrellf@ucsd.edu", + "phone": "996-969-6842", + "street": "56509 Tennyson Park", + "city": "New York", + "relatedContactIds": [ + "41", + "86", + "75", + "49", + "92", + "93", + "47", + "96", + "26", + "57", + "76", + "75", + "55", + "5", + "88", + "21", + "25", + "4", + "87", + "11", + "63", + "16", + "51", + "70", + "65" + ] + }, + { + "id": "17", + "firstname": "Sheppard", + "lastname": "Bolstridge", + "email": "sbolstridgeg@wsj.com", + "phone": "982-513-7145", + "street": "00358 Monterey Terrace", + "city": "New York", + "relatedContactIds": [ + "15", + "70", + "35", + "17", + "3", + "61", + "88", + "86", + "93", + "46", + "3" + ] + }, + { + "id": "18", + "firstname": "Garvey", + "lastname": "McKinnon", + "email": "gmckinnonh@hatena.ne.jp", + "phone": "281-541-9252", + "street": "50809 High Crossing Alley", + "city": "Fort Worth", + "relatedContactIds": [ + "21", + "49", + "20", + "44", + "47", + "16", + "73", + "5", + "84", + "57", + "61", + "63", + "67", + "99", + "45", + "9", + "24", + "39", + "18", + "66" + ] + }, + { + "id": "19", + "firstname": "Elden", + "lastname": "Ring", + "email": "eringi@g.co", + "phone": "265-527-5671", + "street": "62470 Gina Plaza", + "city": "Fort Worth", + "relatedContactIds": [ + "7", + "3", + "62", + "24", + "60", + "10", + "6", + "21" + ] + }, + { + "id": "20", + "firstname": "Connie", + "lastname": "Ceschi", + "email": "cceschij@cafepress.com", + "phone": "687-266-4082", + "street": "70972 Stuart Avenue", + "city": "Fort Worth", + "relatedContactIds": [ + "73", + "23", + "74", + "55", + "65", + "95", + "45", + "4", + "21", + "99", + "56", + "92", + "83", + "26", + "66", + "86", + "26", + "67", + "90", + "68", + "70", + "38", + "100", + "79", + "64", + "37", + "46", + "94" + ] + }, + { + "id": "21", + "firstname": "Charmion", + "lastname": "Phillipp", + "email": "cphillippk@elpais.com", + "phone": "749-465-6113", + "street": "489 Lindbergh Parkway", + "city": "Fort Worth", + "relatedContactIds": [ + "71", + "92", + "74", + "72", + "37", + "24", + "55", + "42", + "29", + "92", + "64", + "29", + "32", + "100", + "52", + "33", + "52", + "33", + "68", + "93", + "77", + "77", + "23", + "69", + "75", + "59", + "42" + ] + }, + { + "id": "22", + "firstname": "Dane", + "lastname": "Palay", + "email": "dpalayl@howstuffworks.com", + "phone": "695-766-3982", + "street": "5444 Clyde Gallagher Terrace", + "city": "Fort Worth", + "relatedContactIds": [ + "2", + "62", + "10", + "76", + "11", + "89", + "74", + "32", + "4", + "27", + "27", + "50", + "79", + "89", + "93", + "57", + "91", + "89", + "13", + "41", + "49", + "13", + "67", + "96", + "77" + ] + }, + { + "id": "23", + "firstname": "Devy", + "lastname": "Bulleyn", + "email": "dbulleynm@ehow.com", + "phone": "996-426-0038", + "street": "7330 Novick Parkway", + "city": "Fort Worth", + "relatedContactIds": [ + "33", + "60", + "93", + "47", + "3", + "39", + "20", + "11", + "34", + "19", + "90", + "52", + "87", + "86", + "74", + "84", + "29", + "56", + "73", + "65", + "23", + "78", + "33", + "88", + "92", + "30", + "76", + "92", + "89", + "57" + ] + }, + { + "id": "24", + "firstname": "Marlo", + "lastname": "Angus", + "email": "mangusn@ted.com", + "phone": "693-385-3039", + "street": "2458 Mandrake Park", + "city": "Detroit", + "relatedContactIds": [ + "99", + "7", + "68", + "78", + "41", + "91", + "7", + "36", + "31", + "25", + "65", + "77", + "19", + "1", + "62", + "96", + "95", + "47", + "87", + "41", + "17", + "42", + "38" + ] + }, + { + "id": "25", + "firstname": "Cassandra", + "lastname": "Ingerson", + "email": "cingersono@hc360.com", + "phone": "172-961-9547", + "street": "1832 Northport Place", + "city": "Detroit", + "relatedContactIds": [ + "23", + "7", + "100", + "77", + "21", + "7", + "5", + "39", + "64", + "32", + "23", + "84", + "54", + "66", + "59", + "26", + "7", + "77", + "22", + "14", + "88", + "83", + "4", + "18", + "52", + "68" + ] + }, + { + "id": "26", + "firstname": "Felix", + "lastname": "Lilley", + "email": "flilleyp@cocolog-nifty.com", + "phone": "163-958-5543", + "street": "93585 Grasskamp Junction", + "city": "Detroit", + "relatedContactIds": [ + "44", + "71", + "53", + "67", + "100", + "100" + ] + }, + { + "id": "27", + "firstname": "Brigham", + "lastname": "Fidell", + "email": "bfidellq@quantcast.com", + "phone": "916-782-2894", + "street": "55067 Emmet Terrace", + "city": "Detroit", + "relatedContactIds": [ + "22", + "31" + ] + }, + { + "id": "28", + "firstname": "Darrell", + "lastname": "Yo", + "email": "dyor@psu.edu", + "phone": "829-854-6749", + "street": "3370 Moland Alley", + "city": "El Paso", + "relatedContactIds": [ + "45", + "71", + "4", + "83", + "25", + "52", + "62", + "29", + "74", + "30", + "73", + "1", + "87", + "18", + "38", + "47", + "14", + "43", + "56", + "64", + "25", + "3", + "54", + "72", + "33", + "5", + "9" + ] + }, + { + "id": "29", + "firstname": "Forster", + "lastname": "O'Gaven", + "email": "fogavens@auda.org.au", + "phone": "410-837-5493", + "street": "0 Sunnyside Junction", + "city": "El Paso", + "relatedContactIds": [ + "21", + "16", + "10", + "79", + "71", + "34", + "89", + "10", + "80", + "44", + "96", + "93", + "93", + "2", + "91", + "14", + "85", + "39", + "25", + "91" + ] + }, + { + "id": "30", + "firstname": "Fayina", + "lastname": "Durtnall", + "email": "fdurtnallt@creativecommons.org", + "phone": "613-332-4522", + "street": "49 Cascade Circle", + "city": "El Paso", + "relatedContactIds": [ + "66", + "14", + "87", + "20", + "1", + "41", + "91", + "23", + "30", + "19", + "29", + "56", + "43", + "63", + "55", + "83" + ] + }, + { + "id": "31", + "firstname": "Woodie", + "lastname": "Thompson", + "email": "wthompsonu@wp.com", + "phone": "218-925-3687", + "street": "3 Monument Parkway", + "city": "El Paso", + "relatedContactIds": [ + "89", + "79", + "22", + "59", + "6", + "49" + ] + }, + { + "id": "32", + "firstname": "Ozzy", + "lastname": "Emanuele", + "email": "oemanuelev@google.co.jp", + "phone": "580-405-2775", + "street": "0 American Ash Way", + "city": "El Paso", + "relatedContactIds": [ + "21", + "42", + "100", + "2", + "21", + "35", + "10", + "63", + "60", + "12", + "74", + "12", + "36", + "81", + "96", + "31", + "74", + "30" + ] + }, + { + "id": "33", + "firstname": "Reggis", + "lastname": "Silverston", + "email": "rsilverstonw@blogspot.com", + "phone": "181-855-1848", + "street": "16369 Rieder Road", + "city": "Memphis", + "relatedContactIds": [ + "31", + "29" + ] + }, + { + "id": "34", + "firstname": "Shane", + "lastname": "Hounsom", + "email": "shounsomx@sbwire.com", + "phone": "639-282-0481", + "street": "2564 Melrose Way", + "city": "Memphis", + "relatedContactIds": [ + "79", + "85", + "50", + "75", + "87", + "11", + "89", + "37", + "5", + "78", + "11", + "41", + "54", + "92", + "46", + "95", + "93", + "63", + "45", + "35", + "66", + "16", + "62", + "100", + "86", + "98" + ] + }, + { + "id": "35", + "firstname": "Audi", + "lastname": "Marriott", + "email": "amarriotty@vistaprint.com", + "phone": "394-428-1689", + "street": "189 Alpine Point", + "city": "Memphis", + "relatedContactIds": [ + "1", + "4", + "99", + "19", + "45", + "18", + "14", + "24", + "73", + "68", + "41", + "44", + "3", + "83", + "16", + "94", + "24", + "36", + "51", + "84", + "45", + "54", + "33", + "43", + "47", + "73", + "10", + "99" + ] + }, + { + "id": "36", + "firstname": "Starlin", + "lastname": "Stidston", + "email": "sstidstonz@scientificamerican.com", + "phone": "906-227-3210", + "street": "827 Blaine Point", + "city": "Memphis", + "relatedContactIds": [ + "23", + "45", + "79", + "93", + "23" + ] + }, + { + "id": "37", + "firstname": "Nathan", + "lastname": "Scrogges", + "email": "nscrogges10@gnu.org", + "phone": "154-685-9931", + "street": "886 Service Circle", + "city": "Memphis", + "relatedContactIds": [ + "62", + "38", + "94", + "97" + ] + }, + { + "id": "38", + "firstname": "Adeline", + "lastname": "McEnhill", + "email": "amcenhill11@baidu.com", + "phone": "727-842-2730", + "street": "0 Annamark Place", + "city": "Seattle", + "relatedContactIds": [ + "63", + "95", + "11", + "46", + "61", + "44", + "59", + "1", + "92", + "86", + "11", + "47", + "78", + "9", + "64", + "24", + "76", + "54", + "44", + "71", + "73", + "42", + "1", + "4", + "10", + "54", + "90", + "37", + "64" + ] + }, + { + "id": "39", + "firstname": "Alaster", + "lastname": "Sancto", + "email": "asancto12@prnewswire.com", + "phone": "409-222-0492", + "street": "8 Doe Crossing Center", + "city": "Seattle", + "relatedContactIds": [ + "98", + "11", + "78", + "33", + "57", + "85", + "81", + "38", + "10", + "41", + "77", + "17", + "74", + "52", + "86", + "27", + "86", + "62", + "100" + ] + }, + { + "id": "40", + "firstname": "Garret", + "lastname": "Turnock", + "email": "gturnock13@cbslocal.com", + "phone": "287-728-4389", + "street": "947 Utah Junction", + "city": "Seattle", + "relatedContactIds": [ + "13", + "98", + "30", + "16", + "99", + "43", + "53", + "40" + ] + }, + { + "id": "41", + "firstname": "Nappy", + "lastname": "Lenaghen", + "email": "nlenaghen14@delicious.com", + "phone": "786-344-7171", + "street": "54 Marquette Avenue", + "city": "Seattle", + "relatedContactIds": [ + "34", + "69", + "25", + "42", + "19", + "48", + "48", + "28", + "52", + "32", + "69", + "78", + "74", + "86", + "43", + "35", + "62", + "32", + "43", + "16" + ] + }, + { + "id": "42", + "firstname": "Eberhard", + "lastname": "Dawltrey", + "email": "edawltrey15@weather.com", + "phone": "374-975-6888", + "street": "1 Anhalt Trail", + "city": "Seattle", + "relatedContactIds": [ + "44", + "85", + "30" + ] + }, + { + "id": "43", + "firstname": "Sarette", + "lastname": "Bateson", + "email": "sbateson16@163.com", + "phone": "497-657-1837", + "street": "986 Dennis Way", + "city": "Seattle", + "relatedContactIds": [ + "3", + "92", + "100", + "78", + "9", + "22", + "62", + "5", + "69", + "2", + "52", + "49", + "91", + "7", + "60", + "41", + "26", + "41" + ] + }, + { + "id": "44", + "firstname": "Katha", + "lastname": "Seamon", + "email": "kseamon17@nationalgeographic.com", + "phone": "913-934-5362", + "street": "64 Burrows Plaza", + "city": "Denver", + "relatedContactIds": [ + "61", + "11", + "2", + "19", + "18", + "61", + "63", + "82" + ] + }, + { + "id": "45", + "firstname": "Nanny", + "lastname": "Schwand", + "email": "nschwand18@blog.com", + "phone": "286-800-6111", + "street": "978 Butternut Alley", + "city": "Denver", + "relatedContactIds": [ + "24", + "24", + "63", + "75", + "7", + "78", + "98", + "39", + "29", + "94" + ] + }, + { + "id": "46", + "firstname": "Prent", + "lastname": "Remer", + "email": "premer19@pagesperso-orange.fr", + "phone": "907-185-4077", + "street": "77 Scott Way", + "city": "Denver", + "relatedContactIds": [ + "94", + "55" + ] + }, + { + "id": "47", + "firstname": "Brendon", + "lastname": "Bickerton", + "email": "bbickerton1a@nhs.uk", + "phone": "709-973-0138", + "street": "0494 Scoville Street", + "city": "Denver", + "relatedContactIds": [ + "17", + "92", + "6", + "27", + "21", + "24", + "51", + "83", + "43", + "81", + "61", + "93", + "60", + "61", + "75", + "68", + "61", + "93" + ] + }, + { + "id": "48", + "firstname": "Cyndia", + "lastname": "Christofides", + "email": "cchristofides1b@slashdot.org", + "phone": "920-603-4653", + "street": "0 Briar Crest Circle", + "city": "Denver", + "relatedContactIds": [ + "47", + "20", + "58", + "56", + "58", + "92", + "48", + "92", + "92", + "94", + "29", + "70", + "39", + "62", + "64", + "35", + "77", + "55" + ] + }, + { + "id": "49", + "firstname": "Lyon", + "lastname": "Vannoort", + "email": "lvannoort1c@istockphoto.com", + "phone": "821-630-4226", + "street": "57 Colorado Parkway", + "city": "Denver", + "relatedContactIds": [ + "88", + "52", + "53", + "83", + "92", + "62", + "60", + "56", + "54", + "22" + ] + }, + { + "id": "50", + "firstname": "Riane", + "lastname": "Peniman", + "email": "rpeniman1d@google.ru", + "phone": "473-151-6582", + "street": "6 Harbort Road", + "city": "Washington", + "relatedContactIds": [ + "26", + "57", + "1" + ] + }, + { + "id": "51", + "firstname": "Sidoney", + "lastname": "Ainscow", + "email": "sainscow1e@mayoclinic.com", + "phone": "981-848-5913", + "street": "47 Vernon Hill", + "city": "Washington", + "relatedContactIds": [ + "79", + "68", + "54", + "62", + "24", + "36", + "28", + "92", + "84", + "41" + ] + }, + { + "id": "52", + "firstname": "Jaime", + "lastname": "Rastall", + "email": "jrastall1f@infoseek.co.jp", + "phone": "129-755-7965", + "street": "8 Di Loreto Plaza", + "city": "Washington", + "relatedContactIds": [ + "10", + "28", + "71", + "10", + "87", + "79", + "66", + "3", + "71", + "27", + "19", + "49", + "18", + "40", + "52", + "69", + "70", + "82", + "90", + "55", + "29" + ] + }, + { + "id": "53", + "firstname": "Cliff", + "lastname": "Bowmer", + "email": "cbowmer1g@google.it", + "phone": "670-665-7680", + "street": "8820 Charing Cross Drive", + "city": "Washington", + "relatedContactIds": [ + "66", + "58", + "63", + "7", + "46", + "64", + "36", + "56", + "20", + "28", + "78", + "94", + "2", + "28", + "96" + ] + }, + { + "id": "54", + "firstname": "Alli", + "lastname": "Astlet", + "email": "aastlet1h@google.com.br", + "phone": "690-185-6023", + "street": "37 Kropf Point", + "city": "Washington", + "relatedContactIds": [ + "88", + "43", + "80", + "30", + "35", + "30", + "79", + "10", + "79" + ] + }, + { + "id": "55", + "firstname": "Stacia", + "lastname": "Aspinell", + "email": "saspinell1i@netscape.com", + "phone": "690-252-1053", + "street": "37983 Vernon Place", + "city": "Boston", + "relatedContactIds": [ + "78", + "19", + "36", + "51", + "21", + "52", + "47", + "28", + "66", + "80", + "26", + "17", + "27", + "59", + "90", + "60", + "94", + "33", + "23" + ] + }, + { + "id": "56", + "firstname": "Cristal", + "lastname": "Heining", + "email": "cheining1j@apache.org", + "phone": "652-391-3748", + "street": "8979 Arapahoe Plaza", + "city": "Boston", + "relatedContactIds": [ + "62", + "41", + "24", + "69", + "40", + "52" + ] + }, + { + "id": "57", + "firstname": "Urbain", + "lastname": "Robelet", + "email": "urobelet1k@amazon.com", + "phone": "302-990-8314", + "street": "2 Lotheville Junction", + "city": "Boston", + "relatedContactIds": [ + "87", + "7", + "2", + "99", + "39", + "76", + "92", + "48", + "9", + "59", + "42", + "6", + "58", + "41", + "77", + "96", + "25", + "33", + "44", + "24", + "19", + "73", + "32", + "49", + "47", + "66", + "67", + "8" + ] + }, + { + "id": "58", + "firstname": "Grete", + "lastname": "Powton", + "email": "gpowton1l@360.cn", + "phone": "989-259-5750", + "street": "5784 Sugar Court", + "city": "Boston", + "relatedContactIds": [ + "1", + "13", + "21", + "9", + "88", + "38", + "9", + "80", + "74", + "46", + "88", + "16", + "34", + "2", + "27", + "18", + "1", + "69", + "40", + "66", + "70", + "51", + "60", + "98", + "56", + "21", + "15", + "66", + "3", + "96" + ] + }, + { + "id": "59", + "firstname": "Bernadine", + "lastname": "Antonoczyk", + "email": "bantonoczyk1m@csmonitor.com", + "phone": "635-323-8492", + "street": "8056 Basil Crossing", + "city": "Boston", + "relatedContactIds": [ + "55", + "28", + "77", + "86", + "24" + ] + }, + { + "id": "60", + "firstname": "Carlyn", + "lastname": "Leroux", + "email": "cleroux1n@discovery.com", + "phone": "155-727-0433", + "street": "39 Cordelia Center", + "city": "Boston", + "relatedContactIds": [ + "52", + "83", + "9", + "89", + "6", + "86", + "35", + "77", + "79", + "15", + "60", + "1", + "28", + "66", + "62", + "96", + "95", + "76", + "48", + "2" + ] + }, + { + "id": "61", + "firstname": "Larina", + "lastname": "Southouse", + "email": "lsouthouse1o@symantec.com", + "phone": "144-170-9302", + "street": "58735 Fuller Park", + "city": "Boston", + "relatedContactIds": [ + "16", + "51", + "46", + "95", + "37", + "56", + "50", + "30", + "69", + "77", + "77", + "87", + "82", + "24", + "78", + "88", + "14", + "99", + "86" + ] + }, + { + "id": "62", + "firstname": "Yvon", + "lastname": "Zorer", + "email": "yzorer1p@sogou.com", + "phone": "339-521-0522", + "street": "8 Hintze Road", + "city": "Boston", + "relatedContactIds": [ + "30", + "49", + "3", + "52", + "76", + "88", + "6", + "4", + "43", + "71", + "5", + "29", + "79", + "88", + "84", + "70", + "98", + "65", + "40", + "45", + "81", + "66", + "60", + "81", + "79", + "90", + "1" + ] + }, + { + "id": "63", + "firstname": "Salome", + "lastname": "Edscer", + "email": "sedscer1q@networkadvertising.org", + "phone": "189-468-3364", + "street": "435 Buell Lane", + "city": "Boston", + "relatedContactIds": [ + "47", + "2", + "60", + "88", + "54", + "97", + "15", + "38", + "28", + "94", + "64", + "58", + "53", + "12", + "77", + "37", + "3", + "74", + "28", + "5" + ] + }, + { + "id": "64", + "firstname": "Raynor", + "lastname": "Souter", + "email": "rsouter1r@linkedin.com", + "phone": "606-446-3047", + "street": "1372 Forest Court", + "city": "Boston", + "relatedContactIds": [ + "82", + "32", + "80", + "14", + "6", + "60", + "38", + "85", + "20", + "94", + "4", + "2", + "44", + "89", + "33", + "57", + "85" + ] + }, + { + "id": "65", + "firstname": "Orson", + "lastname": "Gross", + "email": "ogross1s@dmoz.org", + "phone": "218-852-0070", + "street": "54 Burning Wood Circle", + "city": "Boston", + "relatedContactIds": [ + "62", + "57", + "40", + "38", + "93", + "78", + "4", + "78" + ] + }, + { + "id": "66", + "firstname": "Biddie", + "lastname": "Bestwall", + "email": "bbestwall1t@blogspot.com", + "phone": "355-359-3510", + "street": "2681 Hanover Park", + "city": "Nashville", + "relatedContactIds": [ + "20", + "39", + "6", + "8", + "36", + "14", + "51", + "75", + "16", + "23", + "32" + ] + }, + { + "id": "67", + "firstname": "Yul", + "lastname": "Hakonsen", + "email": "yhakonsen1u@booking.com", + "phone": "824-179-8742", + "street": "74332 Schurz Circle", + "city": "Nashville", + "relatedContactIds": [ + "86", + "79", + "38", + "1", + "71", + "61" + ] + }, + { + "id": "68", + "firstname": "Dorice", + "lastname": "Kynvin", + "email": "dkynvin1v@microsoft.com", + "phone": "299-153-8252", + "street": "02823 Brickson Park Pass", + "city": "Nashville", + "relatedContactIds": [ + "98", + "77", + "18", + "39", + "3", + "92", + "19", + "92", + "96", + "68", + "28", + "68", + "70", + "57", + "20", + "42", + "59", + "4", + "37" + ] + }, + { + "id": "69", + "firstname": "Angus", + "lastname": "Berge", + "email": "aberge1w@amazon.de", + "phone": "882-892-3642", + "street": "4 Scoville Terrace", + "city": "Nashville", + "relatedContactIds": [ + "11", + "75", + "12", + "32", + "47", + "92", + "90", + "50", + "86", + "55", + "64", + "69", + "97", + "84", + "66", + "64", + "18", + "2", + "39", + "4", + "97" + ] + }, + { + "id": "70", + "firstname": "Noellyn", + "lastname": "Mercer", + "email": "nmercer1x@bizjournals.com", + "phone": "587-521-2523", + "street": "4856 Declaration Terrace", + "city": "Nashville", + "relatedContactIds": [ + "65", + "18", + "58", + "92", + "47", + "64", + "4", + "88", + "48", + "47", + "31", + "73", + "70", + "63", + "9", + "54", + "6", + "46", + "91", + "61", + "89" + ] + }, + { + "id": "71", + "firstname": "Jarred", + "lastname": "Loader", + "email": "jloader1y@skype.com", + "phone": "167-538-7946", + "street": "12 Warbler Way", + "city": "Nashville", + "relatedContactIds": [ + "4", + "72", + "60", + "68", + "77", + "2", + "35", + "4", + "99", + "98", + "31", + "16", + "72", + "10", + "88", + "4", + "74", + "74", + "65", + "70", + "78", + "21", + "93", + "54" + ] + }, + { + "id": "72", + "firstname": "Etan", + "lastname": "Abate", + "email": "eabate1z@google.pl", + "phone": "183-777-0106", + "street": "14 Vernon Alley", + "city": "Nashville", + "relatedContactIds": [ + "10", + "88", + "95", + "72", + "39", + "56", + "5", + "24", + "49", + "85", + "17", + "6", + "4", + "27", + "24", + "13", + "5", + "71" + ] + }, + { + "id": "73", + "firstname": "Ella", + "lastname": "Burnham", + "email": "eburnham20@google.ca", + "phone": "266-930-2209", + "street": "8588 Maywood Road", + "city": "Nashville", + "relatedContactIds": [ + "99", + "55", + "45", + "25", + "48", + "21", + "51", + "94", + "39", + "72", + "56", + "50" + ] + }, + { + "id": "74", + "firstname": "Enrique", + "lastname": "Moyce", + "email": "emoyce21@furl.net", + "phone": "338-751-0068", + "street": "5883 Corscot Pass", + "city": "Baltimore", + "relatedContactIds": [ + "61", + "18", + "100", + "43", + "29", + "9", + "80", + "41", + "11", + "54", + "75", + "27", + "34", + "79", + "30", + "56", + "66", + "59", + "70", + "11", + "96", + "55", + "67", + "60", + "48", + "86", + "75", + "56", + "90", + "10" + ] + }, + { + "id": "75", + "firstname": "Alvin", + "lastname": "Zambon", + "email": "azambon22@mozilla.com", + "phone": "551-439-1644", + "street": "37947 Gateway Way", + "city": "Baltimore", + "relatedContactIds": [ + "91", + "87", + "3", + "68", + "87", + "78", + "58", + "66", + "30", + "35", + "87", + "39", + "8", + "81", + "60", + "87", + "56", + "91", + "31", + "89", + "75", + "28", + "71", + "43" + ] + }, + { + "id": "76", + "firstname": "Kristian", + "lastname": "Coxhead", + "email": "kcoxhead23@bing.com", + "phone": "479-956-9226", + "street": "2 Tennyson Circle", + "city": "Baltimore", + "relatedContactIds": [ + "8", + "95", + "86", + "75", + "8", + "49", + "64", + "71", + "31", + "90", + "19", + "11", + "54", + "54", + "30", + "47", + "6", + "24", + "19", + "75" + ] + }, + { + "id": "77", + "firstname": "Pancho", + "lastname": "Woloschinski", + "email": "pwoloschinski24@hhs.gov", + "phone": "842-799-5251", + "street": "78 Calypso Pass", + "city": "Baltimore", + "relatedContactIds": [ + "81", + "23", + "10", + "76", + "38", + "26", + "56", + "45", + "40", + "20", + "92", + "3", + "83", + "39", + "19", + "42", + "44", + "53", + "10", + "77", + "68", + "45", + "3", + "33" + ] + }, + { + "id": "78", + "firstname": "Berti", + "lastname": "Wolfers", + "email": "bwolfers25@about.me", + "phone": "158-232-4876", + "street": "6105 Loomis Road", + "city": "Baltimore", + "relatedContactIds": [ + "8", + "81", + "76", + "63", + "68", + "30", + "1", + "40", + "95", + "47", + "49", + "12", + "7" + ] + }, + { + "id": "79", + "firstname": "Shelbi", + "lastname": "Gartan", + "email": "sgartan26@canalblog.com", + "phone": "270-316-1250", + "street": "384 Tomscot Hill", + "city": "Baltimore", + "relatedContactIds": [ + "81", + "18", + "90", + "13", + "75", + "75", + "99", + "4", + "18", + "72", + "84", + "8", + "55" + ] + }, + { + "id": "80", + "firstname": "Cristi", + "lastname": "Kull", + "email": "ckull27@elpais.com", + "phone": "158-767-7757", + "street": "93468 Spaight Trail", + "city": "Baltimore", + "relatedContactIds": [ + "30", + "26", + "31", + "84", + "100", + "21", + "38", + "58", + "69", + "42", + "53", + "64", + "33", + "71", + "54", + "82", + "92", + "70", + "49", + "43", + "14", + "53", + "31", + "54", + "46", + "73", + "82", + "78" + ] + }, + { + "id": "81", + "firstname": "Laurent", + "lastname": "Le Count", + "email": "llecount28@lycos.com", + "phone": "366-236-8102", + "street": "1 North Terrace", + "city": "Baltimore", + "relatedContactIds": [ + "45", + "7" + ] + }, + { + "id": "82", + "firstname": "Lodovico", + "lastname": "Benezet", + "email": "lbenezet29@dailymotion.com", + "phone": "258-407-0659", + "street": "06769 Dixon Center", + "city": "Baltimore", + "relatedContactIds": [ + "27", + "4", + "3", + "18", + "15", + "90", + "57", + "57", + "49", + "83", + "16", + "44", + "97", + "42", + "56", + "4", + "40" + ] + }, + { + "id": "83", + "firstname": "Beverlie", + "lastname": "Hollyman", + "email": "bhollyman2a@webs.com", + "phone": "684-917-1551", + "street": "6709 Westend Road", + "city": "Baltimore", + "relatedContactIds": [ + "43", + "92", + "44" + ] + }, + { + "id": "84", + "firstname": "Bronny", + "lastname": "Shalloo", + "email": "bshalloo2b@newyorker.com", + "phone": "897-305-8712", + "street": "234 Grayhawk Trail", + "city": "Oklahoma City", + "relatedContactIds": [ + "24", + "84", + "45", + "14", + "32", + "39", + "19", + "53", + "98", + "34", + "73", + "95", + "15", + "23", + "52", + "88", + "87", + "52", + "76" + ] + }, + { + "id": "85", + "firstname": "Ashien", + "lastname": "Wittleton", + "email": "awittleton2c@statcounter.com", + "phone": "593-414-1162", + "street": "471 Twin Pines Point", + "city": "Oklahoma City", + "relatedContactIds": [ + "18", + "88", + "42" + ] + }, + { + "id": "86", + "firstname": "Datha", + "lastname": "Stuttman", + "email": "dstuttman2d@apache.org", + "phone": "274-213-4881", + "street": "5667 Bonner Drive", + "city": "Oklahoma City", + "relatedContactIds": [ + "36", + "9" + ] + }, + { + "id": "87", + "firstname": "Averell", + "lastname": "Whates", + "email": "awhates2e@pcworld.com", + "phone": "901-509-3869", + "street": "21 Dottie Crossing", + "city": "Oklahoma City", + "relatedContactIds": [ + "42", + "29", + "43", + "17", + "67", + "59", + "10", + "63", + "10", + "16", + "34", + "43", + "76", + "61", + "92", + "46", + "56", + "65", + "52", + "33", + "45", + "30", + "84", + "42", + "18", + "12", + "6", + "44", + "34" + ] + }, + { + "id": "88", + "firstname": "Katharine", + "lastname": "Kassel", + "email": "kkassel2f@google.ca", + "phone": "179-877-5021", + "street": "25 Moose Street", + "city": "Oklahoma City", + "relatedContactIds": [ + "66", + "64", + "49", + "26", + "23", + "22", + "24", + "58", + "96", + "98", + "39", + "11", + "22", + "87" + ] + }, + { + "id": "89", + "firstname": "Kingsley", + "lastname": "Pfaffel", + "email": "kpfaffel2g@amazonaws.com", + "phone": "423-747-9306", + "street": "5 Crest Line Circle", + "city": "Oklahoma City", + "relatedContactIds": [ + "34", + "23", + "87", + "22", + "16", + "51", + "69", + "5", + "54", + "56", + "12", + "92", + "51", + "77", + "33", + "90", + "32", + "6", + "42", + "7", + "25", + "8", + "77", + "75", + "88", + "86", + "98" + ] + }, + { + "id": "90", + "firstname": "Hobart", + "lastname": "Tosh", + "email": "htosh2h@tmall.com", + "phone": "760-935-3287", + "street": "95772 6th Junction", + "city": "Portland", + "relatedContactIds": [ + "52", + "41", + "87", + "25", + "39", + "10", + "12", + "13", + "65", + "92" + ] + }, + { + "id": "91", + "firstname": "Marlon", + "lastname": "Curm", + "email": "mcurm2i@nytimes.com", + "phone": "821-689-5277", + "street": "9257 Upham Drive", + "city": "Portland", + "relatedContactIds": [ + "94", + "88", + "83", + "23", + "18", + "32", + "77", + "44", + "17", + "94", + "9", + "78", + "40", + "70", + "6", + "86", + "77", + "67", + "81", + "71" + ] + }, + { + "id": "92", + "firstname": "Ax", + "lastname": "Medler", + "email": "amedler2j@cdc.gov", + "phone": "292-637-3497", + "street": "5 Spaight Center", + "city": "Portland", + "relatedContactIds": [ + "88", + "45", + "6", + "84", + "59", + "31", + "3", + "40", + "100", + "81", + "79", + "42", + "100", + "16", + "23", + "79", + "24", + "51", + "17", + "71", + "70", + "4", + "88", + "38", + "81" + ] + }, + { + "id": "93", + "firstname": "Jehanna", + "lastname": "Groom", + "email": "jgroom2k@rediff.com", + "phone": "805-530-8235", + "street": "8 Scott Junction", + "city": "Portland", + "relatedContactIds": [ + "58", + "87", + "30", + "24", + "74", + "74", + "39", + "2", + "91", + "24", + "43", + "32", + "20", + "23", + "40" + ] + }, + { + "id": "94", + "firstname": "Jerry", + "lastname": "Khristyukhin", + "email": "jkhristyukhin2l@cocolog-nifty.com", + "phone": "341-952-1933", + "street": "20605 Ramsey Avenue", + "city": "Portland", + "relatedContactIds": [ + "8", + "27", + "70", + "55", + "2", + "79", + "22", + "2", + "71", + "72", + "35", + "81", + "49", + "55", + "38", + "46", + "93", + "69", + "46", + "25", + "98", + "97", + "39", + "15", + "2", + "70", + "4", + "54", + "43", + "73" + ] + }, + { + "id": "95", + "firstname": "Germaine", + "lastname": "Sumsion", + "email": "gsumsion2m@timesonline.co.uk", + "phone": "939-932-7402", + "street": "0646 Sage Trail", + "city": "Portland", + "relatedContactIds": [ + "1", + "90", + "68", + "35", + "68", + "94", + "11", + "81", + "54", + "57", + "53", + "15", + "62", + "93", + "47", + "67", + "15", + "47", + "83", + "6", + "14", + "96", + "83", + "20", + "88", + "100", + "19", + "31", + "54" + ] + }, + { + "id": "96", + "firstname": "Florri", + "lastname": "Brunke", + "email": "fbrunke2n@ezinearticles.com", + "phone": "445-575-4372", + "street": "0502 Veith Avenue", + "city": "Las Vegas", + "relatedContactIds": [ + "58", + "84", + "51", + "65", + "50", + "60", + "81", + "10", + "70", + "72", + "31", + "63", + "16", + "20", + "62", + "72", + "85", + "81", + "27", + "34", + "54", + "79", + "98", + "75", + "71" + ] + }, + { + "id": "97", + "firstname": "Gonzalo", + "lastname": "Aland", + "email": "galand2o@washington.edu", + "phone": "742-931-4232", + "street": "6022 Lighthouse Bay Terrace", + "city": "Las Vegas", + "relatedContactIds": [ + "31" + ] + }, + { + "id": "98", + "firstname": "Birgit", + "lastname": "Finnan", + "email": "bfinnan2p@cbsnews.com", + "phone": "663-848-9691", + "street": "63026 Karstens Alley", + "city": "Las Vegas", + "relatedContactIds": [ + "84", + "91", + "68", + "22", + "11", + "76", + "100", + "95", + "1" + ] + }, + { + "id": "99", + "firstname": "Sibyl", + "lastname": "McGillacoell", + "email": "smcgillacoell2q@tumblr.com", + "phone": "444-668-4955", + "street": "329 Merrick Hill", + "city": "Las Vegas", + "relatedContactIds": [ + "54", + "61", + "92", + "76", + "25" + ] + }, + { + "id": "100", + "firstname": "Charmian", + "lastname": "McLurg", + "email": "cmclurg2r@cnet.com", + "phone": "821-884-8382", + "street": "52531 Union Court", + "city": "Las Vegas", + "relatedContactIds": [ + "15", + "8", + "46", + "19", + "72", + "24", + "94" + ] + } +] diff --git a/projects/e2e/workbench-application-platform/contact-app/src/assets/manifest.json b/projects/e2e/workbench-application-platform/contact-app/src/assets/manifest.json new file mode 100644 index 000000000..08437d0e9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/assets/manifest.json @@ -0,0 +1,78 @@ +{ + "name": "Contact Application", + "baseUrl": "#", + "capabilities": [ + { + "type": "activity", + "qualifier": { + "entity": "contacts" + }, + "description": "Lists all contacts and allows to show their personal data.", + "properties": { + "title": "Contacts", + "itemText": "person_outline", + "itemCssClass": "material-icons", + "cssClass": "e2e-contact-list", + "path": "contact/list" + } + }, + { + "type": "view", + "qualifier": { + "entity": "contact", + "id": "*" + }, + "description": "Shows personal data of a contact.", + "properties": { + "path": "contact/:id", + "title": "Contact", + "cssClass": "e2e-contact" + } + }, + { + "type": "popup", + "qualifier": { + "entity": "contact", + "action": "create" + }, + "description": "Allows to create a new contact.", + "properties": { + "path": "contact/new", + "width": "400px", + "height": "390px" + } + }, + { + "type": "popup", + "qualifier": { + "entity": "contact", + "id": "*", + "action": "add-related-contact" + }, + "description": "Allows to add another contact as related person.", + "properties": { + "path": "contact/:id/add-related-contact", + "width": "350px", + "height": "600px" + } + } + ], + "intents": [ + { + "type": "view", + "qualifier": { + "entity": "communication", + "presentation": "list", + "contactId": "*" + } + }, + { + "type": "popup", + "qualifier": { + "entity": "communication", + "action": "create", + "contactId": "*" + } + } + ] +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/environments/environment.now.ts b/projects/e2e/workbench-application-platform/contact-app/src/environments/environment.now.ts new file mode 100644 index 000000000..dc39aca58 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/environments/environment.now.ts @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +export const environment = { + production: true +}; diff --git a/projects/e2e/workbench-application-platform/contact-app/src/environments/environment.ts b/projects/e2e/workbench-application-platform/contact-app/src/environments/environment.ts new file mode 100644 index 000000000..2a785475f --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/environments/environment.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --configuration=now` replaces `environment.ts` with `environment.now.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/projects/e2e/workbench-application-platform/contact-app/src/index.html b/projects/e2e/workbench-application-platform/contact-app/src/index.html new file mode 100644 index 000000000..442f7103a --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/index.html @@ -0,0 +1,12 @@ + + + + + Contact Application + + + + + + + diff --git a/projects/e2e/workbench-application-platform/contact-app/src/main.ts b/projects/e2e/workbench-application-platform/contact-app/src/main.ts new file mode 100644 index 000000000..c7b673cf4 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/projects/e2e/workbench-application-platform/contact-app/src/now.json b/projects/e2e/workbench-application-platform/contact-app/src/now.json new file mode 100644 index 000000000..7f9d9a3eb --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/now.json @@ -0,0 +1,5 @@ +{ + "version": 2, + "name": "scion-workbench-application-platform-contact", + "alias": "scion-workbench-application-platform-contact" +} diff --git a/projects/e2e/workbench-application-platform/contact-app/src/polyfills.ts b/projects/e2e/workbench-application-platform/contact-app/src/polyfills.ts new file mode 100644 index 000000000..f56cc3de6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/polyfills.ts @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/number'; +import 'core-js/es6/math'; +import 'core-js/es6/string'; +import 'core-js/es6/date'; +import 'core-js/es6/array'; +import 'core-js/es6/regexp'; +import 'core-js/es6/map'; +import 'core-js/es6/weak-map'; +import 'core-js/es6/set'; +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + + // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + + /* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/projects/e2e/workbench-application-platform/contact-app/src/styles.scss b/projects/e2e/workbench-application-platform/contact-app/src/styles.scss new file mode 100644 index 000000000..1506f1627 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/src/styles.scss @@ -0,0 +1,3 @@ +@import 'common'; + +@include app-theme(); diff --git a/projects/e2e/workbench-application-platform/contact-app/tsconfig.app.json b/projects/e2e/workbench-application-platform/contact-app/tsconfig.app.json new file mode 100644 index 000000000..0bc50df29 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/tsconfig.app.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../../../out-tsc/contact-app", + "types": [] + } +} diff --git a/projects/e2e/workbench-application-platform/contact-app/tslint.json b/projects/e2e/workbench-application-platform/contact-app/tslint.json new file mode 100644 index 000000000..e3e7b64d8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/contact-app/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/browserslist b/projects/e2e/workbench-application-platform/dev-tools-app/browserslist new file mode 100644 index 000000000..37371cb04 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app-routing.module.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app-routing.module.ts new file mode 100644 index 000000000..afa3ac21e --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app-routing.module.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + {path: 'dev-tools', loadChildren: './dev-tools/dev-tools.module#DevToolsModule'}, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes, {useHash: true})], + exports: [RouterModule] +}) +export class AppRoutingModule { +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.html new file mode 100644 index 000000000..8fe45de6e --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.html @@ -0,0 +1,3 @@ + + + diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.scss new file mode 100644 index 000000000..e1f2859cf --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.scss @@ -0,0 +1,13 @@ +@import 'common'; + +:host { + @include position(absolute, 0, 0, 0, 0); + + > sci-viewport { + @include position(absolute, 0, 0, 0, 0); + + router-outlet { + position: absolute; // take router outlet out of the document flow + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.ts new file mode 100644 index 000000000..15f0590f2 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.component.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent { +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.module.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.module.ts new file mode 100644 index 000000000..49f5b608e --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/app.module.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; +import { WorkbenchApplicationModule } from '@scion/workbench-application.angular'; +import { SciViewportModule } from '@scion/viewport'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { AppRoutingModule } from './app-routing.module'; + +@NgModule({ + declarations: [ + AppComponent, + ], + imports: [ + BrowserModule, + WorkbenchApplicationModule.forRoot(), + SciViewportModule, + AppRoutingModule, + BrowserAnimationsModule, + ], + providers: [], + bootstrap: [ + AppComponent, + ] +}) +export class AppModule { +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.html new file mode 100644 index 000000000..a9a88ee59 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.html @@ -0,0 +1,8 @@ +{{manifest.name}} +{{manifest.symbolicName}} +{{manifest.baseUrl}} + +
+ {{intentCount}} {{intentCount === 1 ? 'intent' : 'intents'}} + {{capabilityCount}} {{capabilityCount === 1 ? 'capability' : 'capabilities'}} +
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.scss new file mode 100644 index 000000000..d9257d144 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.scss @@ -0,0 +1,40 @@ +@import 'common'; + +:host { + display: grid; + grid-template-columns: auto auto; + grid-column-gap: 1em; + grid-row-gap: .5em; + grid-template-rows: auto; + align-items: start; + + > a.app-name { + grid-column: 1/2; + grid-row: 1/2; + font-weight: bold; + } + + > span.app-symbolic-name { + grid-column: 1/2; + grid-row: 2/3; + font-size: smaller; + } + + > a.url { + grid-column: 1/3; + grid-row: 3/4; + font-size: smaller; + } + + > div.chips { + grid-column: 2/3; + grid-row: 1/3; + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + + > span.chip { + @include chip(accentColor(.2), transparent, accentColor(.75)); + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.ts new file mode 100644 index 000000000..8141f6493 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list-item/application-list-item.component.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { Manifest } from '@scion/workbench-application.core'; + +@Component({ + selector: 'app-application-list-item', + templateUrl: './application-list-item.component.html', + styleUrls: ['./application-list-item.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ApplicationListItemComponent { + + @Input() + public manifest: Manifest; + + public get intentCount(): number { + return this.manifest.intents.length; + } + + public get capabilityCount(): number { + return this.manifest.capabilities.length; + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.html new file mode 100644 index 000000000..213303c39 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.html @@ -0,0 +1,5 @@ + + + + + diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.scss new file mode 100644 index 000000000..57bda86d3 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.scss @@ -0,0 +1,10 @@ +@import 'common'; + +:host { + display: flex; + padding: app-padding(); + + > sci-list { + flex: auto; + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.ts new file mode 100644 index 000000000..cfe299814 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-list/application-list.component.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, TrackByFunction } from '@angular/core'; +import { BehaviorSubject, combineLatest, MonoTypeOperatorFunction, Observable, OperatorFunction } from 'rxjs'; +import { Manifest, ManifestRegistryService } from '@scion/workbench-application.core'; +import { map } from 'rxjs/operators'; +import { toFilterRegExp } from '@scion/e2e/common'; + +@Component({ + selector: 'app-application-list', + templateUrl: './application-list.component.html', + styleUrls: ['./application-list.component.scss'], +}) +export class ApplicationListComponent { + + private _filter$ = new BehaviorSubject(null); + + public manifests$: Observable; + + constructor(private _manifestRegistryService: ManifestRegistryService) { + this.manifests$ = combineLatest(this._filter$, this._manifestRegistryService.manifests$) + .pipe( + filterManifests(), + sortManifests() + ); + } + + public onFilter(filterText: string): void { + this._filter$.next(filterText); + } + + public trackByFn: TrackByFunction = (index: number, manifest: Manifest): any => { + return manifest.symbolicName; + }; +} + +function filterManifests(): OperatorFunction<[string, Manifest[]], Manifest[]> { + return map(([filter, manifests]: [string, Manifest[]]): Manifest[] => { + if (!filter) { + return manifests; + } + + const filterRegExp = toFilterRegExp(filter); + return manifests.filter(manifest => filterRegExp.test(manifest.name) || filterRegExp.test(manifest.symbolicName)); + }); +} + +function sortManifests(): MonoTypeOperatorFunction { + return map((manifests: Manifest[]): Manifest[] => [...manifests].sort((mf1, mf2) => mf1.name.localeCompare(mf2.name))); +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.html new file mode 100644 index 000000000..d6eb4e125 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.html @@ -0,0 +1,66 @@ +
+ + {{manifest?.name}} + + + {{manifest?.symbolicName}} + + + {{manifest?.baseUrl}} + + + + {{manifest.manifestUrl}} + + + + SCOPE CHECK DISABLED + +
+ +
+ +
+

Capabilities{{capabilities.length}}

+ + + + + + + + + + + + +
+ + +
+
+
+
+
+ + +
+

Intents{{intents.length}}

+ + + + + + + + + + + + +
+
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.scss new file mode 100644 index 000000000..ddca98d85 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.scss @@ -0,0 +1,134 @@ +@import 'common'; + +:host { + display: flex; + flex-direction: column; + padding: app-padding(); + + > section.application { + flex: none; + display: grid; + grid-template-columns: minmax(80px, 120px) auto auto; + grid-column-gap: 1em; + grid-row-gap: .5em; + grid-template-rows: auto; + margin-bottom: 1.5em; + + border: 1px solid accentColor(.25); + border-radius: 5px; + padding: 1em; + @include grid-container-align-items(center); + + > label.app-name { + grid-column: 1/2; + grid-row: 1/2; + } + + > span.app-name { + grid-column: 2/3; + grid-row: 1/2; + } + + > label.app-symbolic-name { + grid-column: 1/2; + grid-row: 2/3; + } + + > span.app-symbolic-name { + grid-column: 2/3; + grid-row: 2/3; + } + + > label.app-url { + grid-column: 1/2; + grid-row: 3/4; + } + + > a.app-url { + grid-column: 2/3; + grid-row: 3/4; + } + + > label.manifest-url { + grid-column: 1/2; + grid-row: 4/5; + } + + > a.manifest-url { + grid-column: 2/3; + grid-row: 4/5; + } + + > span.scope-check-disabled { + grid-column: 3/4; + grid-row: 1/5; + align-self: start; + justify-self: end; + font-weight: bold; + @include chip(rgba(255, 0, 0, .75), rgba(255, 0, 0, .1), rgba(255, 0, 0, .75)); + margin: 0; + } + } + + > section.sashbox { + flex: auto; + display: flex; + flex-direction: column; + + > section.sash-1, > section.sash-2 { + flex: 1 1 0; + overflow: hidden; + display: flex; + flex-direction: column; + + > h2 { + margin-top: 0; + font-size: 1.25em; + position: relative; // positioning anchor for the badge + align-self: flex-start; + + > span.count-badge { + $size: 12px; + position: absolute; + display: flex; + align-items: center; + justify-content: center; + right: -1.5em; + top: 0; + border-radius: $size/2; + color: #FFFFFF; + font-size: 10px; + font-weight: normal; + min-height: $size; + min-width: $size; + background-color: accentColor(.4); + user-select: none; + } + } + + > sci-filter-field { + margin-bottom: .2em; + } + + > sci-accordion { + flex: auto; + } + } + + > div.splitter { + flex: 0 0 auto; + margin: .5em 0; + width: 20px; + align-self: center; + + > div.sash-indicator { + background: accentColor(); + height: 1px; + + &:not(:first-child) { + margin-top: 1px; + } + } + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.ts new file mode 100644 index 000000000..6a38d57fb --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/application-view/application-view.component.ts @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, ElementRef, OnDestroy, ViewChild } from '@angular/core'; +import { provideWorkbenchView, WorkbenchView } from '@scion/workbench-application.angular'; +import { ActivatedRoute } from '@angular/router'; +import { BehaviorSubject, combineLatest, Observable, of, OperatorFunction, Subject } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; +import { Capability, Intent, Manifest, ManifestRegistryService, NotificationService } from '@scion/workbench-application.core'; +import { toFilterRegExp } from '@scion/e2e/common'; + +@Component({ + selector: 'app-application-view', + templateUrl: './application-view.component.html', + styleUrls: ['./application-view.component.scss'], + providers: [ + provideWorkbenchView(ApplicationViewComponent) + ] +}) +export class ApplicationViewComponent implements OnDestroy { + + private _destroy$ = new Subject(); + + public manifest: Manifest; + public capabilities$: Observable; + public intents$: Observable; + + public sashPositionFr = .5; + + private _capabilityFilter$ = new BehaviorSubject(null); + private _intentFilter$ = new BehaviorSubject(null); + + @ViewChild('sashbox') + private _sashbox: ElementRef; + + constructor(route: ActivatedRoute, + notificationService: NotificationService, + view: WorkbenchView, + private _manifestRegistryService: ManifestRegistryService) { + route.params + .pipe( + map(params => params['symbolicName']), + distinctUntilChanged(), + switchMap(symbolicName => this._manifestRegistryService.manifest$(symbolicName)), + tap(manifest => !manifest && notificationService.notify({ + severity: 'error', + title: 'Application not found', + text: `No application found with given symbolic name '${route.snapshot.params['symbolicName']}'` + })), + filter(Boolean), + takeUntil(this._destroy$) + ) + .subscribe((manifest: Manifest) => { + const capabilities: Capability[] = [...manifest.capabilities].sort((c1, c2) => c1.type.localeCompare(c2.type)); + const intents: Intent[] = [...manifest.intents].sort((i1, it2) => i1.type.localeCompare(it2.type)); + + view.title = manifest.name; + view.heading = 'Application Manifest'; + + this.manifest = manifest; + this.capabilities$ = combineLatest(this._capabilityFilter$, of(capabilities)).pipe(filterCapabilities()); + this.intents$ = combineLatest(this._intentFilter$, of(intents)).pipe(filterIntents()); + }); + } + + public onSash(deltaPx: number): void { + const sashboxHeightPx = this._sashbox.nativeElement.clientHeight; + const sashPositionFr = this.sashPositionFr + (deltaPx / sashboxHeightPx); + this.sashPositionFr = Math.min(1, Math.max(0, sashPositionFr)); + } + + public onCapabilityFilter(filterText: string): void { + this._capabilityFilter$.next(filterText); + } + + public onIntentFilter(filterText: string): void { + this._intentFilter$.next(filterText); + } + + public onSashReset(): void { + this.sashPositionFr = .5; + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} + +function filterCapabilities(): OperatorFunction<[string, Capability[]], Capability[]> { + return map(([filterText, capabilities]: [string, Capability[]]): Capability[] => { + if (!filterText) { + return capabilities; + } + + const filterRegExp = toFilterRegExp(filterText); + return capabilities.filter(capability => ( + filterRegExp.test(capability.type) || + filterRegExp.test(capability.private ? 'private' : 'public') || + Object.keys(capability.qualifier || {}).some(key => filterRegExp.test(key)) || + Object.values(capability.qualifier || {}).some(value => filterRegExp.test(`${value}`))) + ); + }); +} + +function filterIntents(): OperatorFunction<[string, Intent[]], Intent[]> { + return map(([filterText, intents]: [string, Intent[]]): Intent[] => { + if (!filterText) { + return intents; + } + + const filterRegExp = toFilterRegExp(filterText); + return intents.filter(intent => ( + filterRegExp.test(intent.type) || + filterRegExp.test(intent.metadata.implicit ? 'implicit' : 'explicit') || + Object.keys(intent.qualifier || {}).some(key => filterRegExp.test(key)) || + Object.values(intent.qualifier || {}).some(value => filterRegExp.test(`${value}`))) + ); + }); +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.html new file mode 100644 index 000000000..28f358f0a --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.html @@ -0,0 +1,16 @@ + +
+ + PUBLIC + + + PRIVATE + + +
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.scss new file mode 100644 index 000000000..8a0adc136 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.scss @@ -0,0 +1,28 @@ +@import 'common'; + +:host { + display: grid; + justify-content: space-between; + @include grid-container-align-items(center); + grid-template-columns: auto auto; + grid-template-rows: auto; + grid-column-gap: 1em; + + > div.actions { + display: flex; + flex-direction: column; + align-items: flex-end; + + > span.scope { + font-weight: bold; + @include chip(primaryColor(), null, primaryColor()); + margin: 0; + } + + > button.execute { + &:not(:first-child) { + margin-top: .5em; + } + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.ts new file mode 100644 index 000000000..44230022c --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-item/capability-accordion-item.component.ts @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; +import { Capability, ManifestRegistryService, PlatformCapabilityTypes, Popup, PopupService, Qualifier } from '@scion/workbench-application.core'; +import { map, switchMap, takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; + +@Component({ + selector: 'app-capability-accordion-item', + templateUrl: './capability-accordion-item.component.html', + styleUrls: ['./capability-accordion-item.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CapabilityAccordionItemComponent implements OnChanges, OnDestroy { + + private _destroy$ = new Subject(); + private _inputChange$ = new Subject(); + + public execQualifier: Qualifier; + + @Input() + public capability: Capability; + + constructor(private _popupService: PopupService, + manifestRegistryService: ManifestRegistryService, + cd: ChangeDetectorRef) { + this._inputChange$ + .pipe( + switchMap(() => manifestRegistryService.capabilities$(PlatformCapabilityTypes.Popup, this.createExecQualifier())), + map((capabilities: Capability[]) => capabilities.length > 0), + takeUntil(this._destroy$), + ) + .subscribe((executable: boolean) => { + this.execQualifier = (executable ? this.createExecQualifier() : null); + cd.markForCheck(); + }); + } + + public ngOnChanges(changes: SimpleChanges): void { + this._inputChange$.next(); + } + + public onCapabilityExecute(event: MouseEvent): void { + if (!this.execQualifier) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + + const popup: Popup = { + position: 'west', + anchor: event.target as Element, + }; + + this._popupService.open(popup, this.execQualifier); + } + + private createExecQualifier(): Qualifier { + return { + entity: 'capability', + action: 'execute', + type: this.capability.type, + capabilityId: this.capability.metadata.id, + }; + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.html new file mode 100644 index 000000000..c5410653c --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.html @@ -0,0 +1,21 @@ +
+ {{capability.description}} +
+ +
+

Properties

+ +
+ +
+

Used by following applications

+ +
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.scss new file mode 100644 index 000000000..2b17e917c --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.scss @@ -0,0 +1,44 @@ +@import 'common'; + +:host { + display: grid; + grid-template-columns: auto auto; + grid-column-gap: 1em; + grid-row-gap: .5em; + grid-template-rows: auto; + + > section.description { + grid-column: 1/3; + font-style: italic; + } + + > section { + border: 1px solid accentColor(.25); + border-radius: 5px; + padding: 1em; + background-color: #FFFFFF; + font-size: 12px; + + > h2 { + font-size: 1.1em; + margin-top: 0; + margin-bottom: 1em; + } + + > ul { + list-style: none; + margin: 0; + padding: 0; + + > li > a.self { + font-style: italic; + } + } + } + + &:not(.has-properties) { + > section.used-by { + grid-column: 1/3; + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.ts new file mode 100644 index 000000000..e36dba748 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/capability-accordion-panel/capability-accordion-panel.component.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ChangeDetectionStrategy, Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Application, Capability, ManifestRegistryService } from '@scion/workbench-application.core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +@Component({ + selector: 'app-capability-accordion-panel', + templateUrl: './capability-accordion-panel.component.html', + styleUrls: ['./capability-accordion-panel.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CapabilityAccordionPanelComponent implements OnChanges { + + public consumers$: Observable; + + @Input() + public capability: Capability; + + @HostBinding('class.has-properties') + public hasProperties: boolean; + + constructor(private _manifestRegistryService: ManifestRegistryService) { + } + + public ngOnChanges(changes: SimpleChanges): void { + this.hasProperties = Object.keys(this.capability.properties || {}).length > 0; + this.consumers$ = this._manifestRegistryService.capabilityConsumers$(this.capability.metadata.id) + .pipe(map(consumers => [...consumers].sort((c1, c2) => c1.name.localeCompare(c2.name)))); + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools-routing.module.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools-routing.module.ts new file mode 100644 index 000000000..022ea41f8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools-routing.module.ts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ApplicationListComponent } from './application-list/application-list.component'; +import { ApplicationViewComponent } from './application-view/application-view.component'; +import { OutletCapabilityExecPopupComponent } from './outlet-capability-exec-popup/outlet-capability-exec-popup.component'; + +const routes: Routes = [ + {path: 'application-list', component: ApplicationListComponent}, + {path: 'application/:symbolicName', component: ApplicationViewComponent}, + {path: 'view-capability/:id', component: OutletCapabilityExecPopupComponent}, + {path: 'popup-capability/:id', component: OutletCapabilityExecPopupComponent}, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class DevToolsRoutingModule { +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools.module.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools.module.ts new file mode 100644 index 000000000..20181d142 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/dev-tools.module.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SciViewportModule } from '@scion/viewport'; +import { SciAccordionModule, SciFilterFieldModule, SciListModule, SciParamsEnterModule, SciPopupShellModule, SciPropertyModule, SciSashModule } from '@scion/e2e/common'; +import { DevToolsRoutingModule } from './dev-tools-routing.module'; +import { ReactiveFormsModule } from '@angular/forms'; +import { WorkbenchApplicationModule } from '@scion/workbench-application.angular'; +import { ApplicationListComponent } from './application-list/application-list.component'; +import { ApplicationListItemComponent } from './application-list-item/application-list-item.component'; +import { ApplicationViewComponent } from './application-view/application-view.component'; +import { CapabilityAccordionItemComponent } from './capability-accordion-item/capability-accordion-item.component'; +import { QualifierChipListComponent } from './qualifier-chip-list/qualifier-chip-list.component'; +import { IntentAccordionItemComponent } from './intent-accordion-item/intent-accordion-item.component'; +import { IntentAccordionPanelComponent } from './intent-accordion-panel/intent-accordion-panel.component'; +import { CapabilityAccordionPanelComponent } from './capability-accordion-panel/capability-accordion-panel.component'; +import { OutletCapabilityExecPopupComponent } from './outlet-capability-exec-popup/outlet-capability-exec-popup.component'; + +@NgModule({ + declarations: [ + ApplicationListComponent, + ApplicationListItemComponent, + ApplicationViewComponent, + CapabilityAccordionItemComponent, + CapabilityAccordionPanelComponent, + IntentAccordionItemComponent, + IntentAccordionPanelComponent, + QualifierChipListComponent, + OutletCapabilityExecPopupComponent, + ], + imports: [ + CommonModule, + SciViewportModule, + ReactiveFormsModule, + WorkbenchApplicationModule.forChild(), + DevToolsRoutingModule, + SciListModule, + SciAccordionModule, + SciSashModule, + SciFilterFieldModule, + SciPopupShellModule, + SciParamsEnterModule, + SciPropertyModule, + ], + exports: [], + providers: [] +}) +export class DevToolsModule { +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.html new file mode 100644 index 000000000..e3f6bf961 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.html @@ -0,0 +1,5 @@ + +
+ IMPLICIT + NOT HANDLED +
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.scss new file mode 100644 index 000000000..727e0abda --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.scss @@ -0,0 +1,26 @@ +@import 'common'; + +:host { + display: grid; + justify-content: space-between; + @include grid-container-align-items(center); + grid-template-columns: auto auto; + grid-template-rows: auto; + grid-column-gap: 1em; + + > div.hints { + display: flex; + flex-direction: column; + align-items: flex-end; + + > span.implicit { + font-weight: bold; + @include chip(primaryColor(), null, primaryColor(), dotted); + } + + > span.not-handled { + font-weight: bold; + @include chip(rgba(255, 0, 0, .75), rgba(255, 0, 0, .1), rgba(255, 0, 0, .75)); + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.ts new file mode 100644 index 000000000..e1c4bb23f --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-item/intent-accordion-item.component.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Intent, ManifestRegistryService } from '@scion/workbench-application.core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +@Component({ + selector: 'app-intent-accordion-item', + templateUrl: './intent-accordion-item.component.html', + styleUrls: ['./intent-accordion-item.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class IntentAccordionItemComponent implements OnChanges { + + public anyQualifier: boolean; + public unhandled$: Observable; + + @Input() + public intent: Intent; + + constructor(private _manifestRegistryService: ManifestRegistryService) { + } + + public ngOnChanges(changes: SimpleChanges): void { + this.anyQualifier = Object.keys(this.intent.qualifier || {}).includes('*'); + + this.unhandled$ = this._manifestRegistryService.capabilityProviders$(this.intent.metadata.id) + .pipe(map(providers => providers.length === 0)); + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.html new file mode 100644 index 000000000..6590aa9fd --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.html @@ -0,0 +1,12 @@ +
+

Handled by following applications

+ +
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.scss new file mode 100644 index 000000000..cfca1cc74 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.scss @@ -0,0 +1,30 @@ +@import 'common'; + +:host { + display: flex; + + > section { + border: 1px solid accentColor(.25); + border-radius: 5px; + padding: 1em; + background-color: #FFFFFF; + font-size: 12px; + flex: auto; + + > h2 { + font-size: 1em; + margin-top: 0; + margin-bottom: 1em; + } + + > ul { + list-style: none; + margin: 0; + padding: 0; + + > li > a.self { + font-style: italic; + } + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.ts new file mode 100644 index 000000000..4e683ec1a --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/intent-accordion-panel/intent-accordion-panel.component.ts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Application, Intent, ManifestRegistryService } from '@scion/workbench-application.core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +@Component({ + selector: 'app-intent-accordion-panel', + templateUrl: './intent-accordion-panel.component.html', + styleUrls: ['./intent-accordion-panel.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class IntentAccordionPanelComponent implements OnChanges { + + public anyQualifier: boolean; + public providers$: Observable; + + @Input() + public intent: Intent; + + constructor(private _manifestRegistryService: ManifestRegistryService) { + } + + public ngOnChanges(changes: SimpleChanges): void { + this.anyQualifier = Object.keys(this.intent.qualifier || {}).includes('*'); + this.providers$ = this._manifestRegistryService.capabilityProviders$(this.intent.metadata.id) + .pipe(map(providers => [...providers].sort((p1, p2) => p1.name.localeCompare(p2.name)))); + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.html new file mode 100644 index 000000000..7d267eb5e --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.html @@ -0,0 +1,13 @@ + + Execute {{capability?.type}} capability + + +
+ + + +
+
+ + Execute +
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.scss new file mode 100644 index 000000000..786446fba --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.scss @@ -0,0 +1,21 @@ +:host { + display: flex; + flex-direction: column; + + > sci-popup-shell { + flex: auto; + + main { + display: flex; + flex-direction: column; + + > sci-params-enter { + flex: none; + + &:not(:last-child) { + margin-bottom: 1em; + } + } + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.ts new file mode 100644 index 000000000..1611ee8cc --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/outlet-capability-exec-popup/outlet-capability-exec-popup.component.ts @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, OnDestroy } from '@angular/core'; +import { provideWorkbenchPopup, WorkbenchPopup, WorkbenchRouter } from '@scion/workbench-application.angular'; +import { ActivatedRoute, Params } from '@angular/router'; +import { Capability, ManifestRegistryService, NotificationService, PlatformCapabilityTypes, PopupService, Qualifier } from '@scion/workbench-application.core'; +import { Subject } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; +import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { FocusTrapFactory } from '@angular/cdk/a11y'; +import { PARAM_NAME, PARAM_VALUE, SciParamsEnterComponent } from '@scion/e2e/common'; + +const QUALIFIER = 'qualifier'; +const QUERY_PARAMS = 'queryParams'; +const MATRIX_PARAMS = 'matrixParams'; + +@Component({ + selector: 'app-outlet-capability-exec-popup', + templateUrl: './outlet-capability-exec-popup.component.html', + styleUrls: ['./outlet-capability-exec-popup.component.scss'], + providers: [ + provideWorkbenchPopup(OutletCapabilityExecPopupComponent) + ] +}) +export class OutletCapabilityExecPopupComponent implements OnDestroy { + + public readonly QUALIFIER = QUALIFIER; + public readonly QUERY_PARAMS = QUERY_PARAMS; + public readonly MATRIX_PARAMS = MATRIX_PARAMS; + + public capability: Capability; + public form: FormGroup; + public valid: boolean; + + private _destroy$ = new Subject(); + + constructor(route: ActivatedRoute, + manifestRegistryService: ManifestRegistryService, + notificationService: NotificationService, + formBuilder: FormBuilder, + private _popup: WorkbenchPopup, + private _focusTrapFactory: FocusTrapFactory, + private _workbenchRouter: WorkbenchRouter, + private _popupService: PopupService) { + this.form = formBuilder.group({ + [QUALIFIER]: formBuilder.array([]), + [QUERY_PARAMS]: formBuilder.array([]), + [MATRIX_PARAMS]: formBuilder.array([]), + }); + + route.params + .pipe( + map(params => params['id']), + distinctUntilChanged(), + switchMap(capabilityId => manifestRegistryService.capability$(capabilityId)), + tap(manifest => !manifest && notificationService.notify({ + severity: 'error', + title: 'Capability not found', + text: `No capability found with given id '${route.snapshot.params['id']}'` + })), + filter(Boolean), + takeUntil(this._destroy$), + ) + .subscribe(capability => { + this.capability = capability; + this.createQualifierFormControls(capability.qualifier, formBuilder); + this.requestFocus(); + }); + } + + private createQualifierFormControls(qualifier: Qualifier, formBuilder: FormBuilder): void { + const formArray = formBuilder.array([]); + Object.entries(qualifier).forEach(([key, value]) => { + const readonly = (value !== '*'); + formArray.push(formBuilder.group({ + [PARAM_NAME]: formBuilder.control({value: key, disabled: true}), + [PARAM_VALUE]: formBuilder.control({value: (readonly ? value : ''), disabled: readonly}, Validators.required), + })); + }); + this.form.setControl(QUALIFIER, formArray); + } + + private requestFocus(): void { + const focusTrap = this._focusTrapFactory.create(document.body); + focusTrap.focusInitialElementWhenReady().finally(() => focusTrap.destroy()); + } + + public onExecute(): void { + const qualifier: Qualifier = SciParamsEnterComponent.toParams(this.form.get(QUALIFIER) as FormArray); + const queryParams: Params = SciParamsEnterComponent.toParams(this.form.get(QUERY_PARAMS) as FormArray); + const matrixParams: Params = SciParamsEnterComponent.toParams(this.form.get(MATRIX_PARAMS) as FormArray); + + switch (this.capability.type) { + case PlatformCapabilityTypes.View: { + this._workbenchRouter.navigate(qualifier, { + target: 'blank', + matrixParams, + queryParams + }); + break; + } + case PlatformCapabilityTypes.Popup: { + this._popupService.open({ + position: 'east', + anchor: event.target as Element, + queryParams: queryParams, + matrixParams: matrixParams + }, qualifier); + break; + } + default: { + throw Error(`[CapabilityNotHandledError] Capability type not handled [type=${this.capability.type}]`); + } + } + + this._popup.close(); + } + + public ngOnDestroy(): void { + this._destroy$.next(); + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.html new file mode 100644 index 000000000..965937a24 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.html @@ -0,0 +1,9 @@ +
    +
  • + {{type}} +
  • +
  • + {{entry.key}} + {{entry.value}} +
  • +
diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.scss new file mode 100644 index 000000000..d0fadf1f3 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.scss @@ -0,0 +1,54 @@ +@import 'common'; + +:host { + + > ul { + list-style: none; + padding: 0; + margin: 0; + display: flex; + + > li { + @include chip(accentColor(.25), null, accentColor(1)); + + display: flex; + flex-direction: column; + align-items: center; + padding: .25em 1em; + + > span.key { + color: accentColor(.75) + } + + > span.value { + font-size: larger; + font-weight: bold; + color: accentColor(1) + } + + &::before { + display: block; + content: '«qualifier»'; + font-size: smaller; + margin-bottom: .75em; + color: accentColor(.5); + } + } + + > li.type { + @include chip(accentColor(.25), accentColor(.1), accentColor(1)); + min-width: 75px; + + > span.type { + font-size: 1.5em; + font-variant: small-caps; + font-weight: bold; + color: accentColor(1) + } + + &::before { + content: '«type»'; + } + } + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.ts new file mode 100644 index 000000000..056ef7440 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/app/dev-tools/qualifier-chip-list/qualifier-chip-list.component.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Qualifier } from '@scion/workbench-application.core'; +import { KeyValue } from '@angular/common'; + +@Component({ + selector: 'app-qualifier-chip-list', + templateUrl: './qualifier-chip-list.component.html', + styleUrls: ['./qualifier-chip-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class QualifierChipListComponent implements OnChanges { + + private _qualifierKeys: string[]; + + @Input() + public qualifier: Qualifier; + + @Input() + public type: string; + + public ngOnChanges(changes: SimpleChanges): void { + this._qualifierKeys = Object.keys(this.qualifier || {}); + } + + /** + * Compares qualifier entries by their position in the object. + */ + public qualifierKeyCompareFn = (a: KeyValue, b: KeyValue): number => { + return this._qualifierKeys.indexOf(a.key) - this._qualifierKeys.indexOf(b.key); + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/assets/.gitkeep b/projects/e2e/workbench-application-platform/dev-tools-app/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/assets/manifest.json b/projects/e2e/workbench-application-platform/dev-tools-app/src/assets/manifest.json new file mode 100644 index 000000000..715973ec6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/assets/manifest.json @@ -0,0 +1,97 @@ +{ + "name": "SCION Workbench Application Platform DevTools", + "baseUrl": "#", + "capabilities": [ + { + "type": "activity", + "qualifier": { + "entity": "dev-tools" + }, + "description": "Lists all registered applications and allows to show their manifests.", + "properties": { + "title": "DevTools", + "path": "dev-tools/application-list", + "itemText": "apps", + "itemCssClass": "material-icons", + "position": 9999999999 + } + }, + { + "type": "view", + "qualifier": { + "entity": "application-list" + }, + "private": false, + "description": "Lists all registered applications and allows to show their manifests.", + "properties": { + "path": "dev-tools/application-list", + "title": "Application manifests" + } + }, + { + "type": "view", + "qualifier": { + "entity": "application", + "symbolicName": "*" + }, + "private": false, + "description": "Shows the application manifest with all its capabilities, intents and dependent applications.", + "properties": { + "path": "dev-tools/application/:symbolicName", + "title": "Application Manifest" + } + }, + { + "type": "popup", + "qualifier": { + "entity": "capability", + "action": "execute", + "type": "view", + "capabilityId": "*" + }, + "private": false, + "description": "Allows to execute a capability of the type 'view'.", + "properties": { + "path": "dev-tools/view-capability/:capabilityId", + "width": "400px", + "height": "500px" + } + }, + { + "type": "popup", + "qualifier": { + "entity": "capability", + "action": "execute", + "type": "popup", + "capabilityId": "*" + }, + "private": false, + "description": "Allows to execute a capability of the type 'popup'.", + "properties": { + "path": "dev-tools/popup-capability/:capabilityId", + "width": "400px", + "height": "500px" + } + } + ], + "intents": [ + { + "type": "manifest-registry" + }, + { + "type": "notification" + }, + { + "type": "view", + "qualifier": { + "*": "*" + } + }, + { + "type": "popup", + "qualifier": { + "*": "*" + } + } + ] +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.now.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.now.ts new file mode 100644 index 000000000..dc39aca58 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.now.ts @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +export const environment = { + production: true +}; diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.ts new file mode 100644 index 000000000..2a785475f --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/environments/environment.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --configuration=now` replaces `environment.ts` with `environment.now.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/index.html b/projects/e2e/workbench-application-platform/dev-tools-app/src/index.html new file mode 100644 index 000000000..952fb2984 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/index.html @@ -0,0 +1,12 @@ + + + + + SCION Workbench Application Platform DevTools + + + + + + + diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/main.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/main.ts new file mode 100644 index 000000000..c7b673cf4 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/now.json b/projects/e2e/workbench-application-platform/dev-tools-app/src/now.json new file mode 100644 index 000000000..a7c989237 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/now.json @@ -0,0 +1,5 @@ +{ + "version": 2, + "name": "scion-workbench-application-platform-devtools", + "alias": "scion-workbench-application-platform-devtools" +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/polyfills.ts b/projects/e2e/workbench-application-platform/dev-tools-app/src/polyfills.ts new file mode 100644 index 000000000..f56cc3de6 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/polyfills.ts @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/number'; +import 'core-js/es6/math'; +import 'core-js/es6/string'; +import 'core-js/es6/date'; +import 'core-js/es6/array'; +import 'core-js/es6/regexp'; +import 'core-js/es6/map'; +import 'core-js/es6/weak-map'; +import 'core-js/es6/set'; +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + + // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + + /* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/src/styles.scss b/projects/e2e/workbench-application-platform/dev-tools-app/src/styles.scss new file mode 100644 index 000000000..1506f1627 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/src/styles.scss @@ -0,0 +1,3 @@ +@import 'common'; + +@include app-theme(); diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/tsconfig.app.json b/projects/e2e/workbench-application-platform/dev-tools-app/tsconfig.app.json new file mode 100644 index 000000000..2209158a9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/tsconfig.app.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../../../out-tsc/dev-tools-app", + "types": [] + } +} diff --git a/projects/e2e/workbench-application-platform/dev-tools-app/tslint.json b/projects/e2e/workbench-application-platform/dev-tools-app/tslint.json new file mode 100644 index 000000000..e3e7b64d8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/dev-tools-app/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/browserslist b/projects/e2e/workbench-application-platform/host-app/browserslist new file mode 100644 index 000000000..37371cb04 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/app.component.html b/projects/e2e/workbench-application-platform/host-app/src/app/app.component.html new file mode 100644 index 000000000..b73617382 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/app.component.html @@ -0,0 +1 @@ + diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/app.component.ts b/projects/e2e/workbench-application-platform/host-app/src/app/app.component.ts new file mode 100644 index 000000000..169b1f23e --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/app.component.ts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html' +}) +export class AppComponent { +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/app.module.ts b/projects/e2e/workbench-application-platform/host-app/src/app/app.module.ts new file mode 100644 index 000000000..222c6f1f4 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/app.module.ts @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { WorkbenchModule } from '@scion/workbench'; +import { RouterModule } from '@angular/router'; +import { WorkbenchApplicationPlatformModule } from '@scion/workbench-application-platform'; +import { CustomExtensionModule } from './custom-extension/custom-extension.module'; +import { environment } from '../environments/environment'; + +@NgModule({ + declarations: [ + AppComponent, + ], + imports: [ + WorkbenchModule.forRoot(), + WorkbenchApplicationPlatformModule.forRoot({ + applicationConfig: [ + { + symbolicName: 'contact-app', + manifestUrl: environment.contact_app_manifest_url, + }, + { + symbolicName: 'communication-app', + manifestUrl: environment.communication_app_manifest_url, + }, + { + symbolicName: 'devtools-app', + manifestUrl: environment.devtools_app_manifest_url, + scopeCheckDisabled: true, + }, + { + symbolicName: 'testing-app', + exclude: !environment.testing_app_manifest_url, + manifestUrl: environment.testing_app_manifest_url, + }, + { + symbolicName: 'angular-io-app', + manifestUrl: '/assets/angular-io-manifest.json', + }, + ], + }), + RouterModule.forRoot([], { + useHash: true, + initialNavigation: 'disabled' + }), + BrowserAnimationsModule, + BrowserModule, + CustomExtensionModule, + ], + bootstrap: [ + AppComponent + ] +}) +export class AppModule { +} + diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-extension.module.ts b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-extension.module.ts new file mode 100644 index 000000000..270a91107 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-extension.module.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ListMessageboxComponent } from './list-messagebox/list-messagebox.component'; +import { ACTIVITY_ACTION_PROVIDER, INTENT_HANDLER, MessageBoxIntentHandler, NotificationIntentHandler } from '@scion/workbench-application-platform'; +import { ListNotificationComponent } from './list-notification/list-notification.component'; +import { CustomNotifyActivityActionComponent } from './custom-notify-activity-action/custom-notify-activity-action.component'; +import { CustomNotifyActivityActionProvider } from './custom-notify-activity-action/custom-notify-activity-action-provider.service'; + +@NgModule({ + declarations: [ + ListMessageboxComponent, + ListNotificationComponent, + CustomNotifyActivityActionComponent, + ], + imports: [ + CommonModule, + ], + entryComponents: [ + ListMessageboxComponent, + ListNotificationComponent, + CustomNotifyActivityActionComponent, + ], + providers: [ + { + provide: INTENT_HANDLER, + useFactory: provideListMessageBoxIntentHandler, + multi: true, + }, + { + provide: INTENT_HANDLER, + useFactory: provideListNotificationIntentHandler, + multi: true, + }, + { + provide: ACTIVITY_ACTION_PROVIDER, + useClass: CustomNotifyActivityActionProvider, + multi: true + }, + ], +}) +export class CustomExtensionModule { +} + +export function provideListMessageBoxIntentHandler(): MessageBoxIntentHandler { + return new MessageBoxIntentHandler({'type': 'list'}, 'Displays a messagebox with list content to the user.', ListMessageboxComponent); +} + +export function provideListNotificationIntentHandler(): NotificationIntentHandler { + return new NotificationIntentHandler({'type': 'list'}, 'Shows a notification with list content to the user.', ListNotificationComponent); +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action-provider.service.ts b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action-provider.service.ts new file mode 100644 index 000000000..8800c47e9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action-provider.service.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Injectable } from '@angular/core'; +import { ActivityActionProvider } from '@scion/workbench-application-platform'; +import { CustomNotifyActivityActionComponent } from './custom-notify-activity-action.component'; +import { CustomActivityActionTypes } from '@scion/e2e/common'; + +@Injectable() +export class CustomNotifyActivityActionProvider implements ActivityActionProvider { + public type = CustomActivityActionTypes.CustomNotify; + public component = CustomNotifyActivityActionComponent; +} + diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.html b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.html new file mode 100644 index 000000000..aeb7d75de --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.html @@ -0,0 +1,7 @@ + + notifications_none + diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.scss b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.scss new file mode 100644 index 000000000..1400644bc --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.scss @@ -0,0 +1,12 @@ +:host { + display: flex; + align-items: center; + justify-content: center; + padding: .5em; + + > a { + text-decoration: none; + color: rgb(239, 239, 239); + outline: none; + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.ts b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.ts new file mode 100644 index 000000000..b4abc5236 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/custom-notify-activity-action/custom-notify-activity-action.component.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component, Inject } from '@angular/core'; +import { NotificationService } from '@scion/workbench'; +import { ACTIVITY_ACTION } from '@scion/workbench-application-platform'; +import { CustomNotifyActivityAction } from '@scion/e2e/common'; + +@Component({ + selector: 'app-custom-notify-activity-action', + templateUrl: './custom-notify-activity-action.component.html', + styleUrls: ['./custom-notify-activity-action.component.scss'] +}) +export class CustomNotifyActivityActionComponent { + + constructor(@Inject(ACTIVITY_ACTION) public action: CustomNotifyActivityAction, + private _notificationService: NotificationService) { + } + + public onClick(event: Event): void { + event.preventDefault(); + this._notificationService.notify({ + content: this.action.properties.text, + cssClass: this.action.properties.cssClass, + }); + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.html b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.html new file mode 100644 index 000000000..405ac2b7f --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.html @@ -0,0 +1,4 @@ +{{messageBox.input?.text}} +
    +
  • {{item}}
  • +
diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.scss b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.scss new file mode 100644 index 000000000..965a822dc --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.scss @@ -0,0 +1,5 @@ +:host { + > ul { + padding: 0 0 0 1.5em; + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.ts b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.ts new file mode 100644 index 000000000..4c7fbc571 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-messagebox/list-messagebox.component.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component } from '@angular/core'; +import { MessageBox } from '@scion/workbench'; + +@Component({ + selector: 'app-list-messagebox', + templateUrl: './list-messagebox.component.html', + styleUrls: ['./list-messagebox.component.scss'], +}) +export class ListMessageboxComponent { + + constructor(public messageBox: MessageBox) { + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.html b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.html new file mode 100644 index 000000000..c72874272 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.html @@ -0,0 +1,4 @@ +{{notification.input?.text}} +
    +
  • {{item}}
  • +
diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.scss b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.scss new file mode 100644 index 000000000..965a822dc --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.scss @@ -0,0 +1,5 @@ +:host { + > ul { + padding: 0 0 0 1.5em; + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.ts b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.ts new file mode 100644 index 000000000..bb1669e22 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/app/custom-extension/list-notification/list-notification.component.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { Component } from '@angular/core'; +import { Notification } from '@scion/workbench'; + +@Component({ + selector: 'app-list-notification', + templateUrl: './list-notification.component.html', + styleUrls: ['./list-notification.component.scss'] +}) +export class ListNotificationComponent { + + constructor(public notification: Notification) { + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/assets/.gitkeep b/projects/e2e/workbench-application-platform/host-app/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/projects/e2e/workbench-application-platform/host-app/src/assets/angular-io-manifest.json b/projects/e2e/workbench-application-platform/host-app/src/assets/angular-io-manifest.json new file mode 100644 index 000000000..2734593ee --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/assets/angular-io-manifest.json @@ -0,0 +1,30 @@ +{ + "name": "Angular IO", + "baseUrl": "https://angular.io/", + "capabilities": [ + { + "type": "view", + "qualifier": { + "resource": "features" + }, + "description": "Shows features & benefits of the Angular project", + "properties": { + "title": "Angular", + "heading": "Features & Benefits", + "path": "/features" + } + }, + { + "type": "view", + "qualifier": { + "resource": "docs" + }, + "description": "Shows the documentation of the Angular project", + "properties": { + "title": "Angular", + "heading": "Documentation", + "path": "/docs" + } + } + ] +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.eot b/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.eot new file mode 100644 index 0000000000000000000000000000000000000000..460bbadc1a008e937172aedd2f98d16d7e8d5f20 GIT binary patch literal 1616 zcmaJ>U1$?o6h3!ul4)y5t27xXU7bvWS=7dwX%kwyOMDTuCJkLJ`XK8xjcFy#q{$R5 z2-baAmPJ^f77Y8)2cKkFMDVSk4?d_U7Ie$*t3L~};O@)9zG(dJoyl$@#gp8*=X~co z_nx`;%*h9ce)bbFQm9iHU1I_{p6|p3*A;CevH7u&C`1=%j)rNG3S?6Sgb>Y8kxH~e zWwNLSBto-5YE%bHaCACE2^x{ykD~#K4R_EQaT=Na>R_^Wm;XMH4UDseC9C>$=YzjM z8iZXgS@kOBKG@%3?kbg6&o%zIbQ|_HjQa~kYrfC?{a+$}0{+wj0JY2?!oCVSwy@+} zjF55w_AS_Y*)CY@D*X+66ZWnp>tYqTjKF>+{1t1d7`l6TnaJnE`rlUVx`R9+ezBfT zoHwvDPFT6FJO=WEJF`E@WZi<-CakZ`kZOkL4e@);dz9fAz*>hd+`4$k-NcTA@VPUW ztU>Zo9(W&q0%xSZIPv=7>nCrh`L5Xnf)zRt)_nQdt%1pbaZN=;`%aP!gdwiC&4Z#z zk4xhJ>`!9~?r}eN_#Wy;VGvW}=~QwLi}ZIhjSX=px1I~eg7d+5#C}_U|M|LdSs(yn z?=uoXDhkSn@tgc4ZX%8~;_0{=S2a~jYdop#W?CfNuZEZ!7&77s7T-HIn*NfdQ_5DO zG1>YzPUUiSBN{d8x$NmSo$YKfKvmX^sFTf|I-SiqQHUeCStn}X47TVB->3YF9Pkzz z5aDOC<1;*kb)|s){dYgc% zu^*?Gt9cBTf1Y_BjGZwjlIBzdGG!(wCX&giNZ8PW?4%$qPv@&(8A06$M~=ZiZnn7Q zxOpZPly`_b+e~a|U-wS_LpxBukgYq9p0&^Nl<^%QcUKT2>k-8zgx_qd2A9$0dR#+< z!Cu3d#n=+M^z=|a?WPQULqE|AAfkS{&;;Cl+@~b|_XyE1-d>DUFGAFUN@qQsLr;0S z5BiFy`*Gf3PY(c}^7I}WpzlSc`?`UI;Bj>Yddbr{^e;T!2mO+#`_aVkb<5ZQ@EK3< zp;5YVVQzS_U{^Xj;cT&1U$iUwp~T4c?Qh$tZNZshX{Bt{I{WIj%p-Qi(M!cjv1U2N zd3|nGKU%P}wp~fk5!rejyhRDkxFQ>}MGoe9U~{yJ=TX_jvtWugoxrJ!PVx!)0B$x6 A9{>OV literal 0 HcmV?d00001 diff --git a/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.svg b/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.svg new file mode 100644 index 000000000..3a2f8477f --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.svg @@ -0,0 +1,14 @@ + + + +Generated by IcoMoon + + + + + + + + + + \ No newline at end of file diff --git a/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.ttf b/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..042af077e6f70f3e9d3e9248113b96e1636b376e GIT binary patch literal 1452 zcmaJ>O=ufO6#iyM(%O!YonUFfxXEfQqLLrg(b^I=Zc#6R)JQh@G07n$Yk4EP$XZ!i zlNbVVaww$)+EXE-2OoOMp@c$jf##4yQyLm*Vv=jx6ha~GrI1Uae7jmvHJCi@?0oNg z@6CHN^HvZ5c3~3|<8voI$PVra-z9UK<9vD5s{gwCr@sL)O1)aKnsv@Y)IaCkSE+7X zX#IKld+J|t++DVVJ6lnzd@je!Q{`_E;1kKjl0A=lyO@;XNLduH1)y#8{M? z&gZiGL}IvKXktvdrL9sl6oS7?d&uo@F;WXwosM0)?^ME)a@&nerj)=c+loi3G{MlxwMOT{xiSnTe4 z&{f$ql5Vkd`b@FpCMmA(TXd5K&tMx@>o2C@!>?03rwbC;{O$!-Q7e~O?*AKR-fk(^A8ITqp7pzbk>|r zP-e~S^mH~mn}{2FRGjjh*5>Bx^fIEl5l?(V`;^)BHK)w8si=R4yt49kKR~FvjmkHkT*zW=}VCJo-A8j^c$;-{e@}*!Hk*8Ne|1qJV4o z22aU&{nLj`kf)o?cMV=Kd>7;rP=g4s7gU@NcuAZKaEN$4z+s+uJirn1vjHB!2)^(- zJ=9MoMoR}P#FYR`;tvBHBEB5pFcRR`?Z-yQ9}n;VCh+aW#ltIQr-qAI6YWk7PIQ!Q|15KJ};5tXR^YI;{b|jD6mG!FCU{affuA>SIjU7FYIyG0X*fqOh zx%QI2xS<~_J4MH-WpLEb?J|3X%hddeEV!JP$Sq=n?_+-HMS6O5W_aq}Kgm1f4Mi>d A0RR91 literal 0 HcmV?d00001 diff --git a/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.woff b/projects/e2e/workbench-application-platform/host-app/src/assets/fonts/wb-icon.woff new file mode 100644 index 0000000000000000000000000000000000000000..8e98ad14019626f5ae59358287db050a9ef23da0 GIT binary patch literal 1528 zcmaJ>U1$_n6h3$E?oNJ|O_b~ogj8oIizEJQ<4&?eLM-b`z=qufTZ2A`PBzm`%4R3o zoe%?pX&?Gf3iYYr(uX|sNu(6Pw}L+Sprz7+F(~+Cu^@u&i{OL0e)sN-jU{+?&b{CH z&bjxTx%cd>PEAY@BS`cmb<6o`+ZOnJnfmPG91-gPdroN2?&z)ZqO$~U9(GmeAG>b< zQ*j!C+k`D*h4xmeYhQqS1idA+`S*ou^R6>T#5ds23+=TYzMKaM?g8wKP_@eM%rE-q z!M%d53r&%7sOpsw7a4%PTPXXE{#|s=BX49##7OO?p_;Skf}2LpZ-gdpTwGrA8b01v zonAkLfY5=DuW%gXPtzi-d%8Ck3o_I6>t+bw|$L{Ev|Y~7>+hk{|yP;?1o7N7z6 z1RlUBq6R2JsE>N_6FejR@#jzOJh}UnTCZCzF!Vo$wf_3(m;UkoQB4i@kU{STMhxqE z>##mpUndqEyq)=k~HxUnkSpAooifrFbSj7k^Fc!N!~Y z8_Gq&fXKWlNCt@&njyxo@RR5)6MLApshX;$YPQC6+8(B*l6`7|sj)%B%rbM|$guqh zv-8SUvpF6<%~PdP!$_x%MyYsu8)m!02!tx@M%piyPMt26{4~Uuu|+>^;0(6tD}F$^ zFS?r{IZCiiTeJCr=g-H(N4Xp#P^f#Ij`1(~L9989Rk{4g@V-GKmh4NVvB8L$VDDFK zg>Ms6HTJ{Q^3pVvO>Y)9Z$_9DDY%(+$67+MBi;)_v5WS$% zxq#=u`2a_NR{|Wxc_#xL13wwyF6yUmMW;tP!6e{mV+FVpU=DmVz!BgJ0gh6N^Z>`e zp9pXl4bxAnvxgVTUX50178kuhW%8&t}ps56UG7hjSO$XnFJ0g(Uz literal 0 HcmV?d00001 diff --git a/projects/e2e/workbench-application-platform/host-app/src/environments/environment.now.ts b/projects/e2e/workbench-application-platform/host-app/src/environments/environment.now.ts new file mode 100644 index 000000000..17a8085bc --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/environments/environment.now.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +export const environment = { + production: true, + contact_app_manifest_url: 'https://scion-workbench-application-platform-contact.now.sh/assets/manifest.json', + communication_app_manifest_url: 'https://scion-workbench-application-platform-communication.now.sh/assets/manifest.json', + devtools_app_manifest_url: 'https://scion-workbench-application-platform-devtools.now.sh/assets/manifest.json', + testing_app_manifest_url: '' +}; diff --git a/projects/e2e/workbench-application-platform/host-app/src/environments/environment.ts b/projects/e2e/workbench-application-platform/host-app/src/environments/environment.ts new file mode 100644 index 000000000..84e48f7cf --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/environments/environment.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --configuration=now` replaces `environment.ts` with `environment.now.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false, + contact_app_manifest_url: 'http://localhost:5001/assets/manifest.json', + communication_app_manifest_url: 'http://localhost:5002/assets/manifest.json', + devtools_app_manifest_url: 'http://localhost:5003/assets/manifest.json', + testing_app_manifest_url: 'http://localhost:5004/assets/manifest.json', +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/projects/e2e/workbench-application-platform/host-app/src/favicon.ico b/projects/e2e/workbench-application-platform/host-app/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..30ac1ce195cfc49e758a75e4de35e792939b1b7a GIT binary patch literal 34494 zcmdU2{gYP3mA;m4QCnrL`7uRNi@$7DDn(iR0hU->TU!=MNOm^?g@`0U1vPva;vj;& zOkyN)moKBK6(k!2_{E2O1ObB?#SJj7pu;dSATXFPKnOS?1V$O?eV)Ge^ql*B@B6;< zg14&Y^zGZ-=RBuRpYFH2?;X#(&igy>3t#X+Z}ukL;CZ7x&->yR{rmZU?|E+`?dF^P z`t{-fvJe!GAFrGNIkXaB|XzJxlE6*cm$NF+We_(K46f%6t~4mm(2fwQ3;AXvv`cvjI;<~)lBXz~f zj(zd#X5o$}P1}jR2C`?Bw{?Ku3*<>&>-WEEdMH3x< zSfDwMO7cX5jEnVBqytikE z_)GbKPEqA=mGY#MHhicM>Ml}81?A35 zS<*=P^SG}>%Ss)jC^Hyg8A6{b--j~G5C-eKS#gxT1z`)yFx--sw{L{!bq(^o%60uY z7>|aQ>pf2b^Y;$*yeo5kKLc0g!5w+@U)5f)L2vYmk;6bMp!7Q(m#m znTJ81S^LS>jX@iX8nbfbVCrSk+Pkd^w5(Bm@tzlXOnY~3(5^9^xOB)rc+3jhf7lM@ zncpu6jX{)Gct~98zu4DncAVO6ezNar`gA{pZK)gS)>KiJ?cn-QG)^AlUimk3&ue3x zetIu|>f*=F|Iw^Gvery(ovUqWgY*NG=bXdID)GBs9A)la^G!RR(I+y9{BsUHYgV89 zt@-1{Q#Or%HvZuatDB&|RaE_GhyMCSRvEikuf(PPM>u93@W-viU8~HlPxhI`A3m?^ zAEoLatYu|gI!xaDJ@Y>wJa4*sjyRpL{u!MM!{NXJGqvp}=7D!-vpt;8M_nF5Y@C|= z)?*ki-?ZbVQvxEiACaFtEDm6iIL6^_1QFlT2^+_5(0X9}{gZoawf?yLrW= zn4rFj)(PWF_x{4_h5C_atQ-E{pD#r96Wjw&Md}rb@}nqoUf{f7!O;~lolr+kKb;F* z+e-bYm*cauleD<5CpDfhoEakW;0LrC{_wy;{30oKfd}VSZeBzz3H6^xy_FdU!gH!(9Q<6Ub1>>&hR{bIfqwd6 z-^+l-^`SC#CglYme_nL}^Qr^s^QvfBv%`2-yt!VFcavAaOi5q7kA@cSdM_Hfyg?oV z>*(`F*!s*oVOh%Ztb%{4EU2qh*H<)t-E=gO~|A8&um>^!!^T)KS8@n$5jKaI0UoV=Ih@fWNo&vl1*>YFP0 zllS-}{#jTr+VzkvSPz-zM5vNKdDEA;IbIglBWFIsy!+>&xvU6KC4ch10pUDln6q_8 ztX(x$EvLk5;C~+WYR65~Wo=M?3$V^4tin@M;s0UJA@ksFyAD&t?wIEtamlF9+2F>G zHMU(fkF2=xCq4JsU(MFzEoRQ%r;5n1MDb6w!7RRGR(;isd-dNndl%LHH5#jJ*5L{gPMO7E9Ys^AWVcm zWnh@uxx{dtk2*PY?x^q;>TFN(_iZo(tL8m*+XLp+j+cbJUC$KWQ97&hX*1>hADPL! zX9<62d%_=Uq~mqFYF-lm?#6GMr*=MR-tFEU^Al10Q5ks8bDBrO2_k^*=-G?C-u~{lEM8umpdud0M|G zyoG|_JHk`b>DwN%{JVONnqT4f^5oaQ=j>1fE5Sczdy4-O%~!|gzBSA7)am5U-=&*R zzY|^CO}mfTp5i}V*Igv;ezykwPPK6w|CsG5{;4*YCQAW+Q8{9^r})zb-CB1VPn}+Z zzpR-j+MdWjiu(DRZky(l7B9$u8}g;Dxoh4M2S3Vj2SQsKZ>Hz)Z^QG<-~GZbje-Z; zWFkWHxoGWEhd$HN-=u+jb+GuJQR><#kq zd<6GTxi=M-S;;RrNQ=ZNdcOVi@9Ww<(qLaM9GCtQwlVBC4jU85EHdR$X^$fEm$siY zyVB{(#^6Iz_p3!dk(acH%}l`lHrJE5)}pVn_LFC4XdmvwZi>s<@4v0g1?`9HZrcxS zF?ZM|-*V_XCHZIn30#^f2PlOHw`8na5+jIuqPcks^}LFP?j zCqlKZ$vf@Ry0-0DaQ;)+M$*T+O)`!_W_xBvbjEX$l#7?>PvSzguBFYSyu}gNqU0xa z`iD&6u_q4OF)YiV|Ji~OWfU28eh;<~((zYg{TeD2Hucn=Y~A)UN- zJk{kct?MG=m(JrVL4;W5?|UY5&QsW~cFr84^v}7E9fzq$h7;$GJ0BuxVjn`8o)@S5 zlv^&wKR$mP=Y!U{Gf(Ahsi_;jU&OZ*a@cWLWF5O|RH82`BD2n;?I#-d&s4RVC-?o_ z|4mceu3X<05d7^&UFslmh>q{5&(nFdJv`)|}iPI+G`PdpR{bW8%I7ce73x%FHg=|CHjEc{0X>z(2`^cjre-Zmh$&=c5 zMSkekom&-~(fSwrd98De6<2J7Hxj4)(2km6PdeSnU($YD-@rR1B4-+f%%j9UlH`|X zi(CIIW-oRhwrx4~VJEtNBep{-@@Lve_x=D%tI)*3(97!pAVi*f5YE9 z*1C3ORC(I~!5@)7#Wvg-VW)5Url74@20kgZ?~42wk35|1?bbG<<6=L=vTW~vTU{3& zzc^ob1oH=xiS1B0-npn77(~oW3VAnanWJ&u7Y)AMTsEye?dC^^mxk=2q#fn%Bz zcn&!}W@%fJ=Q*_V{4ukjtN;AC=-b+mvW>iSV6BLJc@(nSK1>XvXNg;?WVZ94;65pC z?Ur^zTb8k@ia5?}=k{H}1)0NrSjkKI%LHF$U-p{for`k&uE-DhxJN${I5N-XOWS18 zk~W^yKiY5(eQ3b_K%?6o=BiM5^ z80+lsFzP=ko@+n858Z}*JTB0%D|r8AB;?LMhhu$avj2gd@co;SGcw-48E8O|pXYdN zA5XHS6#L;^;6BJ-bKk5NK49?s_y)g^TOWn~5wV}3Z&v^QP`%_$s|PqZ_AN)~L-5Dl z&P6<f|-6EF1B^Qeaq(Y~gQx}lsaRht*Sj*Lj_|y&e%8(zT!T7J`9*8){)P`dp zhws}h+A-hkJMq5TR|8XjcV%+`&XO4TMugD!7pu`nwQYSB@$2tLR_*_*X>0E7ZvSYjnYCql68uK_ zzYh7?i1se!1FLQ8qh}ABWv$Pc39o!B@%O(dqe1>}g~DIR2iDrwN&QMNYuX_E(-i(x zA6U<}zQ*w1rtl~FKz>WI$apPnr~7ph)}%Bkt7!w;-}yeJgP0Foy>FEkD>a_fuamGQ zr6pC`0Q}DPDf}@X_|#j?N#fbGYTEi5!tZ>a!XNX2(ewTUUQ1gS#sAK!R`UqY2uwWOsPSRcNbjrY3E5`3#O_{MKN_2GP2~N%&tA>S_HS`dH>|zELiSYuYHg1 zccyuV{~n!t5JUz5KhNowI`F%11;_QlnzS!z$~mu z&xoJz@3!{rx9^eGfHO^JrG1~mU)l#IVa!T9DDR;Lzw-wGe`(*R@R#<1Sy+>v4FKM# z9hCNc3V&5TFbQW`S_ANx_I(OJePH5uq|@+}O&?(VvH$Za*oso%@!wyo;vLl@x)>n* z{`+(#=e$`u0hZAFZ$+>b$x~hxTtr9U~Fy4Kues;Ii-Nf>!M#Yrs$6c1^tN3;b34$SUyH-M8g7bioYJ zLunsb0{?*fwt_Hovq2AqePluW4fAce;0k7d4hs3m9Q;?!w-tn$n+~c#r6NM4NLI<+ayx^y#^r8qk=b&T6IBTc@)~_MXiTvg}2wCRY>vw seym_a``f|)P(*+G_#cYEz5P%GsI;T~Pz3M!p$J~RL-7X}KNMm9AG|F>Qvd(} literal 0 HcmV?d00001 diff --git a/projects/e2e/workbench-application-platform/host-app/src/index.html b/projects/e2e/workbench-application-platform/host-app/src/index.html new file mode 100644 index 000000000..0f3dc69af --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/index.html @@ -0,0 +1,13 @@ + + + + + Workbench Application Platform + + + + + + + + diff --git a/projects/e2e/workbench-application-platform/host-app/src/main.ts b/projects/e2e/workbench-application-platform/host-app/src/main.ts new file mode 100644 index 000000000..c7b673cf4 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/projects/e2e/workbench-application-platform/host-app/src/now.json b/projects/e2e/workbench-application-platform/host-app/src/now.json new file mode 100644 index 000000000..2f95df25c --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/now.json @@ -0,0 +1,5 @@ +{ + "version": 2, + "name": "scion-workbench-application-platform", + "alias": "scion-workbench-application-platform" +} diff --git a/projects/e2e/workbench-application-platform/host-app/src/polyfills.ts b/projects/e2e/workbench-application-platform/host-app/src/polyfills.ts new file mode 100644 index 000000000..1d7b9ab94 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/polyfills.ts @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +import 'core-js/es6/symbol'; +import 'core-js/es6/object'; +import 'core-js/es6/function'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/number'; +import 'core-js/es6/math'; +import 'core-js/es6/string'; +import 'core-js/es6/date'; +import 'core-js/es6/array'; +import 'core-js/es6/regexp'; +import 'core-js/es6/map'; +import 'core-js/es6/weak-map'; +import 'core-js/es6/set'; +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +import 'web-animations-js'; // Run `npm install --save web-animations-js`. +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + + // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + + /* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/projects/e2e/workbench-application-platform/host-app/src/styles.scss b/projects/e2e/workbench-application-platform/host-app/src/styles.scss new file mode 100644 index 000000000..ff72f92b8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/src/styles.scss @@ -0,0 +1,5 @@ +@import '../../../../scion/workbench/src/theme/theming'; +@import 'common'; + +@include wb-theme(); +@include app-theme(); diff --git a/projects/e2e/workbench-application-platform/host-app/tsconfig.app.json b/projects/e2e/workbench-application-platform/host-app/tsconfig.app.json new file mode 100644 index 000000000..f06ee9dc5 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/tsconfig.app.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "outDir": "../../../../out-tsc/host-app", + "types": [] + } +} diff --git a/projects/e2e/workbench-application-platform/host-app/tslint.json b/projects/e2e/workbench-application-platform/host-app/tslint.json new file mode 100644 index 000000000..e3e7b64d8 --- /dev/null +++ b/projects/e2e/workbench-application-platform/host-app/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/protractor.conf.js b/projects/e2e/workbench-application-platform/test-runner/protractor.conf.js new file mode 100644 index 000000000..a224f8a3f --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/protractor.conf.js @@ -0,0 +1,35 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +const puppeteer = require('puppeteer'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome', + chromeOptions: { + args: ['--headless', '--window-size=1920,1080'], + binary: puppeteer.executablePath(), + }, + }, + SELENIUM_PROMISE_MANAGER: false, + directConnect: true, + baseUrl: 'http://localhost:5000/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.e2e.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; diff --git a/projects/e2e/workbench-application-platform/test-runner/src/activity.e2e-spec.ts b/projects/e2e/workbench-application-platform/test-runner/src/activity.e2e-spec.ts new file mode 100644 index 000000000..4554ef31f --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/activity.e2e-spec.ts @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { HostAppPO } from './page-object/host-app.po'; +import { browser, protractor } from 'protractor'; +import { expectActivityToExistButHidden, expectActivityToShow, expectPopupToNotExist, expectPopupToShow, expectViewToNotExist, expectViewToShow } from './util/testing.util'; +import { TestingActivityPO } from './page-object/testing-activity.po'; +import { Testcase4a3a8984ActivityPO } from './page-object/testcase-4a3a8984-activity-po'; +import { Testcase28f32b51ActivityPO } from './page-object/testcase-28f32b51-activity.po'; +import { Testcase5782ab19ActivityPO } from './page-object/testcase-5782ab19-activity.po'; +import { Testcase56657ad1ViewPO } from './page-object/testcase-56657ad1-view.po'; +import { TestcaseC8e40918ViewPO } from './page-object/testcase-c8e40918-view.po'; +import { TestcaseA686d615ViewPO } from './page-object/testcase-a686d615-view.po'; +import { TestingViewPO } from './page-object/testing-view.po'; +import { TestcaseCc977da9ViewPO } from './page-object/testcase-cc977da9-view.po'; +import { TestcaseB6a8fe23ViewPO } from './page-object/testcase-b6a8fe23-view.po'; +import { Testcase9c5319f7PopupPO } from './page-object/testcase-9c5319f7-popup.po'; +import { Testcase45dc693fPopupPO } from './page-object/testcase-45dc693f-popup.po'; +import { TestcaseF4286ac4PopupPO } from './page-object/testcase-f4286ac4-popup.po'; +import { Testcase159913adPopupPO } from './page-object/testcase-159913ad-popup.po'; +import { Testcase8a468258PopupPO } from './page-object/testcase-8a468258-popup.po'; + +const E2E_TESTING_ACTIVITY_CONTEXT: string[] = ['e2e-testing-app', 'e2e-activity', 'e2e-testing-activity']; + +describe('Activity', () => { + + const hostAppPO = new HostAppPO(); + + beforeEach(async () => { + await browser.get('/'); + }); + + describe('Registration', () => { + + it('should be registered as specified in the manifest [testcase: d11be592-activity]', async () => { + const activityItemPO = await hostAppPO.findActivityItem('e2e-activity-d11be592'); + + await expect(activityItemPO.getTitle()).toEqual('d29b10b862ae'); + await expect(activityItemPO.getText()).toEqual(''); + await expect(activityItemPO.getCssClasses()).toContain('e2e-activity-d11be592'); + await expect(activityItemPO.getCssClasses()).toContain('fab'); + await expect(activityItemPO.getCssClasses()).toContain('fa-android'); + + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-d11be592', componentSelector: 'app-testing-activity'}); + + const testingActivityPO = new TestingActivityPO(['e2e-testing-app', 'e2e-activity', 'e2e-activity-d11be592']); + const activityPanelPO = await hostAppPO.findActivityPanel('e2e-activity-d11be592'); + await expect(testingActivityPO.getUrlParameters()).toEqual({manifestMatrixParam: 'manifestMatrixParamValue'}); + await expect(testingActivityPO.getUrlQueryParameters()).toEqual({manifestQueryParam: 'manifestQueryParamValue'}); + await expect(activityPanelPO.getTitle()).toEqual('d29b10b862ae'); + await expect(activityPanelPO.getCssClasses()).toContain('e2e-activity-d11be592'); + }); + }); + + describe('Interaction', () => { + + it('should allow to change activity properties', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + + const activityInteractionPO = await testingActivityPO.openActivityInteractionPanel(); + const activityItemPO = await hostAppPO.findActivityItem('e2e-testing-activity'); + const activityPanelPO = await hostAppPO.findActivityPanel('e2e-testing-activity'); + + await activityInteractionPO.enterTitle('e2e:title'); + await expect(activityItemPO.getTitle()).toEqual('e2e:title'); + await expect(activityPanelPO.getTitle()).toEqual('e2e:title'); + + await activityInteractionPO.enterItemText('e2e:item-text'); + await expect(activityItemPO.getText()).toEqual('e2e:item-text'); + + await activityInteractionPO.enterItemCssClass('e2e:item-css-class'); + await expect(activityItemPO.getCssClasses()).toContain('e2e:item-css-class'); + await expect(activityPanelPO.getCssClasses()).not.toContain('e2e:item-css-class'); + + const sizeBefore = await activityPanelPO.getSize(); + await activityInteractionPO.enterDeltaPx(100); + const sizeAfter = await activityPanelPO.getSize(); + await expect(sizeAfter.width).toEqual(sizeBefore.width + 100); + }); + + it('should allow to close the activity', async () => { + const activityItemPO = await hostAppPO.findActivityItem('e2e-testing-activity'); + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + + // close the activity + await activityItemPO.click(); + await expectActivityToExistButHidden({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity'}); + }); + + it('should attach previously detached activity component instance when activating it [testcase: 4a3a8984-activity]', async () => { + const activityItemPO = await hostAppPO.findActivityItem('e2e-activity-4a3a8984'); + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-4a3a8984', componentSelector: 'app-activity-4a3a8984'}); + + const activityPO = new Testcase4a3a8984ActivityPO(); + const componentInstanceUuid = await activityPO.getComponentInstanceUuid(); + + // close the activity + await activityItemPO.click(); + await expectActivityToExistButHidden({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-4a3a8984'}); + + // open the activity + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-4a3a8984', componentSelector: 'app-activity-4a3a8984'}); + await expect(activityPO.getComponentInstanceUuid()).toEqual(componentInstanceUuid); + + // switch to other activity + const testingActivityItemPO = await hostAppPO.findActivityItem('e2e-testing-activity'); + await testingActivityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + + // switch back to the activity + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-4a3a8984', componentSelector: 'app-activity-4a3a8984'}); + await expect(activityPO.getComponentInstanceUuid()).toEqual(componentInstanceUuid); + }); + + it('should receive an activate event if activated, and receive a deactivate event if deactivated [testcase: 28f32b51-activity]', async () => { + const activityItemPO = await hostAppPO.findActivityItem('e2e-activity-28f32b51'); + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-28f32b51', componentSelector: 'app-activity-28f32b51'}); + + const activityPO = new Testcase28f32b51ActivityPO(); + await expect(activityPO.readActiveLog()).toEqual([true]); + + // close the activity + await activityItemPO.click(); + await expectActivityToExistButHidden({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-28f32b51'}); + + // open the activity + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-28f32b51', componentSelector: 'app-activity-28f32b51'}); + await expect(activityPO.readActiveLog()).toEqual([true, false, true]); + + // switch to other activity + const testingActivityItemPO = await hostAppPO.findActivityItem('e2e-testing-activity'); + await testingActivityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + + // switch back to the activity + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-28f32b51', componentSelector: 'app-activity-28f32b51'}); + await expect(activityPO.readActiveLog()).toEqual([true, false, true, false, true]); + }); + + it('should not show the iframe of inactive activities [testcase: 6d806bea-activity]', async () => { + const activityItemPO = await hostAppPO.findActivityItem('e2e-activity-6d806bea'); + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-6d806bea', componentSelector: 'app-activity-6d806bea'}); + + // close the activity + await activityItemPO.click(); + await expectActivityToExistButHidden({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-6d806bea'}); + + // open the activity + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-6d806bea', componentSelector: 'app-activity-6d806bea'}); + + // switch to other activity + const testingActivityItemPO = await hostAppPO.findActivityItem('e2e-testing-activity'); + await testingActivityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + await expectActivityToExistButHidden({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-6d806bea'}); + + // switch back to the activity + await activityItemPO.click(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-6d806bea', componentSelector: 'app-activity-6d806bea'}); + await expectActivityToExistButHidden({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity'}); + }); + }); + + describe('Focus', () => { + + it('should cycle the focus in the activity [testcase: 5782ab19-activity]', async () => { + await hostAppPO.clickActivityItem('e2e-activity-5782ab19'); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-5782ab19', componentSelector: 'app-activity-5782ab19'}); + + const activityPO = new Testcase5782ab19ActivityPO(); + await expect(activityPO.isActiveElement('field-1')).toBeTruthy('(1)'); + + await activityPO.pressTab(); + await expect(activityPO.isActiveElement('field-2')).toBeTruthy('(2)'); + + await activityPO.pressTab(); + await expect(activityPO.isActiveElement('field-3')).toBeTruthy('(3)'); + + await activityPO.pressTab(); + await expect(activityPO.isActiveElement('field-1')).toBeTruthy('(4)'); + + await activityPO.pressTab(); + await expect(activityPO.isActiveElement('field-2')).toBeTruthy('(5)'); + + await activityPO.pressTab(); + await expect(activityPO.isActiveElement('field-3')).toBeTruthy('(6)'); + + await activityPO.pressShiftTab(); + await expect(activityPO.isActiveElement('field-2')).toBeTruthy('(7)'); + + await activityPO.pressShiftTab(); + await expect(activityPO.isActiveElement('field-1')).toBeTruthy('(8)'); + + await activityPO.pressShiftTab(); + await expect(activityPO.isActiveElement('field-3')).toBeTruthy('(9)'); + + await activityPO.pressShiftTab(); + await expect(activityPO.isActiveElement('field-2')).toBeTruthy('(10)'); + + await activityPO.pressShiftTab(); + await expect(activityPO.isActiveElement('field-1')).toBeTruthy('(11)'); + }); + + it('should restore the focus upon activity activation [testcase: 5782ab19-activity]', async () => { + await hostAppPO.clickActivityItem('e2e-activity-5782ab19'); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-5782ab19', componentSelector: 'app-activity-5782ab19'}); + + const activityPO = new Testcase5782ab19ActivityPO(); + await expect(activityPO.isActiveElement('field-1')).toBeTruthy('(1)'); + + await activityPO.pressTab(); + await expect(activityPO.isActiveElement('field-2')).toBeTruthy('(2)'); + + await hostAppPO.clickActivityItem('e2e-testing-activity'); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + + await hostAppPO.clickActivityItem('e2e-activity-5782ab19'); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-5782ab19', componentSelector: 'app-activity-5782ab19'}); + await expect(activityPO.isActiveElement('field-2')).toBeTruthy('(3)'); + }); + + it('should autofocus the first element [testcase: 5782ab19-activity]', async () => { + await hostAppPO.clickActivityItem('e2e-activity-5782ab19'); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-activity-5782ab19', componentSelector: 'app-activity-5782ab19'}); + + const activityPO = new Testcase5782ab19ActivityPO(); + await expect(activityPO.isActiveElement('field-1')).toBeTruthy('Expected first field to be the active element'); + }); + }); + + describe('Activity View Item', () => { + + it('should allow navigation to private views of the same application (implicit intent) [testcase: 354aa6da-activity]', async () => { + await hostAppPO.clickActivityItem('e2e-activity-354aa6da'); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-354aa6da', componentSelector: 'app-view-354aa6da'}); + }); + + it('should allow navigation to public views of the same application (implicit intent) [testcase: 85dde646-activity]', async () => { + await hostAppPO.clickActivityItem('e2e-activity-85dde646'); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-85dde646', componentSelector: 'app-view-85dde646'}); + }); + }); + + describe('Activity Action', () => { + + it('should allow to add and remove activity actions [testcase: 354aa6da-activity]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + const actionPanelPO = await testingActivityPO.openActivityActionsPanel(); + + // hide action + const action = await actionPanelPO.findCustomActivityAction(); + await actionPanelPO.checkCustomActivityAction(false); + await expect(action.isPresent()).toBeFalsy('(1)'); + + // show action + await actionPanelPO.checkCustomActivityAction(true); + await expect(action.isPresent()).toBeTruthy('(2)'); + + // hide action + await actionPanelPO.checkCustomActivityAction(false); + await expect(action.isPresent()).toBeFalsy('(3)'); + }); + + it('should allow to contribute custom activity actions', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + await expectActivityToShow({symbolicAppName: 'testing-app', activityCssClass: 'e2e-testing-activity', componentSelector: 'app-testing-activity'}); + const actionPanelPO = await testingActivityPO.openActivityActionsPanel(); + await actionPanelPO.checkCustomActivityAction(true); + + + const customAction = await hostAppPO.findActivityAction('e2e-custom-activity-action'); + await customAction.click(); + + await expect(await hostAppPO.findNotification('e2e-custom-activity-action')).toBeTruthy(); + }); + + describe('ViewOpenActivityAction', () => { + + it('should allow navigation to private views of the same application (implicit intent) [testcase: 354aa6da-view]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-354aa6da-view-activity-action'); + await panelPO.enterTitle('testcase: 354aa6da-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '354aa6da-view', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-354aa6da-view-activity-action'); + await action.click(); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-354aa6da', componentSelector: 'app-view-354aa6da'}); + }); + + it('should allow navigation to public views of the same application (implicit intent) [testcase: 85dde646-view]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-85dde646-view-activity-action'); + await panelPO.enterTitle('testcase: 85dde646-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '85dde646-view', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-85dde646-view-activity-action'); + await action.click(); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-85dde646', componentSelector: 'app-view-85dde646'}); + }); + + it('should allow navigation to public views of other applications [testcase: d7da51f14c25]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-d7da51f14c25-activity-action'); + await panelPO.enterTitle('testcase: d7da51f14c25'); + await panelPO.enterQualifier({ + entity: 'communication', + presentation: 'list', + contactId: '5', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-d7da51f14c25-activity-action'); + await action.click(); + await expectViewToShow({symbolicAppName: 'communication-app', viewCssClass: 'e2e-communication-list', componentSelector: 'app-communication-view'}); + }); + + it('should not allow navigation to public views of other applications if missing the intent [testcase: 0901198a704b]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-0901198a704b-activity-action'); + await panelPO.enterTitle('testcase: 0901198a704b'); + await panelPO.enterQualifier({ + entity: 'communication', + presentation: 'list', + contactId: '999', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-0901198a704b-activity-action'); + await action.click(); + + const notificationPO = await hostAppPO.findNotification('e2e-not-qualified'); + await expect(notificationPO).not.toBeNull(); + await expect(notificationPO.getSeverity()).toEqual('error'); + await expectViewToNotExist({symbolicAppName: 'communication-app', viewCssClass: 'e2e-communication-list'}); + }); + + it('should not allow navigation to private views of other application [testcase: 0427da7f4a49]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-0427da7f4a49-activity-action'); + await panelPO.enterTitle('testcase: 0427da7f4a49'); + await panelPO.enterQualifier({ + entity: 'contact', + id: '5', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-0427da7f4a49-activity-action'); + await action.click(); + + const notificationPO = await hostAppPO.findNotification('e2e-not-handled'); + await expect(notificationPO).not.toBeNull(); + await expect(notificationPO.getSeverity()).toEqual('error'); + await expectViewToNotExist({symbolicAppName: 'contact-app', viewCssClass: 'e2e-contact'}); + }); + + it('should allow to provide query and matrix parameters [testcase: 56657ad1-view]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-56657ad1-view-activity-action'); + await panelPO.enterTitle('testcase: 56657ad1-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '56657ad1-view', + }); + await panelPO.enterMatrixParams({ + mp1: '41ecdefec0a3', + mp2: 'da67bd554b36', + }); + await panelPO.enterQueryParams({ + qp1: '6378a62700d3', + qp2: 'c5a37d3660ba', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-56657ad1-view-activity-action'); + await action.click(); + + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-56657ad1', componentSelector: 'app-view-56657ad1'}); + + const viewPO = new Testcase56657ad1ViewPO(); + const urlParams = await viewPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: '41ecdefec0a3', + mp2: 'da67bd554b36', + }); + + const urlQueryParams = await viewPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: '6378a62700d3', + qp2: 'c5a37d3660ba', + }); + }); + + it('should allow to receive query and matrix parameters as specified in the manifest [testcase: c8e40918-view]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-c8e40918-view-activity-action'); + await panelPO.enterTitle('testcase: c8e40918-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: 'c8e40918-view', + }); + + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-c8e40918-view-activity-action'); + await action.click(); + + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-c8e40918', componentSelector: 'app-view-c8e40918'}); + + const viewPO = new TestcaseC8e40918ViewPO(); + const urlParams = await viewPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: 'd52f5f88be27', + mp2: '01aa011fb2f4', + }); + + const urlQueryParams = await viewPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: 'f3227d5926c0', + qp2: '88a9cd0cb937', + }); + }); + + it('should allow to merge query and matrix parameters provided from intent (overwrite) and manifest [testcase: a686d615-view]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-a686d615-view-activity-action'); + await panelPO.enterTitle('testcase: a686d615-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: 'a686d615-view', + }); + await panelPO.enterMatrixParams({ + mp1: '557c7323a13c', + mp2: '67dbebc8dd7c', + }); + await panelPO.enterQueryParams({ + qp1: 'a3fa547519cf', + qp2: 'db03e5494054', + }); + + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-a686d615-view-activity-action'); + await action.click(); + + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-a686d615', componentSelector: 'app-view-a686d615'}); + + const viewPO = new TestcaseA686d615ViewPO(); + const urlParams = await viewPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: '557c7323a13c', + mp2: '67dbebc8dd7c', + mpx: 'f406422c77fc', + }); + + const urlQueryParams = await viewPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: 'a3fa547519cf', + qp2: 'db03e5494054', + qpx: '18c9d6c51b0c', + }); + }); + + it('should allow to navigate to an opened view (activateIfPresent=true) [testcase: 4a4e6970-view]', async () => { + // Open testing view to open '4a4e6970-view' + const testingViewPO = new TestingViewPO(); + await testingViewPO.navigateTo(); + const viewNavigationPO = await testingViewPO.openViewNavigationPanel(); + await viewNavigationPO.enterQualifier({ + entity: 'testing', + testcase: '4a4e6970-view', + }); + await viewNavigationPO.selectTarget('blank'); + await viewNavigationPO.execute(); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-4a4e6970', componentSelector: 'app-view-4a4e6970'}); + + // Go back to the testing view + await hostAppPO.clickViewTab('e2e-testing-view'); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-testing-view', componentSelector: 'app-testing-view'}); + await expect(hostAppPO.getViewTabCount()).toBe(2); + + // Add activity action to activate the testing view + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-4a4e6970-view-activity-action'); + await panelPO.enterTitle('testcase: 4a4e6970-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '4a4e6970-view', + }); + await panelPO.checkActivateIfPresent(true); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-4a4e6970-view-activity-action'); + await action.click(); + + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-4a4e6970', componentSelector: 'app-view-4a4e6970'}); + await expect(hostAppPO.getViewTabCount()).toBe(2); + }); + + + it('should allow to close an opened view (closeIfPresent=true) [testcase: 608aa47c-view]', async () => { + // Open testing view to open '4a4e6970-view' + const testingViewPO = new TestingViewPO(); + await testingViewPO.navigateTo(); + const viewNavigationPO = await testingViewPO.openViewNavigationPanel(); + await viewNavigationPO.enterQualifier({ + entity: 'testing', + testcase: '608aa47c-view', + }); + await viewNavigationPO.selectTarget('blank'); + await viewNavigationPO.execute(); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-608aa47c', componentSelector: 'app-view-608aa47c'}); + + // Add activity action to close the testing view + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-608aa47c-view-activity-action'); + await panelPO.enterTitle('testcase: 608aa47c-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '608aa47c-view', + }); + await panelPO.checkCloseIfPresent(true); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-608aa47c-view-activity-action'); + await action.click(); + + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-testing-view', componentSelector: 'app-testing-view'}); + await expect(hostAppPO.getViewTabCount()).toBe(1); + }); + + + it('should substitute path parameters with values from the intent qualifier [testcase: cc977da9-view]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-cc977da9-view-activity-action'); + await panelPO.enterTitle('testcase: cc977da9-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: 'cc977da9-view', + qualifierParam1: 'e82bf49c4768', + qualifierParam2: '1b84a4a926f7' + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-cc977da9-view-activity-action'); + await action.click(); + + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-cc977da9', componentSelector: 'app-view-cc977da9'}); + + const viewPO = new TestcaseCc977da9ViewPO(); + const urlParams = await viewPO.getUrlParameters(); + await expect(urlParams).toEqual({ + a: 'e82bf49c4768', + b: '1b84a4a926f7', + }); + + const urlQueryParams = await viewPO.getUrlQueryParameters(); + await expect(urlQueryParams).toBeNull(); + }); + + it('should substitute matrix and query parameters with values from the intent qualifier [testcase: b6a8fe23-view]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openViewOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-b6a8fe23-view-activity-action'); + await panelPO.enterTitle('testcase: b6a8fe23-view'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: 'b6a8fe23-view', + qualifierParam1: 'd8b74df2c77d', + qualifierParam2: 'e60c81360bee', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-b6a8fe23-view-activity-action'); + await action.click(); + + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-b6a8fe23', componentSelector: 'app-view-b6a8fe23'}); + + const viewPO = new TestcaseB6a8fe23ViewPO(); + const urlParams = await viewPO.getUrlParameters(); + await expect(urlParams).toEqual({ + matrixParam1: 'd8b74df2c77d', + matrixParam2: 'eda2e91468e1', + pathParam1: 'd8b74df2c77d', + }); + + const urlQueryParams = await viewPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + queryParam1: 'e60c81360bee', + queryParam2: '1a3d3aaf937e' + }); + }); + }); + + describe('PopupOpenActivityAction', () => { + + it('should allow navigation to private popups of the same application (implicit intent) [testcase: 1a90c8d2-popup]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-1a90c8d2-popup-activity-action'); + await panelPO.enterTitle('testcase: 1a90c8d2-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '1a90c8d2-popup', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-1a90c8d2-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-1a90c8d2', componentSelector: 'app-popup-1a90c8d2'}); + }); + + it('should allow navigation to public popups of the same application (implicit intent) [testcase: 7330f506-popup]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-7330f506-popup-activity-action'); + await panelPO.enterTitle('testcase: 7330f506-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '7330f506-popup', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-7330f506-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-7330f506', componentSelector: 'app-popup-7330f506'}); + }); + + it('should allow navigation to public popups of other applications [testcase: 924e114f777c]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-924e114f777c-popup-activity-action'); + await panelPO.enterTitle('testcase: 924e114f777c-popup'); + await panelPO.enterQualifier({ + entity: 'communication', + action: 'create', + contactId: '5', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-924e114f777c-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'communication-app', popupCssClass: 'e2e-communication-create', componentSelector: 'app-communication-new-popup'}); + }); + + it('should not allow navigation to public popups of other applications if missing the intent [testcase: 13370b2aa222]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-13370b2aa222-popup-activity-action'); + await panelPO.enterTitle('testcase: 13370b2aa222-popup'); + await panelPO.enterQualifier({ + entity: 'communication', + action: 'create', + contactId: '999', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-13370b2aa222-popup-activity-action'); + await action.click(); + + const notificationPO = await hostAppPO.findNotification('e2e-not-qualified'); + await expect(notificationPO).not.toBeNull(); + await expect(notificationPO.getSeverity()).toEqual('error'); + await expectPopupToNotExist({symbolicAppName: 'communication-app', popupCssClass: 'e2e-communication-create'}); + }); + + it('should not allow navigation to private popups of other application [testcase: cf12d60debc8]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-cf12d60debc8-popup-activity-action'); + await panelPO.enterTitle('testcase: cf12d60debc8-popup'); + await panelPO.enterQualifier({ + entity: 'contact', + action: 'create', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-cf12d60debc8-popup-activity-action'); + await action.click(); + + const notificationPO = await hostAppPO.findNotification('e2e-not-handled'); + await expect(notificationPO).not.toBeNull(); + await expect(notificationPO.getSeverity()).toEqual('error'); + await expectPopupToNotExist({symbolicAppName: 'contact-app', popupCssClass: 'e2e-contact'}); + }); + + it('should allow to provide query and matrix parameters [testcase: 9c5319f7-popup]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-9c5319f7-popup-activity-action'); + await panelPO.enterTitle('testcase: 9c5319f7-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '9c5319f7-popup' + }); + await panelPO.enterMatrixParams({ + mp1: '41ecdefec0a3', + mp2: 'da67bd554b36', + }); + await panelPO.enterQueryParams({ + qp1: '6378a62700d3', + qp2: 'c5a37d3660ba', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-9c5319f7-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-9c5319f7', componentSelector: 'app-popup-9c5319f7'}); + + const popupPO = new Testcase9c5319f7PopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: '41ecdefec0a3', + mp2: 'da67bd554b36', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: '6378a62700d3', + qp2: 'c5a37d3660ba', + }); + }); + + it('should allow to receive query and matrix parameters as specified in the manifest [testcase: 45dc693f-popup]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-45dc693f-popup-activity-action'); + await panelPO.enterTitle('testcase: 45dc693f-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '45dc693f-popup', + }); + + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-45dc693f-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-45dc693f', componentSelector: 'app-popup-45dc693f'}); + + const popupPO = new Testcase45dc693fPopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: 'd52f5f88be27', + mp2: '01aa011fb2f4', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: 'f3227d5926c0', + qp2: '88a9cd0cb937', + }); + }); + + it('should allow to merge query and matrix parameters provided from intent (overwrite) and manifest [testcase: f4286ac4-popup]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-f4286ac4-popup-activity-action'); + await panelPO.enterTitle('testcase: f4286ac4-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: 'f4286ac4-popup', + }); + await panelPO.enterMatrixParams({ + mp1: '557c7323a13c', + mp2: '67dbebc8dd7c', + }); + await panelPO.enterQueryParams({ + qp1: 'a3fa547519cf', + qp2: 'db03e5494054', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-f4286ac4-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-f4286ac4', componentSelector: 'app-popup-f4286ac4'}); + + const popupPO = new TestcaseF4286ac4PopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: '557c7323a13c', + mp2: '67dbebc8dd7c', + mpx: 'f406422c77fc', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: 'a3fa547519cf', + qp2: 'db03e5494054', + qpx: '18c9d6c51b0c', + }); + }); + + it('should substitute path parameters with values from the intent qualifier [testcase: 159913ad-popup]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-159913ad-popup-activity-action'); + await panelPO.enterTitle('testcase: 159913ad-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '159913ad-popup', + qualifierParam1: 'e82bf49c4768', + qualifierParam2: '1b84a4a926f7' + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-159913ad-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-159913ad', componentSelector: 'app-popup-159913ad'}); + + const popupPO = new Testcase159913adPopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + a: 'e82bf49c4768', + b: '1b84a4a926f7', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toBeNull(); + }); + + it('should substitute matrix and query parameters with values from the intent qualifier [testcase: 8a468258-popup]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-8a468258-popup-activity-action'); + await panelPO.enterTitle('testcase: 8a468258-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + testcase: '8a468258-popup', + qualifierParam1: 'd8b74df2c77d', + qualifierParam2: 'e60c81360bee', + }); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-8a468258-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-8a468258', componentSelector: 'app-popup-8a468258'}); + + const popupPO = new Testcase8a468258PopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + matrixParam1: 'd8b74df2c77d', + matrixParam2: 'eda2e91468e1', + pathParam1: 'd8b74df2c77d', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + queryParam1: 'e60c81360bee', + queryParam2: '1a3d3aaf937e' + }); + }); + + + it('should close on focus lost [testcase: 9002887a395c]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-9002887a395c-popup-activity-action'); + await panelPO.enterTitle('testcase: 9002887a395c-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + }); + await panelPO.checkCloseOnFocusLost(true); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-9002887a395c-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // remove focus from the popup + await testingActivityPO.closePopupOpenActivityActionPanel(); + await expectPopupToNotExist({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup'}); + }); + + it('should not close on focus lost [testcase: 2e220909241f]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-2e220909241f-popup-activity-action'); + await panelPO.enterTitle('testcase: 2e220909241f-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + }); + await panelPO.checkCloseOnFocusLost(false); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-2e220909241f-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // remove focus from the popup + await testingActivityPO.closePopupOpenActivityActionPanel(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + }); + + it('should close on escape keystroke [testcase: e2a384f5294a]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-e2a384f5294a-popup-activity-action'); + await panelPO.enterTitle('testcase: e2a384f5294a-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + }); + await panelPO.checkCloseOnEscape(true); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-e2a384f5294a-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // send escape keystroke + await browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); + await expectPopupToNotExist({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup'}); + }); + + it('should not close on escape keystroke [testcase: 5aaa5df79806]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-5aaa5df79806-popup-activity-action'); + await panelPO.enterTitle('testcase: 5aaa5df79806-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + }); + await panelPO.checkCloseOnEscape(false); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-5aaa5df79806-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // send escape keystroke + await browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + }); + + it('should close on grid layout change [testcase: c0ad45e6c742]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-c0ad45e6c742-popup-activity-action'); + await panelPO.enterTitle('testcase: c0ad45e6c742-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + }); + await panelPO.checkCloseOnFocusLost(false); + await panelPO.checkCloseOnGridLayoutChange(true); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-c0ad45e6c742-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // Make a grid layout change + await hostAppPO.moveActivitySash(100); + await expectPopupToNotExist({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup'}); + }); + + it('should not close on grid layout change [testcase: a6919dfd2fb1]', async () => { + const testingActivityPO = new TestingActivityPO(E2E_TESTING_ACTIVITY_CONTEXT); + await testingActivityPO.navigateTo(); + + const panelPO = await testingActivityPO.openPopupOpenActivityActionPanel(); + await panelPO.enterCssClass('fab fa-android e2e-a6919dfd2fb1-popup-activity-action'); + await panelPO.enterTitle('testcase: a6919dfd2fb1-popup'); + await panelPO.enterQualifier({ + entity: 'testing', + }); + await panelPO.checkCloseOnFocusLost(false); + await panelPO.checkCloseOnGridLayoutChange(false); + await panelPO.addAction(); + + // Execute the action + const action = await hostAppPO.findActivityAction('e2e-a6919dfd2fb1-popup-activity-action'); + await action.click(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // Make a grid layout change + await hostAppPO.moveActivitySash(100); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + }); + }); + }); +}); diff --git a/projects/e2e/workbench-application-platform/test-runner/src/message-box.e2e-spec.ts b/projects/e2e/workbench-application-platform/test-runner/src/message-box.e2e-spec.ts new file mode 100644 index 000000000..d04d903f9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/message-box.e2e-spec.ts @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { TestingViewPO } from './page-object/testing-view.po'; +import { HostAppPO } from './page-object/host-app.po'; +import { browser } from 'protractor'; +import { expectViewToNotExist, expectViewToShow } from './util/testing.util'; +import { noop } from 'rxjs'; +import { Testcase61097badMessageBoxPO } from './page-object/testcase-61097bad-msgbox.po'; + +describe('MessageBox', () => { + + const hostAppPO = new HostAppPO(); + const testingViewPO = new TestingViewPO(); + + beforeEach(async () => { + await browser.get('/'); + }); + + it('should show specified actions', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterCssClass('e2e-a6cecbaa-msgbox'); + const actions = {ok: 'OK', cancel: 'Cancel', ['127f38d1a966']: '9ce7b0679386'}; + await msgboxPanelPO.enterActions(actions); + + // close via ok action + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-a6cecbaa-msgbox'); + await expect(msgboxPO.getActions()).toEqual(actions); + await msgboxPO.close('ok'); + await expect(msgboxPanelPO.getCloseAction()).toEqual('ok'); + } + + // close via cancel action + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-a6cecbaa-msgbox'); + await expect(msgboxPO.getActions()).toEqual(actions); + await msgboxPO.close('cancel'); + await expect(msgboxPanelPO.getCloseAction()).toEqual('cancel'); + } + + // close via 127f38d1a966 action + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-a6cecbaa-msgbox'); + await expect(msgboxPO.getActions()).toEqual(actions); + await msgboxPO.close('127f38d1a966'); + await expect(msgboxPanelPO.getCloseAction()).toEqual('127f38d1a966'); + } + }); + + it('should show specified text and title', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterCssClass('e2e-c5dc3af5cd92-msgbox'); + await msgboxPanelPO.enterText('01de40e40df3'); + await msgboxPanelPO.enterTitle('976653342eef'); + await msgboxPanelPO.enterActions({ok: 'OK'}); + + await msgboxPanelPO.open(); + const msgboxPO = await hostAppPO.findMessageBox('e2e-c5dc3af5cd92-msgbox'); + await expect(msgboxPO.getText()).toEqual('01de40e40df3'); + await expect(msgboxPO.getTitle()).toEqual('976653342eef'); + }); + + it('should show specified severity', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterCssClass('e2e-fbf7ec24f2d4-msgbox'); + await msgboxPanelPO.enterActions({ok: 'OK'}); + + // info + await msgboxPanelPO.selectSeverity('info'); + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-fbf7ec24f2d4-msgbox'); + await expect(msgboxPO.getSeverity()).toEqual('info'); + await msgboxPO.close('ok'); + } + + // warn + await msgboxPanelPO.selectSeverity('warn'); + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-fbf7ec24f2d4-msgbox'); + await expect(msgboxPO.getSeverity()).toEqual('warn'); + await msgboxPO.close('ok'); + } + + // error + await msgboxPanelPO.selectSeverity('error'); + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-fbf7ec24f2d4-msgbox'); + await expect(msgboxPO.getSeverity()).toEqual('error'); + await msgboxPO.close('ok'); + } + }); + + it('should apply view modality [testcase: c91805e8]', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterCssClass('e2e-dfa87d85eb1f-msgbox'); + await msgboxPanelPO.selectModality('view'); + await msgboxPanelPO.enterActions({ok: 'OK'}); + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-dfa87d85eb1f-msgbox'); + await expect(msgboxPO.isDisplayed()).toBeTruthy('expected messagebox to be displayed'); + } + + // test if other view can be opened via activity bar + { + await hostAppPO.clickActivityItem('e2e-activity-c91805e8'); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-c91805e8', componentSelector: 'app-view-c91805e8'}); + const msgboxPO = await hostAppPO.findMessageBox('e2e-dfa87d85eb1f-msgbox'); + await expect(msgboxPO.isDisplayed()).toBeFalsy('expected messagebox not to be displayed'); + } + + // switch to disabled view + { + await hostAppPO.clickViewTab('e2e-testing-view'); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-testing-view', componentSelector: 'app-testing-view'}); + const msgboxPO = await hostAppPO.findMessageBox('e2e-dfa87d85eb1f-msgbox'); + await expect(msgboxPO.isDisplayed()).toBeTruthy('expected messagebox to be displayed'); + } + }); + + it('should apply application modality [testcase: c91805e8]', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterCssClass('e2e-dfa87d85eb1f-msgbox'); + await msgboxPanelPO.selectModality('application'); + await msgboxPanelPO.enterActions({ok: 'OK'}); + await msgboxPanelPO.open(); + { + const msgboxPO = await hostAppPO.findMessageBox('e2e-dfa87d85eb1f-msgbox'); + await expect(msgboxPO.isDisplayed()).toBeTruthy('expected messagebox to be displayed'); + } + + // test that other view cannot be opened via activity bar + { + await hostAppPO.clickActivityItem('e2e-activity-c91805e8').then(() => fail('expected activity item not to be clickable')).catch(noop); + await expectViewToNotExist({symbolicAppName: 'testing-app', viewCssClass: 'e2e-view-c91805e8'}); + await expectViewToShow({symbolicAppName: 'testing-app', viewCssClass: 'e2e-testing-view', componentSelector: 'app-testing-view'}); + const msgboxPO = await hostAppPO.findMessageBox('e2e-dfa87d85eb1f-msgbox'); + await expect(msgboxPO.isDisplayed()).toBeTruthy('expected messagebox to be displayed'); + } + }); + + it('should make text selectable', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterCssClass('e2e-cc1bea0bdaa0-msgbox'); + await msgboxPanelPO.enterText('some selectable text'); + await msgboxPanelPO.checkContentSelectable(true); + await msgboxPanelPO.enterActions({ok: 'OK'}); + + await msgboxPanelPO.open(); + const msgboxPO = await hostAppPO.findMessageBox('e2e-cc1bea0bdaa0-msgbox'); + await expect(msgboxPO.isContentSelectable()).toBeTruthy('expected be seletable'); + }); + + it('should make text not selectable', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterCssClass('e2e-cc1bea0bdaa0-msgbox'); + await msgboxPanelPO.enterText('some selectable text'); + await msgboxPanelPO.checkContentSelectable(false); + await msgboxPanelPO.enterActions({ok: 'OK'}); + + await msgboxPanelPO.open(); + const msgboxPO = await hostAppPO.findMessageBox('e2e-cc1bea0bdaa0-msgbox'); + await expect(msgboxPO.isContentSelectable()).toBeFalsy('expected not be seletable'); + }); + + it('should show a custom message box [testcase: 61097bad]', async () => { + await testingViewPO.navigateTo(); + const msgboxPanelPO = await testingViewPO.openMessageBoxPanel(); + + await msgboxPanelPO.enterQualifier({'type': 'list'}); + await msgboxPanelPO.enterCssClass('e2e-61097bad-msgbox'); + await msgboxPanelPO.enterPayload({'items': ['a', 'b', 'c']}); + await msgboxPanelPO.enterActions({ok: 'OK'}); + + await msgboxPanelPO.open(); + const msgboxPO = new Testcase61097badMessageBoxPO('e2e-61097bad-msgbox'); + await expect(msgboxPO.getItems()).toEqual(['a', 'b', 'c']); + }); +}); diff --git a/projects/e2e/workbench-application-platform/test-runner/src/notifcation-box.e2e-spec.ts b/projects/e2e/workbench-application-platform/test-runner/src/notifcation-box.e2e-spec.ts new file mode 100644 index 000000000..4c4c4b6cf --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/notifcation-box.e2e-spec.ts @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { TestingViewPO } from './page-object/testing-view.po'; +import { HostAppPO } from './page-object/host-app.po'; +import { browser } from 'protractor'; +import { Testcase61097badNotificationPO } from './page-object/testcase-61097bad-notification.po'; + +describe('Notification', () => { + + const hostAppPO = new HostAppPO(); + const testingViewPO = new TestingViewPO(); + + beforeEach(async () => { + await browser.get('/'); + }); + + it('should show specified text and title', async () => { + await testingViewPO.navigateTo(); + const notificationPanelPO = await testingViewPO.openNotificationPanel(); + await notificationPanelPO.enterCssClass('e2e-c5dc3af5cd92-notification'); + await notificationPanelPO.enterText('01de40e40df3'); + await notificationPanelPO.enterTitle('976653342eef'); + await notificationPanelPO.show(); + + const notificationPO = await hostAppPO.findNotification('e2e-c5dc3af5cd92-notification'); + + await expect(notificationPO.getText()).toEqual('01de40e40df3'); + await expect(notificationPO.getTitle()).toEqual('976653342eef'); + }); + + it('should show specified severity', async () => { + await testingViewPO.navigateTo(); + const notificationPanelPO = await testingViewPO.openNotificationPanel(); + await notificationPanelPO.enterCssClass('e2e-fbf7ec24f2d4-notification'); + + // info + await notificationPanelPO.selectSeverity('info'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await expect(notificationPO.getSeverity()).toEqual('info'); + await notificationPO.close(); + } + + // warn + await notificationPanelPO.selectSeverity('warn'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await expect(notificationPO.getSeverity()).toEqual('warn'); + await notificationPO.close(); + } + + // error + await notificationPanelPO.selectSeverity('error'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await expect(notificationPO.getSeverity()).toEqual('error'); + await notificationPO.close(); + } + }); + + it('should apply specified duration', async () => { + await testingViewPO.navigateTo(); + const notificationPanelPO = await testingViewPO.openNotificationPanel(); + await notificationPanelPO.enterCssClass('e2e-fbf7ec24f2d4-notification'); + + // short + await notificationPanelPO.selectDuration('short'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await expect(notificationPO.getDuration()).toEqual('short'); + await notificationPO.close(); + } + + // medium + await notificationPanelPO.selectDuration('medium'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await expect(notificationPO.getDuration()).toEqual('medium'); + await notificationPO.close(); + } + + // long + await notificationPanelPO.selectDuration('long'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await expect(notificationPO.getDuration()).toEqual('long'); + await notificationPO.close(); + } + + // infinite + await notificationPanelPO.selectDuration('infinite'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await expect(notificationPO.getDuration()).toBeNull(); + await notificationPO.close(); + } + }); + + it('should allow to close a notification', async () => { + await testingViewPO.navigateTo(); + const notificationPanelPO = await testingViewPO.openNotificationPanel(); + await notificationPanelPO.enterCssClass('e2e-fbf7ec24f2d4-notification'); + + await notificationPanelPO.show(); + await expect(hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification')).not.toBeNull('expected notification to show'); + + const notificationPO = await hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification'); + await notificationPO.close(); + await expect(hostAppPO.findNotification('e2e-fbf7ec24f2d4-notification')).toBeNull('expected notification to be closed'); + }); + + it('should allow to show multiple notifications', async () => { + await testingViewPO.navigateTo(); + const notificationPanelPO = await testingViewPO.openNotificationPanel(); + + await notificationPanelPO.enterCssClass('e2e-6dbbd7fe35c0-notification'); + await notificationPanelPO.show(); + + await notificationPanelPO.enterCssClass('e2e-b5e3e1a38c3d-notification'); + await notificationPanelPO.show(); + + await expect(hostAppPO.findNotification('e2e-6dbbd7fe35c0-notification')).not.toBeNull('expected notification \'6dbbd7fe35c0\' to show'); + await expect(hostAppPO.findNotification('e2e-b5e3e1a38c3d-notification')).not.toBeNull('expected notification \'b5e3e1a38c3d\' to show'); + }); + + it('should allow to replace notifications', async () => { + await testingViewPO.navigateTo(); + + const notificationPanelPO = await testingViewPO.openNotificationPanel(); + + await notificationPanelPO.enterCssClass('e2e-first-notification'); + await notificationPanelPO.enterText('first'); + await notificationPanelPO.enterGroup('group-identity'); + await notificationPanelPO.show(); + { + const notificationPO = await hostAppPO.findNotification('e2e-first-notification'); + await expect(notificationPO.getText()).toEqual('first'); + } + + await notificationPanelPO.enterCssClass('e2e-second-notification'); + await notificationPanelPO.enterText('second'); + await notificationPanelPO.enterGroup('group-identity'); + await notificationPanelPO.show(); + + await expect(hostAppPO.getNotificationCount()).toEqual(1); + + { + const notificationPO = await hostAppPO.findNotification('e2e-first-notification'); + await expect(notificationPO).toBeNull('expected notification \'first\' not to show'); + } + { + const notificationPO = await hostAppPO.findNotification('e2e-second-notification'); + await expect(notificationPO).not.toBeNull('expected notification \'second\' to show'); + await expect(notificationPO.getText()).toEqual('second'); + } + }); + + it('should show a custom notification [testcase: 61097bad]', async () => { + await testingViewPO.navigateTo(); + const notificationPanelPO = await testingViewPO.openNotificationPanel(); + + await notificationPanelPO.enterQualifier({'type': 'list'}); + await notificationPanelPO.enterCssClass('e2e-61097bad-notification'); + await notificationPanelPO.enterPayload({'items': ['a', 'b', 'c']}); + + await notificationPanelPO.show(); + const notificationPO = new Testcase61097badNotificationPO('e2e-61097bad-notification'); + await expect(notificationPO.getItems()).toEqual(['a', 'b', 'c']); + }); +}); diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-actions-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-actions-panel.po.ts new file mode 100644 index 000000000..1712676aa --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-actions-panel.po.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { checkCheckbox, switchToIFrameContext } from '../util/testing.util'; +import { ActivityActionPO, HostAppPO } from './host-app.po'; + +export class ActivityActionsPanelPo { + + private _panel = $('app-activity-actions-panel'); + + constructor(public iframeContext: string[]) { + } + + public async checkShowUrlOpenActivityAction(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('input#show-url-open-activity-action')); + } + + public async checkCustomActivityAction(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('input#show-custom-activity-action')); + } + + public async findUrlOpenActivityAction(): Promise { + return new HostAppPO().findActivityAction('e2e-url-open-activity-action'); + } + + public async findCustomActivityAction(): Promise { + return new HostAppPO().findActivityAction('e2e-custom-activity-action'); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-interaction-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-interaction-panel.po.ts new file mode 100644 index 000000000..c4718effe --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/activity-interaction-panel.po.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; + +export class ActivityInteractionPanelPO { + + private _panel = $('app-activity-interaction-panel'); + + constructor(public iframeContext: string[]) { + } + + public async enterTitle(title: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#title'); + await inputField.clear(); + await inputField.sendKeys(title); + return Promise.resolve(); + } + + public async enterItemText(itemText: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#item-text'); + await inputField.clear(); + await inputField.sendKeys(itemText); + return Promise.resolve(); + } + + public async enterItemCssClass(itemCssClass: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#item-css-class'); + await inputField.clear(); + await inputField.sendKeys(itemCssClass); + return Promise.resolve(); + } + + public async enterDeltaPx(deltaPx: number): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#panel-width-delta'); + await inputField.clear(); + await inputField.sendKeys(deltaPx); + return Promise.resolve(); + } + + public async getActiveLog(): Promise { + await switchToIFrameContext(this.iframeContext); + const activeLog: string = await this._panel.$('textarea#active-log').getAttribute('value'); + return activeLog.split(/\s+/).map(activeLogEntry => JSON.parse(activeLogEntry)); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/host-app.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/host-app.po.ts new file mode 100644 index 000000000..ee586aa36 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/host-app.po.ts @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $, $$, browser, ElementFinder, protractor } from 'protractor'; +import { getCssClasses, switchToMainContext } from '../util/testing.util'; +import { Duration, Severity } from '@scion/workbench-application-platform.api'; +import { ISize } from 'selenium-webdriver'; + +export class HostAppPO { + + /** + * Finds the view tab which has given CSS class set. + * If not found, the promise resolves to `null`. + */ + public async findViewTab(cssClass: string): Promise { + await switchToMainContext(); + const viewTabFinder = $(`wb-view-tab.${cssClass}`); + + const exists = await viewTabFinder.isPresent(); + if (!exists) { + return null; + } + + return new class implements ViewTabPO { + async click(): Promise { + await switchToMainContext(); + await viewTabFinder.click(); + } + + async close(): Promise { + await switchToMainContext(); + + // hover the view-tab to make the close button visible + await browser.actions().mouseMove(viewTabFinder).perform(); + await viewTabFinder.$('.e2e-close').click(); + } + + async getTitle(): Promise { + await switchToMainContext(); + return viewTabFinder.$('.e2e-title').getText(); + } + + async getHeading(): Promise { + await switchToMainContext(); + return viewTabFinder.$('.e2e-heading').getText(); + } + + async isDirty(): Promise { + await switchToMainContext(); + const element = viewTabFinder.$('.e2e-dirty'); + return await element.isPresent() && await element.isDisplayed(); + } + + async isClosable(): Promise { + await switchToMainContext(); + const element = viewTabFinder.$('.e2e-close'); + return await element.isPresent() && await element.isDisplayed(); + } + }; + } + + /** + * Returns the number of view tabs. + */ + public async getViewTabCount(): Promise { + await switchToMainContext(); + return $$('wb-view-tab').count(); + } + + /** + * Returns the number of notifications. + */ + public async getNotificationCount(): Promise { + await switchToMainContext(); + return $$('wb-notification').count(); + } + + /** + * Finds the notification which has given CSS class set. + * If not found, the promise resolves to `null`. + */ + public async findNotification(cssClass: string): Promise { + await switchToMainContext(); + const notificationFinder = $(`wb-notification.${cssClass}`); + + const exists = await notificationFinder.isPresent(); + if (!exists) { + return null; + } + + return new class implements NotificationPO { + async getTitle(): Promise { + await switchToMainContext(); + return notificationFinder.$('.e2e-title').getText(); + } + + async getText(): Promise { + await switchToMainContext(); + return notificationFinder.$('.e2e-text').getText(); + } + + async getSeverity(): Promise { + await switchToMainContext(); + + const cssClasses = await getCssClasses(notificationFinder); + if (cssClasses.includes('e2e-severity-info')) { + return 'info'; + } + else if (cssClasses.includes('e2e-severity-warn')) { + return 'warn'; + } + else if (cssClasses.includes('e2e-severity-error')) { + return 'error'; + } + return null; + } + + async getDuration(): Promise { + await switchToMainContext(); + + const cssClasses = await getCssClasses(notificationFinder); + if (cssClasses.includes('e2e-duration-short')) { + return 'short'; + } + else if (cssClasses.includes('e2e-duration-medium')) { + return 'medium'; + } + else if (cssClasses.includes('e2e-duration-long')) { + return 'long'; + } + else if (cssClasses.includes('infinite')) { + return 'infinite'; + } + return null; + } + + async close(): Promise { + await switchToMainContext(); + await notificationFinder.$('.e2e-close').click(); + // wait until the animation completes + await browser.wait(protractor.ExpectedConditions.stalenessOf(notificationFinder), 5000); + } + }; + } + + /** + * Finds the notification which has given CSS class set. + * If not found, the promise resolves to `null`. + */ + public async findMessageBox(cssClass: string): Promise { + await switchToMainContext(); + const msgboxFinder = $(`wb-message-box.${cssClass}`); + + const exists = await msgboxFinder.isPresent(); + if (!exists) { + return null; + } + + return new class implements MessageBoxPO { + async getTitle(): Promise { + await switchToMainContext(); + return msgboxFinder.$('.e2e-title').getText(); + } + + async getText(): Promise { + await switchToMainContext(); + return msgboxFinder.$('.e2e-text').getText(); + } + + async getSeverity(): Promise { + await switchToMainContext(); + const cssClasses = await getCssClasses(msgboxFinder); + if (cssClasses.includes('e2e-severity-info')) { + return 'info'; + } + else if (cssClasses.includes('e2e-severity-warn')) { + return 'warn'; + } + else if (cssClasses.includes('e2e-severity-error')) { + return 'error'; + } + return null; + } + + async getModality(): Promise<'application' | 'view' | null> { + await switchToMainContext(); + const cssClasses = await getCssClasses(msgboxFinder); + if (cssClasses.includes('e2e-modality-application')) { + return 'application'; + } + else if (cssClasses.includes('e2e-severity-view')) { + return 'view'; + } + return null; + } + + async isContentSelectable(): Promise { + await switchToMainContext(); + + const text = await msgboxFinder.$('.e2e-text').getText(); + + await browser.actions().mouseMove(msgboxFinder.$('.e2e-text')).perform(); + await browser.actions().doubleClick().perform(); + const selection: string = await browser.executeScript('return window.getSelection().toString();') as string; + + return selection && selection.length && text.includes(selection); + } + + async getActions(): Promise<{ [key: string]: string }> { + await switchToMainContext(); + const actions: { [key: string]: string } = {}; + + const actionsFinder = msgboxFinder.$$('button.e2e-action'); + const count = await actionsFinder.count(); + for (let i = 0; i < count; i++) { + const action: ElementFinder = await actionsFinder.get(i); + const cssClasses = await getCssClasses(action); + const actionKey = cssClasses.find(candidate => candidate.startsWith('e2e-action-key-')); + actions[actionKey.substr('e2e-action-key-'.length)] = await action.getText(); + } + + return actions; + } + + async close(action: string): Promise { + await switchToMainContext(); + await msgboxFinder.$(`button.e2e-action.e2e-action-key-${action}`).click(); + // wait until the animation completes + await browser.wait(protractor.ExpectedConditions.stalenessOf(msgboxFinder), 5000); + } + + async isDisplayed(): Promise { + await switchToMainContext(); + return msgboxFinder.isDisplayed(); + } + }; + } + + /** + * Clicks the activity item which has given CSS class set. + * + * The promise returned is rejected if not found. + */ + public async clickActivityItem(cssClass: string): Promise { + await switchToMainContext(); + const activityItemPO = await this.findActivityItem(cssClass); + if (activityItemPO === null) { + return Promise.reject(`Activity item not found [cssClass=${cssClass}]`); + } + await activityItemPO.click(); + } + + /** + * Clicks the view tab which has given CSS class set. + * + * The promise returned is rejected if not found. + */ + public async clickViewTab(cssClass: string): Promise { + await switchToMainContext(); + const viewTabPO = await this.findViewTab(cssClass); + if (viewTabPO === null) { + return Promise.reject(`View tab not found [cssClass=${cssClass}]`); + } + await viewTabPO.click(); + } + + /** + * Finds the activity item which has given CSS class set. + * If not found, the promise resolves to `null`. + */ + public async findActivityItem(cssClass: string): Promise { + await switchToMainContext(); + const activityItemFinder = $(`wb-activity-part .e2e-activity-bar a.e2e-activity-item.${cssClass}`); + const activityPanelFinder = $(`wb-activity-part .e2e-activity-panel.${cssClass}`); + + const exists = await activityItemFinder.isPresent(); + if (!exists) { + return null; + } + + return new class implements ActivityItemPO { + async getTitle(): Promise { + await switchToMainContext(); + return await activityItemFinder.getAttribute('title'); + } + + async getText(): Promise { + await switchToMainContext(); + return await activityItemFinder.getText(); + } + + async getCssClasses(): Promise { + await switchToMainContext(); + return await getCssClasses(activityItemFinder); + } + + async click(): Promise { + await switchToMainContext(); + + const cssClasses = await this.getCssClasses(); + const closePanel = cssClasses.includes('e2e-active'); + await activityItemFinder.click(); + // wait until the animation completes + closePanel && await browser.wait(protractor.ExpectedConditions.stalenessOf(activityPanelFinder), 5000); + } + }; + } + + /** + * Finds the activity panel which has given CSS class set. + * If not found, the promise resolves to `null`. + */ + public async findActivityPanel(cssClass: string): Promise { + await switchToMainContext(); + const activityPanelFinder = $(`wb-activity-part .e2e-activity-panel.${cssClass}`); + + const exists = await activityPanelFinder.isPresent(); + if (!exists) { + return null; + } + + return new class implements ActivityPanelPO { + async getTitle(): Promise { + await switchToMainContext(); + return activityPanelFinder.$('.e2e-activity-title').getText(); + } + + async getSize(): Promise { + await switchToMainContext(); + return activityPanelFinder.getSize(); + } + + async getCssClasses(): Promise { + await switchToMainContext(); + return getCssClasses(activityPanelFinder); + } + }; + } + + /** + * Enlarges or shrinks the activity panel. + */ + public async moveActivitySash(delta: number): Promise { + await switchToMainContext(); + await browser.actions().mouseMove($('div.e2e-activity-sash'), {x: 0, y: 0}).perform(); + await browser.actions() + .mouseDown() + .mouseMove({x: delta, y: 0}) + .mouseUp() + .perform(); + } + + /** + * Finds the activity action which has given CSS class set. + */ + public async findActivityAction(cssClass: string): Promise { + const actionFinder = $(`wb-activity-part .e2e-activity-actions .${cssClass}`); + + return new class implements ActivityActionPO { + async isPresent(): Promise { + await switchToMainContext(); + return actionFinder.isPresent(); + } + + async click(): Promise { + await switchToMainContext(); + await actionFinder.click(); + } + }; + } +} + +export interface ViewTabPO { + getTitle(): Promise; + + getHeading(): Promise; + + isDirty(): Promise; + + isClosable(): Promise; + + close(): Promise; + + click(): Promise; +} + +export interface NotificationPO { + getTitle(): Promise; + + getText(): Promise; + + getSeverity(): Promise; + + getDuration(): Promise; + + close(): Promise; +} + +export interface MessageBoxPO { + getTitle(): Promise; + + getText(): Promise; + + getSeverity(): Promise; + + getModality(): Promise<'view' | 'application' | null>; + + isContentSelectable(): Promise; + + getActions(): Promise<{ [key: string]: string }>; + + close(action: string): Promise; + + isDisplayed(): Promise; +} + +/** + * Represents an activity item in the activity bar. + */ +export interface ActivityItemPO { + getTitle(): Promise; + + getText(): Promise; + + getCssClasses(): Promise; + + click(): Promise; +} + +/** + * Represents an activity panel in the activity part. + */ +export interface ActivityPanelPO { + getTitle(): Promise; + + getSize(): Promise; + + getCssClasses(): Promise; +} + +/* +* Represents a clickable activity action +*/ +export interface ActivityActionPO { + isPresent(): Promise; + + click(): Promise; +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/message-box-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/message-box-panel.po.ts new file mode 100644 index 000000000..0bf001f91 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/message-box-panel.po.ts @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $, browser, protractor } from 'protractor'; +import { checkCheckbox, selectOption, switchToIFrameContext, switchToMainContext } from '../util/testing.util'; +import { Qualifier, Severity } from '@scion/workbench-application-platform.api'; +import { SciParamsEnterPanelPO } from './sci-params-enter.po'; + +export class MessageBoxPanelPO { + + private _panel = $('app-message-box-panel'); + private _cssClasses: string[] = []; + + constructor(public iframeContext: string[]) { + } + + public async enterQualifier(qualifier: Qualifier): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(qualifier, this._panel.$('.e2e-qualifier-panel')); + } + + public async enterTitle(label: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#title'); + await inputField.clear(); + await inputField.sendKeys(label); + return Promise.resolve(); + } + + public async enterText(text: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#text'); + await inputField.clear(); + await inputField.sendKeys(text); + return Promise.resolve(); + } + + public async selectSeverity(value: Severity): Promise { + await switchToIFrameContext(this.iframeContext); + await selectOption(value, this._panel.$('select#severity')); + } + + public async selectModality(value: 'view' | 'application'): Promise { + await switchToIFrameContext(this.iframeContext); + await selectOption(value, this._panel.$('select#modality')); + } + + public async checkContentSelectable(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#content-selectable')); + } + + public async enterCssClass(cssClass: string): Promise { + this._cssClasses = cssClass.split(/\s+/); + + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#css-class'); + await inputField.clear(); + await inputField.sendKeys(cssClass); + return Promise.resolve(); + } + + /** + * Enters given JSON object into the payload field. + */ + public async enterPayload(payload: any): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = $('#payload'); + await inputField.clear(); + await inputField.sendKeys(JSON.stringify(payload)); + return Promise.resolve(); + } + + public async enterActions(actions: { [key: string]: string }): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(actions, this._panel.$('.e2e-action-panel')); + } + + public async getCloseAction(): Promise { + await switchToIFrameContext(this.iframeContext); + return this._panel.$('output.e2e-close-action').getText(); + } + + public async open(): Promise { + await switchToIFrameContext(this.iframeContext); + await this._panel.$('button.e2e-open').click(); + + // wait until the animation completes + if (this._cssClasses.length) { + await switchToMainContext(); + await browser.wait(protractor.ExpectedConditions.elementToBeClickable($(`wb-message-box.${this._cssClasses.join('.')}`)), 5000); + } + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/notification-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/notification-panel.po.ts new file mode 100644 index 000000000..0d653fc37 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/notification-panel.po.ts @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $, browser, protractor } from 'protractor'; +import { selectOption, switchToIFrameContext, switchToMainContext } from '../util/testing.util'; +import { Duration, Qualifier, Severity } from '@scion/workbench-application-platform.api'; +import { SciParamsEnterPanelPO } from './sci-params-enter.po'; + +export class NotificationPanelPO { + + private _panel = $('app-notification-panel'); + private _cssClasses: string[] = []; + + constructor(public iframeContext: string[]) { + } + + public async enterQualifier(qualifier: Qualifier): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(qualifier, this._panel.$('.e2e-qualifier-panel')); + } + + public async enterTitle(label: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#title'); + await inputField.clear(); + await inputField.sendKeys(label); + return Promise.resolve(); + } + + public async enterText(text: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#text'); + await inputField.clear(); + await inputField.sendKeys(text); + return Promise.resolve(); + } + + public async selectSeverity(value: Severity): Promise { + await switchToIFrameContext(this.iframeContext); + await selectOption(value, this._panel.$('select#severity')); + } + + public async selectDuration(value: Duration): Promise { + await switchToIFrameContext(this.iframeContext); + await selectOption(value, this._panel.$('select#duration')); + } + + public async enterGroup(group: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#group'); + await inputField.clear(); + await inputField.sendKeys(group); + return Promise.resolve(); + } + + public async enterCssClass(cssClass: string): Promise { + this._cssClasses = cssClass.split(/\s+/); + + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#css-class'); + await inputField.clear(); + await inputField.sendKeys(cssClass); + return Promise.resolve(); + } + + /** + * Enters given JSON object into the payload field. + */ + public async enterPayload(payload: any): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = $('#payload'); + await inputField.clear(); + await inputField.sendKeys(JSON.stringify(payload)); + return Promise.resolve(); + } + + public async show(): Promise { + await switchToIFrameContext(this.iframeContext); + await this._panel.$('button.e2e-show').click(); + + // wait until the animation completes + if (this._cssClasses.length) { + await switchToMainContext(); + await browser.wait(protractor.ExpectedConditions.elementToBeClickable($(`wb-notification.${this._cssClasses.join('.')}`)), 5000); + } + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-open-activity-action-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-open-activity-action-panel.po.ts new file mode 100644 index 000000000..36ce60218 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-open-activity-action-panel.po.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { checkCheckbox, switchToIFrameContext } from '../util/testing.util'; +import { Qualifier } from '@scion/workbench-application-platform.api'; +import { Params } from '@angular/router'; +import { SciParamsEnterPanelPO } from './sci-params-enter.po'; + +export class PopupOpenActivityActionPanelPO { + + private _panel = $('app-popup-open-activity-action-panel'); + + constructor(public iframeContext: string[]) { + } + + public async enterLabel(label: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#label'); + await inputField.clear(); + await inputField.sendKeys(label); + return Promise.resolve(); + } + + public async enterTitle(label: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#title'); + await inputField.clear(); + await inputField.sendKeys(label); + return Promise.resolve(); + } + + public async enterCssClass(cssClass: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#css-class'); + await inputField.clear(); + await inputField.sendKeys(cssClass); + return Promise.resolve(); + } + + public async enterQualifier(qualifier: Qualifier): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(qualifier, this._panel.$('.e2e-qualifier-panel')); + } + + public async enterMatrixParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-matrix-params-panel')); + } + + public async enterQueryParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-query-params-panel')); + } + + public async checkCloseOnFocusLost(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#onFocusLost')); + } + + public async checkCloseOnEscape(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#onEscape')); + } + + public async checkCloseOnGridLayoutChange(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#onGridLayoutChange')); + } + + public async addAction(): Promise { + await switchToIFrameContext(this.iframeContext); + await this._panel.$('button.e2e-add-action').click(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-panel.po.ts new file mode 100644 index 000000000..eab373e6a --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/popup-panel.po.ts @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { checkCheckbox, selectOption, switchToIFrameContext } from '../util/testing.util'; +import { Qualifier } from '@scion/workbench-application-platform.api'; +import { Params } from '@angular/router'; +import { SciParamsEnterPanelPO } from './sci-params-enter.po'; +import { SciPropertyPanelPO } from './sci-property.po'; + +export class PopupPanelPO { + + private _panel = $('app-popup-panel'); + + constructor(public iframeContext: string[]) { + } + + public async enterQualifier(qualifier: Qualifier): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(qualifier, this._panel.$('.e2e-qualifier-panel')); + } + + public async enterMatrixParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-matrix-params-panel')); + } + + public async enterQueryParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-query-params-panel')); + } + + public async selectPosition(value: 'north' | 'east' | 'south' | 'west'): Promise { + await switchToIFrameContext(this.iframeContext); + await selectOption(value, this._panel.$('select#position')); + } + + public async checkCloseOnFocusLost(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#onFocusLost')); + } + + public async checkCloseOnEscape(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#onEscape')); + } + + public async checkCloseOnGridLayoutChange(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#onGridLayoutChange')); + } + + public async execute(): Promise { + await switchToIFrameContext(this.iframeContext); + await this._panel.$('button.e2e-execute').click(); + } + + public async getResult(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(this.iframeContext); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-result')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-accordion-p.o.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-accordion-p.o.ts new file mode 100644 index 000000000..b60e0f786 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-accordion-p.o.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ElementFinder } from 'protractor'; +import { getCssClasses } from '../util/testing.util'; + +export class SciAccordionPO { + + /** + * Opens or closes the accordion item of given CSS class. + * If `open` is not specified, the item is toggled. + */ + public async toggle(sciAccordionFinder: ElementFinder, cssClass: string, open?: boolean): Promise { + const accordionItem = sciAccordionFinder.$(`section.e2e-accordion-item.${cssClass}`); + const cssClasses = await getCssClasses(accordionItem); + + if (open === undefined) { + open = !cssClasses.includes('e2e-expanded'); + } + + const doOpen = open && !cssClasses.includes('e2e-expanded'); + const doClose = !open && cssClasses.includes('e2e-expanded'); + + if (doOpen || doClose) { + await accordionItem.$('.e2e-accordion-item-header').click(); + } + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-params-enter.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-params-enter.po.ts new file mode 100644 index 000000000..72470b7af --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-params-enter.po.ts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ElementFinder } from 'protractor'; + +export class SciParamsEnterPanelPO { + + /** + * Allows to enter parameters into '' panel. + */ + public async enterParams(params: Object, sciParamsEnterPanel: ElementFinder): Promise { + const addButton = sciParamsEnterPanel.$('button.e2e-add'); + const lastKeyInput = sciParamsEnterPanel.$$('input.e2e-key').last(); + const lastValueInput = sciParamsEnterPanel.$$('input.e2e-value').last(); + + for (const key of Object.keys(params)) { + await addButton.click(); + await lastKeyInput.sendKeys(key); + await lastValueInput.sendKeys(`${params[key]}`); + } + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-property.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-property.po.ts new file mode 100644 index 000000000..4a2324e31 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/sci-property.po.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { ElementFinder } from 'protractor'; + +export class SciPropertyPanelPO { + + /** + * Allows to read properties from '' panel. + */ + public async readProperties(sciPropertyPanel: ElementFinder): Promise<{ [key: string]: string }> { + const keysFinder = sciPropertyPanel.$$('.e2e-key'); + const valuesFinder = sciPropertyPanel.$$('.e2e-value'); + + const propertyCount = await keysFinder.count(); + if (propertyCount === 0) { + return null; + } + + const properties: { [key: string]: string } = {}; + for (let i = 0; i < propertyCount; i++) { + const key = await keysFinder.get(i).getText(); + const value = await valuesFinder.get(i).getText(); + properties[key] = value; + } + + return properties; + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-159913ad-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-159913ad-popup.po.ts new file mode 100644 index 000000000..9ddd09423 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-159913ad-popup.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-popup-159913ad']; + +export class Testcase159913adPopupPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-activity.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-activity.po.ts new file mode 100644 index 000000000..4e0ffe0bc --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-activity.po.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; + +const E2E_TESTING_ACTIVITY_CONTEXT: string[] = ['e2e-testing-app', 'e2e-activity', 'e2e-activity-28f32b51']; + +export class Testcase28f32b51ActivityPO { + + public async readActiveLog(): Promise { + await switchToIFrameContext(E2E_TESTING_ACTIVITY_CONTEXT); + const activeLog: string = await $('textarea#active-log').getAttribute('value'); + return activeLog.split(/\s+/).map(activeLogEntry => JSON.parse(activeLogEntry)); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-view.po.ts new file mode 100644 index 000000000..1c960c140 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-28f32b51-view.po.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-28f32b51']; + +export class Testcase28f32b51ViewPO { + + public async readActiveLog(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + const activeLog: string = await $('textarea#active-log').getAttribute('value'); + return activeLog.split(/\s+/).map(activeLogEntry => JSON.parse(activeLogEntry)); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-45dc693f-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-45dc693f-popup.po.ts new file mode 100644 index 000000000..a0abb0074 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-45dc693f-popup.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-popup-45dc693f']; + +export class Testcase45dc693fPopupPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-4a3a8984-activity-po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-4a3a8984-activity-po.ts new file mode 100644 index 000000000..a9b61c8c9 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-4a3a8984-activity-po.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; + +const E2E_TESTING_ACTIVITY_CONTEXT: string[] = ['e2e-testing-app', 'e2e-activity', 'e2e-activity-4a3a8984']; + +export class Testcase4a3a8984ActivityPO { + + public async getComponentInstanceUuid(): Promise { + await switchToIFrameContext(E2E_TESTING_ACTIVITY_CONTEXT); + return await $('.e2e-component-instance-uuid').getText(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-56657ad1-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-56657ad1-view.po.ts new file mode 100644 index 000000000..672a93d60 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-56657ad1-view.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-56657ad1']; + +export class Testcase56657ad1ViewPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-activity.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-activity.po.ts new file mode 100644 index 000000000..71a1b154b --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-activity.po.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { browser, protractor } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; + +const E2E_TESTING_ACTIVITY_CONTEXT: string[] = ['e2e-testing-app', 'e2e-activity', 'e2e-activity-5782ab19']; + +export class Testcase5782ab19ActivityPO { + + /** + * Returns if given element is the active element. + */ + public async isActiveElement(fieldId: string): Promise { + await switchToIFrameContext(E2E_TESTING_ACTIVITY_CONTEXT); + const activeElementId = await browser.driver.switchTo().activeElement().getAttribute('id'); + return activeElementId === fieldId; + } + + public async pressTab(): Promise { + await switchToIFrameContext(E2E_TESTING_ACTIVITY_CONTEXT); + await browser.actions().sendKeys(protractor.Key.TAB).perform(); + } + + public async pressShiftTab(): Promise { + await switchToIFrameContext(E2E_TESTING_ACTIVITY_CONTEXT); + await browser.actions().sendKeys(protractor.Key.SHIFT, protractor.Key.TAB, protractor.Key.SHIFT).perform(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-popup.po.ts new file mode 100644 index 000000000..ef1bdc653 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-popup.po.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { browser, protractor } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-popup-5782ab19']; + +export class Testcase5782ab19PopupPO { + + /** + * Returns if given element is the active element. + */ + public async isActiveElement(fieldId: string): Promise { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + const activeElementId = await browser.driver.switchTo().activeElement().getAttribute('id'); + return activeElementId === fieldId; + } + + public async pressTab(): Promise { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + await browser.actions().sendKeys(protractor.Key.TAB).perform(); + } + + public async pressShiftTab(): Promise { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + await browser.actions().sendKeys(protractor.Key.SHIFT, protractor.Key.TAB, protractor.Key.SHIFT).perform(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-view.po.ts new file mode 100644 index 000000000..452410797 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-5782ab19-view.po.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { browser, protractor } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-5782ab19']; + +export class Testcase5782ab19ViewPO { + + /** + * Returns if given element is the active element. + */ + public async isActiveElement(fieldId: string): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + const activeElementId = await browser.driver.switchTo().activeElement().getAttribute('id'); + return activeElementId === fieldId; + } + + public async pressTab(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await browser.actions().sendKeys(protractor.Key.TAB).perform(); + } + + public async pressShiftTab(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await browser.actions().sendKeys(protractor.Key.SHIFT, protractor.Key.TAB, protractor.Key.SHIFT).perform(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-msgbox.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-msgbox.po.ts new file mode 100644 index 000000000..892983bb5 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-msgbox.po.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToMainContext } from '../util/testing.util'; + +export class Testcase61097badMessageBoxPO { + + constructor(private _msgboxCssClass: string) { + } + + public async getItems(): Promise { + await switchToMainContext(); + const msgboxFinder = $(`wb-message-box.${this._msgboxCssClass} app-list-messagebox`); + const itemFinder = msgboxFinder.$$('.e2e-item'); + const itemCount = await itemFinder.count(); + + const items: string[] = []; + for (let i = 0; i < itemCount; i++) { + items.push(await itemFinder.get(i).getText()); + } + return items; + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-notification.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-notification.po.ts new file mode 100644 index 000000000..cf3b1494c --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-61097bad-notification.po.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToMainContext } from '../util/testing.util'; + +export class Testcase61097badNotificationPO { + + constructor(private _notificationCssClass: string) { + } + + public async getItems(): Promise { + await switchToMainContext(); + const notificationFinder = $(`wb-notification.${this._notificationCssClass} app-list-notification`); + const itemFinder = notificationFinder.$$('.e2e-item'); + const itemCount = await itemFinder.count(); + + const items: string[] = []; + for (let i = 0; i < itemCount; i++) { + items.push(await itemFinder.get(i).getText()); + } + return items; + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-68f302b4-view-po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-68f302b4-view-po.ts new file mode 100644 index 000000000..88a30cd14 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-68f302b4-view-po.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; +import { ViewNavigationPanelPO } from './view-navigation-panel.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-68f302b4']; + +export class Testcase68f302b4ViewPO { + + public readonly viewNavigationPanelPO = new ViewNavigationPanelPO(E2E_TESTING_VIEW_CONTEXT); + + public async getAppInstanceUuid(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return await $('.e2e-app-instance-uuid').getText(); + } + + public async getComponentInstanceUuid(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return await $('.e2e-component-instance-uuid').getText(); + } + + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-8a468258-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-8a468258-popup.po.ts new file mode 100644 index 000000000..d0505aa17 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-8a468258-popup.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-popup-8a468258']; + +export class Testcase8a468258PopupPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-9c5319f7-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-9c5319f7-popup.po.ts new file mode 100644 index 000000000..07dbf17ed --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-9c5319f7-popup.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-popup-9c5319f7']; + +export class Testcase9c5319f7PopupPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-a686d615-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-a686d615-view.po.ts new file mode 100644 index 000000000..8772d8abd --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-a686d615-view.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-a686d615']; + +export class TestcaseA686d615ViewPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-b6a8fe23-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-b6a8fe23-view.po.ts new file mode 100644 index 000000000..21cca67f5 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-b6a8fe23-view.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-b6a8fe23']; + +export class TestcaseB6a8fe23ViewPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-c8e40918-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-c8e40918-view.po.ts new file mode 100644 index 000000000..38e330c6f --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-c8e40918-view.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-c8e40918']; + +export class TestcaseC8e40918ViewPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-cc977da9-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-cc977da9-view.po.ts new file mode 100644 index 000000000..ae58d8f97 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-cc977da9-view.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-cc977da9']; + +export class TestcaseCc977da9ViewPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-f4286ac4-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-f4286ac4-popup.po.ts new file mode 100644 index 000000000..12dcd9e14 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-f4286ac4-popup.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-popup-f4286ac4']; + +export class TestcaseF4286ac4PopupPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-fc077b32-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-fc077b32-popup.po.ts new file mode 100644 index 000000000..5d88d75c4 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-fc077b32-popup.po.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { getCssClasses, switchToIFrameContext, switchToMainContext } from '../util/testing.util'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-popup-fc077b32']; + +export class Testcasefc077b32PopupPO { + + public async getPosition(): Promise<'north' | 'east' | 'south' | 'west' | null> { + await switchToMainContext(); + const cssClasses = await getCssClasses($(`.wb-popup.e2e-popup-fc077b32`)); + if (cssClasses.includes('e2e-position-north')) { + return 'north'; + } + else if (cssClasses.includes('e2e-position-east')) { + return 'east'; + } + else if (cssClasses.includes('e2e-position-south')) { + return 'south'; + } + else if (cssClasses.includes('e2e-position-west')) { + return 'west'; + } + return null; + } + + public async close(): Promise { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + await $('button#e2e-close').click(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-ffd6a78f-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-ffd6a78f-view.po.ts new file mode 100644 index 000000000..ab08159c2 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testcase-ffd6a78f-view.po.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-view-ffd6a78f']; + +export class TestcaseFfd6a78fViewPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-activity.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-activity.po.ts new file mode 100644 index 000000000..2abe95ecf --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-activity.po.ts @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { HostAppPO } from './host-app.po'; +import { SciAccordionPO } from './sci-accordion-p.o'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; +import { ActivityInteractionPanelPO } from './activity-interaction-panel.po'; +import { ActivityActionsPanelPo } from './activity-actions-panel.po'; +import { ViewOpenActivityActionPanelPO } from './view-open-activity-action-panel.po'; +import { PopupOpenActivityActionPanelPO } from './popup-open-activity-action-panel.po'; + +export class TestingActivityPO { + + constructor(public iframeContext: string[]) { + } + + public async navigateTo(): Promise { + await new HostAppPO().clickActivityItem('e2e-testing-activity'); + } + + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(this.iframeContext); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(this.iframeContext); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } + + public async openActivityInteractionPanel(): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciAccordionPO().toggle($('sci-accordion'), 'e2e-activity-interaction-panel', true); + return new ActivityInteractionPanelPO(this.iframeContext); + } + + public async openActivityActionsPanel(): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciAccordionPO().toggle($('sci-accordion'), 'e2e-activity-actions-panel', true); + return new ActivityActionsPanelPo(this.iframeContext); + } + + public async openViewOpenActivityActionPanel(): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciAccordionPO().toggle($('sci-accordion'), 'e2e-add-view-open-activity-action', true); + return new ViewOpenActivityActionPanelPO(this.iframeContext); + } + + public async openPopupOpenActivityActionPanel(): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciAccordionPO().toggle($('sci-accordion'), 'e2e-add-popup-open-activity-action', true); + return new PopupOpenActivityActionPanelPO(this.iframeContext); + } + + public async closePopupOpenActivityActionPanel(): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciAccordionPO().toggle($('sci-accordion'), 'e2e-add-popup-open-activity-action', false); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-popup.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-popup.po.ts new file mode 100644 index 000000000..d94131aab --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-popup.po.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $, browser, protractor } from 'protractor'; +import { switchToIFrameContext } from '../util/testing.util'; +import { SciPropertyPanelPO } from './sci-property.po'; + +const E2E_TESTING_POPUP_CONTEXT: string[] = ['e2e-testing-app', 'e2e-popup', 'e2e-testing-popup']; + +export class TestingPopupPO { + + /** + * Reads URL parameters. + */ + public async getUrlParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-params')); + } + + /** + * Reads URL query parameters. + */ + public async getUrlQueryParameters(): Promise<{ [key: string]: string }> { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + return new SciPropertyPanelPO().readProperties($('sci-property.e2e-url-query-params')); + } + + /** + * Enters given JSON object into the result field. + */ + public async enterResult(result: any): Promise { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + const inputField = $('textarea.e2e-result'); + await inputField.clear(); + await inputField.sendKeys(JSON.stringify(result)); + return Promise.resolve(); + } + + /** + * Closes the popup and returns the result. + */ + public async ok(): Promise { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + await $('button.e2e-ok').click(); + } + + /** + * Closes the popup without returning a result. + */ + public async escape(): Promise { + await switchToIFrameContext(E2E_TESTING_POPUP_CONTEXT); + await browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-view.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-view.po.ts new file mode 100644 index 000000000..7f8b5dd3a --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/testing-view.po.ts @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { ViewInteractionPanelPO } from './view-interaction-panel.po'; +import { ViewNavigationPanelPO } from './view-navigation-panel.po'; +import { HostAppPO } from './host-app.po'; +import { PopupPanelPO } from './popup-panel.po'; +import { SciAccordionPO } from './sci-accordion-p.o'; +import { switchToIFrameContext } from '../util/testing.util'; +import { MessageBoxPanelPO } from './message-box-panel.po'; +import { NotificationPanelPO } from './notification-panel.po'; + +const E2E_TESTING_VIEW_CONTEXT: string[] = ['e2e-testing-app', 'e2e-view', 'e2e-testing-view']; + +export class TestingViewPO { + + private _component = $('app-testing-view'); + + public async navigateTo(): Promise { + await new HostAppPO().clickActivityItem('e2e-open-testing-view'); + } + + public async openViewInteractionPanel(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await new SciAccordionPO().toggle(this._component.$('sci-accordion'), 'e2e-view-interaction-panel', true); + return new ViewInteractionPanelPO(E2E_TESTING_VIEW_CONTEXT); + } + + public async openViewNavigationPanel(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await new SciAccordionPO().toggle(this._component.$('sci-accordion'), 'e2e-view-navigation-panel', true); + return new ViewNavigationPanelPO(E2E_TESTING_VIEW_CONTEXT); + } + + public async openPopupPanel(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await new SciAccordionPO().toggle(this._component.$('sci-accordion'), 'e2e-popup-panel', true); + return new PopupPanelPO(E2E_TESTING_VIEW_CONTEXT); + } + + public async closePopupPanel(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await new SciAccordionPO().toggle(this._component.$('sci-accordion'), 'e2e-popup-panel', false); + } + + public async openMessageBoxPanel(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await new SciAccordionPO().toggle(this._component.$('sci-accordion'), 'e2e-message-box-panel', true); + return new MessageBoxPanelPO(E2E_TESTING_VIEW_CONTEXT); + } + + public async openNotificationPanel(): Promise { + await switchToIFrameContext(E2E_TESTING_VIEW_CONTEXT); + await new SciAccordionPO().toggle(this._component.$('sci-accordion'), 'e2e-notification-panel', true); + return new NotificationPanelPO(E2E_TESTING_VIEW_CONTEXT); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-interaction-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-interaction-panel.po.ts new file mode 100644 index 000000000..3f60dd1ca --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-interaction-panel.po.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { checkCheckbox, switchToIFrameContext } from '../util/testing.util'; + +export class ViewInteractionPanelPO { + + private _panel = $('app-view-interaction-panel'); + + constructor(public iframeContext: string[]) { + } + + public async enterTitle(title: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#title'); + await inputField.clear(); + await inputField.sendKeys(title); + return Promise.resolve(); + } + + public async enterHeading(heading: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#heading'); + await inputField.clear(); + await inputField.sendKeys(heading); + return Promise.resolve(); + } + + public async markDirty(dirty: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + const checkboxField = this._panel.$('input#dirty'); + await checkCheckbox(dirty, checkboxField); + return Promise.resolve(); + } + + public async setClosable(closable: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + const checkboxField = this._panel.$('input#closable'); + await checkCheckbox(closable, checkboxField); + return Promise.resolve(); + } + + public async close(): Promise { + await switchToIFrameContext(this.iframeContext); + await this._panel.$('button#close').click(); + } + + public async getActiveLog(): Promise { + await switchToIFrameContext(this.iframeContext); + const activeLog: string = await this._panel.$('textarea#active-log').getAttribute('value'); + return activeLog.split(/\s+/).map(activeLogEntry => JSON.parse(activeLogEntry)); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-navigation-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-navigation-panel.po.ts new file mode 100644 index 000000000..7aecb6254 --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-navigation-panel.po.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { checkCheckbox, selectOption, switchToIFrameContext } from '../util/testing.util'; +import { Qualifier } from '@scion/workbench-application-platform.api'; +import { Params } from '@angular/router'; +import { SciParamsEnterPanelPO } from './sci-params-enter.po'; + +export class ViewNavigationPanelPO { + + private _panel = $('app-view-navigation-panel'); + + constructor(public iframeContext: string[]) { + } + + public async enterQualifier(qualifier: Qualifier): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(qualifier, this._panel.$('.e2e-qualifier-panel')); + } + + public async enterMatrixParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-matrix-params-panel')); + } + + public async enterQueryParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-query-params-panel')); + } + + public async checkActivateIfPresent(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#activateIfPresent')); + } + + public async checkCloseIfPresent(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#closeIfPresent')); + } + + public async selectTarget(value: 'self' | 'blank'): Promise { + await switchToIFrameContext(this.iframeContext); + await selectOption(value, this._panel.$('select#target')); + } + + public async execute(): Promise { + await switchToIFrameContext(this.iframeContext); + await this._panel.$('button.e2e-execute').click(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-open-activity-action-panel.po.ts b/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-open-activity-action-panel.po.ts new file mode 100644 index 000000000..82d1c7bcc --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/page-object/view-open-activity-action-panel.po.ts @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms from the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { $ } from 'protractor'; +import { checkCheckbox, switchToIFrameContext } from '../util/testing.util'; +import { Qualifier } from '@scion/workbench-application-platform.api'; +import { Params } from '@angular/router'; +import { SciParamsEnterPanelPO } from './sci-params-enter.po'; + +export class ViewOpenActivityActionPanelPO { + + private _panel = $('app-view-open-activity-action-panel'); + + constructor(public iframeContext: string[]) { + } + + public async enterLabel(label: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#label'); + await inputField.clear(); + await inputField.sendKeys(label); + return Promise.resolve(); + } + + public async enterTitle(label: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#title'); + await inputField.clear(); + await inputField.sendKeys(label); + return Promise.resolve(); + } + + public async enterCssClass(cssClass: string): Promise { + await switchToIFrameContext(this.iframeContext); + const inputField = this._panel.$('input#css-class'); + await inputField.clear(); + await inputField.sendKeys(cssClass); + return Promise.resolve(); + } + + public async enterQualifier(qualifier: Qualifier): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(qualifier, this._panel.$('.e2e-qualifier-panel')); + } + + public async enterMatrixParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-matrix-params-panel')); + } + + public async enterQueryParams(params: Params): Promise { + await switchToIFrameContext(this.iframeContext); + await new SciParamsEnterPanelPO().enterParams(params, this._panel.$('.e2e-query-params-panel')); + } + + public async checkActivateIfPresent(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#activateIfPresent')); + } + + public async checkCloseIfPresent(check: boolean): Promise { + await switchToIFrameContext(this.iframeContext); + await checkCheckbox(check, this._panel.$('#closeIfPresent')); + } + + public async addAction(): Promise { + await switchToIFrameContext(this.iframeContext); + await this._panel.$('button.e2e-add-action').click(); + } +} diff --git a/projects/e2e/workbench-application-platform/test-runner/src/popup.e2e-spec.ts b/projects/e2e/workbench-application-platform/test-runner/src/popup.e2e-spec.ts new file mode 100644 index 000000000..da2f9558e --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/popup.e2e-spec.ts @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2018 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { TestingViewPO } from './page-object/testing-view.po'; +import { HostAppPO } from './page-object/host-app.po'; +import { expectPopupToNotExist, expectPopupToShow } from './util/testing.util'; +import { browser, protractor } from 'protractor'; +import { Testcase9c5319f7PopupPO } from './page-object/testcase-9c5319f7-popup.po'; +import { Testcase45dc693fPopupPO } from './page-object/testcase-45dc693f-popup.po'; +import { TestcaseF4286ac4PopupPO } from './page-object/testcase-f4286ac4-popup.po'; +import { Testcase159913adPopupPO } from './page-object/testcase-159913ad-popup.po'; +import { Testcase8a468258PopupPO } from './page-object/testcase-8a468258-popup.po'; +import { Testcasefc077b32PopupPO } from './page-object/testcase-fc077b32-popup.po'; +import { TestingPopupPO } from './page-object/testing-popup.po'; +import { Testcase5782ab19PopupPO } from './page-object/testcase-5782ab19-popup.po'; + +describe('Popup', () => { + const hostAppPO = new HostAppPO(); + const testingViewPO = new TestingViewPO(); + + beforeEach(async () => { + await browser.get('/'); + }); + + describe('Navigation', () => { + + it('should allow navigation to private popups of the same application (implicit intent) [testcase: 1a90c8d2-popup]', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '1a90c8d2-popup', + }); + await popupPanelPO.execute(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-1a90c8d2', componentSelector: 'app-popup-1a90c8d2'}); + }); + + it('should allow navigation to public popups of the same application (implicit intent) [testcase: 7330f506-popup]', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '7330f506-popup', + }); + await popupPanelPO.execute(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-7330f506', componentSelector: 'app-popup-7330f506'}); + }); + + it('should allow navigation to public popups of other applications', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'communication', + action: 'create', + contactId: '5', + }); + await popupPanelPO.execute(); + + await expectPopupToShow({symbolicAppName: 'communication-app', popupCssClass: 'e2e-communication-create', componentSelector: 'app-communication-new-popup'}); + }); + + it('should not allow navigation to public popups of other applications if missing the intent', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'communication', + action: 'create', + contactId: '999', + }); + await popupPanelPO.execute(); + + const notificationPO = await hostAppPO.findNotification('e2e-not-qualified'); + await expect(notificationPO).not.toBeNull(); + await expect(notificationPO.getSeverity()).toEqual('error'); + await expectPopupToNotExist({symbolicAppName: 'communication-app', popupCssClass: 'e2e-communication-create'}); + }); + + it('should not allow navigation to private popups of other applications', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'contact', + action: 'create', + }); + await popupPanelPO.execute(); + + const notificationPO = await hostAppPO.findNotification('e2e-not-handled'); + await expect(notificationPO).not.toBeNull(); + await expect(notificationPO.getSeverity()).toEqual('error'); + await expectPopupToNotExist({symbolicAppName: 'contact-app', popupCssClass: 'e2e-contact'}); + }); + + it('should allow to provide query and matrix parameters [testcase: 9c5319f7-popup]', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '9c5319f7-popup' + }); + await popupPanelPO.enterMatrixParams({ + mp1: '41ecdefec0a3', + mp2: 'da67bd554b36', + }); + await popupPanelPO.enterQueryParams({ + qp1: '6378a62700d3', + qp2: 'c5a37d3660ba', + }); + await popupPanelPO.execute(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-9c5319f7', componentSelector: 'app-popup-9c5319f7'}); + + const popupPO = new Testcase9c5319f7PopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: '41ecdefec0a3', + mp2: 'da67bd554b36', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: '6378a62700d3', + qp2: 'c5a37d3660ba', + }); + }); + + it('should allow to receive query and matrix parameters as specified in the manifest [testcase: 45dc693f-popup]', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '45dc693f-popup', + }); + + await popupPanelPO.execute(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-45dc693f', componentSelector: 'app-popup-45dc693f'}); + + const popupPO = new Testcase45dc693fPopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: 'd52f5f88be27', + mp2: '01aa011fb2f4', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: 'f3227d5926c0', + qp2: '88a9cd0cb937', + }); + }); + + it('should allow to merge query and matrix parameters provided from intent (overwrite) and manifest [testcase: f4286ac4-popup]', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: 'f4286ac4-popup', + }); + await popupPanelPO.enterMatrixParams({ + mp1: '557c7323a13c', + mp2: '67dbebc8dd7c', + }); + await popupPanelPO.enterQueryParams({ + qp1: 'a3fa547519cf', + qp2: 'db03e5494054', + }); + await popupPanelPO.execute(); + + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-f4286ac4', componentSelector: 'app-popup-f4286ac4'}); + + const popupPO = new TestcaseF4286ac4PopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + mp1: '557c7323a13c', + mp2: '67dbebc8dd7c', + mpx: 'f406422c77fc', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + qp1: 'a3fa547519cf', + qp2: 'db03e5494054', + qpx: '18c9d6c51b0c', + }); + }); + + it('should substitute path parameters with values from the intent qualifier [testcase: 159913ad-popup]', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '159913ad-popup', + qualifierParam1: 'e82bf49c4768', + qualifierParam2: '1b84a4a926f7' + }); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-159913ad', componentSelector: 'app-popup-159913ad'}); + + const popupPO = new Testcase159913adPopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + a: 'e82bf49c4768', + b: '1b84a4a926f7', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toBeNull(); + }); + + it('should substitute matrix and query parameters with values from the intent qualifier [testcase: 8a468258-popup]', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '8a468258-popup', + qualifierParam1: 'd8b74df2c77d', + qualifierParam2: 'e60c81360bee', + }); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-8a468258', componentSelector: 'app-popup-8a468258'}); + + const popupPO = new Testcase8a468258PopupPO(); + const urlParams = await popupPO.getUrlParameters(); + await expect(urlParams).toEqual({ + matrixParam1: 'd8b74df2c77d', + matrixParam2: 'eda2e91468e1', + pathParam1: 'd8b74df2c77d', + }); + + const urlQueryParams = await popupPO.getUrlQueryParameters(); + await expect(urlQueryParams).toEqual({ + queryParam1: 'e60c81360bee', + queryParam2: '1a3d3aaf937e' + }); + }); + }); + + describe('Properties', () => { + it('should be positioned as specified [testcase: fc077b32-popup]', async () => { + await testingViewPO.navigateTo(); + const popupPO = new Testcasefc077b32PopupPO(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: 'fc077b32-popup' + }); + + await popupPanelPO.selectPosition('north'); + await popupPanelPO.execute(); + await expect(popupPO.getPosition()).toEqual('north'); + await popupPO.close(); + + await popupPanelPO.selectPosition('east'); + await popupPanelPO.execute(); + await expect(popupPO.getPosition()).toEqual('east'); + await popupPO.close(); + + await popupPanelPO.selectPosition('south'); + await popupPanelPO.execute(); + await expect(popupPO.getPosition()).toEqual('south'); + await popupPO.close(); + + await popupPanelPO.selectPosition('west'); + await popupPanelPO.execute(); + await expect(popupPO.getPosition()).toEqual('west'); + await popupPO.close(); + }); + + it('should close on focus lost', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + }); + await popupPanelPO.checkCloseOnFocusLost(true); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // remove focus from the popup + await testingViewPO.closePopupPanel(); + await expectPopupToNotExist({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup'}); + }); + + it('should not close on focus lost', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + }); + await popupPanelPO.checkCloseOnFocusLost(false); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // remove focus from the popup + await testingViewPO.closePopupPanel(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + }); + + it('should close on escape keystroke', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + }); + await popupPanelPO.checkCloseOnEscape(true); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // send escape keystroke + await browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); + await expectPopupToNotExist({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup'}); + }); + + it('should not close on escape keystroke', async () => { + await testingViewPO.navigateTo(); + + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + }); + await popupPanelPO.checkCloseOnEscape(false); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // send escape keystroke + await browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + }); + + it('should close on grid layout change', async () => { + // Open activity to have a sash + await hostAppPO.clickActivityItem('e2e-contact-list'); + + // Open popup + await testingViewPO.navigateTo(); + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + }); + await popupPanelPO.checkCloseOnFocusLost(false); + await popupPanelPO.checkCloseOnGridLayoutChange(true); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // Make a grid layout change + await hostAppPO.moveActivitySash(100); + await expectPopupToNotExist({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup'}); + }); + + it('should not close on grid layout change', async () => { + // Open activity to have a sash + await hostAppPO.clickActivityItem('e2e-contact-list'); + + // Open popup + await testingViewPO.navigateTo(); + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + }); + await popupPanelPO.checkCloseOnFocusLost(false); + await popupPanelPO.checkCloseOnGridLayoutChange(false); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + // Make a grid layout change + await hostAppPO.moveActivitySash(100); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + }); + }); + + describe('Interaction', () => { + + it('should return the popup result', async () => { + await testingViewPO.navigateTo(); + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + }); + await popupPanelPO.checkCloseOnFocusLost(false); + await popupPanelPO.checkCloseOnGridLayoutChange(false); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-testing-popup', componentSelector: 'app-testing-popup'}); + + const json = { + value1: '948a14cc1e06', + value2: 'dd06acb924ed', + value3: 'ef247df0be6e', + }; + + const popupPO = new TestingPopupPO(); + await popupPO.enterResult(json); + await popupPO.ok(); + + await expect(popupPanelPO.getResult()).toEqual(json); + }); + }); + + describe('Focus', () => { + + it('should cycle the focus in the popup [testcase: 5782ab19-popup]', async () => { + await testingViewPO.navigateTo(); + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '5782ab19-popup', + }); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-5782ab19', componentSelector: 'app-popup-5782ab19'}); + + const popupPO = new Testcase5782ab19PopupPO(); + await expect(popupPO.isActiveElement('field-1')).toBeTruthy('(1)'); + + await popupPO.pressTab(); + await expect(popupPO.isActiveElement('field-2')).toBeTruthy('(2)'); + + await popupPO.pressTab(); + await expect(popupPO.isActiveElement('field-3')).toBeTruthy('(3)'); + + await popupPO.pressTab(); + await expect(popupPO.isActiveElement('field-1')).toBeTruthy('(4)'); + + await popupPO.pressTab(); + await expect(popupPO.isActiveElement('field-2')).toBeTruthy('(5)'); + + await popupPO.pressTab(); + await expect(popupPO.isActiveElement('field-3')).toBeTruthy('(6)'); + + await popupPO.pressShiftTab(); + await expect(popupPO.isActiveElement('field-2')).toBeTruthy('(7)'); + + await popupPO.pressShiftTab(); + await expect(popupPO.isActiveElement('field-1')).toBeTruthy('(8)'); + + await popupPO.pressShiftTab(); + await expect(popupPO.isActiveElement('field-3')).toBeTruthy('(9)'); + + await popupPO.pressShiftTab(); + await expect(popupPO.isActiveElement('field-2')).toBeTruthy('(10)'); + + await popupPO.pressShiftTab(); + await expect(popupPO.isActiveElement('field-1')).toBeTruthy('(11)'); + }); + + it('should autofocus the first element [testcase: 5782ab19-popup]', async () => { + await testingViewPO.navigateTo(); + const popupPanelPO = await testingViewPO.openPopupPanel(); + await popupPanelPO.enterQualifier({ + entity: 'testing', + testcase: '5782ab19-popup', + }); + await popupPanelPO.execute(); + await expectPopupToShow({symbolicAppName: 'testing-app', popupCssClass: 'e2e-popup-5782ab19', componentSelector: 'app-popup-5782ab19'}); + + const popupPO = new Testcase5782ab19PopupPO(); + await expect(popupPO.isActiveElement('field-1')).toBeTruthy('Expected first field to be the active element'); + }); + }); +}); diff --git a/projects/e2e/workbench-application-platform/test-runner/src/util/testing.util.ts b/projects/e2e/workbench-application-platform/test-runner/src/util/testing.util.ts new file mode 100644 index 000000000..0fc4d355f --- /dev/null +++ b/projects/e2e/workbench-application-platform/test-runner/src/util/testing.util.ts @@ -0,0 +1,147 @@ +import { $, browser, ElementFinder } from 'protractor'; + +/** + * Switches browser testing context to the main document. + */ +export async function switchToMainContext(): Promise { + await browser.switchTo().defaultContent(); + console.log(`Browser testing context switched: commands are sent to the main document.`); +} + +/** + * Switches browser testing context to given diff --git a/projects/scion/workbench/src/lib/remote-site/remote-site.component.scss b/projects/scion/workbench/src/lib/remote-site/remote-site.component.scss index 15ab81f54..6f7682156 100644 --- a/projects/scion/workbench/src/lib/remote-site/remote-site.component.scss +++ b/projects/scion/workbench/src/lib/remote-site/remote-site.component.scss @@ -4,5 +4,7 @@ > iframe { flex: auto; + min-width: 0; + min-height: 0; } } diff --git a/projects/scion/workbench/src/lib/remote-site/remote-site.component.ts b/projects/scion/workbench/src/lib/remote-site/remote-site.component.ts index 4c4e38fda..f89e0a054 100644 --- a/projects/scion/workbench/src/lib/remote-site/remote-site.component.ts +++ b/projects/scion/workbench/src/lib/remote-site/remote-site.component.ts @@ -60,6 +60,12 @@ export class RemoteSiteComponent implements OnDestroy { this._siteOrigin = new URL(url).origin; } + /** + * CSS classes to be added to the iframe tag. + */ + @Input() + public cssClass: string | string[]; + /** * Emits upon the receipt of a message from the remote site. * @@ -75,6 +81,30 @@ export class RemoteSiteComponent implements OnDestroy { @Output() public load = new EventEmitter(); + /** + * Emits when the remote site is about to lose focus. + * + * Requires the remote site to support this feature. + */ + @Output() + public synthFocusout = new EventEmitter(); + + /** + * Emits when the remote site is about to receive focus. + * + * Requires the remote site to support this feature. + */ + @Output() + public synthFocusin = new EventEmitter(); + + /** + * Emits when escape keystroke is pressed in the remote site. + * + * Requires the remote site to support this feature. + */ + @Output() + public synthEscape = new EventEmitter(); + constructor(private _sanitizer: DomSanitizer, private _workbenchLayout: WorkbenchLayoutService, private _renderer: Renderer2, @@ -125,7 +155,8 @@ export class RemoteSiteComponent implements OnDestroy { .subscribe(([event, iframe]: ['start' | 'end', HTMLIFrameElement]) => { if (event === 'start') { this._renderer.setStyle(iframe, 'pointer-events', 'none'); - } else { + } + else { this._renderer.removeStyle(iframe, 'pointer-events'); } }); @@ -147,6 +178,21 @@ export class RemoteSiteComponent implements OnDestroy { throw Error(`[OriginError] Message of illegal origin received [expected=${this._siteOrigin}, actual=${messageEvent.origin}]`); } + const synthEvent = parseSynthEvent(messageEvent.data); + if (synthEvent === 'sci-focusin') { + this._zone.run(() => this.synthFocusin.emit()); + return; + } + if (synthEvent === 'sci-focusout') { + this._zone.run(() => this.synthFocusout.emit()); + return; + } + if (synthEvent === 'sci-escape') { + this._zone.run(() => this.synthEscape.emit()); + document.dispatchEvent(new Event(synthEvent)); + return; + } + this.message.emit(messageEvent.data); // public API: do not emit inside Angular zone }); }); @@ -167,3 +213,24 @@ export class RemoteSiteComponent implements OnDestroy { function bufferUntil(closingNotifier$: Observable): OperatorFunction { return mergeMap((item: T) => combineLatest(of(item), closingNotifier$)); } + +/** + * Parses synthetic event sent by the remote site. + */ +function parseSynthEvent(data: any): string | null { + if (isNullOrUndefined(data) || typeof data !== 'object') { + return null; + } + if (data.protocol !== 'sci://workbench/remote-site') { + return null; + } + if (isNullOrUndefined(data.event)) { + return null; + } + + return data.event; +} + +function isNullOrUndefined(value: any): boolean { + return value === null || value === undefined; +} diff --git a/projects/scion/workbench/src/lib/routing/wb-router-link.directive.ts b/projects/scion/workbench/src/lib/routing/wb-router-link.directive.ts index 6db1b0ad3..b835a794f 100644 --- a/projects/scion/workbench/src/lib/routing/wb-router-link.directive.ts +++ b/projects/scion/workbench/src/lib/routing/wb-router-link.directive.ts @@ -19,6 +19,9 @@ import { WorkbenchService } from '../workbench.service'; /** * Like 'RouterLink' but with functionality to target a view outlet. * + * If in the context of a view and CTRL key is not pressed, by default, navigation replaces the content of the current view. + * Override this default behavior by setting a view target strategy in navigational extras. + * * By default, navigation is relative to the currently activated route, if any. * Prepend the path with a forward slash '/' to navigate absolutely, or set `relativeTo` property in navigational extras to `null`. */ diff --git a/projects/scion/workbench/src/lib/view-part/view-tab/view-tab.component.html b/projects/scion/workbench/src/lib/view-part/view-tab/view-tab.component.html index cb7ba7a92..4f31e9e98 100644 --- a/projects/scion/workbench/src/lib/view-part/view-tab/view-tab.component.html +++ b/projects/scion/workbench/src/lib/view-part/view-tab/view-tab.component.html @@ -1,13 +1,13 @@
-
- +
+ {{view.title}}
-
+
{{heading}}
diff --git a/projects/scion/workbench/src/lib/workbench.service.ts b/projects/scion/workbench/src/lib/workbench.service.ts index 8ba001170..be55251c3 100644 --- a/projects/scion/workbench/src/lib/workbench.service.ts +++ b/projects/scion/workbench/src/lib/workbench.service.ts @@ -17,7 +17,7 @@ import { Router } from '@angular/router'; /** * Root object for the SCION Workbench. * - * It consists of one or more viewparts containing views which can be flexible arranged and dragged around by the user. + * It consists of one or more viewparts containing views which can be flexibly arranged and dragged around by the user. * * The Workbench provides core features of a modern rich web application. * diff --git a/travis-scripts/cd.sh b/travis-scripts/cd.sh new file mode 100644 index 000000000..3a6d58308 --- /dev/null +++ b/travis-scripts/cd.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +TRAVIS_BUILD_DIR=$1 +DIST_DIR=$2 + +echo "Change directory: $DIST_DIR" +cd $TRAVIS_BUILD_DIR/$DIST_DIR diff --git a/travis-scripts/deploy-now.sh b/travis-scripts/deploy-now.sh new file mode 100644 index 000000000..ce0dfa609 --- /dev/null +++ b/travis-scripts/deploy-now.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +TRAVIS_BUILD_DIR=$1 +DIST_DIR=$2 +NOW_TOKEN=$3 + +echo "Change directory: $DIST_DIR" +cd $TRAVIS_BUILD_DIR/$DIST_DIR + +echo "Deploying '$DIST_DIR' to now 'https://zeit.co/scion'" +$TRAVIS_BUILD_DIR/node_modules/.bin/now deploy --token $NOW_TOKEN --team scion && $TRAVIS_BUILD_DIR/node_modules/.bin/now alias --token $NOW_TOKEN --team scion + +echo "Change directory: $TRAVIS_BUILD_DIR" +cd $TRAVIS_BUILD_DIR diff --git a/tsconfig.json b/tsconfig.json index 904c13b0c..298bb0495 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,30 @@ "@scion/workbench/*": [ "dist/scion/workbench/*" ], + "@scion/workbench-application-platform.api": [ + "dist/scion/workbench-application-platform.api" + ], + "@scion/workbench-application-platform.api/*": [ + "dist/scion/workbench-application-platform.api/*" + ], + "@scion/workbench-application-platform": [ + "dist/scion/workbench-application-platform" + ], + "@scion/workbench-application-platform/*": [ + "dist/scion/workbench-application-platform/*" + ], + "@scion/workbench-application.core": [ + "dist/scion/workbench-application.core" + ], + "@scion/workbench-application.core/*": [ + "dist/scion/workbench-application.core/*" + ], + "@scion/workbench-application.angular": [ + "dist/scion/workbench-application.angular" + ], + "@scion/workbench-application.angular/*": [ + "dist/scion/workbench-application.angular/*" + ], "@scion/mouse-dispatcher": [ "dist/scion/mouse-dispatcher" ], @@ -40,7 +64,73 @@ ], "@scion/viewport/*": [ "dist/scion/viewport/*" + ], + "@scion/e2e/common": [ + "dist/scion/e2e/common" + ], + "@scion/e2e/common/*": [ + "dist/scion/e2e/common/*" ] } +// /* +// * Path override to provide LIVE artifacts. +// * Note: DO NOT ACTIVATE FOR PRODUCTION! +// */ +// "paths": { +// "@scion/workbench": [ +// "projects/scion/workbench/src/public_api" +// ], +// "@scion/workbench/*": [ +// "projects/scion/workbench/src/*" +// ], +// "@scion/workbench-application-platform.api": [ +// "projects/scion/workbench-application-platform.api/src/public_api" +// ], +// "@scion/workbench-application-platform.api/*": [ +// "projects/scion/workbench-application-platform.api/src/*" +// ], +// "@scion/workbench-application-platform": [ +// "projects/scion/workbench-application-platform/src/public_api" +// ], +// "@scion/workbench-application-platform/*": [ +// "projects/scion/workbench-application-platform/src/*" +// ], +// "@scion/workbench-application.core": [ +// "projects/scion/workbench-application.core/src/public_api" +// ], +// "@scion/workbench-application.core/*": [ +// "projects/scion/workbench-application.core/src/*" +// ], +// "@scion/workbench-application.angular": [ +// "projects/scion/workbench-application.angular/src/public_api" +// ], +// "@scion/workbench-application.angular/*": [ +// "projects/scion/workbench-application.angular/src/*" +// ], +// "@scion/mouse-dispatcher": [ +// "projects/scion/mouse-dispatcher/src/public_api" +// ], +// "@scion/mouse-dispatcher/*": [ +// "projects/scion/mouse-dispatcher/src/*" +// ], +// "@scion/dimension": [ +// "projects/scion/dimension/src/public_api" +// ], +// "@scion/dimension/*": [ +// "projects/scion/dimension/src/*" +// ], +// "@scion/viewport": [ +// "projects/scion/viewport/src/public_api" +// ], +// "@scion/viewport/*": [ +// "projects/scion/viewport/src/*" +// ], +// "@scion/e2e/common": [ +// "projects/e2e/workbench-application-platform/common/src/public_api" +// ], +// "@scion/e2e/common/*": [ +// "projects/e2e/workbench-application-platform/common/src/*" +// ] +// } } }