├── .codeclimate.yml
├── .eslintignore
├── .github
└── workflows
│ └── main.yaml
├── .gitignore
├── .gitmodules
├── .npmignore
├── .nycrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── core.api.js
├── core.client.js
├── core.common.js
├── core
├── api
│ ├── application.js
│ ├── authentication.js
│ ├── db.js
│ ├── hooks
│ │ ├── hooks.authentication.js
│ │ ├── hooks.authorisations.js
│ │ ├── hooks.logger.js
│ │ ├── hooks.model.js
│ │ ├── hooks.push.js
│ │ ├── hooks.query.js
│ │ ├── hooks.schemas.js
│ │ ├── hooks.service.js
│ │ ├── hooks.storage.js
│ │ ├── hooks.users.js
│ │ └── index.js
│ ├── index.js
│ ├── marshall.js
│ ├── models
│ │ ├── messages.model.mongodb.js
│ │ └── users.model.mongodb.js
│ └── services
│ │ ├── account
│ │ ├── account.hooks.js
│ │ └── account.service.js
│ │ ├── authorisations
│ │ ├── authorisations.hooks.js
│ │ └── authorisations.service.js
│ │ ├── databases
│ │ ├── databases.hooks.js
│ │ └── databases.service.js
│ │ ├── import-export
│ │ ├── import-export.hooks.js
│ │ └── import-export.service.js
│ │ ├── index.js
│ │ ├── mailer
│ │ ├── mailer.hooks.js
│ │ └── mailer.service.js
│ │ ├── messages
│ │ └── messages.hooks.js
│ │ ├── push
│ │ ├── push.hooks.js
│ │ └── push.service.js
│ │ ├── storage
│ │ ├── storage.hooks.js
│ │ └── storage.service.js
│ │ └── users
│ │ ├── users.hooks.js
│ │ └── users.service.js
├── client
│ ├── api.js
│ ├── broadcaster.js
│ ├── capabilities.js
│ ├── components
│ │ ├── KActivity.vue
│ │ ├── KAvatar.vue
│ │ ├── KChip.vue
│ │ ├── KContent.vue
│ │ ├── KDialog.vue
│ │ ├── KEditor.vue
│ │ ├── KExpandable.vue
│ │ ├── KFollower.vue
│ │ ├── KLogo.vue
│ │ ├── KModal.vue
│ │ ├── KPanel.vue
│ │ ├── KScrollArea.vue
│ │ ├── KSponsor.vue
│ │ ├── KStamp.vue
│ │ ├── KStore.vue
│ │ ├── KTab.vue
│ │ ├── KTextArea.vue
│ │ ├── KTree.vue
│ │ ├── KVersion.vue
│ │ ├── account
│ │ │ ├── KAccount.vue
│ │ │ ├── KDeleteAccountManager.vue
│ │ │ ├── KEmailManager.vue
│ │ │ ├── KPasswordManager.vue
│ │ │ ├── KProfile.vue
│ │ │ ├── KResetPassword.vue
│ │ │ ├── KSendResetPassword.vue
│ │ │ ├── KSubscription.vue
│ │ │ ├── KSubscriptionsManager.vue
│ │ │ ├── KVerifyEmailManager.vue
│ │ │ └── index.js
│ │ ├── action
│ │ │ ├── KAction.vue
│ │ │ ├── KBugReportAction.vue
│ │ │ ├── KToggleFullscreenAction.vue
│ │ │ ├── KToggleStickyVisibility.vue
│ │ │ ├── KToggleWidgetVisibility.vue
│ │ │ └── index.js
│ │ ├── app
│ │ │ ├── KAbout.vue
│ │ │ ├── KHome.vue
│ │ │ ├── KPlatform.vue
│ │ │ ├── KRequestProgressBar.vue
│ │ │ ├── KSettings.vue
│ │ │ ├── KTour.vue
│ │ │ ├── KWelcome.vue
│ │ │ └── index.js
│ │ ├── chart
│ │ │ ├── KChart.vue
│ │ │ ├── KDataTable.vue
│ │ │ ├── KStatisticsChart.vue
│ │ │ ├── KTimeSeriesChart.vue
│ │ │ └── index.js
│ │ ├── collection
│ │ │ ├── KBoard.vue
│ │ │ ├── KCard.vue
│ │ │ ├── KCardSection.vue
│ │ │ ├── KColumn.vue
│ │ │ ├── KDescriptionCardSection.vue
│ │ │ ├── KFilter.vue
│ │ │ ├── KFilterView.vue
│ │ │ ├── KGrid.vue
│ │ │ ├── KHistory.vue
│ │ │ ├── KHistoryEntry.vue
│ │ │ ├── KItem.vue
│ │ │ ├── KScrollDown.vue
│ │ │ ├── KScrollToTop.vue
│ │ │ ├── KSearchFilterControl.vue
│ │ │ ├── KSorter.vue
│ │ │ ├── KTable.vue
│ │ │ ├── KTagsFilterControl.vue
│ │ │ ├── KTagsFilterView.vue
│ │ │ ├── KTimeFilterControl.vue
│ │ │ ├── KTimeFilterView.vue
│ │ │ ├── KTimeLine.vue
│ │ │ └── index.js
│ │ ├── document
│ │ │ ├── KBrowser.vue
│ │ │ ├── KCsv.vue
│ │ │ ├── KDocument.vue
│ │ │ ├── KHtml.vue
│ │ │ ├── KImage.vue
│ │ │ ├── KMarkdown.vue
│ │ │ ├── KPdf.vue
│ │ │ ├── KUploader.vue
│ │ │ └── KVideo.vue
│ │ ├── editor
│ │ │ ├── KEditor.vue
│ │ │ ├── KModalEditor.vue
│ │ │ └── index.js
│ │ ├── form
│ │ │ ├── KChipsField.vue
│ │ │ ├── KColorField.vue
│ │ │ ├── KColorScaleField.vue
│ │ │ ├── KDateField.vue
│ │ │ ├── KDateTimeRangeField.vue
│ │ │ ├── KDatetimeField.vue
│ │ │ ├── KEmailField.vue
│ │ │ ├── KFileField.vue
│ │ │ ├── KForm.vue
│ │ │ ├── KIconField.vue
│ │ │ ├── KItemField.vue
│ │ │ ├── KNumberField.vue
│ │ │ ├── KOptionsField.vue
│ │ │ ├── KPasswordField.vue
│ │ │ ├── KPhoneField.vue
│ │ │ ├── KPropertyItemField.vue
│ │ │ ├── KResolutionField.vue
│ │ │ ├── KRoleField.vue
│ │ │ ├── KSelectField.vue
│ │ │ ├── KTextField.vue
│ │ │ ├── KTextareaField.vue
│ │ │ ├── KToggleField.vue
│ │ │ ├── KTokenField.vue
│ │ │ ├── KUnitField.vue
│ │ │ ├── KUrlField.vue
│ │ │ ├── KView.vue
│ │ │ └── index.js
│ │ ├── graphics
│ │ │ └── KIcon.vue
│ │ ├── index.js
│ │ ├── input
│ │ │ ├── KColorChooser.vue
│ │ │ ├── KColorPicker.vue
│ │ │ ├── KIconChooser.vue
│ │ │ ├── KIconPicker.vue
│ │ │ ├── KOptionsChooser.vue
│ │ │ ├── KPalette.vue
│ │ │ ├── KShapePicker.vue
│ │ │ └── index.js
│ │ ├── layout
│ │ │ ├── KFab.vue
│ │ │ ├── KLayout.vue
│ │ │ ├── KOpener.vue
│ │ │ ├── KPage.vue
│ │ │ ├── KWindow.vue
│ │ │ └── index.js
│ │ ├── media
│ │ │ ├── KColorScale.vue
│ │ │ ├── KImageViewer.vue
│ │ │ ├── KMarkdownViewer.vue
│ │ │ ├── KMediaBrowser.vue
│ │ │ ├── KRibbon.vue
│ │ │ ├── KShape.vue
│ │ │ └── index.js
│ │ ├── menu
│ │ │ ├── KMenu.vue
│ │ │ ├── KRadialFab.vue
│ │ │ ├── KRadialFabItem.vue
│ │ │ ├── KSubMenu.vue
│ │ │ └── index.js
│ │ ├── messages
│ │ │ ├── KMessageCard.vue
│ │ │ ├── KMessageComposer.vue
│ │ │ ├── KMessagesTimeLine.vue
│ │ │ └── index.js
│ │ ├── screen
│ │ │ ├── KErrorScreen.vue
│ │ │ ├── KLoginScreen.vue
│ │ │ ├── KLogoutScreen.vue
│ │ │ ├── KOAuthLoginScreen.vue
│ │ │ ├── KOAuthLogoutScreen.vue
│ │ │ ├── KRegisterScreen.vue
│ │ │ ├── KScreen.vue
│ │ │ ├── KScreenFooter.vue
│ │ │ ├── KScreenHeader.vue
│ │ │ ├── KUnauthorizedScreen.vue
│ │ │ └── index.js
│ │ ├── time
│ │ │ ├── KAbsoluteTimeRange.vue
│ │ │ ├── KDate.vue
│ │ │ ├── KDateTime.vue
│ │ │ ├── KDateTimeRange.vue
│ │ │ ├── KRelativeTimeRanges.vue
│ │ │ ├── KTime.vue
│ │ │ ├── KTimeControl.vue
│ │ │ └── index.js
│ │ ├── tool
│ │ │ └── KExportTool.vue
│ │ └── viewer
│ │ │ ├── KModalViewer.vue
│ │ │ └── KViewer.vue
│ ├── composables
│ │ ├── activity.js
│ │ ├── collection-counter.js
│ │ ├── collection-filter.js
│ │ ├── collection-timerange.js
│ │ ├── collection.js
│ │ ├── context.js
│ │ ├── errors.js
│ │ ├── index.js
│ │ ├── layout.js
│ │ ├── messages.js
│ │ ├── pwa.js
│ │ ├── schema.js
│ │ ├── screen.js
│ │ ├── selection.js
│ │ ├── session.js
│ │ ├── store.js
│ │ └── version.js
│ ├── context.js
│ ├── directives
│ │ ├── index.js
│ │ ├── v-drop-file.js
│ │ └── v-hover.js
│ ├── document.js
│ ├── events.js
│ ├── exporter.js
│ ├── filter.js
│ ├── guards.js
│ ├── hooks
│ │ ├── hooks.events.js
│ │ ├── hooks.logger.js
│ │ ├── hooks.offline.js
│ │ ├── hooks.users.js
│ │ └── index.js
│ ├── i18n.js
│ ├── i18n
│ │ ├── core_en.json
│ │ └── core_fr.json
│ ├── index.js
│ ├── layout.js
│ ├── local-cache.js
│ ├── local-storage.js
│ ├── mixins
│ │ ├── index.js
│ │ ├── mixin.base-activity.js
│ │ ├── mixin.base-editor.js
│ │ ├── mixin.base-field.js
│ │ ├── mixin.base-item.js
│ │ ├── mixin.base-modal.js
│ │ ├── mixin.base-viewer.js
│ │ ├── mixin.object-proxy.js
│ │ ├── mixin.schema-proxy.js
│ │ └── mixin.service.js
│ ├── platform.js
│ ├── reader.js
│ ├── readers
│ │ ├── index.js
│ │ ├── reader.blob.js
│ │ ├── reader.csv.js
│ │ └── reader.json.js
│ ├── search.js
│ ├── services
│ │ ├── index.js
│ │ └── local-settings.service.js
│ ├── sorter.js
│ ├── storage.js
│ ├── store.js
│ ├── template-context.js
│ ├── theme.js
│ ├── time.js
│ ├── units.js
│ └── utils
│ │ ├── index.js
│ │ ├── utils.account.js
│ │ ├── utils.actions.js
│ │ ├── utils.collection.js
│ │ ├── utils.colors.js
│ │ ├── utils.content.js
│ │ ├── utils.files.js
│ │ ├── utils.items.js
│ │ ├── utils.locale.js
│ │ ├── utils.math.js
│ │ ├── utils.push.js
│ │ ├── utils.pwa.js
│ │ ├── utils.screen.js
│ │ ├── utils.services.js
│ │ ├── utils.session.js
│ │ ├── utils.shapes.js
│ │ └── utils.time.js
└── common
│ ├── errors.js
│ ├── index.js
│ ├── permissions.js
│ ├── schema.js
│ ├── schemas
│ ├── messages.update.json
│ ├── settings.update.json
│ └── users.update-profile.json
│ ├── utils.js
│ └── utils.offline.js
├── docs
├── .vitepress
│ ├── config.mjs
│ ├── public
│ │ ├── Widgets Workflow Diagram.drawio
│ │ ├── aggregated-feature-data-model.xml
│ │ ├── alert-data-model.xml
│ │ ├── application-hooks.xml
│ │ ├── catalog-data-model.xml
│ │ ├── cd-pipeline-v1.xml
│ │ ├── cd-pipeline-v2.xml
│ │ ├── cd-pipeline.xml
│ │ ├── component-view.xml
│ │ ├── domain-model.xml
│ │ ├── editor-lifecycle.xml
│ │ ├── event-log-lifecycle.xml
│ │ ├── feature-data-model.xml
│ │ ├── global-architecture.xml
│ │ ├── images
│ │ │ ├── PWA-client-server-sync.png
│ │ │ ├── PWA-offline-client.png
│ │ │ ├── PWA-online-client-caching.png
│ │ │ ├── PWA-online-client.png
│ │ │ ├── PWA-server-server-sync.png
│ │ │ ├── aggregated-feature-data-model.png
│ │ │ ├── airtac-list.png
│ │ │ ├── aktnmap-layout.png
│ │ │ ├── aktnmap.png
│ │ │ ├── alert-data-model.png
│ │ │ ├── animated-wall.gif
│ │ │ ├── application-hooks.svg
│ │ │ ├── attributionClosed.png
│ │ │ ├── attributionOpened.png
│ │ │ ├── catalog-data-model.png
│ │ │ ├── cd-pipeline-android.svg
│ │ │ ├── cd-pipeline-app.svg
│ │ │ ├── cd-pipeline-env.svg
│ │ │ ├── cd-pipeline-global.svg
│ │ │ ├── cd-pipeline-ios.svg
│ │ │ ├── cd-pipeline-travis.svg
│ │ │ ├── cd-pipeline-v1.svg
│ │ │ ├── cd-pipeline-v2.svg
│ │ │ ├── component-view.png
│ │ │ ├── desaturate-post-process.png
│ │ │ ├── domain-model.svg
│ │ │ ├── editor-lifecycle.png
│ │ │ ├── feathers-services.png
│ │ │ ├── feature-data-model.png
│ │ │ ├── global-architecture.svg
│ │ │ ├── gradient-path.png
│ │ │ ├── great-circle-2D.png
│ │ │ ├── great-circle-3D.png
│ │ │ ├── item-collections.png
│ │ │ ├── kalisio-banner.png
│ │ │ ├── kano-3D.png
│ │ │ ├── kano-components.png
│ │ │ ├── kano-iframe.png
│ │ │ ├── kano-layout-1.png
│ │ │ ├── kano-layout-2.png
│ │ │ ├── kano-style-2D.png
│ │ │ ├── kano-style-3D.png
│ │ │ ├── kano-weather.png
│ │ │ ├── kdk-workspace.png
│ │ │ ├── layers-panel.png
│ │ │ ├── line-gradient-2D.png
│ │ │ ├── line-offset-2D.png
│ │ │ ├── marker-cluster-2D.png
│ │ │ ├── marker-cluster-3D.png
│ │ │ ├── operations-methods-events.png
│ │ │ ├── theme-colors.svg
│ │ │ ├── timeseries.png
│ │ │ ├── users-data-model.svg
│ │ │ └── wall-3D.png
│ │ ├── items.drawio
│ │ ├── layout.drawio
│ │ ├── manifest.json
│ │ ├── offline.drawio
│ │ ├── organizations-data-model.xml
│ │ ├── theme.drawio
│ │ └── users-data-model.xml
│ └── theme
│ │ ├── custom.css
│ │ └── index.js
├── about
│ ├── contact.md
│ ├── contributing.md
│ ├── introduction.md
│ ├── license.md
│ └── roadmap.md
├── api
│ ├── core
│ │ ├── application.md
│ │ ├── components.md
│ │ ├── components
│ │ │ ├── collections.md
│ │ │ ├── diagrams
│ │ │ │ ├── collections.drawio
│ │ │ │ ├── items.drawio
│ │ │ │ ├── kcard-expanded.png
│ │ │ │ ├── kcard-header-footer.png
│ │ │ │ ├── kcard-heading.png
│ │ │ │ ├── kcard.png
│ │ │ │ ├── kcardsection.png
│ │ │ │ ├── kgrid-header-footer.png
│ │ │ │ ├── kgrid-infinite-scroll.png
│ │ │ │ ├── kgrid-layout.png
│ │ │ │ └── kgrid-pagination.png
│ │ │ ├── graphics.md
│ │ │ ├── items.md
│ │ │ └── time.md
│ │ ├── composables.md
│ │ ├── directives.md
│ │ ├── hooks.md
│ │ ├── introduction.md
│ │ ├── mixins.md
│ │ ├── services.md
│ │ ├── utilities.md
│ │ └── utilities
│ │ │ ├── utils.collection.md
│ │ │ ├── utils.colors.md
│ │ │ ├── utils.locale.md
│ │ │ ├── utils.screen.md
│ │ │ └── utils.services.md
│ ├── introduction.md
│ └── map
│ │ ├── components.md
│ │ ├── composables.md
│ │ ├── globe-mixins.md
│ │ ├── hooks.md
│ │ ├── introduction.md
│ │ ├── map-mixins.md
│ │ ├── mixins.md
│ │ ├── services.md
│ │ ├── utilities.md
│ │ └── utilities
│ │ └── utils.features.md
├── architecture
│ ├── component-view.md
│ ├── data-model-view.md
│ ├── global-architecture.md
│ ├── introduction.md
│ └── main-concepts.md
├── guides
│ ├── basics
│ │ └── introduction.md
│ ├── development
│ │ ├── configure.md
│ │ ├── deploy.md
│ │ ├── develop.md
│ │ ├── publish.md
│ │ ├── setup.md
│ │ └── test.md
│ ├── introduction.md
│ └── migration
│ │ ├── v2.5.md
│ │ └── v2.6.md
├── index.md
├── package.json
└── yarn.lock
├── extras
├── configs
│ ├── helpers.js
│ ├── panes.left.js
│ ├── panes.top.js
│ ├── stickies.js
│ ├── widgets.left.js
│ └── widgets.top.js
├── css
│ └── core.variables.scss
├── icons
│ ├── anticlockwise.png
│ ├── attribution.png
│ ├── center-on-feature.svg
│ ├── clockwise.png
│ ├── json.svg
│ ├── kanban.png
│ ├── map-legend.svg
│ ├── mapillary-marker.png
│ ├── mapillary.png
│ ├── marker-icon-2x.png
│ ├── marker-icon.png
│ ├── marker-shadow.png
│ ├── pdf.png
│ ├── position-cursor.png
│ ├── view-plus.png
│ ├── wind-speed-0.svg
│ ├── wind-speed-10.svg
│ ├── wind-speed-100.svg
│ ├── wind-speed-105.svg
│ ├── wind-speed-15.svg
│ ├── wind-speed-20.svg
│ ├── wind-speed-25.svg
│ ├── wind-speed-30.svg
│ ├── wind-speed-35.svg
│ ├── wind-speed-40.svg
│ ├── wind-speed-45.svg
│ ├── wind-speed-5.svg
│ ├── wind-speed-50.svg
│ ├── wind-speed-55.svg
│ ├── wind-speed-60.svg
│ ├── wind-speed-65.svg
│ ├── wind-speed-70.svg
│ ├── wind-speed-75.svg
│ ├── wind-speed-80.svg
│ ├── wind-speed-85.svg
│ ├── wind-speed-90.svg
│ └── wind-speed-95.svg
├── images
│ ├── kalisio.png
│ ├── north.svg
│ └── target.svg
└── tours
│ ├── core
│ ├── account-profile.js
│ ├── account.js
│ ├── add-member.js
│ ├── add-tag.js
│ ├── create-group.js
│ ├── create-organisation.js
│ ├── create-tag.js
│ ├── edit-member-role.js
│ ├── groups.js
│ ├── join-group.js
│ ├── login.js
│ ├── members.js
│ ├── register.js
│ ├── send-reset-password.js
│ └── tags.js
│ └── map
│ ├── add-layer.js
│ ├── catalog-categories.js
│ ├── catalog-panel.js
│ ├── connect-layer.js
│ ├── create-layer.js
│ ├── create-view.js
│ ├── fab.js
│ ├── home.js
│ ├── import-layer.js
│ ├── navigation-bar.js
│ ├── side-nav.js
│ └── timeline.js
├── map.api.js
├── map.client.globe.js
├── map.client.js
├── map.client.map.js
├── map.common.js
├── map.config.cjs
├── map
├── api
│ ├── config
│ │ ├── categories.cjs
│ │ ├── layers.cjs
│ │ └── sublegends.cjs
│ ├── hooks
│ │ ├── hooks.catalog.js
│ │ ├── hooks.features.js
│ │ ├── hooks.query.js
│ │ └── index.js
│ ├── index.js
│ ├── marshall.js
│ ├── models
│ │ ├── alerts.model.mongodb.js
│ │ ├── catalog.model.mongodb.js
│ │ ├── features.model.mongodb.js
│ │ ├── projects.model.mongodb.js
│ │ └── styles.model.mongodb.js
│ └── services
│ │ ├── alerts
│ │ ├── alerts.hooks.js
│ │ └── alerts.service.js
│ │ ├── catalog
│ │ └── catalog.hooks.js
│ │ ├── daptiles
│ │ └── daptiles.service.js
│ │ ├── features
│ │ ├── features.hooks.js
│ │ └── features.service.js
│ │ ├── index.js
│ │ ├── projects
│ │ └── projects.hooks.js
│ │ └── styles
│ │ └── styles.hooks.js
├── client
│ ├── canvas-draw-context.js
│ ├── capture.js
│ ├── cesium
│ │ └── utils
│ │ │ ├── index.js
│ │ │ ├── utils.cesium.js
│ │ │ ├── utils.events.js
│ │ │ ├── utils.features.js
│ │ │ ├── utils.geojson.js
│ │ │ ├── utils.popup.js
│ │ │ └── utils.style.js
│ ├── components
│ │ ├── KCapture.vue
│ │ ├── KCaptureTextArea.vue
│ │ ├── KCompass.vue
│ │ ├── KEditLayerData.vue
│ │ ├── KFeatureActionButton.vue
│ │ ├── KFeatureEditor.vue
│ │ ├── KFeaturesChart.vue
│ │ ├── KFeaturesFilterEditor.vue
│ │ ├── KFeaturesFilterManager.vue
│ │ ├── KFeaturesTable.vue
│ │ ├── KFilterCondition.vue
│ │ ├── KLayerEditionToolbar.vue
│ │ ├── KLayerEditor.vue
│ │ ├── KMeasureTool.vue
│ │ ├── KProjectMenu.vue
│ │ ├── KTimezoneMap.vue
│ │ ├── catalog
│ │ │ ├── KAddLayer.vue
│ │ │ ├── KBaseLayersSelector.vue
│ │ │ ├── KCategoryItem.vue
│ │ │ ├── KConnectLayer.vue
│ │ │ ├── KCreateLayer.vue
│ │ │ ├── KCreateOfflineView.vue
│ │ │ ├── KCreateView.vue
│ │ │ ├── KFilteredLayerItem.vue
│ │ │ ├── KImportLayer.vue
│ │ │ ├── KLayerCategories.vue
│ │ │ ├── KLayerItem.vue
│ │ │ ├── KLayersList.vue
│ │ │ ├── KLayersPanel.vue
│ │ │ ├── KLayersSelector.vue
│ │ │ ├── KProjectEditor.vue
│ │ │ ├── KProjectManager.vue
│ │ │ ├── KProjectSelector.vue
│ │ │ ├── KProjectsPanel.vue
│ │ │ ├── KSelectLayers.vue
│ │ │ ├── KSelectViews.vue
│ │ │ ├── KViewSelector.vue
│ │ │ ├── KViewsPanel.vue
│ │ │ └── KWeatherLayersSelector.vue
│ │ ├── form
│ │ │ ├── KDirectionField.vue
│ │ │ ├── KLayerCategoryField.vue
│ │ │ ├── KLocationField.vue
│ │ │ ├── KOwsLayerField.vue
│ │ │ ├── KOwsServiceField.vue
│ │ │ ├── KSelectLayersField.vue
│ │ │ ├── KSelectViewsField.vue
│ │ │ └── KTimezoneField.vue
│ │ ├── index.js
│ │ ├── legend
│ │ │ ├── KColorScaleLegend.vue
│ │ │ ├── KImageLegend.vue
│ │ │ ├── KLayerLegend.vue
│ │ │ ├── KLegend.vue
│ │ │ ├── KLegendRenderer.vue
│ │ │ ├── KSymbolsLegend.vue
│ │ │ └── KVariablesLegend.vue
│ │ ├── location
│ │ │ ├── KGeocodersFilter.vue
│ │ │ ├── KLocationCardSection.vue
│ │ │ ├── KLocationMap.vue
│ │ │ ├── KLocationSearch.vue
│ │ │ ├── KLocationTimeLineCard.vue
│ │ │ └── KLocationTip.vue
│ │ ├── selection
│ │ │ ├── KFeaturesSelection.vue
│ │ │ └── KSelectedLayerFeatures.vue
│ │ ├── stickies
│ │ │ ├── KAttribution.vue
│ │ │ ├── KLevelSlider.vue
│ │ │ ├── KNorthArrow.vue
│ │ │ ├── KPosition.vue
│ │ │ └── KTarget.vue
│ │ ├── styles
│ │ │ ├── KLayerStyleAction.vue
│ │ │ ├── KStyleEditor.vue
│ │ │ ├── KStyleEditorSection.vue
│ │ │ ├── KStyleManager.vue
│ │ │ ├── KStylePreview.vue
│ │ │ ├── KStylePreviewItem.vue
│ │ │ ├── KStylePropertiesGroup.vue
│ │ │ ├── KStyleProperty.vue
│ │ │ └── KStyleTip.vue
│ │ ├── tools
│ │ │ ├── KGeolocateTool.vue
│ │ │ └── KSearchTool.vue
│ │ └── widget
│ │ │ ├── KElevationProfile.vue
│ │ │ ├── KInformationBox.vue
│ │ │ ├── KMapillaryViewer.vue
│ │ │ ├── KStackableTimeSeries.vue
│ │ │ └── KTimeSeries.vue
│ ├── composables
│ │ ├── activity.js
│ │ ├── catalog.js
│ │ ├── highlight.js
│ │ ├── index.js
│ │ ├── location.js
│ │ ├── measure.js
│ │ ├── probe.js
│ │ ├── project.js
│ │ ├── selection.js
│ │ └── weather.js
│ ├── elevation-utils.js
│ ├── geocoder.js
│ ├── geolocation.js
│ ├── globe.js
│ ├── hooks
│ │ ├── hooks.offline.js
│ │ └── index.js
│ ├── i18n
│ │ ├── map_en.json
│ │ └── map_fr.json
│ ├── index.js
│ ├── init.js
│ ├── leaflet
│ │ ├── BoxSelection.js
│ │ ├── GSMaPLayer.js
│ │ ├── GradientPath.js
│ │ ├── MaskLayer.js
│ │ ├── ShapeMarker.js
│ │ ├── TiledFeatureLayer.js
│ │ ├── TiledMeshLayer.js
│ │ ├── TiledWindLayer.js
│ │ ├── WindBarb.js
│ │ └── utils
│ │ │ ├── index.js
│ │ │ ├── utils.events.js
│ │ │ ├── utils.geojson.js
│ │ │ ├── utils.popup.js
│ │ │ ├── utils.style.js
│ │ │ └── utils.tiles.js
│ ├── map.js
│ ├── mixins
│ │ ├── globe
│ │ │ ├── index.js
│ │ │ ├── mixin.base-globe.js
│ │ │ ├── mixin.file-layers.js
│ │ │ ├── mixin.geojson-layers.js
│ │ │ ├── mixin.globe-activity.js
│ │ │ ├── mixin.opendap-layers.js
│ │ │ ├── mixin.popup.js
│ │ │ ├── mixin.style.js
│ │ │ └── mixin.tooltip.js
│ │ ├── index.js
│ │ ├── map
│ │ │ ├── index.js
│ │ │ ├── mixin.base-map.js
│ │ │ ├── mixin.canvas-layers.js
│ │ │ ├── mixin.edit-layers.js
│ │ │ ├── mixin.file-layers.js
│ │ │ ├── mixin.geojson-layers.js
│ │ │ ├── mixin.gsmap-layers.js
│ │ │ ├── mixin.heatmap-layers.js
│ │ │ ├── mixin.map-activity.js
│ │ │ ├── mixin.mapillary-layers.js
│ │ │ ├── mixin.pmtiles-layers.js
│ │ │ ├── mixin.popup.js
│ │ │ ├── mixin.style.js
│ │ │ ├── mixin.tiled-mesh-layers.js
│ │ │ ├── mixin.tiled-wind-layers.js
│ │ │ └── mixin.tooltip.js
│ │ ├── mixin.activity.js
│ │ ├── mixin.context.js
│ │ ├── mixin.feature-selection.js
│ │ ├── mixin.feature-service.js
│ │ ├── mixin.infobox.js
│ │ ├── mixin.levels.js
│ │ ├── mixin.style.js
│ │ └── mixin.weacast.js
│ ├── navigator.js
│ ├── pixi-utils.js
│ ├── planets.js
│ ├── readers
│ │ ├── index.js
│ │ ├── reader.geojson.js
│ │ ├── reader.gpx.js
│ │ ├── reader.kml.js
│ │ └── reader.shp.js
│ ├── utils.all.js
│ ├── utils.globe.js
│ ├── utils.js
│ ├── utils.map.js
│ └── utils
│ │ ├── index.js
│ │ ├── utils.capture.js
│ │ ├── utils.catalog.js
│ │ ├── utils.features.js
│ │ ├── utils.js
│ │ ├── utils.layers.js
│ │ ├── utils.location.js
│ │ ├── utils.offline.js
│ │ ├── utils.project.js
│ │ ├── utils.schema.js
│ │ ├── utils.style.js
│ │ ├── utils.time-series.js
│ │ └── utils.weacast.js
└── common
│ ├── dynamic-grid-source.js
│ ├── errors.js
│ ├── geotiff-grid-source.js
│ ├── grid.js
│ ├── index.js
│ ├── meteo-model-grid-source.js
│ ├── moment-utils.js
│ ├── opendap-grid-source.js
│ ├── opendap-utils.js
│ ├── permissions.js
│ ├── schemas
│ ├── capture.create.json
│ ├── catalog.update.json
│ ├── projects.create.json
│ └── projects.update.json
│ ├── time-based-grid-source.js
│ ├── tms-utils.js
│ ├── wcs-grid-source.js
│ ├── wcs-utils.js
│ ├── weacast-grid-source.js
│ ├── wfs-utils.js
│ ├── wms-utils.js
│ └── wmts-utils.js
├── package.json
├── scripts
├── build_docs.sh
├── init_runner.sh
├── run_tests.sh
└── setup_workspace.sh
├── test.api.js
├── test.client.js
├── test
├── api
│ ├── core
│ │ ├── account.test.js
│ │ ├── authentication.test.js
│ │ ├── client.test.js.skip
│ │ ├── config
│ │ │ ├── default.cjs
│ │ │ └── email-templates
│ │ │ │ ├── confirmInvitation
│ │ │ │ └── html.ejs
│ │ │ │ ├── identityChange
│ │ │ │ └── html.ejs
│ │ │ │ ├── newDevice
│ │ │ │ └── html.ejs
│ │ │ │ ├── newSubscription
│ │ │ │ └── html.ejs
│ │ │ │ ├── passwordChange
│ │ │ │ └── html.ejs
│ │ │ │ ├── resendVerifySignup
│ │ │ │ └── html.ejs
│ │ │ │ ├── resetPwd
│ │ │ │ └── html.ejs
│ │ │ │ ├── sendResetPwd
│ │ │ │ └── html.ejs
│ │ │ │ └── verifySignup
│ │ │ │ └── html.ejs
│ │ ├── data
│ │ │ ├── 10k_most_common_passwords.txt
│ │ │ ├── invalid-objects.json
│ │ │ ├── logo.png
│ │ │ ├── schema.json
│ │ │ └── valid-objects.json
│ │ ├── hooks.test.js
│ │ ├── import-export.test.js
│ │ ├── index.js
│ │ ├── index.test.js
│ │ ├── offline.test.js
│ │ ├── push.test.js
│ │ ├── schemas.test.js
│ │ ├── storage.test.js
│ │ └── utils.js
│ ├── index.js
│ └── map
│ │ ├── alerts.test.js
│ │ ├── catalog.test.js
│ │ ├── config
│ │ ├── default.cjs
│ │ └── layers.json
│ │ ├── data
│ │ ├── DescribeCoverage.xml
│ │ ├── GetCoverage.tif
│ │ ├── adsb.observations.json
│ │ ├── dataset.grb.das
│ │ ├── dataset.grb.dds
│ │ ├── dataset.grb.dods
│ │ ├── lat_lon_bounds.grb.dods
│ │ ├── openradiation.json
│ │ ├── subdataset.grb.dods
│ │ ├── vigicrues.observations.H.json
│ │ ├── vigicrues.observations.Q.json
│ │ ├── vigicrues.stations.json
│ │ └── zones.json
│ │ ├── grid-sources.test.js
│ │ ├── hooks.test.js
│ │ ├── index.js
│ │ ├── index.test.js
│ │ └── style.test.js
└── client
│ ├── core
│ ├── account.js
│ ├── api.js
│ ├── collection.js
│ ├── dialogs.js
│ ├── index.js
│ ├── layout.js
│ ├── runner.js
│ ├── screens.js
│ ├── time.js
│ └── utils.js
│ ├── index.js
│ └── map
│ ├── api.js
│ ├── catalog.js
│ ├── controls.js
│ ├── index.js
│ ├── time.js
│ └── utils.js
└── yarn.lock
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | exclude_patterns:
2 | - "lib/"
3 | plugins:
4 | fixme:
5 | enabled: true
6 | checks:
7 | argument-count:
8 | config:
9 | threshold: 4
10 | complex-logic:
11 | config:
12 | threshold: 4
13 | file-lines:
14 | config:
15 | threshold: 500
16 | method-complexity:
17 | config:
18 | threshold: 20
19 | method-count:
20 | config:
21 | threshold: 20
22 | method-lines:
23 | config:
24 | threshold: 50
25 | nested-control-flow:
26 | config:
27 | threshold: 4
28 | return-statements:
29 | config:
30 | threshold: 4
31 | similar-code:
32 | enabled: false
33 | identical-code:
34 | enabled: false
35 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | core/client/components/action/KAction.vue
2 | map/client/components/catalog/KLayersPanel.vue
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # IDE
2 | .vscode
3 | .idea
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 |
11 | # Runtime data
12 | pids
13 | *.pid
14 | *.seed
15 | *.pid.lock
16 |
17 | # Coverage directory used by tools like istanbul
18 | .nyc_output
19 | coverage
20 |
21 | # Dependency directories
22 | node_modules/
23 |
24 | # Compiled library
25 | lib/
26 |
27 | # Optional npm cache directory
28 | .npm
29 |
30 | # Yarn Integrity file
31 | .yarn-integrity
32 |
33 | # dotenv environment variables file
34 | .env
35 |
36 | # draw.io backup
37 | *.bkp
38 | *.dtmp
39 |
40 | # vitepress
41 | docs/.vitepress/cache
42 | docs/.vitepress/dist
43 | docs/node_modules/
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "scripts/kash"]
2 | path = scripts/kash
3 | url = http://github.com/kalisio/kash
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .editorconfig
2 | .jshintrc
3 | .travis.yml
4 | .istanbul.yml
5 | .babelrc
6 | .idea/
7 | docs/
8 |
9 |
--------------------------------------------------------------------------------
/.nycrc:
--------------------------------------------------------------------------------
1 | {
2 | "all": true,
3 | "include": ["core/**/*.js", "map/**/*.js"],
4 | "exclude": ["**/client/**"],
5 | "reporter": ["text", "html", "lcov"]
6 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-20xx Kalisio
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/core.api.js:
--------------------------------------------------------------------------------
1 | // Need this as export * only exports named exports but not the default export
2 | import api from './core/api/index.js'
3 | export default api
4 |
5 | export * from './core/api/index.js'
6 |
--------------------------------------------------------------------------------
/core.client.js:
--------------------------------------------------------------------------------
1 | // Need this as export * only exports named exports but not the default export
2 | import client from './core/client/index.js'
3 | export default client
4 |
5 | export * from './core/client/index.js'
6 |
--------------------------------------------------------------------------------
/core.common.js:
--------------------------------------------------------------------------------
1 | export * from './core/common/index.js'
2 |
--------------------------------------------------------------------------------
/core/api/hooks/hooks.authentication.js:
--------------------------------------------------------------------------------
1 | import makeDebug from 'debug'
2 | import common from 'feathers-hooks-common'
3 | import local from '@feathersjs/authentication-local'
4 |
5 | const debug = makeDebug('kdk:core:authentication:hooks')
6 | const { discard } = common
7 |
8 | // Make it more easy to access
9 | export const hashPassword = local.hooks.hashPassword
10 |
11 | export function discardAuthenticationProviders (hook) {
12 | const providers = hook.app.authenticationProviders || []
13 |
14 | // Iterate through known providers
15 | for (const provider of providers) {
16 | discard(provider)(hook)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/api/hooks/hooks.logger.js:
--------------------------------------------------------------------------------
1 | // A hook that logs service method before, after and error
2 | export function log (hook) {
3 | let message = `${hook.type}: ${hook.path} - Method: ${hook.method}`
4 |
5 | if (hook.type === 'error') {
6 | message += `: ${hook.error.message}`
7 | }
8 |
9 | if (hook.error) {
10 | hook.app.logger.error(message, hook.error.stack)
11 | } else {
12 | hook.app.logger.debug(message)
13 | }
14 |
15 | // Required as the logger causes high CPU usage to serialize messages
16 | // even if the current log level should discard it
17 | // See https://github.com/kalisio/kdk/issues/287
18 | if (process.env.NODE_ENV === 'development') {
19 | hook.app.logger.silly('hook.data', hook.data)
20 | hook.app.logger.silly('hook.params', hook.params)
21 |
22 | if (hook.result) {
23 | hook.app.logger.silly('hook.result', hook.result)
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/core/api/hooks/index.js:
--------------------------------------------------------------------------------
1 | export * from './hooks.authentication.js'
2 | export * from './hooks.authorisations.js'
3 | export * from './hooks.logger.js'
4 | export * from './hooks.model.js'
5 | export * from './hooks.query.js'
6 | export * from './hooks.schemas.js'
7 | export * from './hooks.service.js'
8 | export * from './hooks.storage.js'
9 | export * from './hooks.users.js'
10 | export * from './hooks.push.js'
11 |
--------------------------------------------------------------------------------
/core/api/index.js:
--------------------------------------------------------------------------------
1 | import makeDebug from 'debug'
2 | import services from './services/index.js'
3 | import * as hooks from './hooks/index.js'
4 | import { Schema } from '../common/index.js'
5 |
6 | export * from './services/index.js'
7 | export { hooks }
8 | export * from './db.js'
9 | export * from './authentication.js'
10 | export * from './application.js'
11 | export * from './marshall.js'
12 | export * from '../common/index.js'
13 |
14 | const debug = makeDebug('kdk:core')
15 |
16 | export default async function init (app) {
17 | debug('Initializing KDK core')
18 |
19 | Schema.initialize(app.get('schema'))
20 | await app.configure(services)
21 | }
22 |
--------------------------------------------------------------------------------
/core/api/models/messages.model.mongodb.js:
--------------------------------------------------------------------------------
1 | export default function (app, options) {
2 | const db = options.db || app.db
3 | options.Model = db.collection('messages')
4 | // Collation provided in query ensure sorting to be case insensitive w.r.t. user's language
5 | // We built indices with collation to cover the most used languages, it requires different naming...
6 | options.Model.createIndex({ createdAt: -1 })
7 | options.Model.createIndex({ title: 1 }, { name: 'title-en', collation: { locale: 'en', strength: 1 } })
8 | options.Model.createIndex({ title: 1 }, { name: 'title-fr', collation: { locale: 'fr', strength: 1 } })
9 | options.Model.createIndex({ body: 1 }, { name: 'body-en', collation: { locale: 'en', strength: 1 } })
10 | options.Model.createIndex({ body: 1 }, { name: 'body-fr', collation: { locale: 'fr', strength: 1 } })
11 | options.Model.createIndex({ author: 1 }, { name: 'author-en', collation: { locale: 'en', strength: 1 } })
12 | options.Model.createIndex({ author: 1 }, { name: 'author-fr', collation: { locale: 'fr', strength: 1 } })
13 | }
--------------------------------------------------------------------------------
/core/api/models/users.model.mongodb.js:
--------------------------------------------------------------------------------
1 | export default function (app, options) {
2 | options.Model = app.db.collection('users')
3 | options.Model.createIndex({ email: 1 }, { unique: true })
4 | // Collation provided in query ensure sorting to be case insensitive w.r.t. user's language
5 | // We built indices with collation to cover the most used languages, it requires different naming...
6 | options.Model.createIndex({ 'profile.name': 1 }, { name: 'name-en', collation: { locale: 'en', strength: 1 } })
7 | options.Model.createIndex({ 'profile.name': 1 }, { name: 'name-fr', collation: { locale: 'fr', strength: 1 } })
8 | // Inactive user account might expire at a given date
9 | options.Model.createIndex({ expireAt: 1 }, { expireAfterSeconds: 0 })
10 | }
11 |
--------------------------------------------------------------------------------
/core/api/services/account/account.hooks.js:
--------------------------------------------------------------------------------
1 | import common from 'feathers-hooks-common'
2 | import { enforcePasswordPolicy } from '../../hooks/index.js'
3 |
4 | const { when } = common
5 |
6 | export default {
7 | before: {
8 | all: [],
9 | find: [],
10 | get: [],
11 | create: [
12 | when(
13 | (hook) => ['passwordChange', 'resetPwdShort', 'verifySignupSetPasswordLong', 'verifySignupSetPasswordShort'].includes(hook.data.action),
14 | enforcePasswordPolicy({ userAsItem: false, passwordField: 'value.password' })
15 | ),
16 | ],
17 | update: [],
18 | patch: [],
19 | remove: [],
20 | },
21 |
22 | after: {
23 | all: [],
24 | find: [],
25 | get: [],
26 | create: [],
27 | update: [],
28 | patch: [],
29 | remove: [],
30 | },
31 |
32 | error: {
33 | all: [],
34 | find: [],
35 | get: [],
36 | create: [],
37 | update: [],
38 | patch: [],
39 | remove: [],
40 | },
41 | }
42 |
--------------------------------------------------------------------------------
/core/api/services/authorisations/authorisations.hooks.js:
--------------------------------------------------------------------------------
1 | import { populateSubjects, populateResource } from '../../hooks/index.js'
2 |
3 | export default {
4 | before: {
5 | all: [],
6 | find: [],
7 | get: [],
8 | create: [populateSubjects, populateResource],
9 | update: [],
10 | patch: [],
11 | remove: [populateSubjects, populateResource]
12 | },
13 |
14 | after: {
15 | all: [],
16 | find: [],
17 | get: [],
18 | create: [],
19 | update: [],
20 | patch: [],
21 | remove: []
22 | },
23 |
24 | error: {
25 | all: [],
26 | find: [],
27 | get: [],
28 | create: [],
29 | update: [],
30 | patch: [],
31 | remove: []
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/api/services/databases/databases.hooks.js:
--------------------------------------------------------------------------------
1 | import common from 'feathers-hooks-common'
2 |
3 | const { disallow } = common
4 |
5 | export default {
6 | before: {
7 | // Only used internally
8 | all: [disallow('external')],
9 | find: [],
10 | get: [],
11 | create: [],
12 | update: [],
13 | patch: [],
14 | remove: []
15 | },
16 |
17 | after: {
18 | all: [],
19 | find: [],
20 | get: [],
21 | create: [],
22 | update: [],
23 | patch: [],
24 | remove: []
25 | },
26 |
27 | error: {
28 | all: [],
29 | find: [],
30 | get: [],
31 | create: [],
32 | update: [],
33 | patch: [],
34 | remove: []
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/api/services/databases/databases.service.js:
--------------------------------------------------------------------------------
1 | import mongoManager from 'feathers-mongodb-management'
2 |
3 | export default function (name, app, options) {
4 | return mongoManager.database({ adminDb: app.db.instance.admin(), client: app.db.client })
5 | }
6 |
--------------------------------------------------------------------------------
/core/api/services/import-export/import-export.hooks.js:
--------------------------------------------------------------------------------
1 | import commonHooks from 'feathers-hooks-common'
2 |
3 | export default {
4 | before: {
5 | all: [],
6 | find: [commonHooks.disallow()],
7 | get: [commonHooks.disallow()],
8 | create: [],
9 | update: [commonHooks.disallow()],
10 | patch: [commonHooks.disallow()],
11 | remove: [commonHooks.disallow()]
12 | },
13 |
14 | after: {
15 | all: [],
16 | find: [],
17 | get: [],
18 | create: [],
19 | update: [],
20 | patch: [],
21 | remove: []
22 | },
23 |
24 | error: {
25 | all: [],
26 | find: [],
27 | get: [],
28 | create: [],
29 | update: [],
30 | patch: [],
31 | remove: []
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/api/services/import-export/import-export.service.js:
--------------------------------------------------------------------------------
1 | import { Service } from '@kalisio/feathers-import-export'
2 | import makeDebug from 'debug'
3 |
4 | const debug = makeDebug('kdk:import-export:service')
5 |
6 | export default function (name, app, options) {
7 | const config = app.get('import-export')
8 | debug('Creating import-export service with config ', config)
9 | const s3ServicePath = app.get('apiPath') + '/' + (config.s3Service)
10 | return new Service(Object.assign({ app }, config, { s3ServicePath }))
11 | }
12 |
--------------------------------------------------------------------------------
/core/api/services/mailer/mailer.hooks.js:
--------------------------------------------------------------------------------
1 | import common from 'feathers-hooks-common'
2 |
3 | const { disallow } = common
4 |
5 | export default {
6 | before: {
7 | all: [disallow('external')],
8 | find: [],
9 | get: [],
10 | create: [],
11 | update: [],
12 | patch: [],
13 | remove: []
14 | },
15 |
16 | after: {
17 | all: [],
18 | find: [],
19 | get: [],
20 | create: [],
21 | update: [],
22 | patch: [],
23 | remove: []
24 | },
25 |
26 | error: {
27 | all: [],
28 | find: [],
29 | get: [],
30 | create: [],
31 | update: [],
32 | patch: [],
33 | remove: []
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/core/api/services/mailer/mailer.service.js:
--------------------------------------------------------------------------------
1 | import mailer from 'feathers-mailer'
2 | import makeDebug from 'debug'
3 |
4 | const debug = makeDebug('kdk:core:mailer:service')
5 |
6 | export default function (name, app, options) {
7 | // Keep track of mailer config in service options
8 | const config = Object.assign(options, app.get('mailer'))
9 | debug('Mailer created with config ', config)
10 | return mailer(config)
11 | }
12 |
--------------------------------------------------------------------------------
/core/api/services/messages/messages.hooks.js:
--------------------------------------------------------------------------------
1 | import commonHooks from 'feathers-hooks-common'
2 | import fuzzySearch from 'feathers-mongodb-fuzzy-search'
3 | import { diacriticSearch, marshallComparisonQuery } from '../../hooks/index.js'
4 |
5 | export default {
6 | before: {
7 | all: [],
8 | find: [
9 | fuzzySearch({ fields: ['title', 'body', 'author'] }),
10 | diacriticSearch(),
11 | marshallComparisonQuery
12 | ],
13 | get: [],
14 | create: [commonHooks.setNow('createdAt')],
15 | update: [],
16 | patch: [],
17 | remove: []
18 | },
19 |
20 | after: {
21 | all: [],
22 | find: [],
23 | get: [],
24 | create: [],
25 | update: [],
26 | patch: [],
27 | remove: []
28 | },
29 |
30 | error: {
31 | all: [],
32 | find: [],
33 | get: [],
34 | create: [],
35 | update: [],
36 | patch: [],
37 | remove: []
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/api/services/push/push.hooks.js:
--------------------------------------------------------------------------------
1 | import { deleteExpiredSubscriptions } from '@kalisio/feathers-webpush'
2 | import commonHooks from 'feathers-hooks-common'
3 | import { disallowExternalPush } from '../../hooks/index.js'
4 |
5 | export default {
6 | before: {
7 | all: [],
8 | find: [],
9 | get: [],
10 | create: [commonHooks.when(disallowExternalPush, commonHooks.disallow('external'))],
11 | update: [],
12 | patch: [],
13 | remove: []
14 | },
15 |
16 | after: {
17 | all: [],
18 | find: [],
19 | get: [],
20 | create: [deleteExpiredSubscriptions],
21 | update: [],
22 | patch: [],
23 | remove: []
24 | },
25 |
26 | error: {
27 | all: [],
28 | find: [],
29 | get: [],
30 | create: [],
31 | update: [],
32 | patch: [],
33 | remove: []
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/core/api/services/push/push.service.js:
--------------------------------------------------------------------------------
1 | import { Service } from '@kalisio/feathers-webpush'
2 | import makeDebug from 'debug'
3 |
4 | const debug = makeDebug('kdk:push:service')
5 |
6 | export default function (name, app, options) {
7 | const config = app.get('push')
8 | debug('Creating push service with config ', config)
9 | const service = new Service(Object.assign({ app }, config))
10 |
11 | return service
12 | }
13 |
--------------------------------------------------------------------------------
/core/api/services/storage/storage.hooks.js:
--------------------------------------------------------------------------------
1 | import common from 'feathers-hooks-common'
2 |
3 | const { disallow, discard } = common
4 |
5 | export default {
6 | before: {
7 | all: [],
8 | find: [],
9 | get: [],
10 | create: [],
11 | update: [disallow()],
12 | patch: [disallow()],
13 | remove: []
14 | },
15 |
16 | after: {
17 | all: [],
18 | find: [],
19 | get: [],
20 | create: [discard('buffer')],
21 | update: [],
22 | patch: [],
23 | remove: [discard('buffer')]
24 | },
25 |
26 | error: {
27 | all: [],
28 | find: [],
29 | get: [],
30 | create: [],
31 | update: [],
32 | patch: [],
33 | remove: []
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/core/api/services/users/users.service.js:
--------------------------------------------------------------------------------
1 | export default {
2 | logout (user) {
3 | this.emit('logout', user)
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/core/client/broadcaster.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import logger from 'loglevel'
3 | import config from 'config'
4 |
5 | export const Broadcaster = {
6 | initialize () {
7 | this.channelName = _.get(config, 'appSlug', _.kebabCase(_.get(config, 'appName', 'kdk')))
8 | this.channel = new BroadcastChannel(this.channelName)
9 | logger.debug(`[KDK] Broadcaster initialized with channel '${this.channelName}'`)
10 | },
11 | getChannelName () {
12 | return this.channelName
13 | },
14 | getChannel () {
15 | return this.channel
16 | },
17 | post (message) {
18 | this.channel.postMessage(message)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/core/client/components/KExpandable.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
37 |
38 |
50 |
--------------------------------------------------------------------------------
/core/client/components/KLogo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
32 |
--------------------------------------------------------------------------------
/core/client/components/KSponsor.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
30 |
--------------------------------------------------------------------------------
/core/client/components/KTree.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
32 |
--------------------------------------------------------------------------------
/core/client/components/KVersion.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
12 |
13 |
14 |
20 |
--------------------------------------------------------------------------------
/core/client/components/account/KSubscriptionsManager.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
20 |
21 |
22 |
23 |
46 |
--------------------------------------------------------------------------------
/core/client/components/account/index.js:
--------------------------------------------------------------------------------
1 | import KAccount from './KAccount.vue'
2 | import KProfile from './KProfile.vue'
3 |
4 | export {
5 | KAccount,
6 | KProfile
7 | }
8 |
--------------------------------------------------------------------------------
/core/client/components/action/KBugReportAction.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
39 |
--------------------------------------------------------------------------------
/core/client/components/action/KToggleFullscreenAction.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
26 |
--------------------------------------------------------------------------------
/core/client/components/action/KToggleStickyVisibility.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
42 |
--------------------------------------------------------------------------------
/core/client/components/action/KToggleWidgetVisibility.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
42 |
--------------------------------------------------------------------------------
/core/client/components/action/index.js:
--------------------------------------------------------------------------------
1 | import KAction from './KAction.vue'
2 | import KBugReportAction from './KBugReportAction.vue'
3 |
4 | export {
5 | KAction,
6 | KBugReportAction
7 | }
--------------------------------------------------------------------------------
/core/client/components/app/KHome.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
--------------------------------------------------------------------------------
/core/client/components/app/index.js:
--------------------------------------------------------------------------------
1 | import KAbout from './KAbout.vue'
2 | import KHome from './KHome.vue'
3 | import KPlatform from './KPlatform.vue'
4 | import KSettings from './KSettings.vue'
5 | import KTour from './KTour.vue'
6 | import KWelcome from './KWelcome.vue'
7 |
8 | export {
9 | KAbout,
10 | KHome,
11 | KPlatform,
12 | KSettings,
13 | KTour,
14 | KWelcome
15 | }
16 |
--------------------------------------------------------------------------------
/core/client/components/chart/index.js:
--------------------------------------------------------------------------------
1 | import KChart from './KChart.vue'
2 | import KStatisticsChart from './KStatisticsChart.vue'
3 | import KTimeSeriesChart from './KTimeSeriesChart.vue'
4 |
5 | export {
6 | KChart,
7 | KStatisticsChart,
8 | KTimeSeriesChart
9 | }
10 |
--------------------------------------------------------------------------------
/core/client/components/collection/KBoard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
55 |
--------------------------------------------------------------------------------
/core/client/components/collection/KCardSection.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 | {{ title }}
10 |
11 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
44 |
--------------------------------------------------------------------------------
/core/client/components/collection/KFilterView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
--------------------------------------------------------------------------------
/core/client/components/collection/KSorter.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
47 |
--------------------------------------------------------------------------------
/core/client/components/collection/KTimeFilterControl.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
41 |
--------------------------------------------------------------------------------
/core/client/components/collection/index.js:
--------------------------------------------------------------------------------
1 | import KCard from './KCard.vue'
2 | import KCardSection from './KCardSection.vue'
3 | import KGrid from './KGrid.vue'
4 | import KItem from './KItem.vue'
5 | import KHistory from './KHistory.vue'
6 | import KTable from './KTable.vue'
7 |
8 | export {
9 | KCard,
10 | KCardSection,
11 | KGrid,
12 | KItem,
13 | KHistory,
14 | KTable
15 | }
16 |
--------------------------------------------------------------------------------
/core/client/components/document/KCsv.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ cell }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
46 |
47 |
53 |
--------------------------------------------------------------------------------
/core/client/components/document/KHtml.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
34 |
--------------------------------------------------------------------------------
/core/client/components/document/KMarkdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
42 |
--------------------------------------------------------------------------------
/core/client/components/document/KVideo.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
40 |
--------------------------------------------------------------------------------
/core/client/components/editor/index.js:
--------------------------------------------------------------------------------
1 | import KEditor from './KEditor.vue'
2 | import KModalEditor from './KModalEditor.vue'
3 |
4 | export {
5 | KEditor,
6 | KModalEditor
7 | }
8 |
--------------------------------------------------------------------------------
/core/client/components/form/KEmailField.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
20 |
21 |
22 |
33 |
34 |
35 |
36 |
37 |
44 |
--------------------------------------------------------------------------------
/core/client/components/form/KNumberField.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ model }}
4 |
5 |
20 |
21 |
22 |
33 |
34 |
35 |
36 |
37 |
44 |
--------------------------------------------------------------------------------
/core/client/components/form/KPhoneField.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
19 |
20 |
21 |
32 |
33 |
34 |
35 |
36 |
43 |
--------------------------------------------------------------------------------
/core/client/components/form/KUrlField.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
19 |
20 |
21 |
32 |
33 |
34 |
35 |
36 |
43 |
--------------------------------------------------------------------------------
/core/client/components/form/index.js:
--------------------------------------------------------------------------------
1 | import KForm from './KForm.vue'
2 | import KView from './KView.vue'
3 |
4 | export {
5 | KForm,
6 | KView
7 | }
8 |
--------------------------------------------------------------------------------
/core/client/components/index.js:
--------------------------------------------------------------------------------
1 | import KAvatar from './KAvatar.vue'
2 | import KChip from './KChip.vue'
3 | import KContent from './KContent.vue'
4 | import KDialog from './KDialog.vue'
5 | import KExpandable from './KExpandable.vue'
6 | import KLogo from './KLogo.vue'
7 | import KModal from './KModal.vue'
8 | import KPanel from './KPanel.vue'
9 | import KSponsor from './KSponsor.vue'
10 | import KScrollArea from './KScrollArea.vue'
11 | import KStamp from './KStamp.vue'
12 | import KTextArea from './KTextArea.vue'
13 | import KVersion from './KVersion.vue'
14 |
15 | export {
16 | KAvatar,
17 | KChip,
18 | KContent,
19 | KDialog,
20 | KExpandable,
21 | KLogo,
22 | KModal,
23 | KPanel,
24 | KSponsor,
25 | KScrollArea,
26 | KStamp,
27 | KTextArea,
28 | KVersion
29 | }
30 |
31 | export * from './action/index.js'
32 | export * from './layout/index.js'
33 | export * from './form/index.js'
34 | export * from './collection/index.js'
35 | export * from './editor/index.js'
36 | export * from './input/index.js'
37 | export * from './account/index.js'
38 | export * from './media/index.js'
39 | export * from './menu/index.js'
40 | export * from './screen/index.js'
41 | export * from './time/index.js'
42 | export * from './chart/index.js'
43 | export * from './messages/index.js'
44 |
--------------------------------------------------------------------------------
/core/client/components/input/KPalette.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
42 |
--------------------------------------------------------------------------------
/core/client/components/input/index.js:
--------------------------------------------------------------------------------
1 | import KColorChooser from './KColorChooser.vue'
2 | import KColorPicker from './KColorPicker.vue'
3 | import KIconChooser from './KIconChooser.vue'
4 | import KIconPicker from './KIconPicker.vue'
5 | import KOptionsChooser from './KOptionsChooser.vue'
6 | import KPalette from './KPalette.vue'
7 | import KShapePicker from './KShapePicker.vue'
8 |
9 | export {
10 | KColorChooser,
11 | KColorPicker,
12 | KIconChooser,
13 | KIconPicker,
14 | KOptionsChooser,
15 | KPalette,
16 | KShapePicker
17 | }
18 |
--------------------------------------------------------------------------------
/core/client/components/layout/index.js:
--------------------------------------------------------------------------------
1 | import KFab from './KFab.vue'
2 | import KLayout from './KLayout.vue'
3 | import KPage from './KPage.vue'
4 | import KWindow from './KWindow.vue'
5 |
6 | export {
7 | KFab,
8 | KLayout,
9 | KPage,
10 | KWindow
11 | }
12 |
--------------------------------------------------------------------------------
/core/client/components/media/KMarkdownViewer.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
56 |
--------------------------------------------------------------------------------
/core/client/components/media/KShape.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ tooltip }}
6 |
7 |
8 |
9 |
10 |
32 |
--------------------------------------------------------------------------------
/core/client/components/media/index.js:
--------------------------------------------------------------------------------
1 | import KColorScale from './KColorScale.vue'
2 | import KImageViewer from './KImageViewer.vue'
3 | import KMarkdownViewer from './KMarkdownViewer.vue'
4 | import KMediaBrowser from './KMediaBrowser.vue'
5 | import KShape from './KShape.vue'
6 |
7 | export {
8 | KColorScale,
9 | KMarkdownViewer,
10 | KMediaBrowser,
11 | KImageViewer,
12 | KShape
13 | }
14 |
--------------------------------------------------------------------------------
/core/client/components/menu/index.js:
--------------------------------------------------------------------------------
1 | import KMenu from './KMenu.vue'
2 | import KRadialFab from './KRadialFab.vue'
3 | import KRadialFabItem from './KRadialFabItem.vue'
4 |
5 | export {
6 | KMenu,
7 | KRadialFab,
8 | KRadialFabItem
9 | }
10 |
--------------------------------------------------------------------------------
/core/client/components/messages/index.js:
--------------------------------------------------------------------------------
1 | import KMessageCard from './KMessageCard.vue'
2 | import KMessageComposer from './KMessageComposer.vue'
3 |
4 | export {
5 | KMessageCard,
6 | KMessageComposer
7 | }
8 |
--------------------------------------------------------------------------------
/core/client/components/screen/KErrorScreen.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
24 |
--------------------------------------------------------------------------------
/core/client/components/screen/KLogoutScreen.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
23 |
--------------------------------------------------------------------------------
/core/client/components/screen/KOAuthLoginScreen.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/core/client/components/screen/KOAuthLogoutScreen.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
34 |
--------------------------------------------------------------------------------
/core/client/components/screen/KScreenFooter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
--------------------------------------------------------------------------------
/core/client/components/screen/KScreenHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ flavor }}
4 |
5 |
6 |
7 |
18 |
--------------------------------------------------------------------------------
/core/client/components/screen/KUnauthorizedScreen.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
17 |
--------------------------------------------------------------------------------
/core/client/components/screen/index.js:
--------------------------------------------------------------------------------
1 | import KScreen from './KScreen.vue'
2 |
3 | export {
4 | KScreen
5 | }
6 |
--------------------------------------------------------------------------------
/core/client/components/time/index.js:
--------------------------------------------------------------------------------
1 | import KAbsoluteTimeRange from './KAbsoluteTimeRange.vue'
2 | import KRelativeTimeRanges from './KRelativeTimeRanges.vue'
3 |
4 | export {
5 | KAbsoluteTimeRange,
6 | KRelativeTimeRanges
7 | }
8 |
--------------------------------------------------------------------------------
/core/client/components/tool/KExportTool.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
58 |
--------------------------------------------------------------------------------
/core/client/components/viewer/KModalViewer.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
16 |
48 |
--------------------------------------------------------------------------------
/core/client/components/viewer/KViewer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
31 |
--------------------------------------------------------------------------------
/core/client/composables/index.js:
--------------------------------------------------------------------------------
1 | export * from './activity.js'
2 | export * from './collection-counter.js'
3 | export * from './collection-filter.js'
4 | export * from './collection-timerange.js'
5 | export * from './collection.js'
6 | export * from './context.js'
7 | export * from './errors.js'
8 | export * from './layout.js'
9 | export * from './messages.js'
10 | export * from './pwa.js'
11 | export * from './session.js'
12 | export * from './schema.js'
13 | export * from './screen.js'
14 | export * from './selection.js'
15 | export * from './store.js'
16 | export * from './version.js'
17 |
--------------------------------------------------------------------------------
/core/client/composables/messages.js:
--------------------------------------------------------------------------------
1 | import { api } from '../api.js'
2 |
3 | export function useMessages () {
4 | const messagesService = api.getService('messages')
5 |
6 | // Functions
7 | async function createMessage (message, query) {
8 | return messagesService.create(message, { query })
9 | }
10 |
11 | // Expose
12 | return {
13 | createMessage
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/core/client/composables/screen.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { ref, computed, readonly } from 'vue'
3 | import { useQuasar } from 'quasar'
4 | import { Fullscreen, toggleFullscreen, lockOrientation } from '../utils/utils.screen.js'
5 |
6 | const Orientation = ref(null)
7 |
8 | export function useScreen (options = {}) {
9 | // Data
10 | const $q = useQuasar()
11 | const denseBreakpoint = _.get(options, 'dense', 'sm')
12 | const wideBreakpoint = _.get(options, 'wide', 'sm')
13 |
14 | // Computed
15 | const dense = computed(() => {
16 | return $q.screen.lt[denseBreakpoint]
17 | })
18 | const wide = computed(() => {
19 | return $q.screen.gt[wideBreakpoint]
20 | })
21 | const orientation = computed(() => {
22 | return $q.screen.width >= $q.screen.height ? 'landscape' : 'portrait'
23 | })
24 |
25 | // Expose
26 | return {
27 | Screen: readonly($q.screen),
28 | dense,
29 | wide,
30 | orientation,
31 | Fullscreen: readonly(Fullscreen),
32 | toggleFullscreen,
33 | lockOrientation
34 | }
35 | }
--------------------------------------------------------------------------------
/core/client/composables/store.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { reactive } from 'vue'
3 |
4 | // states store
5 | const Store = {}
6 |
7 | export function useStore (name, initialStore) {
8 | // data
9 | if (!_.has(Store, name)) { // Initialize on first call
10 | _.set(Store, name, reactive(initialStore || {}))
11 | }
12 | const store = _.get(Store, name)
13 |
14 | // functions
15 | function clear () {
16 | _.forOwn(store, function (value, key) {
17 | _.unset(store, key)
18 | })
19 | }
20 | function set (path, value) {
21 | _.set(store, path, value)
22 | }
23 | function get (path, defaultValue) {
24 | // If no path is given return the whole store object
25 | return (path ? _.get(store, path, defaultValue) : store)
26 | }
27 | function unset (path) {
28 | _.unset(store, path)
29 | }
30 | function has (path) {
31 | return _.has(store, path)
32 | }
33 | function forOwn (f) {
34 | _.forOwn(store, function (value, key) {
35 | f(value, key)
36 | })
37 | }
38 |
39 | // expose
40 | return {
41 | Store,
42 | store,
43 | clear,
44 | set,
45 | get,
46 | unset,
47 | has,
48 | forOwn
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/core/client/composables/version.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import config from 'config'
3 | import { ref, computed, readonly } from 'vue'
4 | import { Capabilities } from '../index.js'
5 |
6 | const Version = ref({
7 | client: {
8 | number: _.get(config, 'version'),
9 | buildNumber: _.get(config, 'buildNumber')
10 | },
11 | api: {
12 | number: undefined,
13 | buildNumber: undefined
14 | },
15 | flavor: _.get(config, 'flavor')
16 | })
17 | let isInitialized = false
18 |
19 | export function useVersion () {
20 | // Computed
21 | const clientVersionName = computed(() => {
22 | const clientVersion = Version.value.client
23 | let version = clientVersion.number
24 | if (clientVersion.buildNumber) version += ` (${clientVersion.buildNumber})`
25 | return version
26 | })
27 | const apiVersionName = computed(() => {
28 | const apiVersion = Version.value.api
29 | let version = apiVersion.number
30 | if (apiVersion.buildNumber) version += ` (${apiVersion.buildNumber})`
31 | return version
32 | })
33 |
34 | // Immediate
35 | if (!isInitialized) {
36 | isInitialized = true
37 | Version.value.api.number = Capabilities.get('version')
38 | Version.value.api.buildNumber = Capabilities.get('buildNumber')
39 | }
40 |
41 | // Expose
42 | return {
43 | Version: readonly(Version),
44 | clientVersionName,
45 | apiVersionName
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/client/context.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import logger from 'loglevel'
3 | import config from 'config'
4 | import { api } from './api.js'
5 | import { Store } from './store.js'
6 |
7 | // Export singleton
8 | export const Context = {
9 | serviceName: null,
10 | service: null,
11 | initialize () {
12 | this.serviceName = _.get(config, 'context.service')
13 | if (!_.isEmpty(this.serviceName)) {
14 | // initialize the store
15 | Store.set('context', null)
16 | logger.debug(`[KDK] Context configured with service '${this.serviceName}'`)
17 | }
18 | },
19 | get () {
20 | return Store.get('context')
21 | },
22 | getId () {
23 | return _.get(this.get(), '_id')
24 | },
25 | getRef () {
26 | return Store.getRef('context')
27 | },
28 | getService () {
29 | if (_.isEmpty(this.serviceName)) throw new Error('[KDK] Context service undefined !')
30 | if (this.service) return this.service
31 | this.service = api.getService(this.serviceName)
32 | if (_.isNil(this.service)) throw new Error('[KDK] Context service not found !')
33 | return this.service
34 | },
35 | set (context) {
36 | Store.set('context', context)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/client/directives/index.js:
--------------------------------------------------------------------------------
1 | export * from './v-drop-file.js'
2 | export * from './v-hover.js'
--------------------------------------------------------------------------------
/core/client/directives/v-hover.js:
--------------------------------------------------------------------------------
1 | import { Platform } from '../platform.js'
2 |
3 | export const vHover = {
4 |
5 | mounted (el, binding) {
6 | if (Platform.touch) return
7 | el.__vHoverEnter__ = binding.value.enter || (() => {})
8 | el.__vHoverOver__ = binding.value.over || (() => {})
9 | el.__vHoverLeave__ = binding.value.leave || (() => {})
10 |
11 | // Add Event Listeners
12 | el.addEventListener('mouseenter', el.__vHoverEnter__)
13 | el.addEventListener('mouseover', el.__vHoverOver__)
14 | el.addEventListener('mouseleave', el.__vHoverLeave__)
15 | },
16 |
17 | beforeUnmount (el, binding) {
18 | // Remove Event Listeners
19 | el.removeEventListener('mouseenter', el.__vHoverEnter__)
20 | el.removeEventListener('mouseover', el.__vHoverOver__)
21 | el.removeEventListener('mouseleave', el.__vHoverLeave__)
22 | delete el.__vHoverEnter__
23 | delete el.__vHoverOver__
24 | delete el.__vHoverLeave__
25 | }
26 | }
--------------------------------------------------------------------------------
/core/client/events.js:
--------------------------------------------------------------------------------
1 | import { EventBus } from 'quasar'
2 |
3 | export const Events = new EventBus()
4 |
--------------------------------------------------------------------------------
/core/client/hooks/hooks.events.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { Events } from '../events.js'
3 |
4 | export function emit (hook) {
5 | if (_.get(hook, `params.skip-${hook.type}-event`)) return
6 | Events.emit(hook.type + '-hook', hook)
7 | }
8 |
--------------------------------------------------------------------------------
/core/client/hooks/hooks.logger.js:
--------------------------------------------------------------------------------
1 | // A hook that logs service method before, after and error
2 | import logger from 'loglevel'
3 |
4 | export function log (hook) {
5 | let message = `[KDK] ${hook.type}: ${hook.path} - Method: ${hook.method}`
6 |
7 | if (hook.type === 'error') {
8 | message += `: ${hook.error.message}`
9 | }
10 |
11 | logger.debug(message)
12 | if (hook.error) {
13 | logger.error(hook.error)
14 | }
15 | if (hook.data) {
16 | logger.trace(hook.data)
17 | }
18 | if (hook.params) {
19 | logger.trace(hook.params)
20 | }
21 | if (hook.result) {
22 | logger.trace(hook.result)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/core/client/hooks/hooks.users.js:
--------------------------------------------------------------------------------
1 | export async function checkUnique (hook) {
2 | const accountService = hook.app.getService('account')
3 | try {
4 | await accountService.create({
5 | action: 'checkUnique',
6 | value: { email: hook.data.email }
7 | }, {
8 | // As we manage error we make this call transparent from the client perspective
9 | // This will avoid displaying an error message twice
10 | 'skip-before-event': true,
11 | 'skip-after-event': true,
12 | 'skip-error-event': true
13 | })
14 | } catch (error) {
15 | // BadRequest is thrown when the user already exists, use a more specific message in this case
16 | if (error.code === 400) {
17 | error.data.translation = { key: 'EMAIL_ALREADY_TAKEN' }
18 | }
19 | throw error
20 | }
21 | return hook
22 | }
23 |
--------------------------------------------------------------------------------
/core/client/hooks/index.js:
--------------------------------------------------------------------------------
1 | export * from './hooks.events.js'
2 | export * from './hooks.logger.js'
3 | export * from './hooks.offline.js'
4 | export * from './hooks.users.js'
5 |
--------------------------------------------------------------------------------
/core/client/local-storage.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import logger from 'loglevel'
3 | import config from 'config'
4 |
5 | export const LocalStorage = {
6 | initialize () {
7 | this.prefix = _.get(config, 'appSlug', _.kebabCase(_.get(config, 'appName', 'kdk')))
8 | logger.debug(`[KDK] LocalStorage initialized with prefix: '${this.prefix}'`)
9 | },
10 | localKey (key) {
11 | const keyPrefix = `${this.prefix}-`
12 | if (_.startsWith(keyPrefix)) return key
13 | return `${keyPrefix}${key}`
14 | },
15 | set (key, value) {
16 | const jsonValue = JSON.stringify(value)
17 | window.localStorage.setItem(this.localKey(key), jsonValue)
18 | },
19 | has (key) {
20 | const value = window.localStorage.getItem(this.localKey(key))
21 | return !_.isNil(value)
22 | },
23 | get (key, defaultValue) {
24 | const value = window.localStorage.getItem(this.localKey(key))
25 | if (_.isNil(value)) {
26 | logger.debug(`[KDK] Cannot find local storage value with key '${key}'. Returning default value '${defaultValue}'`)
27 | return defaultValue
28 | }
29 | return JSON.parse(value)
30 | },
31 | clear (key) {
32 | window.localStorage.removeItem(this.localKey(key))
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/client/mixins/index.js:
--------------------------------------------------------------------------------
1 | export * from './mixin.base-activity.js'
2 | export * from './mixin.base-editor.js'
3 | export * from './mixin.base-item.js'
4 | export * from './mixin.base-field.js'
5 | export * from './mixin.base-viewer.js'
6 | export * from './mixin.base-modal.js'
7 | export * from './mixin.object-proxy.js'
8 | export * from './mixin.schema-proxy.js'
9 | export * from './mixin.service.js'
10 |
--------------------------------------------------------------------------------
/core/client/mixins/mixin.base-modal.js:
--------------------------------------------------------------------------------
1 | export const baseModal = {
2 | emits: ['opened', 'closed'],
3 | props: {
4 | routerMode: {
5 | type: Boolean,
6 | default: true
7 | }
8 | },
9 | data () {
10 | return {
11 | isModalOpened: false,
12 | isModalMaximized: false
13 | }
14 | },
15 | methods: {
16 | openModal (maximized = false) {
17 | // Can be overloaded if needed
18 | this.isModalMaximized = maximized
19 | this.isModalOpened = true
20 | this.$emit('opened')
21 | },
22 | closeModal () {
23 | this.isModalOpened = false
24 | if (this.routerMode) {
25 | this.$router.push(this.previousRoute)
26 | }
27 | this.$emit('closed')
28 | }
29 | },
30 | created () {
31 | if (this.routerMode) {
32 | this.previousRoute = this.$router.options.history.state.back
33 | this.openModal()
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/client/mixins/mixin.base-viewer.js:
--------------------------------------------------------------------------------
1 | export const baseViewer = {
2 | props: {
3 | perspective: {
4 | type: String,
5 | default: ''
6 | },
7 | clearButton: {
8 | type: String,
9 | default: ''
10 | },
11 | resetButton: {
12 | type: String,
13 | default: ''
14 | }
15 | },
16 | computed: {
17 | viewerTitle () {
18 | // Retuns the schema title
19 | if (this.getSchema()) {
20 | const schemaTitle = this.getSchema().title
21 | return this.$t(schemaTitle, { object: this.getObject() })
22 | }
23 | return ''
24 | }
25 | },
26 | methods: {
27 | getSchemaName () {
28 | // When used with a service by default use the same name for schema as for service
29 | let schemaName = this.service + '.get'
30 | if (this.perspective) {
31 | schemaName += ('-' + this.perspective)
32 | }
33 | return schemaName
34 | },
35 | async refresh () {
36 | // We can then load the schema/object and local refs in parallel
37 | await Promise.all([
38 | this.loadSchema(this.getSchemaName()),
39 | this.loadObject()
40 | ])
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/core/client/mixins/mixin.object-proxy.js:
--------------------------------------------------------------------------------
1 | import { createQuerablePromise } from '../utils/index.js'
2 |
3 | export const objectProxy = {
4 | props: {
5 | objectId: {
6 | type: String,
7 | default: ''
8 | }
9 | },
10 | data () {
11 | return {
12 | object: null
13 | }
14 | },
15 | methods: {
16 | getObject () {
17 | return this.object
18 | },
19 | getObjectId () {
20 | return this.object ? this.object._id : ''
21 | },
22 | loadObject () {
23 | if (!this.objectId) {
24 | this.object = null
25 | return Promise.resolve(null)
26 | }
27 | // Create a new mixin promise if required
28 | const objectChanged = (this.getObjectId() !== this.objectId)
29 | if (!this.objectPromise || objectChanged) {
30 | this.objectPromise = createQuerablePromise((resolve, reject) => {
31 | this.getService()
32 | .get(this.objectId)
33 | .then(object => {
34 | this.object = object
35 | resolve(object)
36 | })
37 | .catch(error => {
38 | reject(error)
39 | })
40 | })
41 | }
42 | return this.objectPromise
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/core/client/mixins/mixin.service.js:
--------------------------------------------------------------------------------
1 | export const service = {
2 | props: {
3 | service: {
4 | type: String,
5 | default: ''
6 | }
7 | },
8 |
9 | methods: {
10 | getService () {
11 | const service = this.$api.getService(this.service)
12 | if (!service) {
13 | throw new Error('Cannot retrieve target service ' + this.service)
14 | }
15 | return service
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/client/readers/index.js:
--------------------------------------------------------------------------------
1 | export * from './reader.json.js'
2 | export * from './reader.csv.js'
3 | export * from './reader.blob.js'
4 |
--------------------------------------------------------------------------------
/core/client/readers/reader.blob.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import logger from 'loglevel'
3 | import { i18n } from '../i18n.js'
4 |
5 | export const BLOBReader = {
6 | read (files, options) {
7 | if (files.length !== 1) {
8 | logger.debug('[KDK] invalid \'files\' arguments')
9 | return
10 | }
11 | const file = files[0]
12 | logger.debug(`[KDK] reading Blob file ${file.name}`)
13 | return new Promise((resolve, reject) => {
14 | const reader = new FileReader()
15 | reader.onloadend = () => {
16 | const content = reader.result
17 | if (!content) {
18 | reject(new Error(i18n.t('errors.INVALID_BLOB_FILE', { file: file.name })))
19 | return
20 | }
21 | resolve(content)
22 | }
23 | reader.onerror = (error) => {
24 | logger.debug(error)
25 | reject(new Error(i18n.t('errors.CANNOT_READ_FILE', { file: file.name }), { errors: error }))
26 | }
27 | const expectedType = _.get(options, 'type', 'arrayBuffer')
28 | if (expectedType === 'dataUrl') {
29 | reader.readAsDataURL(file)
30 | } else {
31 | if (expectedType !== 'arrayBuffer') logger.error(`[KDK] Undefined expected type ${expectedType}. Read as Array buffer.`)
32 | reader.readAsArrayBuffer(file)
33 | }
34 | })
35 | },
36 | getAdditionalFiles () {
37 | return []
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/core/client/readers/reader.csv.js:
--------------------------------------------------------------------------------
1 | import logger from 'loglevel'
2 | import Papa from 'papaparse'
3 | import { i18n } from '../i18n.js'
4 |
5 | export const CSVReader = {
6 | read (files, options) {
7 | if (files.length !== 1) {
8 | logger.debug('[KDK] invalid \'files\' arguments')
9 | return
10 | }
11 | const file = files[0]
12 | logger.debug(`[KDK] reading CSV file ${file.name}`)
13 | return new Promise((resolve, reject) => {
14 | const reader = new FileReader()
15 | reader.onloadend = () => {
16 | let content = reader.result
17 | const papaParseOptions = Object.assign({ skipEmptyLines: true }, options)
18 | content = Papa.parse(content, papaParseOptions)
19 | if (content.errors.length > 0) {
20 | logger.debug(content.errors)
21 | reject(new Error(i18n.t('errors.INVALID_CSV_FILE', { file: file.name }), { errors: content.errors }))
22 | return
23 | }
24 | resolve(content.data)
25 | }
26 | reader.onerror = (error) => {
27 | logger.debug(error)
28 | reject(new Error(i18n.t('errors.CANNOT_READ_FILE', { file: file.name }), { errors: error }))
29 | }
30 | reader.readAsText(file)
31 | })
32 | },
33 | getAdditionalFiles () {
34 | return []
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/client/readers/reader.json.js:
--------------------------------------------------------------------------------
1 | import logger from 'loglevel'
2 | import { i18n } from '../i18n.js'
3 |
4 | export const JSONReader = {
5 | read (files, options) {
6 | if (files.length !== 1) {
7 | logger.debug('[KDK] invalid \'files\' arguments')
8 | return
9 | }
10 | const file = files[0]
11 | logger.debug(`[KDK] reading JSON file ${file.name}`)
12 | return new Promise((resolve, reject) => {
13 | const reader = new FileReader()
14 | reader.onloadend = () => {
15 | let content = reader.result
16 | try {
17 | content = JSON.parse(content)
18 | } catch (error) {
19 | logger.debug(error)
20 | reject(new Error(i18n.t('errors.INVALID_JSON_FILE', { file }), { errors: error }))
21 | }
22 | resolve(content)
23 | }
24 | reader.onerror = (error) => {
25 | logger.debug(error)
26 | reject(new Error(i18n.t('errors.CANNOT_READ_FILE', { file }), { errors: error }))
27 | }
28 | reader.readAsText(file)
29 | })
30 | },
31 | getAdditionalFiles () {
32 | return []
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/client/sorter.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { Events } from './events.js'
3 | import { Store } from './store.js'
4 |
5 | // Export singleton
6 | export const Sorter = {
7 | initialize () {
8 | // This object is used to sort collections
9 | Store.set('sorter', { field: 'name', order: '1', query: {} })
10 | // Make filter react to external changes to update the query
11 | Events.on('sorter-changed', () => this.updateSorterQuery())
12 | },
13 | get () {
14 | return Store.get('sorter')
15 | },
16 | getField () {
17 | return this.get().field
18 | },
19 | getOrder () {
20 | return this.get().order
21 | },
22 | getQuery () {
23 | return Store.get('sorter.query')
24 | },
25 | // Build sort query
26 | updateSorterQuery () {
27 | const query = { $sort: { [this.getField()]: this.getOrder() } }
28 | // Avoid reentrance as we listen to other filter property changes
29 | if (!_.isEqual(query, this.getQuery())) Store.patch('sorter', { query })
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/client/store.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { toRef } from 'vue'
3 | import { useStore } from './composables/store.js'
4 | import { Events } from './events.js'
5 |
6 | const { store, set, get, unset, has } = useStore('store')
7 |
8 | // Export singleton
9 | export const Store = Object.assign(store, {
10 | get,
11 | has,
12 | // Override write methods to send events
13 | set (path, value) {
14 | const previousValue = get(path)
15 | set(path, value)
16 | const eventName = _.kebabCase(`${path}-changed`)
17 | Events.emit(eventName, value, previousValue)
18 | Events.emit('store-changed', path, value, previousValue)
19 | },
20 | patch (path, value) {
21 | // Patching should not change the object reference to maintain reactivity
22 | const previousValue = get(path)
23 | if (previousValue) {
24 | Object.assign(previousValue, value)
25 | this.set(path, previousValue)
26 | }
27 | },
28 | unset (path) {
29 | unset(path)
30 | const eventName = _.kebabCase(`${path}-changed`)
31 | Events.emit(eventName, undefined)
32 | },
33 | getRef (path) {
34 | const index = path.lastIndexOf('.')
35 | const key = path.substring(index + 1)
36 | const object = (index < 0 ? store : get(path.replace(`.${key}`, '')))
37 | return toRef(object, key)
38 | }
39 | })
40 |
--------------------------------------------------------------------------------
/core/client/template-context.js:
--------------------------------------------------------------------------------
1 | import { useStore } from './composables/store.js'
2 | import { Events } from './events.js'
3 |
4 | const { store, set, get, unset, has } = useStore('template-context')
5 |
6 | // This is a singleton used to inject data in string template evaluation contexts (lodash)
7 | export const TemplateContext = Object.assign(store, {
8 | get,
9 | has,
10 | unset,
11 | // Override write methods to send events
12 | set (path, value) {
13 | const previousValue = get(path)
14 | set(path, value)
15 | Events.emit('template-context-changed', path, value, previousValue)
16 | }
17 | })
18 |
--------------------------------------------------------------------------------
/core/client/utils/utils.files.js:
--------------------------------------------------------------------------------
1 | import path from 'path-browserify'
2 |
3 | export function getFileName (filePath) {
4 | return path.basename(filePath)
5 | }
6 |
7 | export function getExtension (filePath) {
8 | return path.extname(filePath)
9 | }
10 |
11 | export function getBaseName (filePath) {
12 | return path.basename(filePath, getExtension(filePath))
13 | }
14 |
15 | export function getDir (filePath) {
16 | return path.dirname(filePath)
17 | }
18 |
--------------------------------------------------------------------------------
/core/client/utils/utils.items.js:
--------------------------------------------------------------------------------
1 | export const CardSectionProps = {
2 | title: {
3 | type: String,
4 | default: ''
5 | },
6 | item: {
7 | type: Object,
8 | default: () => null
9 | },
10 | actions: {
11 | type: Array,
12 | default: () => null
13 | },
14 | actionsFilter: {
15 | type: [String, Array],
16 | default: () => null
17 | },
18 | hideSeparator: {
19 | type: Boolean,
20 | default: false
21 | },
22 | hideHeader: {
23 | type: Boolean,
24 | default: false
25 | },
26 | dense: {
27 | type: Boolean,
28 | default: false
29 | }
30 | }
--------------------------------------------------------------------------------
/core/client/utils/utils.locale.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import config from 'config'
3 |
4 | export function getBrowserLocale () {
5 | return navigator.language ||
6 | _.get(navigator, 'languages.0') ||
7 | navigator.browserLanguage ||
8 | navigator.userLanguage ||
9 | navigator.systemLanguage
10 | }
11 |
12 | export function getLocale (languageOnly = true) {
13 | const locale = _.get(config, 'locale.default', getBrowserLocale())
14 | if (!languageOnly) return locale
15 | const codes = _.split(locale, '-')
16 | return _.head(codes)
17 | }
18 |
19 | export function getFallbackLocale (languageOnly = true) {
20 | const locale = _.get(config, 'locale.fallbackLocale', 'en-GB')
21 | if (!languageOnly) return locale
22 | const codes = _.split(locale, '-')
23 | return _.head(codes)
24 | }
25 |
--------------------------------------------------------------------------------
/core/client/utils/utils.math.js:
--------------------------------------------------------------------------------
1 | export function clamp (value, min, max) {
2 | return Math.min(Math.max(value, min), max)
3 | }
4 |
5 | export function easeOut (t, linearity = 0.5) {
6 | return 1 - Math.pow(1 - t, 1 / linearity)
7 | }
8 |
9 | export function linear (t, initial = 0, final = 1) {
10 | return initial + t * final
11 | }
12 |
13 | export function cubicBezier (t, x1 = 0.42, y1 = 0, x2 = 0.58, y2 = 1) {
14 | return (
15 | (1 - t) * (1 - t) * (1 - t) * y1 +
16 | 3 * (1 - t) * (1 - t) * t * x1 +
17 | 3 * (1 - t) * t * t * x2 +
18 | t * t * t * y2
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/core/client/utils/utils.time.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment'
2 | import { Time } from '../time.js'
3 |
4 | // Add UTC offset to timezone name
5 | export function getTimezoneLabel (timezone) {
6 | const offset = moment().tz(timezone).format('Z')
7 | return `${timezone} (${offset})`
8 | }
9 |
10 | // Convert to local time with timezone offset
11 | // datetime must be expressed as an ISOString
12 | export function toLocalTimezone (datetime, timezone) {
13 | return timezone ? moment.tz(datetime, timezone) : moment(datetime).local()
14 | }
15 |
16 | // Convert from moment date/time to quasar format in local time zone
17 | export function toQuasarDate (date, format) {
18 | return Time.convertToLocal(date).format(format)
19 | }
20 |
21 | export function toQuasarTime (time, format) {
22 | return Time.convertToLocal(time).format(format)
23 | }
24 |
25 | // Convert from quasar format in local time zone to moment date/time
26 | export function fromQuasarDate (date, format) {
27 | return (Time.getFormatTimezone()
28 | ? moment.tz(date, format, Time.getFormatTimezone())
29 | : moment(date, format))
30 | }
31 |
32 | export function fromQuasarTime (time, format) {
33 | return (Time.getFormatTimezone()
34 | ? moment.tz(time, format, Time.getFormatTimezone())
35 | : moment(time, format))
36 | }
--------------------------------------------------------------------------------
/core/common/errors.js:
--------------------------------------------------------------------------------
1 | export class KError extends Error {}
2 |
--------------------------------------------------------------------------------
/core/common/index.js:
--------------------------------------------------------------------------------
1 | // We faced a bug in babel so that transform-runtime with export * from 'x' generates import statements in transpiled code
2 | // Tracked here : https://github.com/babel/babel/issues/2877
3 | // We tested the workaround given here https://github.com/babel/babel/issues/2877#issuecomment-270700000 with success so far
4 | import * as errors from './errors.js'
5 | import * as permissions from './permissions.js'
6 |
7 | export { errors }
8 | export { permissions }
9 | export * from './schema.js'
10 | export * from './utils.js'
11 |
--------------------------------------------------------------------------------
/core/common/schema.js:
--------------------------------------------------------------------------------
1 | import Ajv from 'ajv'
2 | import addFormats from 'ajv-formats'
3 | import addKeywords from 'ajv-keywords'
4 |
5 | const defaultOptions = {
6 | allErrors: true,
7 | strict: false,
8 | $data: true,
9 | keywords: ['field']
10 | }
11 |
12 | export const Schema = {
13 | initialize (options) {
14 | this.ajv = new Ajv(options || defaultOptions)
15 | addKeywords(this.ajv)
16 | addFormats(this.ajv)
17 | },
18 | register (schema) {
19 | if (!this.ajv) throw new Error('Schema must be initialized first')
20 | if (!schema.$id) throw new Error('the schema must have an `$id` property')
21 | return this.ajv.getSchema(schema.$id) || this.ajv.compile(schema)
22 | },
23 | addKeyword (keyword) {
24 | if (!this.ajv) throw new Error('Schema must be initialized first')
25 | this.ajv.addKeyword(keyword)
26 | },
27 | getKeyword (keyword) {
28 | if (!this.ajv) throw new Error('Schema must be initialized first')
29 | return this.ajv.getKeyword(keyword)
30 | },
31 | removeKeyword (keyword) {
32 | if (!this.ajv) throw new Error('Schema must be initialized first')
33 | this.ajv.removeKeyword(keyword)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/core/common/schemas/messages.update.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-07/schema#",
3 | "$id": "/schemas/messages.edit.json",
4 | "description": "Messages edition schema",
5 | "type": "object",
6 | "properties": {
7 | "body": {
8 | "type": "string",
9 | "minLength": 1,
10 | "field": {
11 | "component": "form/KTextareaField"
12 | }
13 | }
14 | },
15 | "required": ["body"]
16 | }
17 |
--------------------------------------------------------------------------------
/core/common/schemas/users.update-profile.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-07/schema#",
3 | "$id": "http://kalisio.xyz/schemas/users.update-profile.json#",
4 | "title": "schemas.OBJECT_NAME",
5 | "description": "User profile",
6 | "type": "object",
7 | "properties": {
8 | "name": {
9 | "type": "string",
10 | "maxLength": 128,
11 | "minLength": 3,
12 | "field": {
13 | "component": "form/KTextField",
14 | "label": "schemas.NAME_FIELD_LABEL"
15 | }
16 | },
17 | "avatar": {
18 | "type": "object",
19 | "field": {
20 | "component": "form/KFileField",
21 | "label": "schemas.AVATAR_FIELD_LABEL",
22 | "mimeTypes": ".png,.jpg,.jpeg,.webp",
23 | "maxSize": 524288,
24 | "readContent": false,
25 | "storage": {
26 | "path": "avatars/<%= _id %>"
27 | }
28 | }
29 | }
30 | },
31 | "required": ["name"]
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/PWA-client-server-sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/PWA-client-server-sync.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/PWA-offline-client.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/PWA-offline-client.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/PWA-online-client-caching.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/PWA-online-client-caching.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/PWA-online-client.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/PWA-online-client.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/PWA-server-server-sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/PWA-server-server-sync.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/aggregated-feature-data-model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/aggregated-feature-data-model.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/airtac-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/airtac-list.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/aktnmap-layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/aktnmap-layout.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/aktnmap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/aktnmap.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/alert-data-model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/alert-data-model.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/animated-wall.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/animated-wall.gif
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/attributionClosed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/attributionClosed.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/attributionOpened.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/attributionOpened.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/catalog-data-model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/catalog-data-model.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/component-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/component-view.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/desaturate-post-process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/desaturate-post-process.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/editor-lifecycle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/editor-lifecycle.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/feathers-services.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/feathers-services.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/feature-data-model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/feature-data-model.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/gradient-path.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/gradient-path.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/great-circle-2D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/great-circle-2D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/great-circle-3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/great-circle-3D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/item-collections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/item-collections.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kalisio-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kalisio-banner.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-3D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-components.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-components.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-iframe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-iframe.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-layout-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-layout-1.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-layout-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-layout-2.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-style-2D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-style-2D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-style-3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-style-3D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kano-weather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kano-weather.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/kdk-workspace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/kdk-workspace.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/layers-panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/layers-panel.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/line-gradient-2D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/line-gradient-2D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/line-offset-2D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/line-offset-2D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/marker-cluster-2D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/marker-cluster-2D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/marker-cluster-3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/marker-cluster-3D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/operations-methods-events.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/operations-methods-events.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/timeseries.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/timeseries.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/images/wall-3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/.vitepress/public/images/wall-3D.png
--------------------------------------------------------------------------------
/docs/.vitepress/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Kalisio Develoment Kit",
3 | "short_name": "KDK",
4 | "icons": [
5 | {
6 | "src": "https://s3.eu-central-1.amazonaws.com/kalisioscope/kdk/kdk-logo-black-128x128.png",
7 | "sizes": "128x128",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "https://s3.eu-central-1.amazonaws.com/kalisioscope/kdk/kdk-logo-black-192x192.png",
12 | "sizes": "192x192",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "https://s3.eu-central-1.amazonaws.com/kalisioscope/kdk/kdk-logo-black-512x512.png",
17 | "sizes": "512x512",
18 | "type": "image/png"
19 | }
20 | ],
21 | "start_url": "/index.html",
22 | "display": "standalone"
23 | }
--------------------------------------------------------------------------------
/docs/.vitepress/public/theme.drawio:
--------------------------------------------------------------------------------
1 | zZhdb5swFIZ/DZeR+AqUyzVpu4t1nRQp3a4mBxuwamxiTCD59TPBBjI6rVPnkggJ5z32wT7POTaJ5a3y5oGDIntkEBHLtWFjeWvLdR37JpC3Vjl2ShQoIeUYqk6DsMEnpEcqtcIQlRcdBWNE4OJSjBmlKBYXGuCc1ZfdEkYun1qAFE2ETQzIVH3GUGSdeuOGg/4Z4TTTT3aCqLPkQHdWKykzAFk9krw7y1txxkTXypsVIm3wdFy6cfd/sPYT44iKtwzYbsH+8Vgtw/DwZb0+QfpcbxfKywGQSi3YcgMi/d0mTLqVsxZHFYpgXzFtWJRnUJ9kB8cvmsEoW2l7LzjOAT9qZ3JWnb/OqgLSu3Y5qyhE7UQdaa4zLNCmAHFrrWVeSS0TOVHm1tOKEcbPY73k/Gl1TMhIt3eBvKReCs5ekLZQRlE/hXH0dCgQF6gZSSqaD4jlSLRLsrV1qciq1O5J10OiODqPs1GS6HFA5Wbaux7wyYYi+A80XUM0SyTLC34QT/s2kNeUZ+zBJNkZ5OlG18bTM8QTxDE605uvOJMwSWyDMH3v2mD6hmDKunyZFWXo2yEwiHIZzoiS/fiZbBbfxOnp6fv+64GTAJvbZzFN2LVX5YTbK3TffmRGc6M0tcUWrMQCH9CcOMPdLvL/8gb0LpyTE3N2nKY2WYpS8OE4X8X2+1tR6AMf/B+ckzNzdpxLQzhrwCmm6ZzFCe0o8hyDxTk5Ng3SlF+HH7Jn2+jvAO/uFw==
--------------------------------------------------------------------------------
/docs/.vitepress/theme/custom.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --vp-c-brand-1: #3aa7ca;
3 | --vp-c-brand-2: rgb(58, 167, 202, .75);
4 | --vp-c-brand-3: #3aa7ca;
5 | }
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.js:
--------------------------------------------------------------------------------
1 | import theme from 'vitepress-theme-kalisio'
2 | import './custom.css'
3 | export default theme
--------------------------------------------------------------------------------
/docs/about/contact.md:
--------------------------------------------------------------------------------
1 | # Contact
2 |
3 | Please feel free to join our [slack channel](https://kalisio.slack.com/) using the [invitation link](https://join.slack.com/t/kalisio/shared_invite/zt-mfyu6evk-ehKFK7wSle4lX9imk5huew).
--------------------------------------------------------------------------------
/docs/about/introduction.md:
--------------------------------------------------------------------------------
1 | # About
2 |
3 | The **Kalisio Development Kit** (**KDK**) aims to simplify the development of geospatial web applications running on desktop or mobile devices. It is a strongly opiniated stack initially developed to build multitenancy applications provided as SaaS (i.e. Cloud) like [Kalisio Crisis](https://crisis.kalisio.com). However, you can also build legacy applications because of the modularity and the flexibility of the KDK.
4 |
5 | 
6 |
7 | Our objective is to propose a microservice based platform. Each building block has the responsibility to deliver specific and limited functionalities. Such an architectural approach plays a key role in helping us face the challenge of maintaining several mature products that need scalability within multiple contexts in terms of processing, storage, and features delivery.
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/about/license.md:
--------------------------------------------------------------------------------
1 | # License
2 |
3 | MIT License
4 |
5 | Copyright (c) 2017-20xx Kalisio
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/docs/about/roadmap.md:
--------------------------------------------------------------------------------
1 | # Roadmap
2 |
3 | The roadmap is available on [Github](https://github.com/kalisio/kdk/projects/1).
4 |
5 | ## Release Notes
6 |
7 | Release Notes for each modules are available on Github:
8 |
9 | The changelogs are available on [Github](https://github.com/kalisio/kdk/blob/master/CHANGELOG.md)
10 |
11 |
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kcard-expanded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kcard-expanded.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kcard-header-footer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kcard-header-footer.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kcard-heading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kcard-heading.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kcard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kcard.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kcardsection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kcardsection.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kgrid-header-footer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kgrid-header-footer.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kgrid-infinite-scroll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kgrid-infinite-scroll.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kgrid-layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kgrid-layout.png
--------------------------------------------------------------------------------
/docs/api/core/components/diagrams/kgrid-pagination.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/docs/api/core/components/diagrams/kgrid-pagination.png
--------------------------------------------------------------------------------
/docs/api/core/components/graphics.md:
--------------------------------------------------------------------------------
1 | # Graphics
2 |
3 | The `graphics` folder contains reusable components for rendering a variety of graphical elements.
4 |
5 | ## `KIcon`
6 |
7 | The `KIcon` component is a wrapper around [Quasar's Icon](https://quasar.dev/vue-components/icon/) that enables displaying a primary icon with an optional stacked overlay icon. This is useful for creating composite or symbolic icons by layering one icon on top of another. Moreover, and unlike **Quasar**'s built-in **QIcon**, `KIcon` supports any valid HTML color definition.
8 |
9 | ### Props
10 |
11 | | Prop | Type | Default | Description |
12 | | ------ | ------------------ | ----------- | --------------------------------------------------------------------------------- |
13 | | `icon` | `String \| Object` | `undefined` | Main icon name (as string) or an object describing the main icon and its overlay. |
14 |
15 | ### Usage
16 |
17 | * An icon using a name:
18 |
19 | ```html
20 |
21 | ```
22 | * And the same icon with a red slash through it:
23 |
24 | ```html
25 |
35 | ```
--------------------------------------------------------------------------------
/docs/api/core/directives.md:
--------------------------------------------------------------------------------
1 | # Directives
2 |
3 | ::: tip
4 | The **Directives** provided by the **KDK** must be registered by each application within the corresponding `kdk.js` [boot file](https://quasar.dev/quasar-cli-vite/boot-files#anatomy-of-a-boot-file). For instance:
5 |
6 | ```js
7 | // Register global directives
8 | app.directive('hover', kdkCoreDirectives.vHover)
9 | ```
10 | :::
11 |
12 | ## v-hover
13 |
14 | `v-hover` is a lightweight directive that allows you to react when an element either becomes hovered or unhovered.
15 |
16 | Here is an example of use:
17 |
18 | ```html
19 |
20 | ....
21 |
22 |
23 |
38 | ```
39 |
--------------------------------------------------------------------------------
/docs/api/core/introduction.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | ## API
4 |
5 | * [Application](./application.md)
6 | * [Services](./services.md)
7 | * [Hooks](./hooks.md)
8 |
9 | ## Client
10 |
11 | * [Utilities](./utilities.md)
12 | * [Directives](./directives.md)
13 | * [Mixins](./mixins.md)
14 | * [Composables](./composables.md)
15 | * [Components](./components.md)
16 |
--------------------------------------------------------------------------------
/docs/api/core/utilities/utils.locale.md:
--------------------------------------------------------------------------------
1 | # Locale
2 |
3 | ## Overview
4 |
5 | The `utils.locale.js` module provide functions to retrieve locale application settings.
6 |
7 | ## Functions
8 |
9 | ### `getBrowserLocale()`
10 |
11 | Returns the user's browser locale using several possible sources.
12 |
13 | - **Returns:**
14 | - *(string)* — A locale string in the `language-region` format (e.g., `en-US`, `fr-FR`).
15 |
16 | ### `getLocale(languageOnly = true)`
17 |
18 | Retrieves the application's default locale from configuration, falling back to the browser locale if not specified.
19 |
20 | - **Parameters:**
21 | - `languageOnly` *(`boolean`, default: `true`)*: If `true`, returns only the language part of the locale (e.g., `en` from `en-GB`).
22 |
23 | - **Returns:**
24 | - *(string)* — The configured or detected locale string, either full (`en-GB`) or just the language (`en`).
25 |
26 | ### `getFallbackLocale(languageOnly = true)`
27 |
28 | Retrieves the fallback locale defined in the configuration, with an option to extract just the language portion.
29 |
30 | - **Parameters:**
31 | - `languageOnly` *(`boolean`, default: `true`)*: If `true`, returns only the language part of the fallback locale.
32 |
33 | - **Returns:**
34 | - *(string)* — The fallback locale, either full (`en-GB`) or just the language (`en`).
35 |
36 |
--------------------------------------------------------------------------------
/docs/architecture/component-view.md:
--------------------------------------------------------------------------------
1 | # Component view
2 |
3 | The typical components and the underlying dependencies of **KDK** are summarized in the following diagram.
4 |
5 | 
--------------------------------------------------------------------------------
/docs/architecture/introduction.md:
--------------------------------------------------------------------------------
1 | # Architecture
2 |
3 | Before jumping to the [global architecture view](./global-architecture.md) we recommend to read about the [main concepts](./main-concepts.md) of **KDK**.
4 |
5 | You can then have a look to the:
6 | 1. [component-oriented view](./component-view.md)
7 | 2. [data model-oriented view](./data-model-view.md)
8 |
--------------------------------------------------------------------------------
/docs/guides/development/configure.md:
--------------------------------------------------------------------------------
1 | # Configure your app
2 |
3 | Please follow our [application template configuration guide](https://kalisio.github.io/skeleton/guides/development/configure.html).
4 |
--------------------------------------------------------------------------------
/docs/guides/development/deploy.md:
--------------------------------------------------------------------------------
1 | # Deploy your app
2 |
3 | Please follow our [application template deployment guide](https://kalisio.github.io/skeleton/guides/development/deploy.html).
4 |
--------------------------------------------------------------------------------
/docs/guides/development/develop.md:
--------------------------------------------------------------------------------
1 | # Develop with KDK
2 |
3 | KDK and third-party Kalisio modules are [Feathers modules](https://docs.feathersjs.com), so you will find most of the required information in the linked Feathers documentation. Typically for development you will do the following so that a module is ready-to-use:
4 | ```bash
5 | cd kdk
6 | yarn install
7 | yarn link
8 | ```
9 |
10 | ## Linting the code
11 |
12 | The **KDK** relies on [JavaScript standard style](https://github.com/feross/standard).
13 |
14 | To lint the code:
15 |
16 | ```bash
17 | $yarn lint
18 | ```
19 |
20 | You can also lint each of the submodules independently using the following commands:
21 |
22 | ```bash
23 | $yarn lint:core # lint the core part
24 | $yarn lint:map # lint the map part
25 | ```
26 | :::
27 |
28 | ## Web app
29 |
30 | Please follow our [application template development guide](https://kalisio.github.io/skeleton/guides/development/develop.html).
31 |
--------------------------------------------------------------------------------
/docs/guides/development/test.md:
--------------------------------------------------------------------------------
1 | # Testing with KDK
2 |
3 | The **KDK** relies on the [Mocha](https://mochajs.org/) testing framework and the [Chai](https://www.chaijs.com/) assertion library.
4 |
5 | KDK and third-party Kalisio modules are [Feathers modules](https://docs.feathersjs.com/guides/basics/testing.html), so you will find most of the required information in the linked Feathers documentation.
6 |
7 | To run the module tests including linting and coverage : `$ yarn test`
8 |
9 | To speed-up things simply run the tests with: `$ yarn mocha`
10 |
11 | You can run the tests of each submodule independently using the following commands for the KDK:
12 |
13 | ```bash
14 | $yarn mocha:core # test the core module
15 | $yarn mocha:map # test the map module
16 | ```
17 |
18 | :::tip
19 | If you need to perform some specific tests, you can use the `-g` or `--grep` option of the `mocha` command:
20 |
21 | ```bash
22 | $yarn mocha:core -g "core:team" # run the team tests
23 | ```
24 | :::
25 |
26 | ## Web app
27 |
28 | Please follow our [application template testing guide](https://kalisio.github.io/skeleton/guides/development/test.html).
29 |
--------------------------------------------------------------------------------
/docs/guides/introduction.md:
--------------------------------------------------------------------------------
1 | # Guides
2 |
3 | ## The Basics
4 |
5 | The goal of this guide is to get you to the "A-ha!" moment as efficiently as possible. You will learn more about the underlying technological stack and how to deploy your first KDK app.
6 |
7 | * [A Step-by-Step introduction to KDK](./basics/introduction.md)
8 |
9 | ## Development
10 |
11 | In these guides you will learn step-by-step how the setup your development environment. You'll also learn how to create, develop and publish your own app and modules, which is also how we develop the KDK.
12 |
13 | * [Setup your environment](./development/setup.md)
14 | * [Develop with KDK](./development/develop.md)
15 | * [Test with KDK](./development/test.md)
16 | * [Publish with KDK](./development/publish.md)
17 | * [Configure your app](./development/configure.md)
18 | * [Deploy your app](./development/deploy.md)
19 |
20 | ## Migration
21 |
22 | In this guides you will find an overview of the most important new features or breaking changes for each KDK version.
23 |
24 | * [v2.5](./migration/v2.5.md) with related [milestone](https://github.com/kalisio/kdk/milestone/13) on GitHub.
25 | * [v2.6](./migration/v2.6.md) with related [milestone](https://github.com/kalisio/kdk/milestone/14) on GitHub.
26 |
--------------------------------------------------------------------------------
/docs/guides/migration/v2.6.md:
--------------------------------------------------------------------------------
1 | # v2.6 - Not yet released
2 |
3 | More details can be found in the related [milestone](https://github.com/kalisio/kdk/milestone/14) on GitHub.
4 |
5 | ## Major breaking changes
6 |
7 | 💥 Renamed functions in `utils.locale.js` to resolve confusion between `getLocale` and `getAppLocale`, which previously led to inconsistent behavior and locale-related issues.
8 | * Renamed `getLocale` to `getBrowserLocale`
9 | * Renamed `getAppLocale` to `getLocale`.
10 | * Renamed `getAppFallbackLocale` to `getFallbackLocale`
11 |
12 | ::: tip
13 | Both `getLocale`and `getFallbackLocale` have a new signature and allows you to retrieve the full locale in the language-region format (e.g., en-GB). For instance, if the locale is `en-GB`, then
14 | ```
15 | console.log(getLocale())
16 | // => en
17 | console.log(getLocale(false))
18 | // => en-GB
19 | ```
20 | :::
21 |
22 | 💥 Renamed `KLayersSelector` component to `KLayersList` and added new `KLayersSelector` component
23 |
24 | ::: caution
25 | The new `KLayersSelector` component is NOT the old `KLayersSelector` component. They are entirely different components, and `KLayersList` should be now used in place of the old `KLayersSelector` ❗
26 | :::
27 |
28 | ## Major new features
29 |
30 | 👉
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 | hero:
4 | name: KDK
5 | tagline: The Kalisio Development Kit
6 | image:
7 | src: https://s3.eu-central-1.amazonaws.com/kalisioscope/kdk/kdk-icon-color-2048x2048.png
8 | alt: kalisio-kdk
9 | actions:
10 | - theme: brand
11 | text: Learn more about KDK ?
12 | link: /about/introduction
13 | ---
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docs",
3 | "type": "module",
4 | "scripts": {
5 | "dev": "vitepress dev",
6 | "build": "vitepress build",
7 | "preview": "vitepress preview"
8 | },
9 | "devDependencies": {
10 | "keycloak-js": "^23.0.4",
11 | "lodash": "^4.17.21",
12 | "mermaid": "^10.8.0",
13 | "moment": "^2.30.1",
14 | "quasar": "^2.14.3",
15 | "vitepress": "^1.0.0-rc.40",
16 | "vitepress-plugin-mermaid": "^2.0.16",
17 | "vitepress-theme-kalisio": "https://github.com/kalisio/vitepress-theme-kalisio"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/extras/configs/widgets.left.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | LEGEND: {
3 | id: 'legend-widget',
4 | label: 'KLegend.LABEL',
5 | icon: 'las la-atlas',
6 | scrollable: true,
7 | content: { component: 'legend/KLegend' }
8 | },
9 | FEATURES_SELECTION: {
10 | id: 'selection-widget',
11 | label: 'KFeaturesSelection.LABEL',
12 | icon: 'las la-object-group',
13 | scrollable: true,
14 | content: { component: 'selection/KFeaturesSelection' }
15 | },
16 | STYLE_MANAGER: {
17 | id: 'style-manager',
18 | label: 'KStyleManager.TITLE',
19 | icon: 'las la-paint-brush',
20 | scrollable: true,
21 | content: { component: 'styles/KStyleManager' }
22 | }
23 | }
--------------------------------------------------------------------------------
/extras/icons/anticlockwise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/anticlockwise.png
--------------------------------------------------------------------------------
/extras/icons/attribution.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/attribution.png
--------------------------------------------------------------------------------
/extras/icons/clockwise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/clockwise.png
--------------------------------------------------------------------------------
/extras/icons/kanban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/kanban.png
--------------------------------------------------------------------------------
/extras/icons/mapillary-marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/mapillary-marker.png
--------------------------------------------------------------------------------
/extras/icons/mapillary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/mapillary.png
--------------------------------------------------------------------------------
/extras/icons/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/marker-icon-2x.png
--------------------------------------------------------------------------------
/extras/icons/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/marker-icon.png
--------------------------------------------------------------------------------
/extras/icons/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/marker-shadow.png
--------------------------------------------------------------------------------
/extras/icons/pdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/pdf.png
--------------------------------------------------------------------------------
/extras/icons/position-cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/position-cursor.png
--------------------------------------------------------------------------------
/extras/icons/view-plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/icons/view-plus.png
--------------------------------------------------------------------------------
/extras/icons/wind-speed-0.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 0–2 knots
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-10.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 8–12 knots
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-100.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 98–102 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-105.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 102–107 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-15.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 13–17 knots
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-20.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 18–22 knots
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-25.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 23–27 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-30.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 28–32 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-35.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 33–37 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-40.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 38–42 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-45.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 43–47 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 3–7 knots
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-50.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 63–67 knots
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-55.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 53–57 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-60.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 58–62 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-65.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 63–67 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-70.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 68–72 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-75.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 73–77 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-80.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 78–82 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-85.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 83–87 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-90.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 88–92 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/extras/icons/wind-speed-95.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Observed wind speed: 93–97 knots
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/extras/images/kalisio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/extras/images/kalisio.png
--------------------------------------------------------------------------------
/extras/images/north.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/extras/images/target.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/extras/tours/core/account-profile.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#edit-profile',
3 | content: 'tours.account.PROFILE_LABEL',
4 | params: {
5 | placement: 'bottom',
6 | clickOnPrevious: '#left-opener',
7 | clickOnNext: ['#left-opener', '#edit-profile'],
8 | nextDelay: 500
9 | }
10 | }, {
11 | target: '#name-field',
12 | content: 'tours.account.NAME_LABEL',
13 | params: {
14 | placement: 'bottom',
15 | clickOnPrevious: ['#cancel-action', '#left-opener'],
16 | previousDelay: 500
17 | }
18 | }, {
19 | target: '#avatar-field',
20 | content: 'tours.account.AVATAR_LABEL',
21 | params: {
22 | placement: 'bottom'
23 | }
24 | }, {
25 | target: '#ok-button',
26 | content: 'tours.account.UPDATE_LABEL',
27 | params: {
28 | placement: 'left',
29 | clickOnNext: ['#cancel-action', '#left-opener'],
30 | nextDelay: 500
31 | }
32 | }]
33 |
--------------------------------------------------------------------------------
/extras/tours/core/add-tag.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#tag-field',
3 | content: 'tours.add-tag.TAG_NAME_LABEL',
4 | params: {
5 | placement: 'top'
6 | }
7 | }, {
8 | target: '#join-button',
9 | content: 'tours.add-tag.ADD_TAG_LABEL',
10 | params: {
11 | placement: 'left'
12 | }
13 | }]
--------------------------------------------------------------------------------
/extras/tours/core/create-group.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#name-field',
3 | content: 'tours.create-group.GROUP_NAME_LABEL',
4 | params: {
5 | placement: 'bottom'
6 | }
7 | }, {
8 | target: '#description-field',
9 | content: 'tours.create-group.GROUP_DESCRIPTION_LABEL',
10 | params: {
11 | placement: 'bottom'
12 | }
13 | }, {
14 | target: '#apply-button',
15 | content: 'tours.create-group.CREATE_GROUP_LABEL',
16 | params: {
17 | placement: 'left'
18 | }
19 | }]
20 |
--------------------------------------------------------------------------------
/extras/tours/core/create-organisation.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#name-field',
3 | content: 'tours.create-organisation.ORGANISATION_NAME_LABEL',
4 | params: {
5 | placement: 'bottom'
6 | }
7 | }, {
8 | target: '#description-field',
9 | content: 'tours.create-organisation.ORGANISATION_DESCRIPTION_LABEL',
10 | params: {
11 | placement: 'top'
12 | }
13 | }, {
14 | target: '#apply-button',
15 | content: 'tours.create-organisation.CREATE_ORGANISATION_LABEL',
16 | params: {
17 | placement: 'left'
18 | }
19 | }]
20 |
--------------------------------------------------------------------------------
/extras/tours/core/create-tag.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#value-field',
3 | content: 'tours.create-tag.TAG_NAME_LABEL',
4 | params: {
5 | placement: 'bottom'
6 | }
7 | }, {
8 | target: '#icon-field',
9 | content: 'tours.create-tag.TAG_ICON_LABEL',
10 | params: {
11 | placement: 'bottom'
12 | }
13 | }, {
14 | target: '#description-field',
15 | content: 'tours.create-tag.TAG_DESCRIPTION_LABEL',
16 | params: {
17 | placement: 'bottom'
18 | }
19 | }, {
20 | target: '#apply-button',
21 | content: 'tours.create-tag.CREATE_TAG_LABEL',
22 | params: {
23 | placement: 'left'
24 | }
25 | }]
26 |
27 |
--------------------------------------------------------------------------------
/extras/tours/core/edit-member-role.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#role-field',
3 | content: 'tours.role-member.ROLE_LABEL',
4 | params: {
5 | placement: 'top'
6 | }
7 | }, {
8 | target: '#update-button',
9 | content: 'tours.role-member.UPDATE_ROLE_LABEL',
10 | params: {
11 | placement: 'left'
12 | }
13 | }]
14 |
--------------------------------------------------------------------------------
/extras/tours/core/join-group.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#group-field',
3 | content: 'tours.join-group.GROUP_NAME_LABEL',
4 | params: {
5 | placement: 'top'
6 | }
7 | }, {
8 | target: '#join-button',
9 | content: 'tours.join-group.ADD_MEMBER_LABEL',
10 | params: {
11 | placement: 'left'
12 | }
13 | }]
14 |
--------------------------------------------------------------------------------
/extras/tours/core/login.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#email-field',
3 | title: 'tours.login.LOCAL_LABEL',
4 | content: 'tours.login.EMAIL_LABEL',
5 | params: {
6 | placement: 'left'
7 | }
8 | }, {
9 | target: '#password-field',
10 | content: 'tours.login.PASSWORD_LABEL',
11 | params: {
12 | placement: 'left'
13 | }
14 | }, {
15 | target: '#password-field-visibility',
16 | content: 'tours.login.PASSWORD_VISIBILITY_LABEL',
17 | params: {
18 | placement: 'top',
19 | clickDelay: 1000
20 | }
21 | }, {
22 | target: '#local',
23 | content: 'tours.login.LOGIN_LABEL',
24 | params: {
25 | placement: 'right'
26 | }
27 | }, {
28 | target: '#reset-password-link',
29 | link: 'tours.login.LOST_PASSWORD_LINK_LABEL',
30 | params: {
31 | placement: 'bottom',
32 | route: { name: 'send-reset-password' }
33 | }
34 | }, {
35 | target: '#register-link',
36 | link: 'tours.login.REGISTER_LINK_LABEL',
37 | params: {
38 | placement: 'bottom',
39 | route: { name: 'register' }
40 | }
41 | }]
42 |
--------------------------------------------------------------------------------
/extras/tours/core/send-reset-password.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#email-field',
3 | title: 'tours.reset-password.RESET_PROCEDURE_LABEL',
4 | content: 'tours.reset-password.EMAIL_LABEL',
5 | params: {
6 | placement: 'left'
7 | }
8 | }, {
9 | target: '#send-reset-password',
10 | content: 'tours.reset-password.RESET_LABEL',
11 | params: {
12 | placement: 'bottom'
13 | }
14 | }]
15 |
--------------------------------------------------------------------------------
/extras/tours/map/add-layer.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#import-layer',
3 | title: 'tours.add-layer.IMPORT_LAYER_LABEL',
4 | link: 'tours.add-layer.IMPORT_LAYER_LINK_LABEL',
5 | params: {
6 | placement: 'bottom',
7 | clickOnLink: '#import-layer',
8 | tour: 'import-layer'
9 | }
10 | }, {
11 | target: '#connect-layer',
12 | title: 'tours.add-layer.CONNECT_LAYER_LABEL',
13 | link: 'tours.add-layer.CONNECT_LAYER_LINK_LABEL',
14 | params: {
15 | placement: 'bottom',
16 | clickOnLink: '#connect-layer',
17 | tour: 'connect-layer'
18 | }
19 | }, {
20 | target: '#create-layer',
21 | title: 'tours.add-layer.CREATE_LAYER_LABEL',
22 | link: 'tours.add-layer.CREATE_LAYER_LINK_LABEL',
23 | params: {
24 | placement: 'bottom',
25 | clickOnLink: '#create-layer',
26 | tour: 'create-layer'
27 | }
28 | }]
29 |
--------------------------------------------------------------------------------
/extras/tours/map/connect-layer.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#service-field',
3 | content: 'tours.add-layer.SERVICE_LABEL',
4 | params: {
5 | placement: 'bottom'
6 | }
7 | }, {
8 | target: '#layer-field',
9 | content: 'tours.add-layer.SERVICE_LAYER_LABEL',
10 | params: {
11 | placement: 'bottom'
12 | }
13 | }, {
14 | target: '#name-field',
15 | content: 'tours.add-layer.LAYER_NAME_LABEL',
16 | params: {
17 | placement: 'bottom'
18 | }
19 | }, {
20 | target: '#description-field',
21 | content: 'tours.add-layer.LAYER_DESCRIPTION_LABEL',
22 | params: {
23 | placement: 'bottom'
24 | }
25 | }, {
26 | target: '#style-field',
27 | content: 'tours.add-layer.LAYER_STYLE_LABEL',
28 | params: {
29 | placement: 'bottom'
30 | }
31 | }, {
32 | target: '#connect-layer-action',
33 | title: 'tours.add-layer.CONNECT_NEW_LAYER_LABEL',
34 | link: 'tours.add-layer.ADD_LAYER_LINK_LABEL',
35 | params: {
36 | placement: 'left',
37 | tour: 'add-layer'
38 | }
39 | }]
40 |
--------------------------------------------------------------------------------
/extras/tours/map/create-layer.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#name-field',
3 | content: 'tours.add-layer.LAYER_NAME_LABEL',
4 | params: {
5 | placement: 'bottom'
6 | }
7 | }, {
8 | target: '#description-field',
9 | content: 'tours.add-layer.LAYER_DESCRIPTION_LABEL',
10 | params: {
11 | placement: 'bottom'
12 | }
13 | }, {
14 | target: '#schema-field',
15 | content: 'tours.add-layer.LAYER_SCHEMA_LABEL',
16 | params: {
17 | placement: 'bottom'
18 | }
19 | }, {
20 | target: '#featureId-field',
21 | content: 'tours.add-layer.LAYER_FEATURE_ID_LABEL',
22 | params: {
23 | placement: 'bottom'
24 | }
25 | }, {
26 | target: '#create-layer-action',
27 | title: 'tours.add-layer.CREATE_NEW_LAYER_LABEL',
28 | link: 'tours.add-layer.ADD_LAYER_LINK_LABEL',
29 | params: {
30 | placement: 'left',
31 | tour: 'add-layer'
32 | }
33 | }]
34 |
--------------------------------------------------------------------------------
/extras/tours/map/create-view.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#name-field',
3 | content: 'tours.create-view.NAME_FIELD_LABEL',
4 | params: {
5 | placement: 'bottom'
6 | }
7 | }, {
8 | target: '#description-field',
9 | content: 'tours.create-view.DESCRIPTION_FIELD_LABEL',
10 | params: {
11 | placement: 'bottom'
12 | }
13 | }, {
14 | target: '#layers-field',
15 | content: 'tours.create-view.LAYERS_FIELD_LABEL',
16 | params: {
17 | placement: 'bottom'
18 | }
19 | }, {
20 | target: '#apply-button',
21 | title: 'tours.create-view.APPLY_BUTTON_LABEL',
22 | params: {
23 | placement: 'bottom'
24 | }
25 | }]
26 |
--------------------------------------------------------------------------------
/extras/tours/map/fab.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | probeLocation: (options) => {
3 | return Object.assign({
4 | target: '#probe-location',
5 | title: 'tours.fab.PROBE_LABEL',
6 | content: 'tours.fab.PROBE_CURSOR_LABEL',
7 | params: {
8 | placement: 'left'
9 | }
10 | }, options)
11 | },
12 | addLayer: (options) => {
13 | return Object.assign({
14 | target: '#add-layer',
15 | title: 'tours.fab.ADD_LAYER_LABEL',
16 | link: 'tours.fab.ADD_LAYER_LINK_LABEL',
17 | params: {
18 | placement: 'left',
19 | clickOnLink: '#add-layer',
20 | tour: 'add-layer'
21 | }
22 | }, options)
23 | },
24 | createView: (options) => {
25 | return Object.assign({
26 | target: '#create-view',
27 | title: 'tours.fab.CREATE_VIEW_LABEL',
28 | link: 'tours.fab.CREATE_VIEW_LINK_LABEL',
29 | params: {
30 | placement: 'left',
31 | clickOnLink: '#create-view',
32 | tour: 'create-view'
33 | }
34 | }, options)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/extras/tours/map/import-layer.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | target: '#file-field',
3 | content: 'tours.add-layer.FILE_LABEL',
4 | params: {
5 | placement: 'bottom'
6 | }
7 | }, {
8 | target: '#name-field',
9 | content: 'tours.add-layer.LAYER_NAME_LABEL',
10 | params: {
11 | placement: 'bottom'
12 | }
13 | }, {
14 | target: '#description-field',
15 | content: 'tours.add-layer.LAYER_DESCRIPTION_LABEL',
16 | params: {
17 | placement: 'bottom'
18 | }
19 | }, {
20 | target: '#featureId-field',
21 | content: 'tours.add-layer.LAYER_FEATURE_ID_LABEL',
22 | params: {
23 | placement: 'bottom'
24 | }
25 | }, {
26 | target: '#import-layer-action',
27 | title: 'tours.add-layer.IMPORT_NEW_LAYER_LABEL',
28 | link: 'tours.add-layer.ADD_LAYER_LINK_LABEL',
29 | params: {
30 | placement: 'left',
31 | tour: 'add-layer'
32 | }
33 | }]
34 |
--------------------------------------------------------------------------------
/map.api.js:
--------------------------------------------------------------------------------
1 | // Need this as export * only exports named exports but not the default export
2 | import api from './map/api/index.js'
3 | export default api
4 |
5 | export * from './map/api/index.js'
6 |
--------------------------------------------------------------------------------
/map.client.globe.js:
--------------------------------------------------------------------------------
1 | // Need this as export * only exports named exports but not the default export
2 | import client from './map/client/globe.js'
3 | export default client
4 |
5 | export * from './map/client/globe.js'
6 |
--------------------------------------------------------------------------------
/map.client.js:
--------------------------------------------------------------------------------
1 | // Need this as export * only exports named exports but not the default export
2 | import client from './map/client/index.js'
3 | export default client
4 |
5 | export * from './map/client/index.js'
6 |
--------------------------------------------------------------------------------
/map.client.map.js:
--------------------------------------------------------------------------------
1 | // Need this as export * only exports named exports but not the default export
2 | import client from './map/client/map.js'
3 | export default client
4 |
5 | export * from './map/client/map.js'
6 |
--------------------------------------------------------------------------------
/map.common.js:
--------------------------------------------------------------------------------
1 | export * from './map/common/index.js'
2 |
--------------------------------------------------------------------------------
/map.config.cjs:
--------------------------------------------------------------------------------
1 | const getCategories = require('./map/api/config/categories.cjs')
2 | const getLayers = require('./map/api/config/layers.cjs')
3 | const getSublegends = require('./map/api/config/sublegends.cjs')
4 |
5 | module.exports = {
6 | getCategories,
7 | getLayers,
8 | getSublegends
9 | }
10 |
--------------------------------------------------------------------------------
/map/api/hooks/index.js:
--------------------------------------------------------------------------------
1 | export * from './hooks.catalog.js'
2 | export * from './hooks.query.js'
3 | export * from './hooks.features.js'
4 |
--------------------------------------------------------------------------------
/map/api/index.js:
--------------------------------------------------------------------------------
1 | import makeDebug from 'debug'
2 | import services from './services/index.js'
3 | import * as hooks from './hooks/index.js'
4 |
5 | export * from './services/index.js'
6 | export { hooks }
7 | export * from './marshall.js'
8 | export * from '../common/index.js'
9 |
10 | const debug = makeDebug('kdk:map')
11 |
12 | export default async function init () {
13 | const app = this
14 |
15 | debug('Initializing KDK map')
16 |
17 | await app.configure(services)
18 | }
19 |
--------------------------------------------------------------------------------
/map/api/marshall.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 |
3 | function coordinatesToNumbers (value) {
4 | if (typeof value === 'string') {
5 | return _.toNumber(value)
6 | } else if (Array.isArray(value)) {
7 | return value.map(item => coordinatesToNumbers(item))
8 | } else {
9 | return value
10 | }
11 | }
12 |
13 | export function marshallGeometry (geometry) {
14 | if (typeof geometry === 'object') {
15 | // Geospatial operators begin with $
16 | let geoOperator = _.keys(geometry).find(key => key.startsWith('$'))
17 | geoOperator = geometry[geoOperator]
18 | _.forOwn(geoOperator, (value, key) => {
19 | // Geospatial parameters begin with $
20 | if (key.startsWith('$')) {
21 | // Some target coordinates
22 | if (!_.isNil(value.coordinates)) {
23 | value.coordinates = coordinatesToNumbers(value.coordinates)
24 | } else {
25 | // Other simple values or array of values
26 | geoOperator[key] = coordinatesToNumbers(value)
27 | }
28 | }
29 | })
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/map/api/models/alerts.model.mongodb.js:
--------------------------------------------------------------------------------
1 | export default function (app, options) {
2 | const db = options.db || app.db
3 | options.Model = db.collection('alerts')
4 | options.Model.createIndex({ geometry: '2dsphere' })
5 | // Expire at a given date
6 | options.Model.createIndex({ expireAt: 1 }, { expireAfterSeconds: 0 })
7 | }
8 |
--------------------------------------------------------------------------------
/map/api/models/projects.model.mongodb.js:
--------------------------------------------------------------------------------
1 | export default function (app, options) {
2 | const db = options.db || app.db
3 | options.Model = db.collection('projects')
4 | // Collation provided in query ensure sorting to be case insensitive w.r.t. user's language
5 | // We built indices with collation to cover the most used languages, it requires different naming...
6 | options.Model.createIndex({ name: 1 }, { name: 'name-en', collation: { locale: 'en', strength: 1 } })
7 | options.Model.createIndex({ name: 1 }, { name: 'name-fr', collation: { locale: 'fr', strength: 1 } })
8 | }
9 |
--------------------------------------------------------------------------------
/map/api/models/styles.model.mongodb.js:
--------------------------------------------------------------------------------
1 | export default function (app, options) {
2 | const db = options.db || app.db
3 | options.Model = db.collection('styles')
4 | // Collation provided in query ensure sorting to be case insensitive w.r.t. user's language
5 | // We built indices with collation to cover the most used languages, it requires different naming...
6 | options.Model.createIndex({ name: 1 }, { name: 'name-en', collation: { locale: 'en', strength: 1 } })
7 | options.Model.createIndex({ name: 1 }, { name: 'name-fr', collation: { locale: 'fr', strength: 1 } })
8 | options.Model.createIndex({ name: 'text' })
9 | }
10 |
--------------------------------------------------------------------------------
/map/api/services/styles/styles.hooks.js:
--------------------------------------------------------------------------------
1 | import fuzzySearch from 'feathers-mongodb-fuzzy-search'
2 | import { hooks as kdkCoreHooks } from '../../../../core/api/index.js'
3 |
4 | export default {
5 | before: {
6 | all: [],
7 | find: [
8 | fuzzySearch({ fields: ['name'] }),
9 | kdkCoreHooks.diacriticSearch()
10 | ],
11 | get: [],
12 | create: [kdkCoreHooks.checkUnique({ field: 'name' })],
13 | update: [kdkCoreHooks.checkUnique({ field: 'name' })],
14 | patch: [kdkCoreHooks.checkUnique({ field: 'name' })],
15 | remove: []
16 | },
17 |
18 | after: {
19 | all: [],
20 | find: [],
21 | get: [],
22 | create: [],
23 | update: [],
24 | patch: [],
25 | remove: []
26 | },
27 |
28 | error: {
29 | all: [],
30 | find: [],
31 | get: [],
32 | create: [],
33 | update: [],
34 | patch: [],
35 | remove: []
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/map/client/canvas-draw-context.js:
--------------------------------------------------------------------------------
1 | export const CanvasDrawContext = {
2 | initialize () {
3 | if (this.ctx) return
4 | this.ctx = {}
5 | },
6 |
7 | get () {
8 | return this.ctx
9 | },
10 |
11 | merge (ctx) {
12 | this.ctx = Object.assign({}, this.ctx, ctx)
13 | }
14 | }
15 |
16 | CanvasDrawContext.initialize()
17 |
--------------------------------------------------------------------------------
/map/client/capture.js:
--------------------------------------------------------------------------------
1 | import { Notify } from 'quasar'
2 | import { capture } from './utils/utils.capture.js'
3 | import { i18n } from '../../core/client/index.js'
4 |
5 | // Export singleton
6 | export const Capture = {
7 | processing: false,
8 | async process (values) {
9 | if (this.processing) Notify.create({ type: 'negative', message: i18n.t('KCapture.ERROR_MESSAGE') })
10 | else {
11 | this.processing = true
12 | await capture(values)
13 | this.processing = false
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/map/client/cesium/utils/index.js:
--------------------------------------------------------------------------------
1 | export * from './utils.cesium.js'
2 | export * from './utils.events.js'
3 | export * from './utils.geojson.js'
4 | export * from './utils.popup.js'
5 | export * from './utils.style.js'
6 | export * from './utils.features.js'
7 |
--------------------------------------------------------------------------------
/map/client/cesium/utils/utils.events.js:
--------------------------------------------------------------------------------
1 | export function convertCesiumHandlerEvent (type) {
2 | const buttonMapping = {
3 | left: 0,
4 | middle: 1,
5 | right: 2
6 | }
7 | const buttonMovement = type.split('_')
8 | const movement = buttonMovement[1].toLowerCase()
9 | let button = buttonMovement[0].toLowerCase()
10 | let name
11 | if (type.startsWith('PINCH')) name = 'pinch'
12 | else if (type.endsWith('CLICK')) name = 'click'
13 | else if (type.endsWith('DOUBLE_CLICK')) name = 'dblclick'
14 | else if (type.startsWith('WHEEL')) name = 'wheel'
15 | else name = 'mouse'
16 |
17 | if (name === 'mouse') {
18 | name += movement
19 | button = buttonMapping[button]
20 | } else if (name.endsWith('click')) {
21 | button = buttonMapping[button]
22 | } else if (name === 'pinch') {
23 | name += movement
24 | button = undefined
25 | } else {
26 | button = 1 // wheel
27 | }
28 |
29 | return { name, button }
30 | }
--------------------------------------------------------------------------------
/map/client/cesium/utils/utils.features.js:
--------------------------------------------------------------------------------
1 | import { kml } from '@tmcw/togeojson'
2 | import { exportKml } from 'cesium'
3 |
4 | export async function convertEntitiesToGeoJson(entities) {
5 | const features = []
6 | if (entities.values.length === 0) return { type: 'FeatureCollection', features }
7 | // As cesium does not we usually keep track of original feature associated with an entity
8 | _.forEach(entities.values, entity => {
9 | if (entity.feature) features.push(entity.feature)
10 | })
11 | if (features.length > 0) return { type: 'FeatureCollection', features }
12 | // Otherwise try to export as KML then convert to GeoJson
13 | const kmlEntities = await exportKml({ entities, modelCallback: () => '' })
14 | const parser = new DOMParser()
15 | return kml(parser.parseFromString(kmlEntities.kml, 'application/xml'))
16 | }
17 |
--------------------------------------------------------------------------------
/map/client/cesium/utils/utils.popup.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { utils as kdkCoreUtils } from '../../../../core/client/index.js'
3 |
4 | export function getTextTable (properties) {
5 | properties = kdkCoreUtils.dotify(properties)
6 | properties = _.pickBy(properties, value => !_.isNil(value))
7 | const keys = _.keys(properties)
8 | let text
9 | if (keys.length === 0) return null
10 | else if (keys.length === 1) text = _.get(properties, keys[0])
11 | else {
12 | text = keys
13 | .map(key => key + ': ' + _.get(properties, key))
14 | .join('\n')
15 | }
16 | return text
17 | }
--------------------------------------------------------------------------------
/map/client/components/KEditLayerData.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
--------------------------------------------------------------------------------
/map/client/components/index.js:
--------------------------------------------------------------------------------
1 | // Warning: Do not delete this file as it seems to be required to enable webpack directoy scanning (scandir)
2 |
--------------------------------------------------------------------------------
/map/client/components/legend/KColorScaleLegend.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
36 |
--------------------------------------------------------------------------------
/map/client/components/legend/KImageLegend.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
47 |
48 |
53 |
--------------------------------------------------------------------------------
/map/client/components/legend/KLegendRenderer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ $tie(label) }}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/map/client/components/location/KGeocodersFilter.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
43 |
--------------------------------------------------------------------------------
/map/client/components/stickies/KNorthArrow.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
27 |
--------------------------------------------------------------------------------
/map/client/components/stickies/KTarget.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
27 |
28 |
35 |
--------------------------------------------------------------------------------
/map/client/composables/index.js:
--------------------------------------------------------------------------------
1 | export * from './activity.js'
2 | export * from './highlight.js'
3 | export * from './location.js'
4 | export * from './measure.js'
5 | export * from './probe.js'
6 | export * from './selection.js'
7 | export * from './weather.js'
8 | export * from './catalog.js'
9 | export * from './project.js'
10 |
--------------------------------------------------------------------------------
/map/client/globe.js:
--------------------------------------------------------------------------------
1 | import * as commonMixins from './mixins/index.js'
2 | import * as globeMixins from './mixins/globe/index.js'
3 | import * as hooks from './hooks/index.js'
4 | import * as utils from './utils.globe.js'
5 | import init from './init.js'
6 |
7 | const mixins = Object.assign({}, commonMixins, { globe: globeMixins })
8 |
9 | export * from './geolocation.js'
10 | export * from './planets.js'
11 | export * from './navigator.js'
12 | export { hooks }
13 | export { utils }
14 | export { mixins }
15 | export * from '../common/index.js'
16 | export * from './init.js'
17 |
18 | export default init
19 |
--------------------------------------------------------------------------------
/map/client/hooks/index.js:
--------------------------------------------------------------------------------
1 | export * from './hooks.offline.js'
2 |
--------------------------------------------------------------------------------
/map/client/index.js:
--------------------------------------------------------------------------------
1 | import * as composables from './composables/index.js'
2 | import * as commonMixins from './mixins/index.js'
3 | import * as mapMixins from './mixins/map/index.js'
4 | import * as globeMixins from './mixins/globe/index.js'
5 | import * as hooks from './hooks/index.js'
6 | import * as utils from './utils.all.js'
7 | import * as elevationUtils from './elevation-utils.js'
8 | import init from './init.js'
9 | const mixins = Object.assign({}, commonMixins, { map: mapMixins, globe: globeMixins })
10 |
11 | export * from './geolocation.js'
12 | export * from './capture.js'
13 | export * from './planets.js'
14 | export * from './navigator.js'
15 | export * from './canvas-draw-context.js'
16 | export { hooks }
17 | export { utils }
18 | export { elevationUtils }
19 | export { composables }
20 | export { mixins }
21 | export * from '../common/index.js'
22 | export * from './init.js'
23 |
24 | export default init
25 |
--------------------------------------------------------------------------------
/map/client/leaflet/utils/index.js:
--------------------------------------------------------------------------------
1 | export * from './utils.events.js'
2 | export * from './utils.geojson.js'
3 | export * from './utils.popup.js'
4 | export * from './utils.style.js'
5 | export * from './utils.tiles.js'
6 |
--------------------------------------------------------------------------------
/map/client/leaflet/utils/utils.popup.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { utils as kdkCoreUtils } from '../../../../core/client/index.js'
3 |
4 | export function getHtmlTable (properties) {
5 | properties = kdkCoreUtils.dotify(properties)
6 | properties = _.pickBy(properties, value => !_.isNil(value))
7 | const keys = _.keys(properties)
8 | let html
9 | if (keys.length === 0) return null
10 | else if (keys.length === 1) html = _.get(properties, keys[0])
11 | else {
12 | const borderStyle = ' style="border: 1px solid black; border-collapse: collapse;"'
13 | html = ''
14 | html += keys
15 | .map(key => '' + key + ' ' + _.get(properties, key) + ' ')
17 | .join('')
18 | html += '
'
19 | }
20 | return html
21 | }
--------------------------------------------------------------------------------
/map/client/map.js:
--------------------------------------------------------------------------------
1 | import * as composables from './composables/index.js'
2 | import * as commonMixins from './mixins/index.js'
3 | import * as mapMixins from './mixins/map/index.js'
4 | import * as hooks from './hooks/index.js'
5 | import * as utils from './utils.map.js'
6 | import init from './init.js'
7 |
8 | const mixins = Object.assign({}, commonMixins, { map: mapMixins })
9 |
10 | export * from './geolocation.js'
11 | export * from './planets.js'
12 | export * from './navigator.js'
13 | export { hooks }
14 | export { utils }
15 | export { composables }
16 | export { mixins }
17 | export * from '../common/index.js'
18 | export * from './init.js'
19 |
20 | export default init
21 |
--------------------------------------------------------------------------------
/map/client/mixins/globe/index.js:
--------------------------------------------------------------------------------
1 | export * from './mixin.base-globe.js'
2 | export * from './mixin.geojson-layers.js'
3 | export * from './mixin.file-layers.js'
4 | export * from './mixin.style.js'
5 | export * from './mixin.tooltip.js'
6 | export * from './mixin.popup.js'
7 | export * from './mixin.globe-activity.js'
8 | export * from './mixin.opendap-layers.js'
9 |
--------------------------------------------------------------------------------
/map/client/mixins/index.js:
--------------------------------------------------------------------------------
1 | export * from './mixin.activity.js'
2 | export * from './mixin.context.js'
3 | export * from './mixin.feature-selection.js'
4 | export * from './mixin.feature-service.js'
5 | export * from './mixin.infobox.js'
6 | export * from './mixin.levels.js'
7 | export * from './mixin.style.js'
8 | export * from './mixin.weacast.js'
9 |
--------------------------------------------------------------------------------
/map/client/mixins/map/index.js:
--------------------------------------------------------------------------------
1 | export * from './mixin.base-map.js'
2 | export * from './mixin.geojson-layers.js'
3 | export * from './mixin.file-layers.js'
4 | export * from './mixin.edit-layers.js'
5 | export * from './mixin.style.js'
6 | export * from './mixin.tooltip.js'
7 | export * from './mixin.popup.js'
8 | export * from './mixin.map-activity.js'
9 | export * from './mixin.tiled-mesh-layers.js'
10 | export * from './mixin.tiled-wind-layers.js'
11 | export * from './mixin.heatmap-layers.js'
12 | export * from './mixin.mapillary-layers.js'
13 | export * from './mixin.gsmap-layers.js'
14 | export * from './mixin.canvas-layers.js'
15 | export * from './mixin.pmtiles-layers.js'
16 |
--------------------------------------------------------------------------------
/map/client/mixins/map/mixin.gsmap-layers.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { Time } from '../../../../core/client/time.js'
3 | import { GSMaPLayer } from '../../leaflet/GSMaPLayer.js'
4 |
5 | export const gsmapLayers = {
6 | methods: {
7 | async createLeafletGSMaPLayer (options) {
8 | const leafletOptions = options.leaflet || options
9 | // Check for valid type
10 | if (leafletOptions.type !== 'gsmapLayer') return
11 |
12 | // Copy options
13 | const colorMap = _.get(options, 'variables[0].chromajs', null)
14 | if (colorMap) Object.assign(leafletOptions, { chromajs: colorMap })
15 |
16 | // Add current time to options
17 | leafletOptions.time = Time.getCurrentTime()
18 |
19 | // Then create layer
20 | return new GSMaPLayer(leafletOptions)
21 | }
22 | },
23 | created () {
24 | // Register the new layer constructor
25 | this.registerLeafletConstructor(this.createLeafletGSMaPLayer)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/map/client/mixins/map/mixin.style.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import { getDefaultPointStyle, getDefaultLineStyle, getDefaultPolygonStyle } from '../../utils.map.js'
3 |
4 | export const style = {
5 | created () {
6 | this.registerStyle('point', getDefaultPointStyle)
7 | this.registerStyle('line', getDefaultLineStyle)
8 | this.registerStyle('polygon', getDefaultPolygonStyle)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/map/client/mixins/mixin.feature-selection.js:
--------------------------------------------------------------------------------
1 | export const featureSelection = {
2 | watch: {
3 | 'selection.items': {
4 | handler () {
5 | this.updateHighlights()
6 | this.handleWidget(this.getWidgetForSelection())
7 | }
8 | },
9 | 'probe.item': {
10 | handler () {
11 | this.updateHighlights()
12 | this.handleWidget(this.getWidgetForProbe())
13 | }
14 | }
15 | },
16 | methods: {
17 | updateHighlights () {
18 | this.clearHighlights()
19 | this.getSelectedItems().forEach(item => {
20 | this.highlight(item.feature || item.location, item.layer)
21 | })
22 | if (this.hasProbedLocation()) this.highlight(this.getProbedLocation(), this.getProbedLayer())
23 | },
24 | handleWidget (widget) {
25 | // If window already open on another widget keep it
26 | if (widget && (widget !== 'none') && !this.isWidgetWindowVisible(widget)) this.openWidget(widget)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/map/client/mixins/mixin.infobox.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 |
3 | export const infobox = {
4 | methods: {
5 | getDefaultInfoBox (feature, options) {
6 | let properties = feature.properties
7 | if (properties) {
8 | const engineOptions = _.get(options, this.engine, options)
9 | // Check if explicitely disabled first
10 | if (_.has(engineOptions, 'infobox') && !_.get(engineOptions, 'infobox')) return []
11 | if (_.has(properties, 'infobox') && !_.get(properties, 'infobox')) return []
12 | // Otherwise merge options
13 | const infoboxStyle = Object.assign({},
14 | _.get(this, 'activityOptions.engine.infobox'),
15 | engineOptions.infobox, properties.infobox)
16 |
17 | if (infoboxStyle.pick) {
18 | properties = _.pick(properties, infoboxStyle.pick)
19 | } else if (infoboxStyle.omit) {
20 | properties = _.omit(properties, infoboxStyle.omit)
21 | }
22 | }
23 | return properties
24 | }
25 | },
26 | created () {
27 | this.registerStyle('infobox', this.getDefaultInfoBox)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/map/client/mixins/mixin.style.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 |
3 | export const style = {
4 | methods: {
5 | registerStyle (type, generator) {
6 | // Initialize on first registration
7 | if (!this[type + 'Factory']) this[type + 'Factory'] = []
8 | this[type + 'Factory'].push(generator)
9 | },
10 | unregisterStyle (type, generator) {
11 | _.pull(this[type + 'Factory'], generator)
12 | },
13 | generateStyle () {
14 | const args = Array.from(arguments)
15 | const type = args[0]
16 | if (!this[type + 'Factory']) return
17 | args.shift()
18 | let style
19 | // Iterate over all registered generators until we find one
20 | // Last registered overrides previous ones (usefull to override default styles)
21 | for (let i = this[type + 'Factory'].length - 1; i >= 0; i--) {
22 | const generator = this[type + 'Factory'][i]
23 | style = generator(...args)
24 | if (style) break
25 | }
26 | return style
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/map/client/navigator.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import logger from 'loglevel'
3 | import { Store, Platform, LocalStorage } from '../../core/client/index.js'
4 |
5 | export const Navigator = {
6 | initialize () {
7 | this.availableApps = {
8 | waze: 'https://waze.com/ul?q=<%= lat %>,<%= lon %>',
9 | 'google-maps': 'https://www.google.com/maps/dir/?api=1&destination=<%= lat %>,<%= lon %>',
10 | 'apple-plan': 'https://maps.apple.com/place?ll=<%= lat %>,<%= lon %>'
11 | }
12 | const settings = LocalStorage.get('settings')
13 | if (_.isNil(settings)) {
14 | let app = 'google-maps'
15 | if (Platform.ios) app = 'apple-plan'
16 | Store.set('navigator', app)
17 | logger.debug('[KDK] Navigator initialized to:', this.get())
18 | } else {
19 | logger.debug('[KDK] Navigator initialized to:', settings.navigator)
20 | }
21 | },
22 | get () {
23 | return Store.get('navigator')
24 | },
25 | navigateTo (lat, lon) {
26 | // Retrieve the default app
27 | const app = this.get()
28 | if (_.isEmpty(app)) {
29 | logger.debug('[KDK] Default navigator is undefined')
30 | return
31 | }
32 | // Template the url
33 | const compiledUrl = _.template(this.availableApps[app])
34 | const interpolatedUrl = compiledUrl({ lat, lon })
35 | // Open the interpolated url
36 | window.open(interpolatedUrl)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/map/client/readers/index.js:
--------------------------------------------------------------------------------
1 | export * from './reader.geojson.js'
2 | export * from './reader.kml.js'
3 | export * from './reader.gpx.js'
4 | export * from './reader.shp.js'
5 |
--------------------------------------------------------------------------------
/map/client/readers/reader.gpx.js:
--------------------------------------------------------------------------------
1 | import logger from 'loglevel'
2 | import { gpx } from '@tmcw/togeojson'
3 | import { i18n } from '../../../core/client/i18n.js'
4 |
5 | export const GPXReader = {
6 | read (files, options) {
7 | if (files.length !== 1) {
8 | logger.debug('invalid \'files\' arguments')
9 | return
10 | }
11 | const file = files[0]
12 | logger.debug(`reading GPX file ${file.name}`)
13 | return new Promise((resolve, reject) => {
14 | const reader = new FileReader()
15 | reader.onloadend = () => {
16 | let content = reader.result
17 | try {
18 | content = gpx(new DOMParser().parseFromString(content, 'text/xml'))
19 | } catch (error) {
20 | logger.debug(error)
21 | reject(new Error(i18n.t('errors.INVALID_GPX_FILE', { file: file.name }), { errors: error }))
22 | return
23 | }
24 | resolve(content)
25 | }
26 | reader.onerror = (error) => {
27 | logger.debug(error)
28 | reject(new Error(i18n.t('errors.CANNOT_READ_FILE', { file: file.name }), { errors: error }))
29 | }
30 | reader.readAsText(file)
31 | })
32 | },
33 | getAdditionalFiles () {
34 | return []
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/map/client/utils.all.js:
--------------------------------------------------------------------------------
1 | export * from './utils/index.js'
2 | export * from './leaflet/utils/index.js'
3 | export * from './cesium/utils/index.js'
4 |
--------------------------------------------------------------------------------
/map/client/utils.globe.js:
--------------------------------------------------------------------------------
1 | export * from './utils/index.js'
2 | export * from './cesium/utils/index.js'
3 |
--------------------------------------------------------------------------------
/map/client/utils.js:
--------------------------------------------------------------------------------
1 | export * from './utils/index.js'
2 | // Now in separated files to avoid mixin Leaflet/Cesium elements
3 | // export * from './leaflet/utils.js'
4 | // export * from './cesium/utils.js'
5 |
--------------------------------------------------------------------------------
/map/client/utils.map.js:
--------------------------------------------------------------------------------
1 | export * from './utils/index.js'
2 | export * from './leaflet/utils/index.js'
3 |
--------------------------------------------------------------------------------
/map/client/utils/index.js:
--------------------------------------------------------------------------------
1 | export * from './utils.js'
2 | export * from './utils.capture.js'
3 | export * from './utils.catalog.js'
4 | export * from './utils.features.js'
5 | export * from './utils.layers.js'
6 | export * from './utils.location.js'
7 | export * from './utils.offline.js'
8 | export * from './utils.project.js'
9 | export * from './utils.schema.js'
10 | export * from './utils.style.js'
11 | export * from './utils.time-series.js'
12 |
--------------------------------------------------------------------------------
/map/client/utils/utils.project.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 |
3 | export function getCatalogProjectQuery (project) {
4 | // As we keep track of ID/name depending on if a layer is a user-defined one or not we need to process both
5 | const idQuery = { _id: { $in: _.map(_.filter(project.layers, '_id'), '_id') } }
6 | const nameQuery = { name: { $in: _.map(_.filter(project.layers, 'name'), 'name') } }
7 | return { $or: [idQuery, nameQuery] }
8 | }
9 |
--------------------------------------------------------------------------------
/map/common/errors.js:
--------------------------------------------------------------------------------
1 | import { errors } from '../../core/common/index.js'
2 |
3 | export class KGeolocationError extends errors.KError {}
4 |
--------------------------------------------------------------------------------
/map/common/moment-utils.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment'
2 |
3 | export function readAsTimeOrDuration (conf) {
4 | let ret = null
5 | if (typeof conf === 'string') {
6 | if (conf.charAt(0) === 'P') {
7 | // treat as a duration
8 | ret = moment.duration(conf)
9 | } else {
10 | // treat as time
11 | ret = moment.utc(conf)
12 | }
13 |
14 | ret = ret.isValid() ? ret : null
15 | } else if (!conf) {
16 | ret = moment.duration(0)
17 | }
18 |
19 | return ret
20 | }
21 |
22 | export function makeTime (timeOrDuration, referenceTime) {
23 | return moment.isDuration(timeOrDuration) ? referenceTime.clone().add(timeOrDuration) : timeOrDuration
24 | }
25 |
--------------------------------------------------------------------------------
/map/common/permissions.js:
--------------------------------------------------------------------------------
1 | // Hook computing map abilities for a given user
2 | export function defineUserAbilities (subject, can, cannot) {
3 | can('service', 'geocoder')
4 | can('create', 'geocoder')
5 | can('service', 'catalog')
6 | can('read', 'catalog')
7 | can('service', 'projects')
8 | can('read', 'projects')
9 | can('service', 'alerts')
10 | can('read', 'alerts')
11 | can('service', 'styles')
12 | can('read', 'styles')
13 | // can('service', 'daptiles')
14 | // can('get', 'daptiles')
15 | }
16 |
--------------------------------------------------------------------------------
/map/common/schemas/catalog.update.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-07/schema#",
3 | "$id": "http://www.kalisio.xyz/schemas/catalog.update.json#",
4 | "title": "schemas.OBJECT_NAME",
5 | "description": "Layer edition schema",
6 | "type": "object",
7 | "properties": {
8 | "name": {
9 | "type": "string",
10 | "maxLength": 128,
11 | "minLength": 3,
12 | "field": {
13 | "component": "form/KTextField",
14 | "label": "schemas.CATALOG_NAME_FIELD_LABEL"
15 | }
16 | },
17 | "description": {
18 | "type": ["string", "null"],
19 | "maxLength": 256,
20 | "field": {
21 | "component": "form/KTextField",
22 | "label": "schemas.CATALOG_DESCRIPTION_FIELD_LABEL"
23 | }
24 | },
25 | "featureId": {
26 | "type": ["string", "null"],
27 | "maxLength": 256,
28 | "field": {
29 | "component": "form/KTextField",
30 | "label": "schemas.CATALOG_FEATURE_ID_FIELD_LABEL"
31 | }
32 | },
33 | "featureLabel": {
34 | "type": ["string", "null"],
35 | "maxLength": 256,
36 | "field": {
37 | "component": "form/KTextField",
38 | "label": "schemas.CATALOG_FEATURE_LABEL_FIELD_LABEL"
39 | }
40 | }
41 | },
42 | "required": ["name"]
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/scripts/build_docs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | # set -x
4 |
5 | THIS_FILE=$(readlink -f "${BASH_SOURCE[0]}")
6 | THIS_DIR=$(dirname "$THIS_FILE")
7 | ROOT_DIR=$(dirname "$THIS_DIR")
8 | WORKSPACE_DIR="$(dirname "$ROOT_DIR")"
9 |
10 | . "$THIS_DIR/kash/kash.sh"
11 |
12 | ## Parse options
13 | ##
14 |
15 | PUBLISH=false
16 | CI_STEP_NAME="Build docs"
17 | while getopts "pr:" OPT; do
18 | case $OPT in
19 | p) # publish doc
20 | PUBLISH=true
21 | ;;
22 | r) # report outcome to slack
23 | CI_STEP_NAME=$OPTARG
24 | load_env_files "$WORKSPACE_DIR/development/common/SLACK_WEBHOOK_LIBS.enc.env"
25 | trap 'slack_ci_report "$ROOT_DIR" "$CI_STEP_NAME" "$?" "$SLACK_WEBHOOK_LIBS"' EXIT
26 | ;;
27 | *)
28 | ;;
29 | esac
30 | done
31 |
32 |
33 | ## Build docs
34 | ##
35 |
36 | build_docs "$ROOT_DIR" "kalisio/kdk" "$PUBLISH"
37 |
38 |
--------------------------------------------------------------------------------
/scripts/init_runner.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | # set -x
4 |
5 | JOB_ID=$1
6 |
7 | THIS_FILE=$(readlink -f "${BASH_SOURCE[0]}")
8 | THIS_DIR=$(dirname "$THIS_FILE")
9 |
10 | . "$THIS_DIR/kash/kash.sh"
11 |
12 | ### Github Actions
13 |
14 | init_github_run_tests() {
15 | install_reqs age sops nvm node20 mongo7 cc_test_reporter
16 | }
17 |
18 | init_github_additional_tests() {
19 | install_reqs age sops nvm node20 node22 mongo8
20 | }
21 |
22 | init_github_build_docs() {
23 | install_reqs age sops nvm node18
24 | }
25 |
26 | begin_group "Init $CI_ID for $JOB_ID"
27 |
28 | init_"${CI_ID}_${JOB_ID}"
29 |
30 | end_group "Init $CI_ID for $JOB_ID"
31 |
--------------------------------------------------------------------------------
/scripts/run_tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | # set -x
4 |
5 | THIS_FILE=$(readlink -f "${BASH_SOURCE[0]}")
6 | THIS_DIR=$(dirname "$THIS_FILE")
7 | ROOT_DIR=$(dirname "$THIS_DIR")
8 | WORKSPACE_DIR="$(dirname "$ROOT_DIR")"
9 |
10 | . "$THIS_DIR/kash/kash.sh"
11 |
12 | ## Parse options
13 | ##
14 |
15 | NODE_VER=20
16 | MONGO_VER=7
17 | CI_STEP_NAME="Run tests"
18 | CODE_COVERAGE=false
19 | while getopts "m:n:cr:" option; do
20 | case $option in
21 | m) # defines mongo version
22 | MONGO_VER=$OPTARG
23 | ;;
24 | n) # defines node version
25 | NODE_VER=$OPTARG
26 | ;;
27 | c) # publish code coverage
28 | CODE_COVERAGE=true
29 | ;;
30 | r) # report outcome to slack
31 | CI_STEP_NAME=$OPTARG
32 | load_env_files "$WORKSPACE_DIR/development/common/SLACK_WEBHOOK_LIBS.enc.env"
33 | trap 'slack_ci_report "$ROOT_DIR" "$CI_STEP_NAME" "$?" "$SLACK_WEBHOOK_LIBS"' EXIT
34 | ;;
35 | *)
36 | ;;
37 | esac
38 | done
39 |
40 | ## Init workspace
41 | ##
42 |
43 | . "$WORKSPACE_DIR/development/workspaces/libs/libs.sh" kdk
44 |
45 | ## Run tests
46 | ##
47 |
48 | run_lib_tests "$ROOT_DIR" "$CODE_COVERAGE" "$NODE_VER" "$MONGO_VER"
49 |
--------------------------------------------------------------------------------
/test.api.js:
--------------------------------------------------------------------------------
1 | export * from './test/client/index.js'
--------------------------------------------------------------------------------
/test.client.js:
--------------------------------------------------------------------------------
1 | export * from './test/client/index.js'
--------------------------------------------------------------------------------
/test/api/core/client.test.js.skip:
--------------------------------------------------------------------------------
1 | import logger from 'loglevel'
2 | import chai, { util, expect } from 'chai'
3 | import chailint from 'chai-lint'
4 | import 'jsdom-global/register'
5 | import 'babel-polyfill'
6 | import fetch from 'isomorphic-fetch'
7 | // Importing the whole weacast module makes Leaflet time dimension fail due to jQuery not be defined
8 | // The following workaround, although presented as working on the internet, does not help
9 | // import jQuery from 'jquery'
10 | // window.jQuery = window.$ = jQuery
11 | // global.jQuery = global.$ = jQuery
12 | // For now simply testing the API
13 | import { kalisio } from '../src/client'
14 |
15 | window.fetch = fetch
16 |
17 | describe('kClient', () => {
18 | let app
19 |
20 | before(() => {
21 | chailint(chai, util)
22 | app = kalisio()
23 | })
24 |
25 | it('is ES6 compatible', () => {
26 | expect(typeof kalisio).to.equal('function')
27 | })
28 |
29 | it('registers the users service', () => {
30 | expect(app.users).toExist()
31 | })
32 |
33 | it('registers the log options', () => {
34 | logger.info('This is a log test')
35 | expect(logger.getLevel()).to.equal(logger.levels.ERROR)
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/confirmInvitation/html.ejs:
--------------------------------------------------------------------------------
1 | <%= email.subject %>
2 |
3 | Dear <%= user.profile.name %>.
4 |
5 | You'be been invited to join us
6 |
7 | An account has been created for you and is ready to use with the following details:
8 |
9 | email: <%= user.email %>
10 | password: <%= user.password %>
11 |
12 |
13 |
14 |
15 | Follow this link to access the login page.
16 |
17 | If you do not want to get registrated to kApp please let us know by following this link .
18 |
19 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/identityChange/html.ejs:
--------------------------------------------------------------------------------
1 | [Kalisio KDK] <%= email.subject %>
2 |
3 | Hi <%= user.profile.name %>, your user information was just changed. Please verify that you made these changes.
4 |
5 | <% for (var key in user.verifyChanges) {%>
6 | <%= key %>: <%= user.verifyChanges[key] %>
7 | <% } %>
8 |
9 |
10 | Use the verification code below to approve the changes.
11 |
12 | <%= user.verifyShortToken %>
13 |
14 | If you didn't request this change please let us know by following this link .
15 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/newDevice/html.ejs:
--------------------------------------------------------------------------------
1 | <%= email.subject %>
2 |
3 | Hi <%= user.profile.name %>, your account was just signed in from a new <%= device.platform %> device. You're getting this email to make sure it was you.
4 |
5 | Follow this link to check the activity.
6 |
7 | If you do not recognize this activity please let us know by following this link .
8 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/newSubscription/html.ejs:
--------------------------------------------------------------------------------
1 | [Kalisio KDK] <%= email.subject %>
2 |
3 | Hi <%= user.profile.name %>, your account was just signed in from a new <%= subscription.browser.name %> browser. You are getting this email to make sure it was you.
4 |
5 | Follow this link to check the activity.
6 |
7 | If you do not recognize this activity please let us know by following this link .
8 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/passwordChange/html.ejs:
--------------------------------------------------------------------------------
1 | <%= email.subject %>
2 |
3 | Hi <%= user.profile.name %>, the password associated to your email <%= user.email %> was just changed.
4 |
5 | If you didn't request this change please let us know by following this link .
6 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/resendVerifySignup/html.ejs:
--------------------------------------------------------------------------------
1 | [Kalisio KDK] <%= email.subject %>
2 |
3 | Thank you for signing up <%= user.profile.name %>.
4 |
5 | Please verify your email <%= user.email %> so you can reset your password if need be. You may still use the site if your email is unverified but we can't send you emails.
6 |
7 | Use the verification code below to verify your email.
8 |
9 | <%= user.verifyShortToken %>
10 |
11 | If you didn't request this change please let us know by following this link .
12 |
13 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/resetPwd/html.ejs:
--------------------------------------------------------------------------------
1 | <%= email.subject %>
2 |
3 | Hi <%= user.profile.name %>, the password associated to your email <%= user.email %> was just reset.
4 |
5 | If you didn't request this change please let us know by following this link .
6 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/sendResetPwd/html.ejs:
--------------------------------------------------------------------------------
1 | [Kalisio KDK] <%= email.subject %>
2 |
3 | Hi <%= user.profile.name %>, we got a request to reset your password associated to your email <%= user.email %>.
4 |
5 | Follow this link and use the verification code below to reset your password.
6 |
7 | Use the verification code below to reset your password.
8 |
9 | <%= user.resetShortToken %>
10 |
11 | If you didn't request this change please let us know by following this link .
12 |
13 |
--------------------------------------------------------------------------------
/test/api/core/config/email-templates/verifySignup/html.ejs:
--------------------------------------------------------------------------------
1 | <%= email.subject %>
2 |
3 | Your email <%= user.email %> has been verified. We can now safely send you a link to reset your password if you ever need it.
4 |
--------------------------------------------------------------------------------
/test/api/core/data/invalid-objects.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "Feature",
4 | "properties": {
5 | "id": "PUI-PPI-B9-1",
6 | "value": 150
7 | },
8 | "geometry": {
9 | "type": "LineString",
10 | "coordinates": [
11 | 139.72669982910156,
12 | 35.64739990234375,
13 | 0
14 | ]
15 | }
16 | },
17 | {
18 | "type": "Feature",
19 | "properties": {
20 | "id": "PUI-PPI-B9-2",
21 | "value": 150
22 | },
23 | "geometry": {
24 | "type": "Point",
25 | "coordinates": []
26 | }
27 | },
28 | {
29 | "type": "Feature",
30 | "properties": {
31 | "id": "PUI-PPI-B9-3",
32 | "value": 150
33 | },
34 | "geometry": {
35 | "type": "Point",
36 | "coordinates": [
37 | 139.72669982910156,
38 | 35.64739990234375,
39 | 0
40 | ]
41 | }
42 | },
43 | {
44 | "type": "Feature",
45 | "properties": {
46 | "type": "manual",
47 | "id": "PUI-PPI-B9-4",
48 | "date": "2022-01-07",
49 | "time": "16:20:20"
50 | },
51 | "geometry": {
52 | "type": "Point",
53 | "coordinates": [
54 | 139.72669982910156,
55 | 35.64739990234375,
56 | 0
57 | ]
58 | }
59 | }
60 | ]
--------------------------------------------------------------------------------
/test/api/core/data/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/test/api/core/data/logo.png
--------------------------------------------------------------------------------
/test/api/core/data/valid-objects.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "Feature",
4 | "properties": {
5 | "type": "manual",
6 | "id": "PUI-PPI-B9-1",
7 | "date": "2022-01-07",
8 | "time": "16:20:02",
9 | "value": 61
10 | },
11 | "geometry": {
12 | "type": "Point",
13 | "coordinates": [
14 | 1.95,
15 | 43.31,
16 | 0
17 | ]
18 | }
19 | },
20 | {
21 | "type": "Feature",
22 | "properties": {
23 | "type": "automatic",
24 | "id": "PUI-PPI-B9-2",
25 | "date": "2022-01-07",
26 | "time": "16:20:20",
27 | "value": 150
28 | },
29 | "geometry": {
30 | "type": "Point",
31 | "coordinates": [
32 | 1.95,
33 | 43.31,
34 | 0
35 | ]
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/test/api/core/index.js:
--------------------------------------------------------------------------------
1 | export * from './utils.js'
2 |
--------------------------------------------------------------------------------
/test/api/index.js:
--------------------------------------------------------------------------------
1 | import * as core from './core/index.js'
2 | import * as map from './map/index.js'
3 |
4 | export { core, map }
--------------------------------------------------------------------------------
/test/api/map/data/GetCoverage.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/test/api/map/data/GetCoverage.tif
--------------------------------------------------------------------------------
/test/api/map/data/dataset.grb.dds:
--------------------------------------------------------------------------------
1 | Dataset {
2 | Int32 LatLon_Projection;
3 | Float32 lat[lat = 361];
4 | Float32 lon[lon = 721];
5 | Float64 reftime;
6 | Float64 time[time = 25];
7 | Float32 height_above_ground[height_above_ground = 10];
8 | Grid {
9 | ARRAY:
10 | Float32 Temperature_height_above_ground[time = 25][height_above_ground = 10][lat = 361][lon = 721];
11 | MAPS:
12 | Float64 time[time = 25];
13 | Float32 height_above_ground[height_above_ground = 10];
14 | Float32 lat[lat = 361];
15 | Float32 lon[lon = 721];
16 | } Temperature_height_above_ground;
17 | } mf-arpege-05/2019/11/26/06/T6086_G_T_Hau_20191126060000.grb;
18 |
--------------------------------------------------------------------------------
/test/api/map/data/dataset.grb.dods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/test/api/map/data/dataset.grb.dods
--------------------------------------------------------------------------------
/test/api/map/data/lat_lon_bounds.grb.dods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/test/api/map/data/lat_lon_bounds.grb.dods
--------------------------------------------------------------------------------
/test/api/map/data/subdataset.grb.dods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/test/api/map/data/subdataset.grb.dods
--------------------------------------------------------------------------------
/test/api/map/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kalisio/kdk/f549695948c120831ebc754e53c2d0dedfbb9c55/test/api/map/index.js
--------------------------------------------------------------------------------
/test/client/core/dialogs.js:
--------------------------------------------------------------------------------
1 | import { click, isElementVisible } from './utils.js'
2 |
3 | export async function closeWelcomeDialog (page) {
4 | await click(page, '.q-dialog #close-button')
5 | }
6 |
7 | export async function closeInstallDialog (page) {
8 | await click(page, '.q-dialog #ignore-button')
9 | }
10 |
11 | export async function isToastVisible (page) {
12 | return isElementVisible(page, '[role="alert"]')
13 | }
14 |
--------------------------------------------------------------------------------
/test/client/core/index.js:
--------------------------------------------------------------------------------
1 | export * from './account.js'
2 | export * from './api.js'
3 | export * from './collection.js'
4 | export * from './dialogs.js'
5 | export * from './layout.js'
6 | export * from './runner.js'
7 | export * from './screens.js'
8 | export * from './time.js'
9 | export * from './utils.js'
10 |
--------------------------------------------------------------------------------
/test/client/core/time.js:
--------------------------------------------------------------------------------
1 | import makeDebug from 'debug'
2 |
3 | const debug = makeDebug('kdk:core:test:time')
4 |
5 | export async function setCurrentTime (page, time) {
6 | debug(`Setting current time to ${time}`)
7 | await page.evaluate((time) => {
8 | window.$time.setCurrentTime(time)
9 | }, time)
10 | }
11 |
--------------------------------------------------------------------------------
/test/client/index.js:
--------------------------------------------------------------------------------
1 | import * as core from './core/index.js'
2 | import * as map from './map/index.js'
3 |
4 | export { core, map }
--------------------------------------------------------------------------------
/test/client/map/api.js:
--------------------------------------------------------------------------------
1 | import * as core from '../core/index.js'
2 |
3 | // Decorate core API with some of the required features for map
4 | export class Api extends core.Api {
5 | createClient (options = {}) {
6 | const client = super.createClient(options)
7 |
8 | client.createGeoJsonFeature = async (layerId, coordinates, properties = {}, service = 'features') => {
9 | // Deduce geometry type from coordinates
10 | let type = 'Point'
11 | if (Array.isArray(coordinates[0])) {
12 | type = (Array.isArray(coordinates[0][0]) ? 'Polygon' : 'LineString')
13 | }
14 | const feature = await client.getService(service).create(Object.assign({
15 | type: 'Feature',
16 | geometry: {
17 | type,
18 | coordinates
19 | },
20 | layer: layerId
21 | }, properties))
22 | return feature
23 | }
24 |
25 | client.updateGeoJsonFeature = async (featureId, coordinates, properties = {}, service = 'features') => {
26 | const feature = await client.getService(service).patch(featureId, Object.assign({
27 | 'geometry.coordinates': coordinates
28 | }, properties))
29 | return feature
30 | }
31 |
32 | return client
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/client/map/index.js:
--------------------------------------------------------------------------------
1 | export * from './api.js'
2 | export * from './catalog.js'
3 | export * from './controls.js'
4 | export * from './time.js'
5 | export * from './utils.js'
6 |
--------------------------------------------------------------------------------
/test/client/map/time.js:
--------------------------------------------------------------------------------
1 | import makeDebug from 'debug'
2 | import * as core from '../core/index.js'
3 |
4 | const debug = makeDebug('kdk:map:test:time')
5 |
6 | export async function openTimeline (page) {
7 | const isTimelineOpened = await core.isPaneVisible(page, 'bottom')
8 | if (!isTimelineOpened) await core.clickOpener(page, 'bottom')
9 | return isTimelineOpened
10 | }
11 |
12 | export async function clickTimelineHour (page, hour, wait = 1000) {
13 | const isTimelineOpened = await openTimeline(page)
14 | await core.click(page, '#time-button', wait)
15 | const xpath = `//div[contains(@class, "q-time__clock-pos-${hour}")]`
16 | const elements = await page.$x(xpath)
17 | if (elements.length > 0) {
18 | elements[0].click()
19 | await page.waitForTimeout(wait)
20 | debug(`Clicked timeline hour ${hour}`)
21 | } else {
22 | debug(`Timeline hour ${hour} not found`)
23 | }
24 | if (!isTimelineOpened) await core.clickOpener(page, 'bottom')
25 | }
26 |
--------------------------------------------------------------------------------
/test/client/map/utils.js:
--------------------------------------------------------------------------------
1 | import * as core from '../core/index.js'
2 |
3 | /* Moves the map for a specific times:
4 | - in a choosen direction (left, right, up, down)
5 | - zoom in or out
6 | */
7 | export async function moveMap (page, direction, times, wait = 500) {
8 | let dir
9 | if (direction === 'up') { dir = 'ArrowUp' } else if (direction === 'down') { dir = 'ArrowDown' } else if (direction === 'left') { dir = 'ArrowLeft' } else if (direction === 'right') { dir = 'ArrowRight' } else if (direction === 'in') { dir = '+' } else if (direction === 'out') { dir = '-' }
10 | await page.focus('#map')
11 | await page.waitForTimeout(wait)
12 | let i = 0
13 | for (i = 0; i < times; i++) {
14 | await page.keyboard.press(dir)
15 | await page.waitForTimeout(wait)
16 | }
17 | }
18 |
19 | /* Zooms the map to a specific level
20 | */
21 | export async function zoomToLevel (page, storePath, level, wait = 500) {
22 | // FIXME: better way to get activity state ?
23 | // At current time the activity should implement state saving to make it work
24 | const zoom = await core.getFromStore(page, `${storePath}.state.zoom`)
25 | const diff = level - zoom
26 | const action = (level > zoom) ? 'in' : 'out'
27 | await moveMap(page, action, Math.abs(diff), wait)
28 | await page.waitForTimeout(wait)
29 | }
30 |
--------------------------------------------------------------------------------