diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74dfb91ee9..082c11aceb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ In order to contribute you can submitting bug reports or suggest some correction ## Code of Conduct This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md), please read it and follow it -before contributing. If you find someone that is not respecting it please report its behaviour. +before contributing. If you find someone that is not respecting it please report its behavior. ## How Can I Contribute diff --git a/docs/products/fast_data_v2/farm_data/CHANGELOG.md b/docs/products/fast_data_v2/farm_data/CHANGELOG.md index d546248b28..224d38d843 100644 --- a/docs/products/fast_data_v2/farm_data/CHANGELOG.md +++ b/docs/products/fast_data_v2/farm_data/CHANGELOG.md @@ -9,6 +9,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.1] - 2026-02-19 + +### Fixed + +- Fixed control plane startup behavior to resume +- Explicit error on missing SERVICE_NAME missing var + ## [0.6.0] - 2026-02-02 ### BREAKING diff --git a/docs/products/fast_data_v2/kango/CHANGELOG.md b/docs/products/fast_data_v2/kango/CHANGELOG.md index e3c52f4a77..22b6309fab 100644 --- a/docs/products/fast_data_v2/kango/CHANGELOG.md +++ b/docs/products/fast_data_v2/kango/CHANGELOG.md @@ -9,6 +9,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.1] - 2026-02-19 + +### Fixed + +- Fixed control plane startup behavior to resume +- Explicit error on missing SERVICE_NAME missing var + ## [0.6.0] - 2026-02-02 ### BREAKING diff --git a/docs/products/fast_data_v2/runtime_management/application_configuration.md b/docs/products/fast_data_v2/runtime_management/application_configuration.md index b04d3ea70e..ccdd045d9f 100644 --- a/docs/products/fast_data_v2/runtime_management/application_configuration.md +++ b/docs/products/fast_data_v2/runtime_management/application_configuration.md @@ -90,6 +90,55 @@ During the deployment process, the files will be automatically applied to the ac Without these permissions, the Control Plane service cannot discover Fast Data workloads (Mongezium, Stream Processor, Farm Data, Kango) in your namespace and the Control Plane Frontend will not display your pipeline. +:::caution +When deploying the `control-plane-role.yaml` and `control-plane-role-binding.yaml` manifests, the Service Account or user performing the deployment (the "deployer") **must have sufficient permissions to manage RBAC resources within the target namespace**. +::: + +If the deployer lacks these permissions, the pipeline will fail with an error similar to: + +> `User "..." cannot patch resource "roles" in API group "rbac.authorization.k8s.io" in the namespace "..."` + +This typically happens because, in many Kubernetes distributions (such as Azure AKS), the ability to modify security roles is restricted to prevent unauthorized privilege escalation. + +**Corrective Action** + +Before deploying these manifests, ensure that the deployer Service Account (e.g., `console-deployer`) has a **Role** or **ClusterRole** bound to it that allows the following actions in the target namespace: + +* **Resources**: `roles`, `rolebindings` +* **API Group**: `rbac.authorization.k8s.io` +* **Verbs**: `get`, `list`, `watch`, `create`, `update`, `patch` + +#### **Example: Granting RBAC management to the deployer** + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: rbac-manager-role + namespace: {YOUR_NAMESPACE} +rules: + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["roles", "rolebindings"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rbac-manager-binding + namespace: {YOUR_NAMESPACE} +subjects: + - kind: ServiceAccount + name: console-deployer # The name of your CI/CD service account + namespace: mia-platform +roleRef: + kind: Role + name: rbac-manager-role + apiGroup: rbac.authorization.k8s.io + +``` + +In some managed environments like **Azure AKS**, ensure that your Azure identity also has the "Azure Kubernetes Service Cluster Admin" or "Azure Kubernetes Service RBAC Admin" role if you are using Azure RBAC integration. + #### In-Memory Storage You can opt for in-memory storage for your pipeline runtime states instead of persisting them. @@ -113,8 +162,6 @@ The Control Plane Frontend is already pre-configured and ready to be deployed. N The Envoy API Gateway serves as the entry point for the Fast Data Control Plane application, providing essential routing and security capabilities. -The Envoy API Gateway microservice is pre-configured and ready to be deployed. The routing configuration is automatically generated based on the endpoint definitions, and no manual intervention is required. - #### Exposed Endpoints The application pre-configures two endpoints that are automatically routed by Envoy: @@ -123,6 +170,16 @@ The application pre-configures two endpoints that are automatically routed by En - **`/`** - Routes requests to the Control Plane Frontend service +#### Required Advanced Configuration + +Since the application uses the **WebSocket protocol** for bidirectional communication, you must add the following configuration to the **patches.yaml** file within the Advanced Configurations section of the Design Area: + +```yaml +- listener_name: frontend + 'filter_chains.0.filters.0.typed_config.upgrade_configs': + upgrade_type: "websocket" +``` + ## Workloads Configuration To enable proper communication between the Control Plane and the Fast Data workloads deployed in your namespace, each Fast Data workload must be configured to connect to the Control Plane. @@ -137,8 +194,14 @@ For each of the Fast Data workloads (Mongezium, Stream Processor, Farm Data, and } ``` +Moreover, it is necessary to add the `SERVICE_NAME` environment variable with the following parameters: + +- **Value Type**: `From Downward API` +- **Field Path**: `metadata.labels['KEY']` +- **Label Key**: `app.kubernetes.io/name` + :::note -Without this configuration, the Fast Data workloads will operate independently and will not be visible or controllable through the Control Plane interface. +Without this configuration, the Fast Data workloads will operate independently and will not be controllable through the Control Plane interface. ::: ### Additional Configuration Parameters @@ -148,7 +211,7 @@ Optionally, it is possible to add other parameters to the "control plane" config - **`onCreate`**: Initial state when the workload for the first time is deployed and connects to the control plane. Available values are `"pause"` or `"resume"`. Set to `"pause"` to ensure the workload waits for explicit Control Plane commands from UI before start data consumption from data streams. :::note -If no `onCreate` behavior is defined in the microservice ConfigMap, the **default runtime state** is **Running**. This design choice safeguards real-time data flows by preventing service interruptions when adding Control Plane connectivity to established Fast Data workloads. +If no `onCreate` behavior is defined in the microservice ConfigMap, the **default runtime state** is **Running**, so the **resume** state. This design choice safeguards real-time data flows by preventing service interruptions when adding Control Plane connectivity to established Fast Data workloads. `onCreate` is applied solely if the Fast Data workload is the first time that is deployed. Otherwise, the parameter will be not considered by Control Plane, as it reads the last saved runtime state. ::: @@ -165,7 +228,7 @@ If no `onCreate` behavior is defined in the microservice ConfigMap, the **defaul ## Application Deployment -Once you have concluded all the above mentioned configuration steps, you can easily deploy your Project configuration! +Once you have concluded all the above mentioned configuration steps, it's time to **deploy your Project**! Verify the success of your deploy by: diff --git a/docs/products/fast_data_v2/runtime_management/compatibility_matrix.md b/docs/products/fast_data_v2/runtime_management/compatibility_matrix.md index 9e9caca165..6763e22632 100644 --- a/docs/products/fast_data_v2/runtime_management/compatibility_matrix.md +++ b/docs/products/fast_data_v2/runtime_management/compatibility_matrix.md @@ -13,23 +13,23 @@ Please ensure that versions shown in the matrix are respected in your deployed e | Service | Version | MongoDB | |-------------------------|---------|---------| -| Control Plane | 0.1.0 | \>=7.0 | +| Control Plane | 0.1.1-mongodb | \>=7.0 | ## Fast Data Services Here is provided the compatibility matrix between Control Plane components and the Fast Data Engine v2 workloads that need to communicate with them. Please ensure that your services respect the following matrix. -| [Control Plane Frontend](/products/fast_data_v2/runtime_management/application_configuration.md) | [Control Plane Piper](/products/fast_data_v2/runtime_management/application_configuration.md) | [Mongezium](/products/fast_data_v2/mongezium_cdc/10_Overview.md) | [Stream Processor](/products/fast_data_v2/stream_processor/10_Overview.md) | [Farm Data](/products/fast_data_v2/farm_data/10_Overview.md) | [Kango](/products/fast_data_v2/kango/10_Overview.md) | +| [Control Plane Frontend](/products/fast_data_v2/runtime_management/application_configuration.md) | [Control Plane](/products/fast_data_v2/runtime_management/application_configuration.md) | [Mongezium](/products/fast_data_v2/mongezium_cdc/10_Overview.md) | [Stream Processor](/products/fast_data_v2/stream_processor/10_Overview.md) | [Farm Data](/products/fast_data_v2/farm_data/10_Overview.md) | [Kango](/products/fast_data_v2/kango/10_Overview.md) | |:----------------------:|:-------------------:|:----------------------------------------------------------:|:---------------------------------------------------------------------:|:------------------------------------------------------:|:----------------------------------------------:| -| 0.1.0 | 0.1.0 | \>=0.5.0 | \>=0.6.0 | \>=0.6.0 | \>=0.6.0 | +| 0.1.2 | 0.1.1-mongodb | \>=0.5.0 | \>=0.6.0 | \>=0.6.0 | \>=0.6.0 | ## Service Latest Versions | Service | Version | |-----------------------------------------------------------------------------------------------|---------| -| [Control Plane Frontend](/products/fast_data_v2/runtime_management/application_configuration.md) | 0.1.0 | -| [Control Plane Piper](/products/fast_data_v2/runtime_management/application_configuration.md) | 0.1.0 | +| [Control Plane Frontend](/products/fast_data_v2/runtime_management/application_configuration.md) | 0.1.2 | +| [Control Plane](/products/fast_data_v2/runtime_management/application_configuration.md) | 0.1.1-mongodb | | [Mongezium](/products/fast_data_v2/mongezium_cdc/10_Overview.md) | 0.5.0 | | [Stream Processor](/products/fast_data_v2/stream_processor/10_Overview.md) | 0.6.0 | | [Farm Data](/products/fast_data_v2/farm_data/10_Overview.md) | 0.6.0 | @@ -37,11 +37,11 @@ Please ensure that your services respect the following matrix. ## Internal Compatibility -| Service | Control Plane Frontend | Control Plane Piper | Mongezium | Stream Processor | Farm Data | Kango | +| Service | Control Plane Frontend | Control Plane | Mongezium | Stream Processor | Farm Data | Kango | |---------------------------:|:----------------------:|:-------------------:|:---------:|:----------------:|:---------:|:-----:| -| Control Plane Frontend - 0.1.0 | _N/A_ | 0.1.0 | 0.5.0 | 0.6.0 | 0.6.0 | 0.6.0 | -| Control Plane Piper - 0.1.0 | 0.1.0 | _N/A_ | 0.5.0 | 0.6.0 | 0.6.0 | 0.6.0 | -| Mongezium - 0.5.0 | 0.1.0 | 0.1.0 | _N/A_ | 0.6.0 | 0.6.0 | 0.6.0 | -| Stream Processor - 0.6.0 | 0.1.0 | 0.1.0 | 0.5.0 | _N/A_ | 0.6.0 | 0.6.0 | -| Farm Data - 0.6.0 | 0.1.0 | 0.1.0 | 0.5.0 | 0.6.0 | _N/A_ | 0.6.0 | -| Kango - 0.6.0 | 0.1.0 | 0.1. | 0.5.0 | 0.6.0 | 0.6.0 | _N/A_ | +| Control Plane Frontend - 0.1.2 | _N/A_ | 0.1.1-mongodb | 0.5.0 | 0.6.0 | 0.6.0 | 0.6.0 | +| Control Plane - 0.1.1-mongodb | 0.1.2 | _N/A_ | 0.5.0 | 0.6.0 | 0.6.0 | 0.6.0 | +| Mongezium - 0.5.0 | 0.1.2 | 0.1.1-mongodb | _N/A_ | 0.6.0 | 0.6.0 | 0.6.0 | +| Stream Processor - 0.6.0 | 0.1.2 | 0.1.1-mongodb | 0.5.0 | _N/A_ | 0.6.0 | 0.6.0 | +| Farm Data - 0.6.0 | 0.1.2 | 0.1.1-mongodb | 0.5.0 | 0.6.0 | _N/A_ | 0.6.0 | +| Kango - 0.6.0 | 0.1.2 | 0.1.1-mongodb | 0.5.0 | 0.6.0 | 0.6.0 | _N/A_ | diff --git a/docs/products/fast_data_v2/stream_processor/CHANGELOG.md b/docs/products/fast_data_v2/stream_processor/CHANGELOG.md index a705601cc4..afa712a4a0 100644 --- a/docs/products/fast_data_v2/stream_processor/CHANGELOG.md +++ b/docs/products/fast_data_v2/stream_processor/CHANGELOG.md @@ -10,6 +10,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.1] - 2026-02-19 + +### Fixed + +- Fixed control plane startup behavior to resume +- Explicit error on missing SERVICE_NAME missing var + ## [0.6.0] - 2026-02-02 ### BREAKING diff --git a/release-notes/v14.5.0.mdx b/release-notes/v14.5.0.mdx index 1b32200825..f7278c01f5 100644 --- a/release-notes/v14.5.0.mdx +++ b/release-notes/v14.5.0.mdx @@ -7,16 +7,7 @@ image: "img/release-note-link-preview.png" import Accordion from '@site/src/components/Accordion/index.js'; import dataAccordion from '@site/src/config/release-notes/release-note-v14-5-0.json'; -_February 05th, 2026_ - -:::info - -Mia-Platform Console v14.5.0 is **now in Preview** and will be generally available on February 19th. - -Console SaaS users can try out v14.5.0 latest improvements in Preview! Open a Service Request to ask for the creation of a sandbox Company in case you do not have access to any Company. - -For self-hosted installations, please read the [following guidelines](#how-to-update-your-console). -::: +_February 19th, 2026_ ## Fast Data Control Plane v2 @@ -24,7 +15,7 @@ Let's welcome the **Fast Data Control Plane v2**, the runtime management solutio Fast Data Control Plane application provides a general overview of the Fast Data v2 pipelines released on the runtime environment, and allows to monitor and govern the execution steps of your data pipelines. -Discover all the capabilities and benefits of Fast Data Control Plane v2 in the [official documentation](/docs/14.5.0/products/fast_data_v2/runtime_management/overview). +Discover all the capabilities and benefits of Fast Data Control Plane v2 in the [official documentation](/docs/products/fast_data_v2/runtime_management/overview). ![Control Plane Fast Data Pipeline](img/fast-data-pipeline.png) @@ -52,7 +43,7 @@ To try it, go the **Feature Preview** section inside your **Project settings**, ## How to update your Console -For self-hosted installations, please head to the [self hosted upgrade guide](/docs/infrastructure/self-hosted/installation-chart/how-to-upgrade) or contact your Mia-Platform referent and upgrade to _Console Helm Chart_ `v15.0.8-beta.1`. +For self-hosted installations, please head to the [self hosted upgrade guide](/docs/infrastructure/self-hosted/installation-chart/how-to-upgrade) or contact your Mia-Platform referent and upgrade to _Console Helm Chart_ `v15.0.8`. ### Bill of materials diff --git a/release-notes/v14.5.1.mdx b/release-notes/v14.5.1.mdx new file mode 100644 index 0000000000..d853530799 --- /dev/null +++ b/release-notes/v14.5.1.mdx @@ -0,0 +1,70 @@ +--- +id: v14.5.1 +title: Version 14.5.1 Release Notes +image: "img/release-note-link-preview.png" +--- + +import Accordion from '@site/src/components/Accordion/index.js'; +import dataAccordion from '@site/src/config/release-notes/release-note-v14-5-1.json'; + +_February 19th, 2026_ + +:::info + +Mia-Platform Console v14.5.1 is **now in Preview** and will be generally available on March 05th. + +Console SaaS users can try out v14.5.1 latest improvements in Preview! Open a Service Request to ask for the creation of a sandbox Company in case you do not have access to any Company. + +For self-hosted installations, please read the [following guidelines](#how-to-update-your-console). +::: + + + +## How to update your Console + +For self-hosted installations, please head to the [self hosted upgrade guide](/docs/infrastructure/self-hosted/installation-chart/how-to-upgrade) or contact your Mia-Platform referent and upgrade to _Console Helm Chart_ `v15.0.9-beta.0`. + +### Bill of materials + +| Image repository | Version | +| ----------------------------------------------------------------------- | :-------------: | +| docker.io/envoyproxy/ratelimit | 19f2079f | +| nexus.mia-platform.eu/api-portal/website | 2.2.0 | +| nexus.mia-platform.eu/back-kit/mfe-toolkit-on-prem | 1.3.10 | +| nexus.mia-platform.eu/backoffice/login-site | 7.2.3 | +| nexus.mia-platform.eu/console/aggregated-website | 1.5.57 | +| nexus.mia-platform.eu/console/api-gateway | 0.2.9 | +| nexus.mia-platform.eu/console/backend | 32.9.1 | +| nexus.mia-platform.eu/console/catalog-service | 1.7.1 | +| nexus.mia-platform.eu/console/deploy-service | 8.1.2 | +| nexus.mia-platform.eu/console/environments-variables | 3.6.1 | +| nexus.mia-platform.eu/console/events-manager | 1.4.4 | +| nexus.mia-platform.eu/console/extensibility-manager | 2.1.0 | +| nexus.mia-platform.eu/console/favorites-service | 2.3.1 | +| nexus.mia-platform.eu/console/feature-toggle-service | 1.3.7 | +| nexus.mia-platform.eu/console/kubernetes-service | 8.4.6 | +| nexus.mia-platform.eu/console/license-manager | 3.0.3 | +| nexus.mia-platform.eu/console/license-metrics-generator | 6.0.6 | +| nexus.mia-platform.eu/console/mcp-server | 1.2.1 | +| nexus.mia-platform.eu/console/mia-assistant | 1.3.8 | +| nexus.mia-platform.eu/console/mia-craft-bff | 1.2.5 | +| nexus.mia-platform.eu/console/notification-provider | 2.2.5 | +| nexus.mia-platform.eu/console/project-service | 2.1.0 | +| nexus.mia-platform.eu/console/rbac-manager-bff | 2.1.2 | +| nexus.mia-platform.eu/console/scripts/bindings-cleaner | 1.2.2 | +| nexus.mia-platform.eu/console/scripts/configuration-history-cleaner | 0.4.1 | +| nexus.mia-platform.eu/console/scripts/marketplace-sync | 10.10.1 | +| nexus.mia-platform.eu/console/scripts/mia-assistant-embeddings-importer | latest | +| nexus.mia-platform.eu/console/scripts/software-catalog-sync | 0.7.17 | +| nexus.mia-platform.eu/console/scripts/version-upgrader | 11.1.2-hotfix.0 | +| nexus.mia-platform.eu/console/tenant-overview | 4.1.0 | +| nexus.mia-platform.eu/core/authentication-service | 3.13.1 | +| nexus.mia-platform.eu/core/authorization-service | 2.4.3 | +| nexus.mia-platform.eu/core/client-credentials | 3.4.1 | +| nexus.mia-platform.eu/core/crud-service | 6.10.3 | +| nexus.mia-platform.eu/core/proxy-manager | 3.5.0 | +| nexus.mia-platform.eu/core/swagger-aggregator | 3.9.6 | +| nexus.mia-platform.eu/microlc/middleware | 3.4.0 | +| nexus.mia-platform.eu/plugins/files-service | 2.10.5 | +| nexus.mia-platform.eu/plugins/ses-mail-notification-service | 3.5.0 | +| nexus.mia-platform.eu/rond-authz/rond | 1.14.2 | diff --git a/release-notes/versions.md b/release-notes/versions.md index 13b8147cc7..cce6d08d15 100644 --- a/release-notes/versions.md +++ b/release-notes/versions.md @@ -9,8 +9,19 @@ import Changelog from '@site/src/components/Changelog'; +## [v14.5.1](/release-notes/v14.5.1.mdx) +*February 19th, 2026* + +This release enhances the merge capabilities in the Console Design Area by introducing **support for merging configurations from versions**, complementing the existing merge from revisions feature. +Additionally, the **Orchestrator Generator** payload has been enriched with configuration change identifiers and public variables. +For **Fast Data**, there are some available version updates for both Fast Data Control Plane v2 services and Fast Data Engine service. + +[Read the release notes](/release-notes/v14.5.1.mdx) + +--- + ## [v14.5.0](/release-notes/v14.5.0.mdx) -*February 05th, 2026* +*February 19th, 2026* This release introduces the **Fast Data Control Plane v2**, the runtime management solution for Fast Data v2, that allows to visualize and control Fast Data v2 pipelines at runtime. Additionally, a new **interface for merging configurations** is now available in Beta, improving the DevX in the Console Design Area. diff --git a/sidebarsReleaseNotes.js b/sidebarsReleaseNotes.js index a0c1f12384..7d8f212f28 100644 --- a/sidebarsReleaseNotes.js +++ b/sidebarsReleaseNotes.js @@ -11,6 +11,7 @@ export default { }, "items": [ {"id": "versions", "type": "doc"}, + {"id": "v14.5.1", "type": "doc", "label": "v14.5.1"}, {"id": "v14.5.0", "type": "doc", "label": "v14.5.0"}, {"id": "v14.4.2", "type": "doc", "label": "v14.4.2 - LTS"}, {"id": "v14.4.1", "type": "doc", "label": "v14.4.1"}, diff --git a/src/config/release-notes/release-note-v14-5-1.json b/src/config/release-notes/release-note-v14-5-1.json new file mode 100644 index 0000000000..51308ba4e9 --- /dev/null +++ b/src/config/release-notes/release-note-v14-5-1.json @@ -0,0 +1,74 @@ +[ + { + "title": "Console", + "icon": "console", + "defaultOpen": true, + "type": "versions", + "items": { + "newFeatures": [ + { + "title": "Merge of configurations starting from a version", + "description": [ + "In the Design Area, we have added support for merging from versions, in addition to the existing merge from revisions feature.", + "Clicking the _Merge from another revision_ icon now displays a list of all available revisions and versions of your Project, allowing you to select the one you wish to merge into your current configuration." + ] + } + ], + "improvements": [ + { + "title": "Orchestrator Generator payload information enhancement", + "description": [ + "When using the [Orchestrator Generator](/docs/products/console/company-configuration/providers/extensions/orchestrator-generator/overview) in your Enhanced Workflow Project, the sent payload now includes:", + "- **`changesId`**: the configuration change identifier, within the `configurationRef` field", + "- the list of **public variables** for the specific deployment environment, available within the `unsecretedVariables` field." + ] + } + ], + "bugFixes": [] + } + }, + { + "title": "Fast Data", + "icon": "fast-data", + "defaultOpen": true, + "type": "versions", + "items": { + "newFeatures": [], + "improvements": [ + { + "title": "Fast Data Control Plane v2 Application", + "description": [ + "The new versions of Fast Data Control Plane v2 services are available: the `v0.1.1-mongodb` (and `v0.1.1`) of the _Control Plane_ service are available, the `v0.1.2` of the _Control Plane Frontend_ service is available.", + "For the _Ingest_ execution step implemented by [Mongezium CDC plugin](/docs/14.5.0/products/fast_data_v2/mongezium_cdc/overview), now source assets are rendered in Control Plane UI.", + "For more information about service latest versions, check out the [compatibility matrix](/docs/14.5.1/products/fast_data_v2/runtime_management/compatibility_matrix#service-latest-versions)." + ] + }, + { + "title": "Stream Processor v0.6.1", + "description": [ + "The new version `v0.6.1` of the _Stream Processor_ is available!", + "This version introduces some fixes about service default startup behavior when using Fast Data Control Plane v2.", + "Refer to the [JSON Schema](https://cdn.mia-platform.eu/runtime/platform/data-fabric/stream-processor/v0.6.1/stream-processor.schema.json) for configuration details and check the service [changelog](/docs/14.5.1/products/fast_data_v2/stream_processor/changelog) for more information." + ] + }, + { + "title": "Farm Data v0.6.1", + "description": [ + "The new version `v0.6.1` of the _Farm Data_ is available!", + "This version introduces some fixes about service default startup behavior when using Fast Data Control Plane v2.", + "Refer to the [JSON Schema](https://cdn.mia-platform.eu/runtime/platform/data-fabric/farm-data/v0.6.1/farm-data.schema.json) for configuration details and check the service [changelog](/docs/14.5.1/products/fast_data_v2/farm_data/changelog) for more information." + ] + }, + { + "title": "Kango v0.6.1", + "description": [ + "The new version `v0.6.1` of the _Kango_ service is available!", + "This version introduces some fixes about service default startup behavior when using Fast Data Control Plane v2.", + "Refer to the [JSON Schema](https://cdn.mia-platform.eu/runtime/platform/data-fabric/kango/v0.6.1/kango.schema.json) for configuration details and check the service [changelog](/docs/14.5.1/products/fast_data_v2/kango/changelog) for more information." + ] + } + ], + "bugFixes": [] + } + } +] diff --git a/versioned_docs/version-14.5.0/products/fast_data_v2/runtime_management/application_configuration.md b/versioned_docs/version-14.5.0/products/fast_data_v2/runtime_management/application_configuration.md index b04d3ea70e..f554937862 100644 --- a/versioned_docs/version-14.5.0/products/fast_data_v2/runtime_management/application_configuration.md +++ b/versioned_docs/version-14.5.0/products/fast_data_v2/runtime_management/application_configuration.md @@ -137,8 +137,14 @@ For each of the Fast Data workloads (Mongezium, Stream Processor, Farm Data, and } ``` +Moreover, it is necessary to add the `SERVICE_NAME` environment variable with the following parameters: + +- **Value Type**: `From Downward API` +- **Field Path**: `metadata.labels['KEY']` +- **Label Key**: `app.kubernetes.io/name` + :::note -Without this configuration, the Fast Data workloads will operate independently and will not be visible or controllable through the Control Plane interface. +Without this configuration, the Fast Data workloads will operate independently and will not be controllable through the Control Plane interface. ::: ### Additional Configuration Parameters @@ -148,7 +154,7 @@ Optionally, it is possible to add other parameters to the "control plane" config - **`onCreate`**: Initial state when the workload for the first time is deployed and connects to the control plane. Available values are `"pause"` or `"resume"`. Set to `"pause"` to ensure the workload waits for explicit Control Plane commands from UI before start data consumption from data streams. :::note -If no `onCreate` behavior is defined in the microservice ConfigMap, the **default runtime state** is **Running**. This design choice safeguards real-time data flows by preventing service interruptions when adding Control Plane connectivity to established Fast Data workloads. +If no `onCreate` behavior is defined in the microservice ConfigMap, the **default runtime state** is **Running**, so the **resume** state. This design choice safeguards real-time data flows by preventing service interruptions when adding Control Plane connectivity to established Fast Data workloads. `onCreate` is applied solely if the Fast Data workload is the first time that is deployed. Otherwise, the parameter will be not considered by Control Plane, as it reads the last saved runtime state. ::: @@ -165,7 +171,7 @@ If no `onCreate` behavior is defined in the microservice ConfigMap, the **defaul ## Application Deployment -Once you have concluded all the above mentioned configuration steps, you can easily deploy your Project configuration! +Once you have concluded all the above mentioned configuration steps, it's time to **deploy your Project**! Verify the success of your deploy by: diff --git a/versioned_docs/version-14.5.1/getting-started/faqs.md b/versioned_docs/version-14.5.1/getting-started/faqs.md new file mode 100644 index 0000000000..7d13030abd --- /dev/null +++ b/versioned_docs/version-14.5.1/getting-started/faqs.md @@ -0,0 +1,76 @@ +--- +id: faqs +title: Mia-Platform FAQs +sidebar_label: Mia-Platform FAQs +--- + +### Mia-Platform Console + +#### What is Mia-Platform Console? +Mia-Platform Console is a Platform Builder used to create and manage a custom Internal Developer Platform (IDP). It is a centralized developer portal designed to industrialize and govern the entire cloud-native software development lifecycle, from infrastructure connection and API design to deployment and monitoring. + +#### What are the main benefits of using the Console? +The main benefits are improved governance, developer self-service, and a lower cognitive load. It empowers development teams with self-service capabilities, abstracts away cloud-native complexity, and allows platform engineering teams to enforce standards and best practices, creating "golden paths" for developers. + +For a more detailed list of questions and answers about this product, see the [dedicated FAQ section](/getting-started/faqs/mia-platform-console-faqs.md). + +*** + +### Mia-Platform Fast Data + +#### What is Mia-Platform Fast Data? +Mia-Platform Fast Data is a solution for building a **Digital Integration Hub (DIH)**. It collects data from various sources, known as **Systems of Record (SoR)**, standardizes them into collections called **Projections**, and then aggregates them in near real-time into read-optimized data models called **Single Views**. + +#### Why would an organization use Fast Data? +Organizations use Fast Data to create a high-performance, real-time data layer that decouples modern applications from legacy systems. This approach offloads legacy systems, ensures data is consistently available 24/7, and provides an up-to-date, aggregated view of fast-changing data to be consumed by APIs and applications with low latency. + +For a more detailed list of questions and answers about this product, see the [dedicated FAQ section](/getting-started/faqs/mia-platform-fast-data-faqs.md). + +*** + +### Mia-Platform Microfrontend Composer + +#### What is the Microfrontend Composer? +The Microfrontend Composer is a low-code/no-code tool within the Console for building user interfaces like backoffices, dashboards, and developer portals. It allows users to visually assemble pages by configuring and combining pre-built or custom web components. + +#### How does it work and what are its key components? +The Composer is powered by **micro-lc**, an open-source microfrontend orchestrator that renders the final application. Pages are typically built using **Back-Kit**, a library of pre-built web components (tables, forms, buttons) that communicate with each other through an event-driven system. The entire application configuration is served by a lightweight web server. + +For a more detailed list of questions and answers about this product, see the [dedicated FAQ section](/getting-started/faqs/mia-platform-microfrontend-composer-faqs.md). + +*** + +### Mia-Platform Data Catalog + +#### What is the purpose of the Mia-Platform Data Catalog? +The Data Catalog is a centralized solution for discovering, understanding, and governing all data assets within an organization. It functions as a single source of truth, allowing users to find relevant datasets, understand their quality, and trace their origin and transformations (lineage). + +#### What kind of information can I find in the Data Catalog? +For each data asset (like a database table or a Fast Data Projection), you can find detailed metadata, including its schema, a business description, owners, and tags. A key feature is **Data Lineage**, which provides a visual graph showing the data's origin and how it flows and transforms across different systems. + +For a more detailed list of questions and answers about this product, see the [dedicated FAQ section](/getting-started/faqs/mia-platform-data-catalog-faqs.md). + +*** + +### Mia-Platform Software Catalog + +#### What is the Software Catalog and how is it different from the Marketplace? +The **Software Catalog** is the backend management solution used by platform engineers to create, version, and govern all reusable software assets (like Plugins and Templates). The **Marketplace** is the user-facing UI inside the Console, where developers browse and consume the assets made available by the Software Catalog to add them to their projects. + +#### Why is the Software Catalog important for a Platform Engineering team? +It is a crucial tool for implementing an effective Internal Developer Platform (IDP). It allows a platform team to enforce standardization and best practices by providing a curated library of approved components. This promotes reusability, accelerates development by offering "golden paths," and ensures governance over the software assets used across the organization. + +For a more detailed list of questions and answers about this product, see the [dedicated FAQ section](/getting-started/faqs/mia-platform-software-catalog-faqs.md). + +*** + +### Runtime Components + +#### What are Runtime Components? +Runtime Components are ready-to-use software assets available in the Marketplace that can be added to projects to speed up development. They are the functional building blocks, like plugins and templates, that developers use to assemble their applications on the platform. + +#### What is the main difference between a Plugin and a Template? +* A **Plugin** is a pre-built, ready-to-use Docker image that functions like a "black box." You configure it but do not modify its source code. It's used for common, standardized functionalities. +* A **Template** is a boilerplate Git repository that serves as a starting point. It gets cloned into your project, giving you full ownership of the code to modify and extend as needed. It's used for building custom services. + +For a more detailed list of questions and answers about this product, see the [dedicated FAQ section](/getting-started/faqs/mia-platform-runtime-components-faqs.md). diff --git a/versioned_docs/version-14.5.1/getting-started/faqs/mia-platform-console-faqs.md b/versioned_docs/version-14.5.1/getting-started/faqs/mia-platform-console-faqs.md new file mode 100644 index 0000000000..3243b73f83 --- /dev/null +++ b/versioned_docs/version-14.5.1/getting-started/faqs/mia-platform-console-faqs.md @@ -0,0 +1,246 @@ +--- +id: mia-platform-console-faqs +title: Mia-Platform Console FAQs +sidebar_label: Console FAQs +--- + +### General Concepts & Project Management + +#### What is the Mia-Platform Console? +The Mia-Platform Console is a cloud-native Platform Builder that functions as an **Internal Developer Platform (IDP)**. It's designed to help organizations industrialize and govern the entire software development lifecycle. By providing a centralized **developer hub**, it simplifies cloud-native complexity, empowers development teams with self-service capabilities, and allows **platform engineers** to enforce governance and **platform engineering best practices**. The Mia-Platform Console manages everything from infrastructure connection to API design, deployment, and monitoring. +[Discover more](/products/console/overview-dev-suite.md) + +#### What is a "Company" in the Mia-Platform Console? +A **Company** is the highest-level organizational unit in the Mia-Platform Console. It acts as a container for multiple **Projects** and provides centralized governance. At the Company level, you configure shared resources that are inherited by all its projects, such as Kubernetes cluster connections, **Providers** (like Git providers and secret managers), and default project templates. This structure allows an organization to manage different business units or teams in an isolated and organized manner. +[Discover more](/products/console/company-configuration/create-company.md) + +#### What is the difference between a Project and an Environment? +* A **Project** is where you build your services. It contains all the necessary configurations, including microservices, APIs, data models (CRUDs), and public variables. Each Project belongs to a Company. +* An **Environment** represents a specific deployment stage within a Project, such as `Development`, `Staging`, or `Production`. Each environment is mapped to a unique namespace in a Kubernetes cluster, allowing you to deploy and test your services in isolated runtime contexts. + [Discover more](/products/console/project-configuration/application-project.md) + +#### What is a "Project Blueprint" and why is it important? +A **Project Blueprint** is a pre-configured Git repository that serves as a starting point for creating new Projects. It includes a default structure, sample configurations, and often pre-defined **CI/CD** pipelines. Using templates is a core aspect of **platform engineering best practices** because it enforces standardization, ensures consistency across projects, and dramatically speeds up the onboarding of new applications by providing developers with a "golden path". +[Discover more](/products/console/company-configuration/project-blueprint.md) + +#### How do I create a new Project? +To create a new Project, you must first have a Company, a Git Provider, a CI/CD Provider, a Secret Management Provider and a Project Template configured. From the Console homepage, click "Create Project" and follow the three-step wizard: +1. **General**: Provide a name, description, and choose the project workflow (Standard or Enhanced). +2. **Repository**: Select a Git Provider, define the repository path, set visibility, and choose a starting template. +3. **Environments**: Review the environments that will be automatically configured based on the Company's defaults. + [Discover more](/products/console/project-configuration/create-a-project.mdx) + +#### What is the Enhanced Project Workflow and why should I use it? +The Enhanced Project Workflow is a significant evolution from the standard, Git-centric model. It improves the developer experience by managing the project's logical state directly within the Console, rather than relying on Git for every change. This results in much faster performance in the Design area. Kubernetes configurations are generated only at deploy time, which also enables a pull-based, **GitOps** deployment strategy. It is the recommended workflow for all new projects. +[Discover more](/products/console/set-up-infrastructure/overview.md) + +#### What is the difference between a branch and a revision in the Console? +* In the **Standard Workflow**, the Console uses **branches** that directly correspond to Git branches in your configuration repository. All configuration changes are saved via commits to these branches. +* In the **Enhanced Project Workflow**, the concept of branches is replaced by **Revisions**. A Revision is a line of development managed within the Console, consisting of a series of immutable snapshots. This approach decouples the design process from Git, which is only used to store the final orchestrator files upon deployment. + [Discover more](/products/console/set-up-infrastructure/revisions-and-versions.md) + +#### How do I save my configuration changes in the Design area? +In the top-right corner of the Design area, click on the branch/revision name to open the management popover. If you have unsaved changes, a "Save configuration" button will be active. Clicking it opens a modal where you must provide a commit title and an optional message. This action creates a new commit (in Standard Workflow) or a new snapshot (in Enhanced Workflow). if there are remote changes and you want to make your changes too, a warning shows up when opening the action popover, telling the users that they have current local changes but there are also remote changes that should be addressed +[Discover more](/products/console/api-console/api-design/overview.md) + +#### How can I merge configurations between two branches or revisions? +From the branch/revision management popover in the Design area, you can select "Merge from another branch". This will open a diff editor where you can compare the configurations of the source and target branches/revisions side-by-side. You can review all changes, resolve conflicts by editing the configuration directly, and then confirm the merge. The merged configuration must then be saved. +[Discover more](/products/console/api-console/api-design/merge_collaboration.md) + +#### What are Infrastructure Projects? +Infrastructure Projects are a specialized project type designed for Operations teams and **platform engineers** to manage infrastructure using **Infrastructure as Code** (IaC) principles. Instead of managing applications, these projects manage infrastructure components like cloud resources (e.g., using **Terraform**) or Kubernetes operators. They support a two-phase deployment process (`plan` and `apply`) to ensure changes are reviewed before execution, providing better control over infrastructure provisioning. +[Discover more](/products/console/project-configuration/infrastructure-project.md) + +#### How can I delete a Project? +You can delete a Project from the **Project Settings -> Advanced** tab. Clicking the "Delete Project" button will open a confirmation modal where you must type the project's name to confirm. This action is irreversible and will remove the project from the Console, with options to also delete associated namespaces and archive the Git repository. +[Discover more](/products/console/project-configuration/delete-a-project.md) + +--- +### Configuration & Design + +#### How do I create a new microservice in my project? +You can create a microservice from the **Design -> Microservices** section, typically by starting from a **Template** or an **Example** from the Marketplace. +1. Click "Create a Microservice" and select "From Marketplace". +2. Choose a template (e.g., "Node.js Template" for **JavaScript** or "Spring Boot Template" for "Java"). +3. Provide a name, description, and specify the details for the new Git repository that will be created for your service's code. + After creation, you can configure its Docker image, resources, environment variables, and more. + [Discover more](/products/console/api-console/api-design/custom_microservice_get_started.md) + +#### What is the difference between creating a microservice from a Template vs. a Docker Image? +* **From a Template/Example**: This method is for creating a *new* microservice. The Console creates a new Git repository for you by cloning the template's source code. You get a complete, ready-to-code starting point with best practices for logging, health checks, and **CI/CD** already configured. +* **From a Docker Image**: This method is for integrating an *existing* microservice. You provide the name of a pre-built Docker image. The Console does not create a code repository; it only creates the configuration to deploy that existing image as part of your project. + [Discover more](/products/console/api-console/api-design/services.md) + +#### How do I expose a microservice with a public URL? +To expose a microservice, you need to create an **Endpoint**. +1. Go to **Design -> Endpoints** and click "Create new endpoint". +2. Define a **Base Path** (e.g., `/my-api`), which is the public URL path. +3. Set the **Type** to "Microservice". +4. Select the microservice you want to expose from the dropdown. + This configuration instructs the API Gateway to handle **ingressing** traffic from the specified base path to your internal microservice. + [Discover more](/products/console/api-console/api-design/endpoints.md) + +#### What is the difference between Public Variables and Secret Variables? +* **Public Variables** are environment-specific variables managed in the **Design -> Public Variables** section. They are stored in plain text within your Git configuration repository and are suitable for non-sensitive data, like feature flags or public URLs. +* **Secret Variables** are for sensitive data like passwords or API tokens. They are managed in the **Project Overview -> Variables** section and are stored securely in a **secrets manager** (like GitLab CI/CD variables, HashiCorp Vault, or **Azure Key Vault**), not in the Git repository. + [Discover more](/products/console/project-configuration/manage-environment-variables/index.md) + +#### How do I configure Kubernetes probes (Liveness & Readiness) for my microservice? +In the microservice's detail page, under the **Runtime** card, you can configure probes. +* **Readiness Probe**: Tells Kubernetes when your container is ready to start accepting traffic. +* **Liveness Probe**: Tells Kubernetes if your container is still running and healthy. If it fails, Kubernetes will restart the container. + For each probe, you can specify the path (e.g., `/-/healthz`), port, initial delay, and other parameters. + [Discover more](/products/console/api-console/api-design/microservice-runtime-resources.md) + +#### What is a CronJob in the Console and how do I create one? +A **CronJob** is a Kubernetes resource that runs a job on a repeating schedule (e.g., for nightly data processing or cleanup tasks). You can create one from the **Design -> CronJobs** section. You need to provide a name, a Docker image to run, and a schedule in standard cron format (e.g., `0 2 * * *` for 2 AM daily). +[Discover more](/products/console/api-console/api-design/jobs-cronjob.md) + +#### What is a CRUD and how do I create one? +A CRUD is a data collection stored in MongoDB that is automatically exposed via a full set of RESTful APIs for Create, Read, Update, and Delete operations. This allows you to quickly bootstrap a data-driven service without writing any backend code. You can create one from the **Design -> MongoDB CRUD** section by providing a name for the collection and then defining its data schema (fields, types, and validation rules). +[Discover more](/products/console/api-console/api-design/crud_advanced.md) + +#### How do I manage ConfigMaps for a microservice? +In the microservice's detail page, go to the **ConfigMaps & Secrets** tab. Here you can create a new ConfigMap or mount an existing one. You define a **Runtime Mount Path** (where the files will be available inside the container) and then add files to the ConfigMap. This is useful for managing configuration files that are separate from your application code. +[Discover more](/products/console/api-console/api-design/services.md) + +#### Can I use Kustomize for environment-specific configurations? +Yes, Kustomize is fully supported. When you enable it for a project, an `overlays` directory is created in your configuration repository. Inside this directory, you can create a folder for each environment (e.g., `production`) containing patch files and a `kustomization.yaml`. These patches are applied over the base configuration at deployment time, allowing you to declaratively modify resources for specific environments. +[Discover more](/products/console/project-configuration/kustomize-your-configurations/index.md) + +--- +### Deployment & Runtime + +#### How do I deploy my project's configuration? +You deploy from the **Deploy** section. +1. Select the target environment. +2. Select the branch, tag, or version to deploy. +3. Review the comparison of what's currently running versus the new configuration. +4. Choose between **Smart Deploy** (only deploys changed services) or **Deploy All**. +5. Clicking "Deploy" triggers the configured **CI/CD** pipeline to apply the changes to the cluster. + [Discover more](/products/console/deploy/overview.md) + +#### How does "Smart Deploy" work? +**Smart Deploy** optimizes the deployment process by only redeploying services whose configurations have actually changed since the last deployment. The Console calculates a checksum of a service's configuration (including its Docker image, environment variables, mounted ConfigMaps, etc.). If the checksum in the new release is different from the one currently running in the environment, the service is marked for deployment. This saves time and resources, especially in large projects. +[Discover more](/products/console/deploy/overview.md) + +#### What happens if a deployment fails and how can I check the history? +If a deployment pipeline fails, the Console will show a "Failed" status in the **Deploy** section. The **History** tab in this section provides a log of all past deployments for each environment. You can see the status (Success, Failed, Pending), who triggered it, when it happened, and a direct link to the pipeline logs in your **CI/CD tool** to investigate the cause of the failure. +[Discover more](/products/console/deploy/overview.md) + +#### How can I monitor the status of my deployed services? +The **Runtime** section provides a live view of your Kubernetes resources. You can: +* View the status of all **Pods** (running, pending, crashed). +* Inspect individual pods to see CPU/memory usage, event history, and real-time logs. +* Monitor other resources like **Deployments**, **Services**, and **CronJobs**. + [Discover more](/products/console/monitoring/introduction.md) + +#### How can I restart a single pod from the Console? +Yes. Go to the **Runtime** section, find the pod you want to restart in the Pods list. On the right side of the pod's row, there is an options menu (three dots). Clicking it will reveal a "Restart" option. This will safely terminate the existing pod, and Kubernetes will automatically create a new one to replace it. This is useful for recovering a pod that is in a bad state. +[Discover more](/products/console/monitoring/resources/pods.md) + +#### How can I view the logs of a running microservice? +Go to the **Runtime** section, select the environment, and find the pod for your microservice. Clicking on the pod name takes you to its detail view. The **Logs** tab shows a real-time stream of the container's logs. You can pause the stream, search for keywords, and download the logs. +[Discover more](/products/console/monitoring/resources/pods.md) + +#### How can I debug a service locally while it's connected to the remote cluster? +The Console integrates with **Telepresence**. From the **Debug** section, you can get a command that intercepts traffic from the remote cluster and redirects it to the service instance running on your local machine. This allows you to use local debuggers and see code changes instantly without a full deployment cycle, which is a massive productivity boost. +[Discover more](/products/console/debugging/telepresence.md) + +#### What is the API Portal? +The API Portal, accessible from the **Documentation** section, automatically generates and displays interactive API documentation (using OpenAPI/Swagger) for all your exposed endpoints. Developers can use it to explore APIs, understand their schemas, and test them live by making API calls directly from the browser, which greatly accelerates integration tasks. +[Discover more](/products/console/project-configuration/documentation-portal.md) + +--- +### Security & Access Management + +#### How does Role-Based Access Control (RBAC) work in the Console? +The Console uses a hierarchical RBAC model. Permissions are grouped into **Roles** (e.g., `Developer`, `Maintainer`), and roles are assigned to users or groups at different levels (Console, Company, or Project). Permissions are inherited downwards, so a `Company Owner` has full admin rights over all projects within that company. This allows for both broad and granular control over who can do what. +[Discover more](/products/console/identity-and-access-management/console-levels-and-permission-management.md) + +#### What is the difference between a `Developer` and a `Maintainer` role? +The key difference is deployment rights. +* A **`Developer`** can edit the project configuration in the Design area (create services, endpoints, etc.) and save their changes. They can view runtime environments but cannot deploy to them. +* A **`Maintainer`** has all the permissions of a Developer, plus the ability to trigger deployments to runtime environments. This role is typically assigned to team leads or senior developers responsible for releases. + [Discover more](/products/console/identity-and-access-management/console-levels-and-permission-management.md) + +#### How do I add a new user to my Company or Project? +A `Company Owner` can add users at the Company level from the **IAM -> Users** section by inviting them via email and assigning a role. A `Project Administrator` can manage roles for existing company users at the Project level. You can assign roles directly to individual users or, for easier management, add users to a **Group** that has the desired role. +[Discover more](/products/console/identity-and-access-management/manage-users.md) + +#### How do I create a Service Account and what is it used for? +A `Company Owner` can create a **Service Account** from the **IAM -> Service Accounts** section. A Service Account is a non-human identity used for automation, primarily in **CI/CD** pipelines. Instead of a username/password, it uses client credentials or a private key JWT for authentication. You assign it a role just like a regular user to grant it the specific permissions it needs to perform its tasks, such as triggering a deployment. +[Discover more](/products/console/identity-and-access-management/manage-service-accounts.md) + +#### How do Groups simplify user management? +Groups allow you to manage permissions for multiple users at once. Instead of assigning the `Developer` role to 20 individual users, you can create a "Developers" group, assign the `Developer` role to the group, and then add the 20 users to that group. All members of the group inherit the role's permissions. This is much more efficient and less error-prone, especially for large teams. +[Discover more](/products/console/identity-and-access-management/manage-groups.md) + +#### How do I protect an endpoint? +You can secure an endpoint from its configuration page in the **Design -> Endpoints** section. The **Security** tab offers several options: +* **Authentication required**: If checked, the user must be logged in. +* **API Key required**: If checked, a valid API Key must be sent in the `client-key` or `secret` header. +* **User Group Permission**: An expression-based rule for fine-grained control. You can write logic based on the user's groups (e.g., `groups.admin`) or the API key's client type (e.g., `clientType == 'my-app'`). + [Discover more](/products/console/api-console/api-design/endpoints.md) + +#### How does the authorization flow work for a protected endpoint? +1. A client sends a request with credentials to the **API Gateway**. +2. The API Gateway forwards the request headers to the **Authorization Service**. +3. The Authorization Service calls an **Authentication Manager** (like the `auth0-client`) to validate the credentials and get user information (ID, groups, etc.). +4. The Authorization Service evaluates the endpoint's **User Group Permission** expression against the user's info. +5. If authorized, it returns success to the API Gateway, which then forwards the request to the target microservice, adding headers like `miauserid` and `miausergroups`. + [Discover more](/products/console/project-configuration/authorization-flow.md) + +#### How can I implement more advanced authorization with policies? +For advanced authorization, you can enable **Rönd**, an open-source sidecar based on Open Policy Agent (OPA). With Rönd, you can write declarative policies in the **Rego** language to enforce complex rules, such as: +* **Row Filtering**: Filtering data from a CRUD response based on user attributes (e.g., a user can only see their own orders). +* **Response Filtering**: Removing specific fields from a response body (e.g., hiding a `salary` field from non-admin users). +* **Attribute-Based Access Control (ABAC)** on the request itself. + [Discover more](/products/console/api-console/api-design/authorization.md) + +--- +### Advanced Features & Extensibility + +#### How can I extend the Console with custom functionality? +The Console's **Extensibility** feature allows you to add custom pages to the sidebar navigation by embedding external web applications as an ` +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| --------- | ---------- | ------------------- | ------- | ------------------------------------------------------------------- | +| `urlMask` | `url-mask` | [UrlMask][url-mask] | - | url mask to apply to the current path to extract dynamic parameters | +| `src` | `src` | string | - | the url source of the rendered iframe | + + +### Listens to + +This component listens to no event. + +### Emits + +This component emits no event. diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/230_dynamic_title.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/230_dynamic_title.md new file mode 100644 index 0000000000..9aed3e9a97 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/230_dynamic_title.md @@ -0,0 +1,91 @@ +--- +id: dynamic_title +title: Dynamic Title +sidebar_label: Dynamic Title +--- + + + + + +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data + + + +```html + +``` + +The Dynamic Title renders a label designed to work as the title of a page. +The content of the title is retrieved from a specified field of the first element of the underlying dataset. + +The Dynamic Title listens to [display-data] events to extract the value to show from the payload. + +## How to configure + +The Dynamic Title needs property `datasourceKey` to be specified, +indicating the name of the field to use to extract the content from the first entry. + +```json +{ + "tag": "bk-dynamic-title", + "properties": { + "datasourceKey": "name" + } +} +``` + +## Examples + +A Dynamic Title configured like + +```json +{ + "tag": "bk-dynamic-title", + "properties": { + "datasourceKey": "name" + } +} +``` + +that receives a [display-data] event with payload + +```json +{ + "data": [ + { + "name": "John Smith", + "email": "jsmith@test.com", + "budget": 1000 + }, + { + "name": "Steve Grobb", + "email": "sgrobb@test.com", + "budget": 2000 + } + ] +} +``` + +renders a title with content "John Smith". + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| --------------- | ---------------- | ------ | ------- | ------------------------------------------------------- | +| `datasourceKey` | `datasource-key` | string | - | the field that should be used to pick the data to show. | + +### Listens to + +| event | action | +| -------------- | --------------------------------- | +| [display-data] | retrieves data to show as content | + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/240_expandable_filters.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/240_expandable_filters.md new file mode 100644 index 0000000000..08748a3bd1 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/240_expandable_filters.md @@ -0,0 +1,327 @@ +--- +id: expandable_filters +title: Expandable Filters +sidebar_label: Expandable Filters +--- + + + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[writable-views]: /runtime-components/plugins/crud-service/50_writable_views.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema + +[filters]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filters +[filter-operators]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filter-operators +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[filter]: /products/microfrontend-composer/back-kit/70_events.md#filter +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[lookup-data]: /products/microfrontend-composer/back-kit/70_events.md#lookup-data +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query + +[bk-filters-manager]: /products/microfrontend-composer/back-kit/60_components/310_filters_manager.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-filter-drawer]: /products/microfrontend-composer/back-kit/60_components/300_filter_drawer.md + + + +```html + +``` + + + +The Expandable Filters consist in a form which allows to apply [filters] to a collection. +Each field of the form is associated to a field of the collection and to a [filter operator][filter-operators]. +Upon submitting the form: + - inserted values for each field are used to create an array of filters with the corresponding associated + collection field and filter operator. + No filter is applied for fields without values. + - The need to filter the data according to such filters is signaled to other components. + This is achieved by emitting a [change-query] event. + Components such as the [CRUD Client][bk-crud-client] might pick up on this request. + Note that, differently from the [Filter Drawer][bk-filter-drawer], + the Expandable Filters are not designed to interact with the [Filters Manager][bk-filters-manager]. + +The form is hidden/spawned whenever the request to provide support for applying filters is signaled. +That is, whenever a [filter] event is received. + +The fields within the form are organized into a grid with a maximum number of columns of 4, which shrinks to 3 or 2 depending on the window width. + + + +## How to configure + +Properties `dataSchema` and `filtersConfig` should be specified in the Expandable Filters configuration. + +```json +{ + "tag": "bk-expanded-filters", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "dishes": {"type": "array", "format": "multilookup"}, + "name": {"type": "string"}, + "orderedAt": {"type": "string", "format": "date-time"}, + } + }, + "filtersConfig": [ + { + "property": "orderedAt", + "operator": "between" + }, + "dishes", + "name" + ] + } +} +``` + +The [data-schema] describes the structure of the underlying data, while `filtersConfig` specifies the fields to show and their associated collection property and [filter operator][filter-operators]. +`filtersConfig` is an array of strings and/or objects with keys "property" and "operator". +String entries are interpreted as the collection property to associate to the field, and a default operator is used. +The default operator is always `equal` unless the property is of format `multilookup`, in which case `includesAll` is used. +It is not possible to specify the same property more than once. + +Properties with `filterOptions.hidden` set to true in the data-schema are not shown. + +:::caution +Filters on properties of type array or object are not available, unless they have format `lookup` of `multilookup` (only for array field). +::: + + +### Bootstrap - Apply filters from URL + +If property `readFromUrl` is set to true, the Expandable Filters parse the page URL to retrieve the query parameter `filters`. +If found, its content is converted to filters that are used to initialize the form values and are applied accordingly to [filtersConfig](#how-to-configure). + +### Lookup fields (writable views) + +Fields described inside the data-schema as having type `object` or `array` and format `lookup` are rendered respectively as select and multi-select fields. + +Options for such fields will be dynamically fetched from the endpoint specified in `basePath` property, using the `/lookup` route provided by the [CRUD Service][crud-service] to [writable views][writable-views] (version 6.9.0 or higher) , which returns a list of objects. +Each option fetched like this should have at least a `label` field, which is used as display value inside the form, and a `value` field which is used as unique identifier for such option. + +:::caution +If you use the `_id` field as `value` in your lookups, remember to set its type as `string`. +::: + +### Locale + +The texts of the Expandable Filters can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + buttons: { + applyButton: LocalizedText + clearButton: LocalizedText + }, + valueInputPlaceholder: LocalizedText + valueSelectPlaceholder: LocalizedText + true: LocalizedText + false: LocalizedText + datePicker: { + lang: { + locale: LocalizedText, + placeholder: LocalizedText + rangePlaceholder: { + start: LocalizedText + stop: LocalizedText + }, + today: LocalizedText + now: LocalizedText + backToToday: LocalizedText + ok: LocalizedText + clear: LocalizedText + month: LocalizedText + year: LocalizedText + timeSelect: LocalizedText + dateSelect: LocalizedText + monthSelect: LocalizedText + yearSelect: LocalizedText + decadeSelect: LocalizedText + monthBeforeYear: 'true' | 'false' + previousMonth: LocalizedText + nextMonth: LocalizedText + previousYear: LocalizedText + nextYear: LocalizedText + previousDecade: LocalizedText + nextDecade: LocalizedText + previousCentury: LocalizedText + nextCentury: LocalizedText + }, + timePickerLocale:{ + placeholder: LocalizedText + } + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +### Example: Basic Usage + +Given the following configuration, +```json +{ + "tag": "bk-expanded-filters", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "dishes": {"type": "array", "format": "multilookup"}, + "name": {"type": "string"}, + "orderedAt": {"type": "string", "format": "date-time"}, + } + }, + "filtersConfig": [ + { + "property": "orderedAt", + "operator": "between" + }, + "dishes", + "name" + ] + } +} +``` + +it is possible to specify a value for filtering properties `dishes`, `name` and `orderedAt`. +Assuming the inserted values to be representable as: + +```json +{ + "orderedAt": ["2023-03-03T09:00:00.000Z", "2023-03-03T12:00:00.000Z"], + "name": "Joe", + "dishes": ["dish-1", "dish-2"] +} +``` + +Then the emitted filters look like: + +```json +{ + "property": "orderedAt", + "operator": "between", + "value": ["2023-03-03T09:00:00.000Z", "2023-03-03T12:00:00.000Z"] +}, +{ + "property": "name", + "operator": "equal", + "value": "Joe" +}, +{ + "property": "dishes", + "operator": "includesAll", + "value": ["dish-1", "dish-2"] +} +``` + +If a component such as the [CRUD Client][bk-crud-client] is included in the page (and provided with the same data-schema), these filters are chained inside an `$and` mongo-like query and used to retrieved filtered data. + + +### Example: Apply filters from URL + +Assuming the Expandable Filters to be configured like: + +```json +{ + "tag": "bk-expanded-filters", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "price": {"type": "number"}, + "orderedAt": {"type": "string", "format": "date-time"} + } + }, + "filtersConfig": [ + "name", + {"property": "price", "operator": "less"}, + {"property": "orderedAt", "operator": "between"} + ] + } +} +``` + +and the following query parameter to be included in the URL of the current plugin: + +```json +{ + "filters": [ + {"property": "name", "operator": "equal", "value": "test"}, + {"property": "price", "operator": "less", "value": 10}, + {"property": "orderedAt", "operator": "less", "value": "2023-03-03T09:00:00.000Z"} + ] +} +``` + +then a [change-query] event will be emitted with filters: + +```json +{ + "property": "name", + "operator": "equal", + "value": "test" +}, +{ + "property": "price", + "operator": "less", + "value": 10 +} +``` + +Filter on field "orderedAt" is not emitted since the filter operator `less` does not correspond to the one specified for the property inside `filtersConfig` (`between`). + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ---------------------- | ------------------------- | -------------------------------------------- | ------- | --------------------------------------------------------------------- | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data-schema describing the fields of the collection to query | +| `filtersConfig` | - | [FiltersConfig](#filtersconfig)[] | - | lists the filters to include in the component | +| `openByDefault` | `open-by-default` | boolean | false | whether to show the component by default | +| `liveSearchTimeout` | `live-search-timeout` | number | 5000 | lookup live-search timeout | +| `liveSearchItemsLimit` | `live-search-items-limit` | number | 10 | max items to fetch on regex live search | +| `readFromUrl` | `read-from-url` | boolean | false | whether filters from URL should be read and applied at bootstrap time | +| `basePath` | - | string | - | endpoint to use to fetch lookup options | + +#### FiltersConfig + +```typescript +type FiltersConfig = string | { + property: string + operator: string +} +``` + + +### Listens to + +| event | action | +| -------------- | -------------------------------------------- | +| [filter] | display/close the expanded filters component | +| [display-data] | retrieves data to build lookup options | +| [lookup-data] | retrieves data to build lookup options | + + +### Emits + +| event | description | +| -------------- | -------------------------------------------------------------------- | +| [change-query] | when done filling or clearing the form, applies or clear the filters | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/250_export_modal.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/250_export_modal.md new file mode 100644 index 0000000000..14471b51ea --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/250_export_modal.md @@ -0,0 +1,159 @@ +--- +id: export_modal +title: Export Modal +sidebar_label: Export Modal +--- + + + + + +[bk-export-client]: /products/microfrontend-composer/back-kit/60_components/120_crud_export_client.md +[format-specifiers]: https://www.mongodb.com/docs/manual/reference/operator/aggregation/dateToString/#std-label-format-specifiers +[UTC-offsets]: https://en.wikipedia.org/wiki/List_of_UTC_offsets +[Olson-timezone-identifier]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + + +[export-data]: /products/microfrontend-composer/back-kit/70_events.md#export-data +[export-data/request-config]: /products/microfrontend-composer/back-kit/70_events.md#export-data---request-config +[export-data/user-config]: /products/microfrontend-composer/back-kit/70_events.md#export-data---user-config + + + +![export-modal](img/bk-export-modal.png) + +```html + +``` + +The Export Modal renders a form inside a modal with standard fields that allow user to configure a data export task. + +It opens whenever a component signals the need to specify configuration for an export task. That is, whenever a [export-data/request-config] event is received. + +It is usually best to have this event emitted by a component like the [CRUD Export Client][bk-export-client], which uses it to open the modal with an associated `transactionId`. +For instance, the [CRUD Export Client][bk-export-client] emits a [export-data/request-config] event upon listening to an [export-data] event. + + +The Export Modal allows the user to specify: + - the format onto which data should be exported ("csv" or "xlsx") + - what fiters to apply to the data to be exported. Options are to export the whole collection, to apply the same filters that have been applied to the current visualization of the collection, to export selected items only + - what fields of the collection to include in the export result + - if the specified format is "csv", what separator to use (comma or semicolon) + - the date format of each date type field, if any + - the date time zone of each date type field, if any + +Upon submitting the form, the Export Modal signals the need to export data accordingly with the specified options. +A component like the [CRUD Export Client][bk-export-client] might pick up on the export request. + + +## How to configure + +The Export Modal does not require any particular configuration, however it is possible to specify the options for the date format and date time zone select inputs. + +```json +{ + "tag": "bk-export-modal" +} +``` + +### Date format options + +To specify the options for the date format select inputs, `dateFormatOptions` must be used. The default is `YYYY-MM-DDTHH:mm:ss.msZ`. +They accept an array of `Options`: + +```typescript +type Option = { + label: string + value: string +} +``` + +The value must be a `MongoDB` supported format. See [Format Specifiers][format-specifiers] for more information. + +```json +{ + "tag": "bk-export-modal", + "properties": { + "dateFormatOptions": [ + {"value": "%d-%m-%Y", "label": "DD-MM-YYYY"} + ] + } +} +``` + +### Time zone options + +To specify the options for the date time zone, `dateTimeZoneOptions` must be used. The default is `UTC time`. + +It is an array of `Option` like the one described above. The value must be an [UTC Offsets][UTC-offsets] or a [Olson Timezone Identifier][Olson-timezone-identifier]. + +```json +{ + "tag": "bk-export-modal", + "properties": { + "dateTimeZoneOptions": [ + {"value": "+01:00", "label": "(GMT +01:00) Berlin/Rome"}, + {"value": "Africa/Cairo", "label": "Cairo"} + ] + } +} +``` + + +### Locale + +The texts of the Export Modal can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + modalTitle: LocalizedText + fileFormat: LocalizedText + fileFormatCSVOption: LocalizedText + fileFormatExcelOption: LocalizedText + items: LocalizedText + itemsAllOption: LocalizedText + itemsFilteredOption: LocalizedText + itemsSelectedOption: LocalizedText + columns: LocalizedText + columnsAllOption: LocalizedText + columnsCustomizedOption: LocalizedText + columnsCustomizedPlaceholeder: LocalizedText + csvSeparator: LocalizedText + csvSeparatorCommaOption: LocalizedText + csvSeparatorSemicolonOption: LocalizedText + okButton: LocalizedText + cancelButton: LocalizedText + columnsName: LocalizedText + columnNameIdOption: LocalizedText + columnNameLabelOption: LocalizedText + format: string + formatCustomizedPlaceholder: string + timezone: string, + timezoneCustomizedPlaceholder: string +} +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ------------------- | --------- |-------------------|----------------------------------------------------------------------------------------------------|---------------------------------------------------| +| dateFormatOptions | - | Option[] | `[{value: '%Y-%m-%d', label: 'YYYY-MM-DD'}, {value: '%Y-%m-%d %H:%M', label: 'YYYY-MM-DD HH:mm'}]` | The list of options for the date format select | +| dateTimeZoneOptions | - | Option[] | `[{value: '\', label: '\'}]` | The list of options for the date time zone select | + +### Listens to + +| event | action | +| ---------------------------- | --------------------- | +| [export-data/request-config] | prompts modal opening | + + +### Emits + +| event | description | +| ------------------------- | --------------------------------------------------------- | +| [export-data/user-config] | notifies the bus of user config for next export data task | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/260_file_manager.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/260_file_manager.md new file mode 100644 index 0000000000..9cbfca80cb --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/260_file_manager.md @@ -0,0 +1,90 @@ +--- +id: file_manager +title: File Manager +sidebar_label: File Manager +--- + + + + + + +[files-service]: /runtime-components/plugins/files-service/configuration.mdx +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md + +[bk-file-client]: /products/microfrontend-composer/back-kit/60_components/290_file_service_client.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + +[file-management]: /products/microfrontend-composer/back-kit/80_examples/30_plugin_navigation.md + +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file +[create-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#create-data-with-file +[upload-file]: /products/microfrontend-composer/back-kit/70_events.md#upload-file +[uploaded-file]: /products/microfrontend-composer/back-kit/70_events.md#uploaded-file +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[delete-file]: /products/microfrontend-composer/back-kit/70_events.md#delete-file +[error]: /products/microfrontend-composer/back-kit/70_events.md#error + + + + +```html + +``` + +Manages file upload transactions by holding a unique transaction ID hash map. Since files are often linked to a collection entry but stored on a different service, it might be handy to control file upload through a transaction manager. Two steps are needed to successfully upload a file: + +1. handle file uploads to a storage service. Assuming a backend service such as [Mia Platform's Files Service][files-service], a component like the [File Service Client][bk-file-client] could perform such task. +2. handle updates to the CRUD collection. Assuming a backend service such as [Mia Platform's CRUD Service][crud-service], this task could be handled by the [CRUD Client][bk-crud-client]. + +The File Manager component processes requests originating from other components to create or update data in a CRUD collection, which also require operations involving uploading files to a designated file storage service. The requests that trigger these actions are typically in the form of [create-data-with-file] or [update-data-with-file] events. + +These events encapsulate both the data to be created or updated and additional information within their meta section. The meta data aids in extracting the files that require uploading from the payload. + +The flow of this process can be summarized as follows: + +- The File Manager identifies within the payload all files that should be uploaded. +- For each identified file, the File Manager initiates an upload request to the designated file storage service. +- Upon receiving notifications confirming successful file uploads, the File Manager proceeds to signal the request for creating or updating data using the complete payload from the initial triggering event. +- However, in the event of an error notification being received, the entire transaction is retracted. This includes deleting any files that were already uploaded as part of the incomplete transaction. + +Further details on how Back-Kit components can be composed to handle file fields are available in the [specific section][file-management]. + +## How to configure + +The File Manger does not require any configuration. + +```json +{ + "tag": "bk-file-manager" +} +``` + +## API + +### Properties & Attributes + +None + +### Listens to + +| event | action | emits | on error | +|-------|--------|-------|----------| +|[update-data-with-file]|initiates an upload file transaction attaching a unique ID and attempting upload file to the storage service|[upload-file]| - | +|[create-data-with-file]|initiates an upload file transaction attaching a unique ID and attempting upload file to the storage service|[upload-file]| - | +|[uploaded-file]|continues a `create-data-with-file` or `update-data-with-file` transaction by patching the CRUD collection with the `upload-file` metadata|[update-data],[create-data]| - | +|[error]|interrupts a registered transaction due to an occurred `error` event carrying a `meta`. If the file was stored but the collection wasn't successfully patched, then the file is deleted|[delete-file]| - | + +### Emits + +| event | description | +| ------------- | ------------------------------------------------------------------------------------------------------------------- | +| [upload-file] | contains file and metadata to be stored | +| [update-data] | after storage, contains reference metadata used to patch a collection containing reference to such file | +| [create-data] | after storage, contains reference metadata used to create an item into collection containing reference to such file | +| [create-data] | after storage, contains reference metadata used to create an item into collection containing reference to such file | +| [delete-file] | contains file metadata to trigger file deletion | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/270_file_picker_drawer.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/270_file_picker_drawer.md new file mode 100644 index 0000000000..7a2b63ea87 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/270_file_picker_drawer.md @@ -0,0 +1,245 @@ +--- +id: file_picker_drawer +title: File Picker Drawer +sidebar_label: File Picker Drawer +--- + + + + + +[files-service]: /runtime-components/plugins/files-service/configuration.mdx + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[file-management]: /products/microfrontend-composer/back-kit/80_examples/10_file_management.md +[link-file-to-record]: /products/microfrontend-composer/back-kit/70_events.md#link-file-to-record +[upload-file]: /products/microfrontend-composer/back-kit/70_events.md#upload-file +[download-file]: /products/microfrontend-composer/back-kit/70_events.md#download-file +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[fetch-files]: /products/microfrontend-composer/back-kit/70_events.md#fetch-files +[fetched-files]: /products/microfrontend-composer/back-kit/70_events.md#fetched-files +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file + +[bk-file-client]: /products/microfrontend-composer/back-kit/60_components/290_file_service_client.md +[bk-file-manager]: /products/microfrontend-composer/back-kit/60_components/260_file_manager.md + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + + + +```html + +``` + + + +The File Picker Drawer renders a drawer containing a drag-and-drop area to handle file uploads / downloads. + +The File Picker Drawer is designed to handle fields that hold metadata about storage location for files saved in a file storage service and handled by [Mia Platform's Files Service][files-service]. +Such fields are identifiable in a [data-schema] as fields of type `object` or `array` and format `file`, and their value is expected to extend the schema: + +```json +{ + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, + "size": { + "type": "number" + }, + "location": { + "type": "string" + } +} +``` + +The File Picker Drawer opens when a component signals the request to update a file field associated to the item of a collection with event [link-file-to-record], +and allows interaction with such field through a drag-and-drop area + +In particular, it allows: + - request the download of the corresponding file from the file storage service, via the [download-file] event. + Such event could be handled by a component such as the [File Service Client][bk-file-client]. + - The upload of new files, with consequent update of the CRUD collection item with the storage metadata of the new file. + This request is signaled with the [update-data-with-file] event, and could be picked up by a component such as the [File Manger][bk-file-manager]. + +Further details on how Back-Kit components can be composed to handle file fields are available in the [specific section][file-management]. + +## How to configure + +For its basic usage, File Picker Drawer does not require any configuration. + +```json +{ + "tag": "bk-file-picker-drawer" +} +``` + +However, such File Picker Drawer assumes handled file field to always be of type object - that is, links at most one file to the field.\ +A [data-schema] should be provided to the File Picker Drawer with `dataSchema` property in case the file filed to handle might be of type array (thus allowing multiple files to be linked to it), +or if the uploaded files should have extra [metadata](#metadata). + +### Metadata + +File fields may themselves have a `dataSchema` or `items` property. + +When that is the case, the File Picker Drawer not only include the drag-and-drop area but also provides an area to edit the additional metadata associated with the file field. +For file fields of type object, a form is displayed, while for file fields of type array, an accordion of forms. + +:::caution +Only fields of type string are supported for metadata. +::: + +```json +{ + "tag": "bk-file-picker-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "image": { + "type": "object", + "format": "file", + "dataSchema": { + "type": "object", + "properties": { + // <- here are fields to be handled as metadata associated to the `image` field + } + } + } + } + } + } +} +``` + + +### Locale + +The texts of the File Picker Drawer can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + formTitle: LocalizedText + filePickerTitle: LocalizedText + ctaLabel: LocalizedText + filePicker: { + dragAndDropCaption: LocalizedText + removeFile: LocalizedText + checkboxCaption: LocalizedText + metaDataTitle: LocalizedText + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +### Example: Basic Usage + +A File Picker Drawer configured like the following: + +```json +{ + "tag": "bk-file-picker-drawer", + "dataSchema": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "avatar": { + "type": "object", + "format": "file" + } + } + } +} +``` + +upon receiving to a [link-file-to-record] event with the following payload and meta + +```json +{ + "payload": { + "_id": "item-id-1", + "name": "Joe", + "avatar": { + "_id": "file-id", + "name": "fileName.jpg", + "file": "file.jpg", + "size": 3992, + "location": "/v2/files/download/file.jpg" + } + }, + "meta": { + "property": "avatar" + } +} +``` + +would open, allowing to request the download the file associated to the "image" field and allowing to upload a new via a drag-and-drop area.\ +Being the "avatar" field of type object, the File Picker Drawer allows at most one file to be linked to it. +After uploading a new file and submitting, the File Picker Drawer signals the need to upload the new file, +and consequently patch the "image" field of the connected item with the storage location metadata of the new file. + +This request is signaled by emitting the [update-data-with-file], like: + +```json +{ + "payload": { + "_id": "item-id-1", + "name": "Joe", + "avatar": { + ... // -> this contains the uploaded file + }, + }, + "meta": { + "property": ["avatar"] + } + +} +``` + +The payload of the event contains the newly uploaded file inside field "avatar". +The meta of the event indicates what property should be used to extract the file from the payload to upload. +A component like the [File Manager][bk-file-manager] should pick up on this event. + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| --------------------- | ----------------------- | -------------------------------------------- | ------- | --------------------------------------------------- | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data schema describing the fields of the collection | +| `mask` | `mask` | boolean | true | whether to mask or not the drawer | +| `rootElementSelector` | `root-element-selector` | string | - | root element to append the drawer to | +| `width` | `width` | number | 500 | width of the drawer | + +### Listens to + +| event | action | +| --------------------- | ------------------------------------------------ | +| [loading-data] | disables footer submit button | +| [link-file-to-record] | launches the upload of a file from selected ones | + + +### Emits + +| event | description | +| ----------------------- | ------------------------------------------------------------------------------------------------ | +| [update-data-with-file] | updates data by uploading a new file and patching the dataset with its storage location metadata | +| [update-data] | requests data update after unlinking the file to the record | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/280_file_picker_modal.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/280_file_picker_modal.md new file mode 100644 index 0000000000..daddd4f09b --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/280_file_picker_modal.md @@ -0,0 +1,343 @@ +--- +id: file_picker_modal +title: File Picker Modal +sidebar_label: File Picker Modal +--- + + + + + +[files-service]: /runtime-components/plugins/files-service/configuration.mdx + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[file-management]: /products/microfrontend-composer/back-kit/80_examples/10_file_management.md +[link-file-to-record]: /products/microfrontend-composer/back-kit/70_events.md#link-file-to-record +[upload-file]: /products/microfrontend-composer/back-kit/70_events.md#upload-file +[download-file]: /products/microfrontend-composer/back-kit/70_events.md#download-file +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[fetch-files]: /products/microfrontend-composer/back-kit/70_events.md#fetch-files +[fetched-files]: /products/microfrontend-composer/back-kit/70_events.md#fetched-files +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data + +[bk-file-client]: /products/microfrontend-composer/back-kit/60_components/290_file_service_client.md +[bk-file-manager]: /products/microfrontend-composer/back-kit/60_components/260_file_manager.md + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + + + +```html + +``` + + + +The File Picker Modal renders a modal containing a drag-and-drop area to handle file uploads / downloads. + +The File Picker Modal is designed to handle fields that hold metadata about storage location for files saved in a file storage service and handled by [Mia Platform's Files Service][files-service]. +Such fields are identifiable in a [data-schema] as fields of type `object` or `array` and format `file`, and their value is expected to extend the schema: + +```json +{ + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, + "size": { + "type": "number" + }, + "location": { + "type": "string" + } +} +``` + +The File Picker Modal opens when a component signals the request to update a file field associated to the item of a collection with event [link-file-to-record], +and allows interaction with such field through a drag-and-drop area. + +In particular, it allows: + - request the download of the corresponding file from the file storage service, via the [download-file] event. + Such event could be handled by a component such as the [File Service Client][bk-file-client]. + - The upload of new files, with consequent update of the CRUD collection item with the storage metadata of the new file. + This request is signaled with the [update-data-with-file] event, and could be picked up by a component such as the [File Manger][bk-file-manager]. + +Further details on how Back-Kit components can be composed to handle file fields are available in the [specific section][file-management]. + +## How to configure + +For its basic usage, File Picker Modal does not require any configuration. + +```json +{ + "tag": "bk-file-picker-modal" +} +``` + +However, such File Picker Modal assumes handled file field to always be of type object - that is, links at most one file to the field. +A [data-schema] should be provided to the File Picker Modal with `dataSchema` property in case the file filed to handle might be of type array (thus allowing multiple files to be linked to it), or if the uploaded files should have extra [metadata](#metadata). + +### Metadata + +File fields may themselves have a `dataSchema` or `items` property. + +When that is the case, the File Picker Modal not only include the drag-and-drop area but also provides an area to edit the additional metadata associated with the file field. For file fields of type object, a form is displayed, while for file fields of type array, an accordion of forms. + +:::caution +Only fields of type string are supported for metadata. +::: + +```json +{ + "tag": "bk-file-picker-modal", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "image": { + "type": "object", + "format": "file", + "dataSchema": { + "type": "object", + "properties": { + // <- here are fields to be handled as metadata associated to the `image` field + } + } + } + } + } + } +} +``` + +### Preview Files + +The File Picker Modal offers a file preview feature located below the drag-and-drop area. +Specifically, it allows for the preview of uploaded files that are currently associated with the field under consideration. +This preview functionality can be enabled by configuring the `previewUploadedFiles` property with the value "preview". + +Moreover, when the `previewUploadedFiles` property is configured as "fetch", the File Picker Modal follows this sequence of actions: +- It initiates a request to retrieve files from the file storage service by emitting the [fetch-files] event. +- A component, such as the [File Service Client][bk-file-client], may respond to the request and communicate the fetched files using the [fetched-files] event. +- If this happens, the fetched files are presented in a preview format within the modal. +- This preview feature allows users to interact with the files through checkboxes for selecting items. +- When a user selects a file using this method, the associated field establishes a connection with that chosen file. +- If [metadata](#metadata) is available for the files, it can be accessed through a modal within the modal. + The metadata will be presented based on the data-schema specified for the corresponding file field being updated. + Some metadata fields may not be visible, if not included in the data-schema. +Note: to use this feature with [Mia Platform's Files Service][files-service], version 2.7.0 or higher is required. + + + +### Locale + +The texts of the File Picker Modal can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + formTitle: LocalizedText + filePickerTitle: LocalizedText + ctaLabel: LocalizedText + filePicker: { + dragAndDropCaption: LocalizedText + removeFile: LocalizedText + checkboxCaption: LocalizedText + metaDataTitle: LocalizedText + preview: { + openFile: LocalizedText + brokenFile: LocalizedText + absentFile: LocalizedText + loadMore: LocalizedText + } + previewDrawer: { + dateFormat: LocalizedText + closeTitle: LocalizedText + metaDataTitle: LocalizedText + brokenFile: LocalizedText + absentFile: LocalizedText + downloadCta: LocalizedText + } + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +## Examples + +### Example: Basic Usage + +A File Picker Modal can configured like the following: + +```json +{ + "tag": "bk-file-picker-modal", + "dataSchema": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "avatar": { + "type": "object", + "format": "file" + } + } + } +} +``` + +upon receiving to a [link-file-to-record] event with the following payload and meta + +```json +{ + "payload": { + "_id": "item-id-1", + "name": "Joe", + "avatar": { + "_id": "file-id", + "name": "fileName.jpg", + "file": "file.jpg", + "size": 3992, + "location": "/v2/files/download/file.jpg" + } + }, + "meta": { + "property": "avatar" + } +} +``` + +would open, allowing to request the download the file associated to the "image" field and allowing to upload a new via a drag-and-drop area. +Being the "avatar" field of type object, the File Picker Modal allows at most one file to be linked to it. +After uploading a new file and submitting, the File Picker Modal signals the need to upload the new file, and consequently patch the "image" field of the connected item with the storage location metadata of the new file. +This request is signaled by emitting the [update-data-with-file], like: + +```json +{ + "payload": { + "_id": "item-id-1", + "name": "Joe", + "avatar": { + ... // -> this contains the uploaded file + }, + }, + "meta": { + "property": ["avatar"] + } + +} +``` + +The payload of the event contains the newly uploaded file inside field "avatar". +The meta of the event indicates what property should be used to extract the file from the payload to upload. +A component like the [File Manager][bk-file-manager] should pick up on this event. + +### Example: Preview files + +A File Picker Modal can be configured like the following: + +```json +{ + "tag": "bk-file-picker-modal", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "avatar": { + "type": "object", + "format": "file" + } + } + }, + "previewUploadedFiles": "fetch" + } +} +``` + +Upon opening, the File Picker Modal requests files to be fetched from the file service storage. +This is achieved by emitting a [fetch-files] event, with a payload like: + +```json +{ + "page": 0 +} +``` + +The `page` option is included in the request to enable data pagination for the fetched files. +In the File Picker Modal, a button is provided that allows users to request the retrieval of additional files, increasing the value of the `page` field. + +If a response is received in the form of a [fetched-files] event, such as: + +```json +{ + "files": [ + { + "_id": "avatar-img-id", + "name": "avatar-img-name.jpg", + "file": "avatar-img.jpg", + "size": 3992, + "location": "/v2/files/download/avatar-img.jpg" + }, + { + "_id": "avatar-img2-id", + "name": "avatar-img2-mame.jpg", + "file": "avatar-img2.jpg", + "size": 2412, + "location": "/v2/files/download/avatar-img2.jpg" + }, + ] +} +``` + +The File Picker Modal displays a preview of these fetched files within its interface. +Users can interact with the displayed files by selecting them. +Selecting a file establishes a link between the chosen file and the field being handled by the File Picker Modal. + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ---------------------- | ------------------------ | -------------------------------------------- | ------- | -------------------------------------------------------- | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data schema describing the fields of the collection | +| `rootElementSelector` | `root-element-selector` | string | - | root element to append the modal to | +| `width` | `width` | number | 500 | width of the modal | +| `previewUploadedFiles` | `preview-uploaded-files` | "none" \| "preview" \| "fetch" | "none" | allows to preview uploaded files and files from a bucket | + + +### Listens to + +| event | action | +| --------------------- | ------------------------------------------------ | +| [loading-data] | disables footer submit button | +| [link-file-to-record] | launches the upload of a file from selected ones | +| [fetched-files] | receives files to display as preview | + + +### Emits + +| event | description | +| ----------------------- | -------------------------------------------------------------------------------------------------------- | +| [update-data-with-file] | requests data update by uploading a new file and patching the dataset with its storage location metadata | +| [update-data] | requests data update after unlinking the file to the record | +| [fetch-files] | requests files to be fetched for preview | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/290_file_service_client.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/290_file_service_client.md new file mode 100644 index 0000000000..f0f257e19a --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/290_file_service_client.md @@ -0,0 +1,427 @@ +--- +id: file_service_client +title: File Service Client +sidebar_label: File Service Client +--- + + + + + +[files-service]: /runtime-components/plugins/files-service/configuration.mdx +[query-params]: /runtime-components/plugins/files-service/usage.mdx#query-parameters +[micro-lc]: https://micro-lc.io/docs + +[file-management]: /products/microfrontend-composer/back-kit/80_examples/10_file_management.md + +[bk-pdf-viewer]: /products/microfrontend-composer/back-kit/60_components/480_pdf_viewer.md + +[upload-file]: /products/microfrontend-composer/back-kit/70_events.md#upload-file +[uploaded-file]: /products/microfrontend-composer/back-kit/70_events.md#uploaded-file +[error]: /products/microfrontend-composer/back-kit/70_events.md#error +[download-file]: /products/microfrontend-composer/back-kit/70_events.md#download-file +[downloaded-file]: /products/microfrontend-composer/back-kit/70_events.md#downloaded-file +[delete-file]: /products/microfrontend-composer/back-kit/70_events.md#delete-file +[deleted-file]: /products/microfrontend-composer/back-kit/70_events.md#deleted-file +[fetch-files]: /products/microfrontend-composer/back-kit/70_events.md#fetch-files +[fetched-file]: /products/microfrontend-composer/back-kit/70_events.md#fetched-files +[success]: /products/microfrontend-composer/back-kit/70_events.md#success +[show-in-viewer]: /products/microfrontend-composer/back-kit/70_events.md#show-in-viewer + + + +```html + +``` + +The File Service Client manages http requests towards an instance of [Mia Files Service][files-service] to upload, download, store files. + +Further details on how Back-Kit components can be composed to handle file fields are available in the [specific section][file-management]. + +## How to configure + +To configure the File Service Client, property `basePath` should be specified. `basePath` is the base path of the URL to which HTTP requests are sent, i.e. the endpoint targeting the Files Service. + +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/files" + } +} +``` + +### Download and Preview File + +When a component signals the need to download a file (that is, emits a [download-file] event), the File Service Client by default performs a GET request to `/download/`. +Upon successful download, an [deleted-file] event is emitted, else an [error] event. + +However, if the meta field of the `download-file` event has key `showInViewer` set to true, the File Service Client attempts to fetch the file and, in case of success, notifies via [show-in-viewer] event that the file needs to be previewed, else notifies the failure with an [error] event. A component such as the [Pdf Viewer][bk-pdf-viewer] could pick up the `show-in-viewer` request. +If meta field `showInViewer` in `download-file` meta is set to "skip-checks", the File Service Client does not attempt to download the file, but rather immediately signals the request for the file to be previewed. + +#### Query Parameters Tuning + +Property `queryParams` handles how the file is downloaded, in compliance with [Files Service specifications][query-params] + +```json +{ + "download": 1, + "downloadWithOriginalName": 1, + "useOriginalName": 1 +} +``` + +Parameter `download` and `downloadWithOriginalName` are used when downloading the file, while parameter `useOriginalName` is used to fetch a file which should be previewed rather than downloaded. + +### Upload and Delete Files + +The File Service Client acts as a proxy between rendering components and the Files Service, facilitating the communication and interaction between the two. +It is designed to handle various types of events that may be received from other components, leading to HTTP requests being made to the Files Service. These events include: + +- **Upload File** + When a [upload-file][upload-file] event is received, the File Service Client sends a POST request to its base path + with a multipart body containing the file form the payload of the event, aiming at uploading the file to the file storage service. + In case the meta field of the event includes extra information (`metaData`), this is also included in the body of the POST request. + Upon successful upload, an [uploaded-file] event and a [success] event are emitted, else an [error] event. + +- **Delete File** + When a [delete-file][delete-file] event is received, the File Service Client sends a DELETE request to `/`, + where the name of the file is taken from the payload of the event, aiming at removing the file from the file storage service. + Upon successful deletion, an [deleted-file] event and a [success] event are emitted, else an [error] event. + + +### Fetch all Files + +Beginning from Files Service version 2.7.0, route `/files` is available. Reaching this route with a GET request allows to retrieve the list of files metadata handled by the Files Service. Data fetched in this way are paginated. + +The following query parameters can be appended to the GET + - `limit`: number of items to be fetched per page + - `page`: number of pages to skip + - `dateFrom`: filters out all files that were updated afterwards + +Upon receiving a [fetch-files] event, the File Service Client triggers a GET to `/files`, appending query parameters as specified in the payload of the event. + + +### Rerouting HTTP requests + +Property `reroutingRules` allows to reroute HTTP calls based on the their pathname and HTTP method. + +`reroutingRules` is an shaped like an array of objects with keys `from` and `to`. + - key `from` allows to specify two strings that are matched against the url pathname and HTTP method of the request + - key `to` allows to specify a string, being the URL pathname to which the request is redirected + +Each emitted HTTP request is matched against all rules using its `from` key. The request is rerouted to the value specified in the `to` key of first macthing rule. +Requests that match no rule are not redirected. + +:::info +If key `from` of an entry of `reroutingRules` is a string, all HTTP methods will be matched. +::: + +The regular expression specified in the `from` key of an entry of `reroutingRules` may include groups, which can be referenced in the `to` key using the character "$" and the index of the group or its name. + +```json +{ + "reroutingRules": [ + { + "from": { + "url": "/files/", + "method": "POST" + }, + "to": "/upload-file/" + }, + { + "from": { + "url": "/files/download/([^/]+)", + "method": "GET" + }, + "to": "/download/$1" + } + ] +} +``` + +## Examples + +### Example: Download File + +A File Service Client configured like the following: +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/files" + } +} +``` + +upon listening to a `download-file` event with payload +```json +{ + "file": "avatar.jpg" +} +``` + +triggers a GET call to `/files/download/avatar.jpg` with query parameters +```json +{ + "download": 1, + "downloadWithOriginalName": 1 +} +``` + +### Example: Query Parameters + +The File Service Client allows to configure the query parameters to be included in the HTTP call that is performed to download a file through property `queryParams`. + +A File Service Client configured like the following: +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/files", + "queryParams": { + "downloadWithOriginalName": 0 + } + } +} +``` + +upon listening to a `download-file` event with payload +```json +{ + "file": "avatar.jpg" +} +``` + +triggers a GET call to `/files/download/avatar.jpg` with query parameters +```json +{ + "download": 1, + "downloadWithOriginalName": 0 +} +``` + +### Example: Show in viewer + +A File Service Client configured like the following +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/files" + } +} +``` + +upon listening to a `download-file` event with this payload and meta: +```json +{ + "payload": { + "file": "avatar.jpg" + }, + "meta": { + "showInViewer": true + } +} + +``` + +attempts to download the file and, on success, emits a [show-in-viewer] event with payload: +```json +{ + "url": "/files/download/avatar.jpg?useOriginalName=1" +} +``` + +Depending on the `showInViewer` value in meta, the File Service Client has different behaviors: + - `"showInViewer": true`: it attempts to download the file and, on success, emits a [show-in-viewer] event. + - `"showInViewer": "skip-checks"`: it emits a `show-in-viewer` event, without first attempting to download the file. + + +:::info +If the plugin orchestration is managed by [micro-lc] (version 2 or higher) and `showInViewer` is `true`, headers configured in the `micro-lc` configuration are forwarded, while if `showInViewer` is `skip-checks`, they are not. +::: + +### Example: Fetch File List + +A File Service Client configured like the following: +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/file-service" + } +} +``` + +upon listening to a [fetch-files] event with payload +```json +{ + "limit": 20, + "page": 2 +} +``` + +triggers a GET call to `/file-service/files/` with query parameters identical to the payload of the event +```json +{ + "limit": 20, + "page": 2 +} +``` + + +### Example: Upload File + +A File Service Client configured like the following: +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/files" + } +} +``` + +upon listening to a [upload-file] event with payload +```json +{ + "file": { + ... // file to upload + } +} +``` +and meta +```json +{ + "metaData": { + "fileOwner": "Andrew" + } +} +``` + +triggers a POST call to `/files/` with a multipart body translation to the payload of the event as well as the extra information inside `meta.metaData` +```json +{ + "file": { + ... // file to upload + }, + "fileOwner": "Andrew" +} +``` + +### Example: Delete File + +A File Service Client configured like the following: +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/files" + } +} +``` + +upon listening to a [delete-file] event with payload +```json +{ + "file": "avatar.jpg" +} +``` + +triggers a DELETE call to `/avatar.jpg` + + + +### Example: Reroute HTTP Requests + +A File Service Client configured like the following: + +```json +{ + "tag": "bk-file-client", + "properties": { + "basePath": "/files", + "reroutingRules": [ + { + "from": { + "url": "/files/download/([^/]+)", + "method": "GET" + }, + "to": "/download/$1" + }, + { + "from": { + "url": "/files/", + "method": "POST" + }, + "to": "/upload-file/" + } + ] + } +} +``` + +requests to download a file form the path "/download/" instead of the default "/files/download/", and to upload a file from the path "/upload-file/" instead of the default "/files/". + +The HTTP request triggered to download a file would normally be a GET call against the "/files/download/name-of-the-file" path. +This call matches the first entry of `reroutingRules`; therefore, it is rerouted to "/download/name-of-the-file". +Notice how the "$" character can be used in the target path to reference groups captured in the regular expression specified inside `from.url`. + +The HTTP request to upload a file would normally be a POST call directed to "/files/". Such a request is intercepted by the second rule specified in `reroutingRules` and redirected to "/upload-file/". + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ---------------- | --------- |------------------------------------|-----------------------------------------------------------------------| ---------------------------------------------------------------------------------------------- | +| `basePath` | - | string | - | the URL base path to which to send HTTP requests | +| `headers` | - | `{[key: string]: string}` | - | headers to add when an HTTP request is sent | +| `credentials` | - | 'include'\|'omit'\|'same-origin' | - | credentials policy to apply to HTTP requests | +| `queryParams` | - | [QueryParams](#queryparams) | `{"download": 1,"downloadWithOriginalName": 1, "useOriginalName": 1}` | query parameters to be passed to the Files Service, according to [its interface][query-params] | +| `reroutingRules` | - | [ReroutingRule](#reroutingrule)[] | - | rules to redirect HTTP request to new routes | + +#### QueryParams + +```typescript +interface QueryParams { + download: 0 | 1 + downloadWithOriginalName: 0 | 1 + useOriginalName: 0 | 1 +} +``` + +#### ReroutingRule + +```typescript +type ReroutingRule = { + from: string | { url: string, method: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE' } + to: string +} +``` + +### Listens to + +| event | action | emits | on error | +| --------------- | ---------------------------------------------------------- | ---------------------------- | -------- | +| [upload-file] | sends a `POST` request to upload a file | [uploaded-file], [success] | [error] | +| [download-file] | sends a `GET` request to download/preview a file | [downloaded-file], [success] | [error] | +| [delete-file] | sends a `DELETE` request to remova a file from storage | [deleted-file], [success] | [error] | +| [fetch-files] | sends a `GET` request to fetch uploaded files from storage | [fetched-file], [success] | [error] | + + +### Emits + +| event | description | +| ----------------- | ------------------------------------------------------ | +| [uploaded-file] | notifies successful file upload | +| [downloaded-file] | notifies successful file download | +| [deleted-file] | notifies successful file deletion | +| [show-in-viewer] | requests to preview a PDF file inside a viewer | +| [success] | notifies successful HTTP request | +| [error] | contains http error messages when something goes wrong | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/300_filter_drawer.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/300_filter_drawer.md new file mode 100644 index 0000000000..51cf794a40 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/300_filter_drawer.md @@ -0,0 +1,286 @@ +--- +id: filter_drawer +title: Filter Drawer +sidebar_label: Filter Drawer +--- + + + + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[writable-views]: /runtime-components/plugins/crud-service/50_writable_views.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[filters-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#filters-options +[filter-operators]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filter-operators +[filter]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filters + +[add-filter]: /products/microfrontend-composer/back-kit/70_events.md#add-filter +[filter]: /products/microfrontend-composer/back-kit/70_events.md#filter +[change-filter]: /products/microfrontend-composer/back-kit/70_events.md#change-filter +[lookup-data]: /products/microfrontend-composer/back-kit/70_events.md#lookup-data +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data + +[bk-filters-manager]: /products/microfrontend-composer/back-kit/60_components/310_filters_manager.md + + + + +```html + +``` + +![filter-drawer](img/bk-filter-drawer.png) + +The Filter Drawer allows to compile a [filter] and signal the need for it to be applied on top of the already applied filters. +In particular, submitting the Filter Drawer injects the compiled filter into the payload of an [add-filter] event, which is listened by components such as the [Filters Manger][bk-filters-manager]. + +The Filter Drawer becomes visible whenever the request to provide support for applying filters is signaled. +That is, whenever events [filter] or [change-filter] are received. +The [change-filter] event allows to carry an object representation of a filter in its payload that is used by the Filter Drawer to initialize its fields. + + +## How to configure + +For its most basic usage, the Filter Drawer requires a [data-schema] describing the fields of the collection to filter. + +```json +{ + "tag": "bk-filter-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "name": {"type": "string"} + } + } + } +} +``` + +### Filters Options + +[Data-schema][data-schema] supports [options][filters-options] that are specific for how the data should be interpreted within the context of data filtering. + +In particular, + - `hidden` controls whether the property should not be available to be selected for compiling a filter + - `availableOperators` controls what [operators][filter-operators] should be available for the given property. + Note that the type of each property also limits the available operators + + +### Lookup fields (writable views) + +The Filter Drawer renders the filter value field as a select or a multi-select for fields described inside the data-schema as having type `object` or `array` and format `lookup`. + +Options for such fields will be dynamically fetched from the endpoint specified in `basePath` property, using the `/lookup` route provided by the [CRUD Service][crud-service] to [writable views][writable-views] (version 6.9.0 or higher) , which returns a list of objects. +Each option fetched like this should have at least a `label` field, which is used as display value inside the form, and a `value` field which is used as unique identifier for such option. + +:::caution +If you use the `_id` field as `value` in your lookups, remember to set its type as `string`. +::: + +### Locale + +The texts of the Filter Drawer can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + title: LocalizedText + description: LocalizedText + ctaLabel: LocalizedText + propertyPlaceholder: LocalizedText + operatorPlaceholder: LocalizedText + valueInputPlaceholder: LocalizedText + valueSelectPlaceholder: LocalizedText + namePlaceholder: LocalizedText + propertyRequired: LocalizedText + operatorRequired: LocalizedText + valueRequired: LocalizedText + valueLabelMap: { + between: { + start: LocalizedText + stop: LocalizedText + }, + notBetween: { + start: LocalizedText + stop: LocalizedText + } + }, + validationMessages: { + array: LocalizedText + file: LocalizedText + object: LocalizedText + }, + operators: { + equals: LocalizedText + exists: LocalizedText + doesNotEqual: LocalizedText + contains: LocalizedText + startsWith: LocalizedText + endsWith: LocalizedText + before: LocalizedText + beforeOrEqual: LocalizedText + on: LocalizedText + notOn: LocalizedText + after: LocalizedText + afterOrEqual: LocalizedText + is: LocalizedText + isNot: LocalizedText + greater: LocalizedText + greaterOrEqual: LocalizedText + less: LocalizedText + lessOrEqual: LocalizedText + includesSome: LocalizedText + includesAll: LocalizedText + includesExactly: LocalizedText + doesNotInclude: LocalizedText + between: LocalizedText + notBetween: LocalizedText + hasLengthEqual: LocalizedText + hasLengthGreaterEqual: LocalizedText + hasLengthLessEqual: LocalizedText + }, + datePicker: { + lang: { + locale: LocalizedText + placeholder: LocalizedText + rangePlaceholder: { + start: LocalizedText + stop: LocalizedText + }, + today: LocalizedText + now: LocalizedText + backToToday: LocalizedText + ok: LocalizedText + clear: LocalizedText + month: LocalizedText + year: LocalizedText + timeSelect: LocalizedText + dateSelect: LocalizedText + monthSelect: LocalizedText + yearSelect: LocalizedText + decadeSelect: LocalizedText + monthBeforeYear: 'true' | 'false' + previousMonth: LocalizedText + nextMonth: LocalizedText + previousYear: LocalizedText + nextYear: LocalizedText + previousDecade: LocalizedText + nextDecade: LocalizedText + previousCentury: LocalizedText + nextCentury: LocalizedText + }, + timePickerLocale:{ + placeholder: LocalizedText + } + }, + true: LocalizedText + false: LocalizedText +} +``` + +## Examples + +### Example: Basic Usage + +Through a Filter Drawer configured like: + +```json +{ + "tag": "bk-filter-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } +} +``` + +it is possible to create a filter on property "name" and a filter on property "price". +After selecting the desired property, the Filter Drawer allows to select an [operator][filter-operators] for the filter among those that are compatible with the property type. +Finally, a value can be provided. The kind input field to provide the value changes according to the [type and format][data-schema] of the selected property, as well as the operator. +Upon submission, the resulting filter is propagated through the payload of an [add-filter] event. For instance, + +```json +{ + "label": "add-filter", + "payload": { + "property": "name", + "operator": "contains", + "value": "Smith" + } +} +``` + +### Example: Filters options + +With a Filter Drawer configured like: + +```json +{ + "tag": "bk-filter-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "filtersOptions": { + "hidden": true + } + }, + "price": { + "type": "number", + "filtersOptions": { + "availableOperators": ["equals", "doesNotEqual"] + } + } + } + } + } +} +``` + +Due to the value of `filtersOptions` fields in the data-schema, it is possible to compile a filter only for property "price", and only based on operators "equal" and "doesNotEqual". + +## API + +### Properties & Attributes + + +| property | attribute | type | default | description | +| ---------------------- | ------------------------- | -------------------------------------------- | ------- | ------------------------------------------------------------ | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data-schema describing the fields of the collection to query | +| `liveSearchItemsLimit` | `live-search-items-limit` | number | 10 | max items to fetch on regex live search | +| `liveSearchTimeout` | `live-search-timeout` | number | 5000 | live-search timeout | +| `rootElementSelector` | `root-element-selector` | string | - | root element to append the drawer to | +| `width` | `width` | string | - | width occupied by the component | +| `editorHeight` | `editor-height` | string \| number | - | height of object/array editor | +| `basePath` | - | string | - | endpoint to use to fetch lookup options | + +### Listens to + + +| event | action | +| --------------- | ----------------------------------------------------------------- | +| [filter] | claims the drawer, closing concurrent ones, to enter a new filter | +| [change-filter] | enters filter edit mode | +| [lookup-data] | receives lookup data | +| [loading-data] | sets the component to loading state | + +### Emits + + +| event | description | +| ------------ | -------------------------------------------------------------- | +| [add-filter] | when done filling the form, notices deployment of a new filter | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/30_antd_theme_manager.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/30_antd_theme_manager.md new file mode 100644 index 0000000000..f27f4d8e2a --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/30_antd_theme_manager.md @@ -0,0 +1,154 @@ +--- +id: antd_theme_manager +title: Antd Theme Manager +sidebar_label: Antd Theme Manager +--- + + + + + +[ant-design]: https://ant.design/ +[mlc-antd-theme-manager]: https://micro-lc.io/add-ons/components/mlc-antd-theme-manager +[setStyle]: https://micro-lc.io/api/micro-lc-api/extensions#csssetstyle + + + +The Antd Theme Manager is a logical web component (does not render) that can be included in applications layout to inject an [Ant Design][ant-design] compatible theme. +This component is analogous to [mlc-antd-theme-manager] component from `micro-lc`. + +The web component calculates the CSS variables needed by `Ant Design Dynamic Theme` from a set of base colors (namely: primary, info, success, processing, error, and warning colors). +These variables are then injected globally through `micro-lc` API [setStyle method][setStyle]. + + +## How to configure + +The Antd Theme Manager component should be provided with variables that describe an [Ant Design][ant-design] compatible theme. +Property `primaryColor` sets the primary color of the theme and is usually provided. + +```json +{ + "tag": "bk-antd-theme-manager", + "properties": { + "themingUrl": "/theme-info", + "primaryColor": "771e1e" + } +} +``` + +### Set variables - fetch data dynamically + +Properties `primaryColor`, `infoColor`, `successColor`, `processingColor`, `errorColor`, `warningColor`, `fontFamily` can be set to describe the theme of the page. + +There are two options for setting each property: a string value or an object with the keys `path` and, optionally, `default`. +If a string value is used, it initializes the property directly. + +However, if the `themingUrl` property is provided, the corresponding property is initialized by applying the `path` (in JavaScript notation) to the current user's object-like representation. +The user information is obtained during bootstrap using property `themingUrl` as endpoint. + +## Examples + +With a configuration like: + +```json +{ + "tag": "bk-antd-theme-manager", + "properties": { + "themingUrl": "/theme-info", + "infoColor": "#F9C939", + "primaryColor": { + "path": "colors.primary" + }, + "successColor": { + "path": "colors.success" + }, + "processingColor": { + "path": "colors.processing" + }, + "errorColor": { + "path": "colors.error", + "default": "#25B864" + } + } +} +``` + +and assuming that a GET to the endpoint `/theme-info` returns + +```json +{ + "colors": { + "primary": "#43FA54", + "success": "#46C872" + } +} +``` + +Theming variables would be initialized to: + +```jsonc +{ + "primaryColor": "#43FA54", + "infoColor": "#F9C939", + "successColor": "#46C872", + "errorColor": "#25B864", + "processingColor": "#1890FF", + "warningColor": "#FAAD14", + "fontFamily": "'-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', 'sans-serif', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'" +} +``` + +Particularly: + +- **primaryColor** is retrieved from the response of the GET call to `/theme-info` + +- **infoColor** is set to the value provided in the configuration + +- **successColor** is retrieved from the response of the GET call to `/theme-info` + +- **errorColor** cannot be retrieved from the response of the GET call to `/theme-info`, so is set to the provided default in the configuration + +- **processingColor** cannot be retrieved from the response of the GET call to `/theme-info`, so is set to the default value of the `processingColor` property + +- **warningColor** is set to the default value of the `warningColor` property + +- **fontFamily** is set to the default value of the `fontFamily` property + + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| --------------- | ---------------- | ---------------------- | ---------- | --------------------------------------------------------- | +| varsPrefix | - | string \| string[] | 'micro-lc' | prefix to apply to css variables | +| themingUrl | theming-url | string | - | optional endpoint to call to initialize theming variables | +| primaryColor | primary-color | [Variable](#variable) | '#1890FF' | primary color | +| infoColor | info-color | [Variable](#variable) | '#1890FF' | info color | +| successColor | success-color | [Variable](#variable) | '#52C41A' | success color | +| processingColor | processing-color | [Variable](#variable) | '#1890FF' | processing color | +| errorColor | error-color | [Variable](#variable) | '#FF4D4F' | error color | +| warningColor | warning-color | [Variable](#variable) | '#FAAD14' | warning color | +| fontFamily | font-family | [Variable](#variable) | "'-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', 'sans-serif', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'" | fonts | + + +#### Variable + +```typescript +type Variable = string | { + path: string + default?: string +} +``` + +### Listens to + +None + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/310_filters_manager.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/310_filters_manager.md new file mode 100644 index 0000000000..e90b09faac --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/310_filters_manager.md @@ -0,0 +1,192 @@ +--- +id: filters_manager +title: Filters Manager +sidebar_label: Filters Manager +--- + + + + + +[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[filters-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#filters-options +[filters]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filters +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[change-filter]: /products/microfrontend-composer/back-kit/70_events.md#change-filter +[add-filter]: /products/microfrontend-composer/back-kit/70_events.md#add-filter + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-filter-drawer]: /products/microfrontend-composer/back-kit/60_components/300_filter_drawer.md + + + + +```html + +``` + + + +The Filters Manager manages the display, application, and modification of filters. +If no filter has been applied, the Filters Manager does not render anything. +Otherwise, a counter of applied filters is displayed. Upon clicking on the filters counter, a pop-up that lists such filters is displayed. +Each of these can be toggled and un-toggled, removed, or it is possible to emit the request for editing it. + +The Filters Manager listens to the request to add a new filter to existing ones, i.e. listens to [add-filter] events. +A component like the [Filter Drawer][bk-filter-drawer] could be the source of such request. +Applied filters are converted into a mongo-like query and propagated to other components, requesting to use such query when fetching data from the backend - that is, the query is injected into the payload of a [change-query] event. A component like the [CRUD client][bk-crud-client] listens to the `change-query` event and fetches data using its payload as query. + +## How to configure + +The Filters Manager does not require any particular configuration for its most basic usage: + +```json +{ + "tag": "bk-filters-manager" +} +``` + +### Bootstrap - Apply filters from URL + +Upon connecting to the page, the Filters Manager parses the page URL to retrieve the query parameter `filters`. +If found, its content is converted to [filters], and the request is issued to use such filters upon data retrieval. + +### Hide Filters + +A [data-schema] can be provided to the Filters Manager using property `dataSchema`, which might provide information for each field of the collection on how it should be used [with respect to filtering][filters-options]. + +In particular, filters on properties that include within their data-schema description the option to be hidden in filters: + +```json +{ + "filtersOptions": { + "hidden": true + } +} +``` + +are not included in the list of filters that is displayed by the Filters Manger. Nonetheless, the Filters Manger still requests the filter to be applied. + +### Persistent filters + +Property `saveFilters` allows to save filters to [local-storage]. +Filters are saved in local-storage through a key which can be customized with property `localStorageKey`, and defaults to `bk-filters-manager-store-` followed by the pathname of the current URL. +Upon connecting to the page, the Filters Manger fetches filters from local-storage and applies them. + +:::caution +To avoid data clashing, `localStorageKey` should be unique per page. +::: + +### Locale + +The texts of the Filters Manager can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + customFilters: LocalizedText + appliedFilter: LocalizedText + appliedFilters: LocalizedText + toggleFilter: LocalizedText + untoggleFilter: LocalizedText + deleteFilter: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +A Filters Manager that does not hold in its state any filter yet, with no particular configuration: +```json +{ + "tag": "bk-filters-manager" +} +``` + +upon receiving an [add-filter] event with payload: +```json +{ + "property": "name", + "operator": "equal", + "value": "Bruce" +} +``` + +emits a [change-query] event with payload: +```json +{ + "filters": [ + { + "property": "name", + "operator": "equal", + "value": "Bruce" + } + ] +} +``` + +And, upon receiving a second [add-filter] with payload: +```json +{ + "property": "price", + "operator": "greater", + "value": 15 +} +``` + +emits a [change-query] event with payload: +```json +{ + "filters": [ + { + "property": "name", + "operator": "equal", + "value": "Bruce" + }, + { + "property": "price", + "operator": "greater", + "value": 15 + } + ] +} +``` + + + + +## API + +### Properties & Attributes + + +| property | attribute | type | default | description | +| ----------------- | ------------------- | -------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data-schema describing the fields of the collection to query | +| `filters` | - | [Filter][filters][] | [] | List of currently applied filters | +| `hide` | `hide` | boolean | false | Hides the rendered component | +| `saveFilters` | `save-filters` | boolean | false | if true, filters are automatically saved to local storage | +| `localStorageKey` | `local-storage-key` | strign | bk-filters-manager-storage-`{pathname}` | key used to identify filters saved in local-storage. Defaults to a string composed of 'bk-filters-manager-storage-' and the pathname of the current URL. | + +### Listens to + + +| event | action | +| ------------ | -------------------- | +| [add-filter] | applies a new filter | + +### Emits + + +| event | description | +| --------------- | ----------------------------------------------- | +| [change-query] | requires data filtering | +| [change-filter] | triggers the modification of an existing filter | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/320_footer_&_item_state.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/320_footer_&_item_state.md new file mode 100644 index 0000000000..e917b2563e --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/320_footer_&_item_state.md @@ -0,0 +1,101 @@ +--- +id: footer_&_item_state +title: Footer & Item State +sidebar_label: Footer & Item State +--- + + + + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[predefined-fields]: /runtime-components/plugins/crud-service/10_overview_and_usage.md#predefined-collection-properties + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[count-data]: /products/microfrontend-composer/back-kit/70_events.md#count-data +[selected-data-bulk]: /products/microfrontend-composer/back-kit/70_events.md#selected-data-bulk +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[update-state-bulk]: /products/microfrontend-composer/back-kit/70_events.md#update-state-bulk + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + + + +```html + +``` + +![footer](img/bk-footer.png) + +The Footer & Item State renders an element counter and button acting on a selected dataset subset. It is designed to be placed as footer of a plugin page. + +The Footer & Item State keeps track of selected items monitoring the [selected-data-bulk] event. +When all selected items share the same `__STATE__` field, a button is rendered. +`__STATE__` field is one of the [predefined fields][predefined-fields] in collections handled vis [Mia Platform's CRUD Service][crud-service]. +Upon clicking the button, a request is sent to update the `__STATE__` field of selected items in a bulk operation. +This is achieved by the emission of an [update-state-bulk] event. +A component like the [CRUD Client][bk-crud-client] may manage this event. + +## How to configure + +The Footer & Item State does not require any explicit configuration. + +```json +{ + "tag": "bk-footer" +} +``` + +It is possible to disable the state change functionality by setting `disableStateChange` property to true. + + +### Locale + +The texts of the Footer can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + stateChangeCta: { + PUBLIC: LocalizedText + DRAFT: LocalizedText + TRASH: LocalizedText + }, + element: LocalizedText + elements: LocalizedText + selected: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| -------------------- | ---------------------- | ------- | ------- | ------------------------------------ | +| `disableStateChange` | `disable-state-change` | boolean | false | toggles state change functionalities | + +### Listens to + +| event | action | +| ------------------------------ | ----------------------------------------------------------------------------------------------------- | +| [loading-data] | sets internal loading state | +| [count-data] | adjusts footer counter to currently viewed dataset | +| [selected-data-bulk] | prepares callToAction on a given dataset subset | +| [nested-navigation-state/push] | updates internal representation of the current nesting path by adding one step | +| [nested-navigation-state/back] | updates internal representation of the current nesting path by removing the specified number of steps | + +### Emits + +| event | description | +| ------------------- | ------------------------------------------------------- | +| [update-state-bulk] | Updates the state of selected items in a bulk operation | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/330_form_card.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/330_form_card.md new file mode 100644 index 0000000000..4d7f507263 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/330_form_card.md @@ -0,0 +1,436 @@ +--- +id: form_card +title: Form Card +sidebar_label: Form Card +--- + + + + + + +[handlebars]: https://handlebarsjs.com/guide/expressions.html +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[predefined-fields]: /runtime-components/plugins/crud-service/10_overview_and_usage.md#predefined-collection-properties + +[bk-dynamic-from-card]: /products/microfrontend-composer/back-kit/60_components/190_dynamic_form_card.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[form-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#form-options +[helpers]: /products/microfrontend-composer/back-kit/40_core_concepts.md#helpers +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic configurations]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration + +[cardschema-header]: /products/microfrontend-composer/back-kit/60_components/140_card.md#header +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-file-manager]: /products/microfrontend-composer/back-kit/60_components/260_file_manager.md + +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[require-confirm]: /products/microfrontend-composer/back-kit/70_events.md#require-confirm +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[create-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#create-data-with-file +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file +[success]: /products/microfrontend-composer/back-kit/70_events.md#success +[error]: /products/microfrontend-composer/back-kit/70_events.md#error + + + + +:::caution +This component is deprecated. The [Dynamic Form Card][bk-dynamic-from-card] should be used instead. +::: + +```html + +``` + +![form-card](img/bk-form-card.png) + + +The Form Card renders a card containing a form to edit or create items described by the `dataSchema`. + +## How to configure + +For a basic usage of the Form Card, providing a data-schema to interpret the structure of the data to handle is sufficient. +Several [customizations][data-schema] can be applied to the provided data-schema that tune how the data is handled by the component. +Particularly, but not limited to, every field supports a set of [options][form-options] specific for forms. + +```json +{ + "tag": "bk-form-card", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id_": { + "type": "string", + "formOptions": { + "hidden": true // no input is rendered for _id field, but the Form Card still holds its value in the internal representation of the form values + } + }, + "__STATE__": { + "type": "string", + "default": "PUBLIC", + "enum": [ // enum string fields are rendered as select fields + "PUBLIC", + "DRAFT", + "TRASH" + ] + }, + "name": { + "type": "string" + }, + "price": { + "type": "number" + } + } + } + } +} +``` + +The components operates in two different modes: + +- *insert*: submitting the form signals the need for an item creation. Configurable by setting property `formKind` to "add". +- *edit*: submitting the form signals the need for an item creation. Configurable by setting property `formKind` to "edit" (default). + +If `formKind` is not specified, the Form Card operates in *edit* mode. + +When newly fetched data becomes available through a [display-data] event, the Form Card initiates its field. The component extracts values from one of the elements within the received data and interprets them based on its data-schema. The `dataIndex` property governs the selection of which data element to use for this purpose by specifying its index. By default, the card selects the first element (corresponding to `dataIndex` value 0) for this process + + +### Modes + +When the component reacts to the [display-data] event and property `formKind` is set to "add", the form initializes its fields with values specified in the payload of the event. + +In this mode, upon clicking on the submit button of the footer, the Form Card signals the request to push a new item to a CRUD collection, emitting the event [create-data] with payload extracted from the object representation of the form values. +A component such as the [CRUD Client][bk-crud-client] could pick up on the `create-data` event. +If the form contains files, the component emits a [create-data-with-file] event, which signals the need to upload files to a file storage service on top of pushing the item to a CRUD collection. +A component like the [File Manager][bk-file-manager] could listen to this event. + +A `transactionId` is added to the meta field of the emitted event to handle possible errors. + +#### Edit + +When the component reacts to the [display-data] event and property `formKind` is set to "add", the form initializes its fields with the values specified in the payload of the event. + +By clicking on the submit button, the Form Card signals the request to update an item in the CRUD collection, emitting the event [update-data] with payload providing the fields to change in the item. The item to update is identified by its `_id` field, which is a [predefined field][predefined-fields] of [Mia Platform's CRUD Service][crud-service] collections. +A component such as the [CRUD Client][bk-crud-client] could pick up on the `update-data` event. +If the form contains files, the component emits a [update-data-with-file] event, which signals the need to upload files to a file storage service on top of updating the item in the CRUD collection. +A component like the [File Manager][bk-file-manager] could listen to this event. + +A `transactionId` is added to the meta field of the emitted event to handle possible errors. + + +### After submission + +When done filling up the form, usually the Form Card requests data update or creation (via an [update-data] or [create-data] event) according to the operating [mode](#modes). +Usually an http-like client takes care of these operations. +It is often useful to perform other tasks upon successful creation or editing. +The prop `afterFinishEvents` allows to append events or `pushState` navigation instructions. +This feature can be configured by providing to `afterFinishEvents` + +1. a string, which will pipe an event using its value as label +2. an array of strings, launching multiple events in the given order +3. an event, + +```typescript +{ + label: string + payload: Record + meta?: Record +} +``` + +4. an array of events, +5. a **single** `pushState` context, which is a generic object data and an optional URL to perform navigation + +```typescript +{ + data: any + url?: string +} +``` + +:::caution +if `data` is an object and current `window.history.state` is an object, they are merged with priority to `data`'s keys +::: + +Form context can be used into the events/pushState sent after submission using [handlebars] notation. +Each event payload and both `pushState` arguments are parsed with handlebars injecting the following context + +```typescript +{ + values: Record + response: Record +} +``` + +where `values` is the form values and `response` contains an object representation of the content of the payload of the [success] event linked to the form submission request. + + +### Integrate custom labels + +Custom labels can be specified as [LocalizedText][localized-text] as card title, CTA button label, require confirm message. +Such labels can be scoped based on whether the form is in [edit or create mode](#modes). + +```json +{ + "tag": "bk-form-drawer", + "properties": { + "customLabels": { + "create": { + "title": { + "en": "Add new order", + "it": "Aggiungi nuovo ordine" + }, + "ctaLabel": { + "en": "Submit", + "it": "Submit Order" + }, + "unsavedChangesContent": { + "it": "Chiudendo ora si perderà l'ordine non salvate, procedere?", + "en": "Closing now will discard new order, do you want to continue?" + }, + "saveChangesContent": { + "it": "Verrà creato un nuovo ordine, procedere?", + "en": "A new order will be created, continue?" + } + }, + "update": { + "title": { + "en": "Order detail", + "it": "Dettaglio ordine" + }, + "ctaLabel": { + "en": "Update Order", + "it": "Salva Ordine" + }, + "unsavedChangesContent": { + "it": "Chiudendo ora si perderanno tutte le modifiche non salvate all'ordine, procedere?", + "en": "Closing now will discard changes to the order, do you want to continue?" + }, + "saveChangesContent": { + "it": "Verrà creato un nuovo ordine, procedere?", + "en": "A new order will be created, continue?" + } + } + } + } +} +``` + +Not all keys need to be specified, as `customLabels` is merged with default labels. +For instance, the following is a valid configuration of `customLabels`: + +```json +{ + "tag": "bk-form-drawer", + "properties": { + "customLabels": { + "create": { + "title": { + "en": "Add new order", + "it": "Aggiungi nuovo ordine" + } + }, + "update": { + "title": { + "en": "Order detail", + "it": "Dettaglio ordine" + } + } + } + } +} +``` + + +### Locale + +The texts of the Form Card can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + title: LocalizedText + ctaLabel: LocalizedText + cancelLabel: LocalizedText + unsavedChangesContent: LocalizedText + saveChangesContent: LocalizedText + form: { + validationMessages:{ + default: LocalizedText, + required: LocalizedText, + enum: LocalizedText, + whitespace: LocalizedText, + date:{ + format: LocalizedText, + parse: LocalizedText, + invalid: LocalizedText + }, + types:{ + string: LocalizedText, + method: LocalizedText, + array: LocalizedText, + object: LocalizedText, + number: LocalizedText, + date: LocalizedText, + boolean: LocalizedText, + integer: LocalizedText, + float: LocalizedText, + regexp: LocalizedText, + email: LocalizedText, + url: LocalizedText, + hex: LocalizedText, + file: LocalizedText + }, + string:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + number:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + array:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText, + unique: LocalizedText + }, + pattern:{ + mismatch: LocalizedText + } + }, + datePicker: { + lang: { + locale: LocalizedText, + placeholder: LocalizedText, + rangePlaceholder: { + start: LocalizedText, + stop: LocalizedText + }, + today: LocalizedText, + now: LocalizedText, + backToToday: LocalizedText, + ok: LocalizedText, + clear: LocalizedText, + month: LocalizedText, + year: LocalizedText, + timeSelect: LocalizedText, + dateSelect: LocalizedText, + monthSelect: LocalizedText, + yearSelect: LocalizedText, + decadeSelect: LocalizedText, + monthBeforeYear: 'true' | 'false', + previousMonth: LocalizedText, + nextMonth: LocalizedText, + previousYear: LocalizedText, + nextYear: LocalizedText, + previousDecade: LocalizedText, + nextDecade: LocalizedText, + previousCentury: LocalizedText, + nextCentury: LocalizedText + }, + timePickerLocale:{ + placeholder: LocalizedText + } + }, + filePicker:{ + drawerTitle: LocalizedText, + filePickerTitle: LocalizedText, + dragAndDropCaption: LocalizedText, + ctaLabel: LocalizedText + }, + objectEditor:{ + editorView: LocalizedText, + tableView: LocalizedText + }, + editor:{ + editorView: LocalizedText, + rawView: LocalizedText + }, + htmlEditor: { + preview: LocalizedText, + html: LocalizedText + }, + geopoint:{ + latitude: LocalizedText, + longitude: LocalizedText, + phLatitude: LocalizedText, + phLongitude: LocalizedText + }, + element: LocalizedText, + elements: LocalizedText, + true: LocalizedText, + false: LocalizedText + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ----------------------------- | --------------------------------- | -------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------- | +| `afterFinishEvents` | - | ConfigurableEvents | - | events or state push to concatenate after successful finish action has been performed | +| `allowAutoDisableDeps` | `allow-auto-disable-deps` | boolean | false | if true, dependent lookup and multilookup select fields are automatically disabled in case of no options | +| `customLabels` | - | [FormCardLocale](#customlabels) | - | custom localized texts shown as CTA buttons labels | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data schema describing the fields of the collection to filter | +| `enableSubmitOnFormUntouched` | `enable-submit-on-form-untouched` | boolean | false | boolean to enable footer call-to-action even if no field within the form has been touched | +| `formKind` | - | "add" \| "edit" | "edit" | data management strategy when setting initial values from displayData: add or edit (default) | +| `liveSearchItemsLimit` | `live-search-items-limit` | number | 10 | max items to fetch on regex live search | +| `liveSearchTimeout` | `live-search-timeout` | number | 5000 | live-search timeout | +| `readonlyOnView` | `readonly-on-view` | boolean | false | upon marking this prop as true, on selecting a record, the form will be displayed as readonly, with no possibility to edit | +| `editorHeight` | `editor-height` | string \| number | - | height of object/array editor | +| `header` | - | [CardSchema.header][cardschema-header] | - | Card header | + + +#### CustomLabels + +```typescript +type CustomLabels = { + title?: LocalizedText + ctaLabel?: LocalizedText + saveChangesContent?: LocalizedText + cancelLabel?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +### Listens to + + +| event | action | +| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| [display-data] | initializes the form to create or update an item, potentially applying default fields from data schema or data provided in the payload of the event | +| [success] | notifies correct data update as a result of form submission | +| [error] | notifies that something went wrong during form submission | + +### Emits + + +| event | description | +| ----------------------- | --------------------------------------------------------- | +| configurable event | property `afterFinishEvents` allows to emit custom events | +| [require-confirm] | triggered when trying to save the form with unsaved data | +| [create-data] | requests data creation | +| [update-data] | requests data update | +| [create-data-with-file] | requests data creation and file upload | +| [update-data-with-file] | requests data update and file upload | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/340_form_drawer.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/340_form_drawer.md new file mode 100644 index 0000000000..6492a38b20 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/340_form_drawer.md @@ -0,0 +1,532 @@ +--- +id: form_drawer +title: Form Drawer +sidebar_label: Form Drawer +--- + + + + + + +[handlebars]: https://handlebarsjs.com/guide/expressions.html + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[predefined-fields]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[writable-views]: /runtime-components/plugins/crud-service/50_writable_views.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[form-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#form-options +[helpers]: /products/microfrontend-composer/back-kit/40_core_concepts.md#helpers +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic configurations]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration +[inline-queries]: /products/microfrontend-composer/back-kit/40_core_concepts.md#inline-queries + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-dynamic-form-drawer]: /products/microfrontend-composer/back-kit/60_components/200_dynamic_form_drawer.md +[bk-file-manager]: /products/microfrontend-composer/back-kit/60_components/260_file_manager.md +[bk-confirmation-modal]: /products/microfrontend-composer/back-kit/60_components/160_confirmation_modal.md +[bk-file-picker-modal]: /products/microfrontend-composer/back-kit/60_components/280_file_picker_modal.md +[bk-file-picker-drawer]: /products/microfrontend-composer/back-kit/60_components/270_file_picker_drawer.md + +[add-new]: /products/microfrontend-composer/back-kit/70_events.md#add-new +[selected-data]: /products/microfrontend-composer/back-kit/70_events.md#selected-data +[require-confirm]: /products/microfrontend-composer/back-kit/70_events.md#require-confirm +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[create-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#create-data-with-file +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file +[success]: /products/microfrontend-composer/back-kit/70_events.md#success +[error]: /products/microfrontend-composer/back-kit/70_events.md#error +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/display]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---dispaly + + + + +:::caution +This component is deprecated. The [Dynamic Form Drawer][bk-dynamic-form-drawer] should be used instead. +::: + +```html + +``` + +![form-drawer](img/bk-form-drawer.png) + +The Form Drawer is used to display a drawer containing a form to edit or create items described by the `dataSchema`. + +## How to configure + +For a basic usage of the Form Drawer, providing a data-schema to interpret the structure of the data to handle is sufficient. +Several [customizations][data-schema] can be applied to the provided data-schema that tune how the data is handled by the component. +Particularly, but not limited to, every field supports a set of [options][form-options] specific for forms. + +```json +{ + "tag": "bk-form-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id_": { + "type": "string", + "formOptions": { + "hidden": true // no input is rendered for _id field, but the Form Drawer still holds its value in the internal representation of the form values + } + }, + "__STATE__": { + "type": "string", + "default": "PUBLIC", + "enum": [ // enum string fields are rendered as select fields + "PUBLIC", + "DRAFT", + "TRASH" + ] + }, + "name": { + "type": "string" + }, + "price": { + "type": "number" + } + } + } + } +} +``` + + +The Form Drawer can be opened in two different modes: + +- *insert*: submitting the form signals the need for an item creation. This mode is activated upon listening to an [add-new] event +- *edit*: submitting the form signals the need for an item creation. This mode is activated upon listening to an [selected-data] event + + +### Modes + +#### Insert + +When the component reacts to the [add-new] event, the drawer opens and the form initializes its fields with values specified in the payload of the event. +In this mode, upon clicking on the submit button of the footer, the Form Drawer signals the request to push a new item to a CRUD collection, emitting the event [create-data] with payload extracted from the state of the form, particularly its values. +A component such as the [CRUD Client][bk-crud-client] could pick up on the `create-data` event. +If the form contains files, the component emits a [create-data-with-file] event, which signals the need to upload files to a file storage service on top of pushing the item to a CRUD collection. +A component like the [File Manager][bk-file-manager] could listen to this event. + +A `transactionId` is added to the meta field of the emitted event to handle possible errors. + +#### Edit + +When the component reacts to the [selected-data] event, the drawer opens and the form initializes its fields with the values specified in the payload of the event. + +By clicking on the submit button, the Form Drawer signals the request to update an item in the CRUD collection, emitting the event [update-data] with payload determined the state of the form, particularly its values +The item to update is identified by its `_id` field, which is a [predefined field][predefined-fields] of [Mia Platform's CRUD Service][crud-service] collections. +A component such as the [CRUD Client][bk-crud-client] could pick up on the `update-data` event. +If the form contains files, the component emits a [update-data-with-file] event, which signals the need to upload files to a file storage service on top of updating the item in the CRUD collection. +A component like the [File Manager][bk-file-manager] could listen to this event. + +A `transactionId` is added to the meta field of the emitted event to handle possible errors. + +### After submission + +When done filling up the form, usually the Form Drawer requests data update or creation (via an [update-data] or [create-data] event) according to the operating [mode](#modes). +Usually an http-like client takes care of these operations. +It is often useful to perform other tasks upon successful creation or editing. +The prop `afterFinishEvents` allows to append events or `pushState` navigation instructions. +This feature can be configured by providing to `afterFinishEvents` + +1. a string, which will pipe an event using its value as label +2. an array of strings, launching multiple events in the given order +3. an event, + +```typescript +{ + label: string + payload: Record + meta?: Record +} +``` + +4. an array of events, +5. a **single** `pushState` context, which is a generic object data and an optional URL to perform navigation + +```typescript +{ + data: any + url?: string +} +``` + +:::caution +if `data` is an object and current `window.history.state` is an object, they are merged with priority to `data`'s keys +::: + +Form context can be used into the events/pushState sent after submission using [handlebars] notation. +Each event payload and both `pushState` arguments are parsed with handlebars injecting the following context + +```typescript +{ + values: Record + response: Record +} +``` + +where `values` is the form values and `response` contains an object representation of the content of the payload of the [success] event linked to the form submission request. + + +### Confirmation dialog on save and on close + +It is possible to require confirmation before submitting the form or closing the drawer, using the `requireConfirm` property. +`requireConfirm` accepts a boolean or an object value, and defaults to `false`. + +It is furthermore possible to scope confirmation request configuration depending on the triggering action, either closing the drawer or submitting the form: + +```json +{ + "requireConfirm": { + "onSave": ..., // boolean or object configuration + "onClose": ... // boolean or object configuration + } +} +``` + +#### 1. Boolean type + +If `requireConfirm` is set to true, the Form Drawer, upon submission or closing, signals that confirmation for an actions is needed with event [require-confirm]. +A component such as the [Confirmation Modal][bk-confirmation-modal] could react to the event. + +#### 2. Object type + +An object such as: +```typescript +{ + cancelText?: LocalizedText // cancel button text + okText?: LocalizedText // ok button text + content?: LocalizedText // the content text + title?: LocalizedText // the title text +} +``` +can be provided as value to `requireConfirm`. +[LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +```json +{ + "content": { + "it": "Verrà creato un nuovo elemento, procedere?", + "en": "A new element will be created, continue?" + } +} +``` + +This allows to request customized labels in the confirmation dialog-box. +When structure in this way, the value for property `requireConfirm` is appended to the [require-confirm] event. +If this request is picked up by a component such as the [Confirmation Modal][bk-confirmation-modal], this prompts the user for confirmation via a pop-up dialog-box having the specified labels. + + +### Integrate custom labels + +Custom labels can be specified as [LocalizedText][localized-text] as drawer title, CTA button label, require confirm message. +Such labels can be scoped based on whether the form is in [edit or create mode](#modes). + +```json +{ + "tag": "bk-form-drawer", + "properties": { + "customLabels": { + "create": { + "title": { + "en": "Add new order", + "it": "Aggiungi nuovo ordine" + }, + "ctaLabel": { + "en": "Submit", + "it": "Submit Order" + }, + "unsavedChangesContent": { + "it": "Chiudendo ora si perderà l'ordine non salvate, procedere?", + "en": "Closing now will discard new order, do you want to continue?" + }, + "saveChangesContent": { + "it": "Verrà creato un nuovo ordine, procedere?", + "en": "A new order will be created, continue?" + } + }, + "update": { + "title": { + "en": "Order detail", + "it": "Dettaglio ordine" + }, + "ctaLabel": { + "en": "Update Order", + "it": "Salva Ordine" + }, + "unsavedChangesContent": { + "it": "Chiudendo ora si perderanno tutte le modifiche non salvate all'ordine, procedere?", + "en": "Closing now will discard changes to the order, do you want to continue?" + }, + "saveChangesContent": { + "it": "Verrà creato un nuovo ordine, procedere?", + "en": "A new order will be created, continue?" + } + } + } + } +} +``` + +Not all keys need to be specified, as `customLabels` is merged with default labels. +For instance, the following is a valid configuration of `customLabels`: + +```json +{ + "tag": "bk-form-drawer", + "properties": { + "customLabels": { + "create": { + "title": { + "en": "Add new order", + "it": "Aggiungi nuovo ordine" + } + }, + "update": { + "title": { + "en": "Order detail", + "it": "Dettaglio ordine" + } + } + } + } +} +``` + +### File fields with meta-data + +Fields described in the data-schema as having the type `object` or `array` and format `file` are rendered in the form as drag-and-drop fields. These fields enable interaction with uploaded files and allow uploading new files. + +However, when such fields include a `dataSchema` or `items` property, they are presented within the form as a link along with a button. + +The link enables the downloading of the files present in the initial values of the form. +Clicking the button triggers the appearance of components such as [File Picker Modal][bk-file-picker-modal] or [File Picker Drawer][bk-file-picker-drawer], provided they are included in the plugin configuration. +Both the File Picker Modal and File Picker Drawer offer interaction with the uploaded files and the option to set metadata for newly uploaded files. In this context, the `dataSchema` and `items` properties define the structure of the associated file metadata. + +Upon submission, the form initiates a request to push or update data within a CRUD collection and upload new files to a file storage service. +This is accomplished by emitting either a [create-data-with-file] or an [update-data-with-file] event, which can be intercepted by components like the [File Manager][bk-file-manager]. + + +### Locale + +The texts of the Form Drawer can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + create: { + title: LocalizedText + ctaLabel: LocalizedText + unsavedChangesContent: LocalizedText + saveChangesContent: LocalizedText + subtitle: LocalizedText + } + update: { + title: LocalizedText + ctaLabel: LocalizedText + unsavedChangesContent: LocalizedText + saveChangesContent: LocalizedText + subtitle: LocalizedText + } + form: { + validationMessages:{ + default: LocalizedText, + required: LocalizedText, + enum: LocalizedText, + whitespace: LocalizedText, + date:{ + format: LocalizedText, + parse: LocalizedText, + invalid: LocalizedText + }, + types:{ + string: LocalizedText, + method: LocalizedText, + array: LocalizedText, + object: LocalizedText, + number: LocalizedText, + date: LocalizedText, + boolean: LocalizedText, + integer: LocalizedText, + float: LocalizedText, + regexp: LocalizedText, + email: LocalizedText, + url: LocalizedText, + hex: LocalizedText, + file: LocalizedText + }, + string:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + number:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + array:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText, + unique: LocalizedText + }, + pattern:{ + mismatch: LocalizedText + } + }, + datePicker: { + lang: { + locale: LocalizedText, + placeholder: LocalizedText, + rangePlaceholder: { + start: LocalizedText, + stop: LocalizedText + }, + today: LocalizedText, + now: LocalizedText, + backToToday: LocalizedText, + ok: LocalizedText, + clear: LocalizedText, + month: LocalizedText, + year: LocalizedText, + timeSelect: LocalizedText, + dateSelect: LocalizedText, + monthSelect: LocalizedText, + yearSelect: LocalizedText, + decadeSelect: LocalizedText, + monthBeforeYear: 'true' | 'false', + previousMonth: LocalizedText, + nextMonth: LocalizedText, + previousYear: LocalizedText, + nextYear: LocalizedText, + previousDecade: LocalizedText, + nextDecade: LocalizedText, + previousCentury: LocalizedText, + nextCentury: LocalizedText + }, + timePickerLocale:{ + placeholder: LocalizedText + } + }, + filePicker:{ + drawerTitle: LocalizedText, + filePickerTitle: LocalizedText, + dragAndDropCaption: LocalizedText, + ctaLabel: LocalizedText + }, + objectEditor:{ + editorView: LocalizedText, + tableView: LocalizedText + }, + editor:{ + editorView: LocalizedText, + rawView: LocalizedText + }, + htmlEditor: { + preview: LocalizedText, + html: LocalizedText + }, + geopoint:{ + latitude: LocalizedText, + longitude: LocalizedText, + phLatitude: LocalizedText, + phLongitude: LocalizedText + }, + element: LocalizedText, + elements: LocalizedText, + true: LocalizedText, + false: LocalizedText + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## API + +### Properties & Attributes + + +| property | attribute | type | default | description | +| ----------------------------- | ------------------------- |--------------------------------------------------------------------------------------------------------------------| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `afterFinishEvents` | - | ConfigurableEvents | - | events or state push to concatenate after successful finish action has been performed | +| `allowAutoDisableDeps` | `allow-auto-disable-deps` | boolean | false | if true, dependent lookup and multilookup select fields are automatically disabled in case of no options | +| `customMessageOnAbsentLookup` | - | [LocalizedText][localized-text] | - | override lookup value in case lookup is not resolved due to lack of data | +| `dataCustomActions` | - | DrawerDataActionConfig[] | [] | list of actions to render per row | +| `liveSearchTimeout` | `live-search-timeout` | number | 5000 | live-search timeout | +| `rootElementSelector` | `root-element-selector` | string | - | Selector to specify where the container should be appended | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | Data schema describing the fields of the collection to filter | +| `readonlyOnView` | `read-only-on-view` | boolean | false | Upon marking this prop as true, on selecting a record, the form will be displayed as readonly, with no possibility to edit | +| `editorHeight` | `editor-height` | string \| number | - | Height of the object/array editor field | +| `allowNavigation` | `allow-navigation` | boolean \| 'show-editor' | true | When true, objects and arrays are displayed as a clickable label which allows navigating to nested objects and arrays if a dataSchema is specified. When 'show-editor', the navigation is allowed, and the object/array fields are displayed in a JSON editor. When false, the navigation is not allowed, and the object/array fields are displayed in a JSON editor | +| `width` | - | string \| number | - | Width of the drawer | +| `liveSearchItemsLimit` | `live-search-items-limit` | number | 10 | Max items to fetch on regex live search | +| `customLabels` | - | [CustomLabels](#customlabels) \| `{insert: CustomLabels, update: CustomLabels}` | - | Custom localized texts shown as title and CTA button label | +| `requireConfirm` | - | boolean \| [RequireConfirmOpts](#requireconfirmopts) \| `{onSave: RequireConfirmOpts, onSave: RequireConfirmOpts}` | false | Whether or not the component should request confirmation before closing and/or before saving | + + +#### RequireConfirmOpts + +```typescript +type RequireConfirmOpts = boolean | { + cancelText?: LocalizedText + okText?: LocalizedText + content?: LocalizedText + title?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +#### CustomLabels + +```typescript +type CustomLabels = { + title?: LocalizedText + ctaLabel?: LocalizedText + saveChangesContent?: LocalizedText + unsavedChangesContent?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +### Listens to + +| event | action | +| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| [add-new] | opens the drawer to create a new item, potentially applying default fields from data schema or data provided in the payload of the event | +| [selected-data] | opens the drawer to edit a selected item, filling in its fields from the data provided in the payload of the event | +| [nested-navigation-state/push] | updates internal representation of the current navigation path by adding one step | +| [nested-navigation-state/back] | updates internal representation of the current navigation path by removing the specified number of steps | +| [nested-navigation-state/display] | updates internal representation of the current navigation and closes the drawer | +| [success] | notifies correct data update as a result of form submission | +| [error] | notifies that something went wrong during form submission | + +### Emits + + +| event | description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| configurable event | property `afterFinishEvents` allows to emit custom events | +| [require-confirm] | triggered when trying to close the modal with unsaved data. `requireConfirm` property allows to customize this behavior | +| [create-data] | requests data creation | +| [update-data] | requests data update | +| [create-data-with-file] | requests data creation and file upload | +| [update-data-with-file] | requests data update and file upload | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/350_form_modal.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/350_form_modal.md new file mode 100644 index 0000000000..47553db293 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/350_form_modal.md @@ -0,0 +1,688 @@ +--- +id: form_modal +title: Form Modal +sidebar_label: Form Modal +--- + + + + + + + + +[monaco-editor]: https://microsoft.github.io/monaco-editor/ +[handlebars]: https://handlebarsjs.com/guide/expressions.html + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[predefined-fields]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[writable-views]: /runtime-components/plugins/crud-service/50_writable_views.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[nested-schemas]: /products/microfrontend-composer/back-kit/80_examples/20_nested_data.md +[form-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#form-options +[helpers]: /products/microfrontend-composer/back-kit/40_core_concepts.md#helpers +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic configurations]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration +[inline-queries]: /products/microfrontend-composer/back-kit/40_core_concepts.md#inline-queries + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md +[bk-dynamic-form-modal]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md +[bk-form-wizard]: /products/microfrontend-composer/back-kit/60_components/360_form_wizard.md +[bk-file-manager]: /products/microfrontend-composer/back-kit/60_components/260_file_manager.md +[bk-file-picker-modal]: /products/microfrontend-composer/back-kit/60_components/280_file_picker_modal.md +[bk-file-picker-drawer]: /products/microfrontend-composer/back-kit/60_components/270_file_picker_drawer.md +[bk-confirmation-modal]: /products/microfrontend-composer/back-kit/60_components/160_confirmation_modal.md +[bk-notifications]: /products/microfrontend-composer/back-kit/60_components/460_notifications.md + +[add-new]: /products/microfrontend-composer/back-kit/70_events.md#add-new +[add-new-external]: /products/microfrontend-composer/back-kit/70_events.md#add-new-external +[selected-data]: /products/microfrontend-composer/back-kit/70_events.md#selected-data +[require-confirm]: /products/microfrontend-composer/back-kit/70_events.md#require-confirm +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[create-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#create-data-with-file +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file +[success]: /products/microfrontend-composer/back-kit/70_events.md#success +[error]: /products/microfrontend-composer/back-kit/70_events.md#error +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/display]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---dispaly + + + + +:::caution +This component is deprecated. The [Dynamic Form Modal][bk-dynamic-form-modal] or the [Form Wizard][bk-form-wizard] should be used instead. +::: + +```html + +``` + +![form-modal](img/bk-form-modal.png) + +The Form Modal is used to display a modal containing a form to edit or create items described by the `dataSchema`. + +## How to configure + +For a basic usage of the Form Modal, providing a data-schema to interpret the structure of the data to handle is sufficient. +Several [customizations][data-schema] can be applied to the provided data-schema that tune how the data is handled by the component. +Particularly, but not limited to, every field supports a set of [options][form-options] specific for forms. + +```json +{ + "tag": "bk-form-modal", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id_": { + "type": "string", + "formOptions": { + "hidden": true // no input is rendered for _id field, but the Form Modal still holds its value in the internal representation of the form values + } + }, + "__STATE__": { + "type": "string", + "default": "PUBLIC", + "enum": [ // enum string fields are rendered as select fields + "PUBLIC", + "DRAFT", + "TRASH" + ] + }, + "name": { + "type": "string" + }, + "price": { + "type": "number" + } + } + } + } +} +``` + +The Form Modal can be opened in three different modes: + +- *insert*: submitting the form signals the need for an item creation. This mode is activated upon listening to an [add-new] event +- *edit*: submitting the form signals the need for an item creation. This mode is activated upon listening to an [selected-data] event +- *external*: submitting the form triggers a POST request being performed to an endpoint specified with `extraEndpoint` property. This mode is activated upon listening to an [add-new-external] event + +### Modes + +#### Insert + +When the component reacts to the [add-new] event, the modal opens and the form initializes its fields with values specified in the payload of the event. +In this mode, upon clicking on the submit button of the footer, the Form Modal signals the request to push a new item to a CRUD collection, emitting the event [create-data] with payload extracted from the state of the form, particularly its values. +A component such as the [CRUD Client][bk-crud-client] could pick up on the `create-data` event. +If the form contains files, the component emits a [create-data-with-file] event, which signals the need to upload files to a file storage service on top of pushing the item to a CRUD collection. +A component like the [File Manager][bk-file-manager] could listen to this event. + +A `transactionId` is added to the meta field of the emitted event to handle possible errors. + +#### Edit + +When the component reacts to the [selected-data] event, the modal opens and the form initializes its fields with the values specified in the payload of the event. + +By clicking on the submit button, the Form Modal signals the request to update an item in the CRUD collection, emitting the event [update-data] with payload determined the state of the form, particularly its values +The item to update is identified by its `_id` field, which is a [predefined field][predefined-fields] of [Mia Platform's CRUD Service][crud-service] collections. +A component such as the [CRUD Client][bk-crud-client] could pick up on the `update-data` event. +If the form contains files, the component emits a [update-data-with-file] event, which signals the need to upload files to a file storage service on top of updating the item in the CRUD collection. +A component like the [File Manager][bk-file-manager] could listen to this event. + +A `transactionId` is added to the meta field of the emitted event to handle possible errors. + +#### External + +When the component reacts to the [add-new-external] event AND the property `extraEndpoint` is specified, the modal opens and the form initializes its fields with the values specified in the payload of the event. + +By clicking on the submit button, the Form Modal performs a HTTP POST to the endpoint specified in the `extraEndpoint` property, using its values as body. + +The outcome of the HTTP request is notified to other components emitting either [success] or [error] event. Either way, a `triggeredBy` field is injected into the meta of the event with value `bk-form-modal-extra-endpoint`. Components such as the [Notifications][bk-notifications] leverage `triggeredBy` for displaying push notifications. + +If the form contains files, the POST is performed with a multipart body. + +### After submission + +When done filling up the form, usually the Form Modal requests data update or creation (via an [update-data] or [create-data] event) according to the operating [mode](#modes). +Usually an http-like client takes care of these operations. +It is often useful to perform other tasks upon successful creation or editing. +The prop `afterFinishEvents` allows to append events or `pushState` navigation instructions. +This feature can be configured by providing to `afterFinishEvents` + +1. a string, which will pipe an event using its value as label +2. an array of strings, launching multiple events in the given order +3. an event, + +```typescript +{ + label: string + payload: Record + meta?: Record +} +``` + +4. an array of events, +5. a **single** `pushState` context, which is a generic object data and an optional URL to perform navigation + +```typescript +{ + data: any + url?: string +} +``` + +:::caution +if `data` is an object and current `window.history.state` is an object, they are merged with priority to `data`'s keys +::: + +Form context can be used into the events/pushState sent after submission using [handlebars] notation. +Each event payload and both `pushState` arguments are parsed with handlebars injecting the following context + +```typescript +{ + values: Record + response: Record +} +``` + +where `values` is the form values and `response` contains an object representation of the content of the payload of the [success] event linked to the form submission request. + + +### Confirmation dialog on save and on close + +It is possible to require confirmation before submitting the form or closing the modal, using the `requireConfirm` property. +`requireConfirm` accepts a boolean or an object value, and defaults to `false`. + +It is furthermore possible to scope confirmation request configuration depending on the triggering action, either closing the modal or submitting the form: + +```json +{ + "requireConfirm": { + "onSave": ..., // boolean or object configuration + "onClose": ... // boolean or object configuration + } +} +``` + +#### 1. Boolean type + +If `requireConfirm` is set to true, the Form Modal, upon submission or closing, signals that confirmation for an actions is needed with event [require-confirm]. +A component such as the [Confirmation Modal][bk-confirmation-modal] could react to the event. + +#### 2. Object type + +An object such as: +```typescript +{ + cancelText?: LocalizedText // cancel button text + okText?: LocalizedText // ok button text + content?: LocalizedText // the content text + title?: LocalizedText // the title text +} +``` +can be provided as value to `requireConfirm`. +[LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +```json +{ + "content": { + "it": "Verrà creato un nuovo elemento, procedere?", + "en": "A new element will be created, continue?" + } +} +``` + +This allows to request customized labels in the confirmation dialog-box. +When structure in this way, the value for property `requireConfirm` is appended to the [require-confirm] event. +If this request is picked up by a component such as the [Confirmation Modal][bk-confirmation-modal], this prompts the user for confirmation via a pop-up dialog-box having the specified labels. + + +### Integrate custom labels + +Custom labels can be specified as [LocalizedText][localized-text] as modal title, CTA button label, require confirm message. +Such labels can be scoped based on whether the form is in [edit or create mode](#modes). + +```json +{ + "tag": "bk-form-modal", + "properties": { + "customLabels": { + "create": { + "title": { + "en": "Add new order", + "it": "Aggiungi nuovo ordine" + }, + "ctaLabel": { + "en": "Submit", + "it": "Submit Order" + }, + "unsavedChangesContent": { + "it": "Chiudendo ora si perderà l'ordine non salvate, procedere?", + "en": "Closing now will discard new order, do you want to continue?" + }, + "saveChangesContent": { + "it": "Verrà creato un nuovo ordine, procedere?", + "en": "A new order will be created, continue?" + } + }, + "update": { + "title": { + "en": "Order detail", + "it": "Dettaglio ordine" + }, + "ctaLabel": { + "en": "Update Order", + "it": "Salva Ordine" + }, + "unsavedChangesContent": { + "it": "Chiudendo ora si perderanno tutte le modifiche non salvate all'ordine, procedere?", + "en": "Closing now will discard changes to the order, do you want to continue?" + }, + "saveChangesContent": { + "it": "Verrà creato un nuovo ordine, procedere?", + "en": "A new order will be created, continue?" + } + } + } + } +} +``` + +Not all keys need to be specified, as `customLabels` is merged with default labels. +For instance, the following is a valid configuration of `customLabels`: + +```json +{ + "tag": "bk-form-modal", + "properties": { + "customLabels": { + "create": { + "title": { + "en": "Add new order", + "it": "Aggiungi nuovo ordine" + } + }, + "update": { + "title": { + "en": "Order detail", + "it": "Dettaglio ordine" + } + } + } + } +} +``` + + +### Nested objects + +By default, objects and arrays are displayed in the Form Modal as JSONs inside an [editor][monaco-editor]. +This is not true for objects and arrays of specific [formats][data-schema] such as `file` or `multilookup`, and for objects / arrays for which a data-schema is defined. + +In particular, properties `allowObjectAsTable` and `allowNavigation` control how object and array fields with a provided data-schema (and no specific `format`) are rendered inside the modal. +- `allowObjectAsTable` controls whether or not the nested fields should be rendered as an editor, a read-only table, or both. +- `allowNavigation` allows to emit a [nested-navigation-state/push] event by clicking on the [nested field][nested-schemas] label + +By default, setting `allowNavigation` to true disables editor visualization for nested fields. The following table explains how the two properties interact: + +| `allowObjectAsTable` | `allowNavigation` | end result | +| -------------------- | ----------------- | ---------- | +| true | true | Table visualization only, label can be clicked | +| true | "show-editor" | Table + editor, label can be clicked | +| true | false | Table + editor, label cannot be clicked | +| false | true | No table nor editor, label can be clicked (default configuration) | +| false | "show-editor" | Editor visualization only, label can be clicked | +| false | false | Editor visualization only, label cannot be clicked | + +By default, `allowObjectAsTable` is false, `allowNavigation` is true. + +:::info +When `allowObjectAsTable` is true, the resulting table supports a subset of the features supported by the [Table component][bk-table]. +Some of the limitations with respect to the Table include: + - lookups are not resolved + - row selection is disabled + - row click is disabled +::: + + +### File fields with meta-data + +Fields described in the data-schema as having the type `object` or `array` and format `file` are rendered in the form as drag-and-drop fields. These fields enable interaction with uploaded files and allow uploading new files. + +However, when such fields include a `dataSchema` or `items` property, they are presented within the form as a link along with a button. + +The link enables the downloading of the files present in the initial values of the form. +Clicking the button triggers the appearance of components such as [File Picker Modal][bk-file-picker-modal] or [File Picker Drawer][bk-file-picker-drawer], provided they are included in the plugin configuration. +Both the File Picker Modal and File Picker Drawer offer interaction with the uploaded files and the option to set metadata for newly uploaded files. In this context, the `dataSchema` and `items` properties define the structure of the associated file metadata. + +Upon submission, the form initiates a request to push or update data within a CRUD collection and upload new files to a file storage service. +This is accomplished by emitting either a [create-data-with-file] or an [update-data-with-file] event, which can be intercepted by components like the [File Manager][bk-file-manager]. + + +### Wizard + + +![wizard-form-modal](img/wizard-form-modal.png) + +It is possible to split data insertion into multiple steps via the `wizard` property. + +:::info +Wizard representation is currently only availabe when inserting new data, not in case of update. +::: + +`wizard` allows values like the following: + +- `true` +- `false` +- an array of objects like: + +```typescript +{ + keys: string[], + labels: { + wizardNext?: LocalizedText + wizardPrevious?: LocalizedText + wizardAddNew?: LocalizedText + wizardSubmit?: LocalizedText + stepperTitle?: LocalizedText + stepperSubtitle?: LocalizedText + accordionHeader?: LocalizedText + accordionEmptyComponent?: LocalizedText + } + asForm?: boolean +} +``` + +Each such element maps to a step of the wizard as follows: + +| property | description | +|----------|-------------| +| `keys` | fields to display in the step | +| `labels` | localized labels with the text to show | +| `asForm` | whether to visualize a single nested object as a form / nested array accordion of forms. Ignored if the step includes more than one field | + +If a step meets the following requirements: + +- only includes one field +- the field is of type `object` or `array` and has a property `dataSchema` +- `asForm` is set to true + +Then the field will be displayed as a form in case of an `object` field, or as an accordion of forms in case of an `array` field. + +![wizard-form-modal-accordion](img/wizard-form-modal-accordion.png) + +`labels` are mapped to displayed text as follows: + +| key | description | +|----------|-------------| +| `wizardNext` | Button for going to next step | +| `wizardPrevious` | Button for going back to previous step | +| `wizardAddNew` | Button for adding a new element to an array, when displayed as an accordion | +| `wizardSubmit` | Button for submitting the form in the final step | +| `stepperTitle` | Title of the stepper component | +| `stepperSubtitle` | Subtitle of the stepper component | +| `accordionHeader` | Title of the accordion panel. An incremental is automatically added as panels are added to the accordion | +| `accordionEmptyComponent` | Text to display when the accordion is empty | + +By default, `wizard` property is false. + +When set to `true`: + +- the fields are automatically split so that: + - the first group contains all fields that are not nested objects or nested arrays + - each of the following steps contains one of the remaining fields, with `asForm` set to true +- default labels are applied. + + +### Locale + +The texts of the Form Modale can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + create: { + title: LocalizedText + ctaLabel: LocalizedText + unsavedChangesContent: LocalizedText + saveChangesContent: LocalizedText + subtitle: LocalizedText + wizard: { + wizardNext: LocalizedText + wizardPrevious: LocalizedText + wizardAddNew: LocalizedText + wizardSubmit: LocalizedText + stepperTitle: LocalizedText + stepperSubtitle: LocalizedText + accordionHeader: LocalizedText + accordionEmptyComponent: LocalizedText + } + } + update: { + title: LocalizedText + ctaLabel: LocalizedText + unsavedChangesContent: LocalizedText + saveChangesContent: LocalizedText + subtitle: LocalizedText + } + form: { + validationMessages:{ + default: LocalizedText, + required: LocalizedText, + enum: LocalizedText, + whitespace: LocalizedText, + date:{ + format: LocalizedText, + parse: LocalizedText, + invalid: LocalizedText + }, + types:{ + string: LocalizedText, + method: LocalizedText, + array: LocalizedText, + object: LocalizedText, + number: LocalizedText, + date: LocalizedText, + boolean: LocalizedText, + integer: LocalizedText, + float: LocalizedText, + regexp: LocalizedText, + email: LocalizedText, + url: LocalizedText, + hex: LocalizedText, + file: LocalizedText + }, + string:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + number:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + array:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText, + unique: LocalizedText + }, + pattern:{ + mismatch: LocalizedText + } + }, + datePicker: { + lang: { + locale: LocalizedText, + placeholder: LocalizedText, + rangePlaceholder: { + start: LocalizedText, + stop: LocalizedText + }, + today: LocalizedText, + now: LocalizedText, + backToToday: LocalizedText, + ok: LocalizedText, + clear: LocalizedText, + month: LocalizedText, + year: LocalizedText, + timeSelect: LocalizedText, + dateSelect: LocalizedText, + monthSelect: LocalizedText, + yearSelect: LocalizedText, + decadeSelect: LocalizedText, + monthBeforeYear: 'true' | 'false', + previousMonth: LocalizedText, + nextMonth: LocalizedText, + previousYear: LocalizedText, + nextYear: LocalizedText, + previousDecade: LocalizedText, + nextDecade: LocalizedText, + previousCentury: LocalizedText, + nextCentury: LocalizedText + }, + timePickerLocale:{ + placeholder: LocalizedText + } + }, + filePicker:{ + drawerTitle: LocalizedText, + filePickerTitle: LocalizedText, + dragAndDropCaption: LocalizedText, + ctaLabel: LocalizedText + }, + objectEditor:{ + editorView: LocalizedText, + tableView: LocalizedText + }, + editor:{ + editorView: LocalizedText, + rawView: LocalizedText + }, + htmlEditor: { + preview: LocalizedText, + html: LocalizedText + }, + geopoint:{ + latitude: LocalizedText, + longitude: LocalizedText, + phLatitude: LocalizedText, + phLongitude: LocalizedText + }, + element: LocalizedText, + elements: LocalizedText, + true: LocalizedText, + false: LocalizedText + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## API + +### Properties & Attributes + + +| property | attribute | type | default | description | +|-------------------------------|---------------------------|--------------------------------------------------------------------------------------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `afterFinishEvents` | - | ConfigurableEvents | - | events or state push to concatenate after successful finish action has been performed | +| `allowAutoDisableDeps` | `allow-auto-disable-deps` | boolean | false | if true, dependent lookup and multilookup select fields are automatically disabled in case of no options | +| `customMessageOnAbsentLookup` | - | [LocalizedText][localized-text] | - | override lookup value in case lookup is not resolved due to lack of data | +| `liveSearchTimeout` | `live-search-timeout` | number | 5000 | live-search timeout | +| `rootElementSelector` | `root-element-selector` | string | - | Selector to specify where the container should be appended | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | Data schema describing the fields of the collection to filter | +| `readonlyOnView` | `read-only-on-view` | boolean | false | Upon marking this prop as true, on selecting a record, the form will be displayed as readonly, with no possibility to edit | +| `editorHeight` | `editor-height` | string \| number | - | Height of the object/array editor field | +| `allowNavigation` | `allow-navigation` | boolean \| 'show-editor' | true | When true, objects and arrays are displayed as a clickable label which allows navigating to nested objects and arrays if a dataSchema is specified. When 'show-editor', the navigation is allowed, and the object/array fields are displayed in a JSON editor. When false, the navigation is not allowed, and the object/array fields are displayed in a JSON editor | +| `width` | - | string \| number | - | Width of the modal | +| `liveSearchItemsLimit` | `live-search-items-limit` | number | 10 | Max items to fetch on regex live search | +| `customLabels` | - | [CustomLabels](#customlabels) \| `{insert: CustomLabels, update: CustomLabels}` | - | Custom localized texts shown as title and CTA button label | +| `requireConfirm` | - | boolean \| [RequireConfirmOpts](#requireconfirmopts) \| `{onSave: RequireConfirmOpts, onSave: RequireConfirmOpts}` | false | Whether or not the component should request confirmation before closing and/or before saving | +| `allowObjectAsTable` | `allow-object-as-table` | boolean | false | allows to visualize objects and arrays without specific format and a dataschema in both a editor and read-only table | +| `extraEndpoint` | `extra-endpoint` | string | - | when specified, it is possible to perform a POST request to an external collection specified by the endpoint | +| `height` | `height` | string | '60vh' | height of the modal | +| `wizard` | - | boolean \| [WizardStepSchema](#wizardstepschema)[] | - | array of options for setting up a wizard. If true, a default wizard is utilized. | + +#### RequireConfirmOpts + +```typescript +type RequireConfirmOpts = boolean | { + cancelText?: LocalizedText + okText?: LocalizedText + content?: LocalizedText + title?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +#### CustomLabels + +```typescript +type CustomLabels = { + title?: LocalizedText + ctaLabel?: LocalizedText + saveChangesContent?: LocalizedText + unsavedChangesContent?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +#### WizardStepSchema + +```typescript +type WizardStepSchema = { + keys: string[], + labels: { + wizardNext?: LocalizedText + wizardPrevious?: LocalizedText + wizardAddNew?: LocalizedText + wizardSubmit?: LocalizedText + stepperTitle?: LocalizedText + stepperSubtitle?: LocalizedText + accordionHeader?: LocalizedText + accordionEmptyComponent?: LocalizedText + } + asForm?: boolean +} +``` + +### Listens to + +| event | action | +|-------|--------| +| [add-new] | opens the modal to create a new item, potentially applying default fields from data schema or data provided in the payload of the event | +| [add-new-external] | opens the modal to perform a POST request, filling in its fields from the data provided in the payload of the event | +| [selected-data] | opens the modal to edit a selected item, filling in its fields from the data provided in the payload of the event | +| [nested-navigation-state/push] | updates internal representation of the current navigation path by adding one step | +| [nested-navigation-state/back] | updates internal representation of the current navigation path by removing the specified number of steps | +| [nested-navigation-state/display] | updates internal representation of the current navigation and closes the modal | +| [success] | notifies correct data update as a result of form submission | +| [error] | notifies that something went wrong during form submission | + +### Emits + + +| event | description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| configurable event | property `afterFinishEvents` allows to emit custom events | +| [require-confirm] | triggered when trying to close the modal with unsaved data. `requireConfirm` property allows to customize this behavior | +| [create-data] | requests data creation | +| [update-data] | requests data update | +| [create-data-with-file] | requests data creation and file upload | +| [update-data-with-file] | requests data update and file upload | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/360_form_wizard.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/360_form_wizard.md new file mode 100644 index 0000000000..75d9ce09e0 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/360_form_wizard.md @@ -0,0 +1,665 @@ +--- +id: form_wizard +title: Form Wizard +sidebar_label: Form Wizard +--- + + + + + + + +[handlebars]: https://handlebarsjs.com/guide/expressions.html + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[predefined-fields]: /runtime-components/plugins/crud-service/10_overview_and_usage.md#predefined-collection-properties +[writable-views]: /runtime-components/plugins/crud-service/50_writable_views.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[form-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#form-options +[helpers]: /products/microfrontend-composer/back-kit/40_core_concepts.md#helpers +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic configurations]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration +[action]: /products/microfrontend-composer/back-kit/50_actions.md + +[bk-dynamic-form-modal]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md + +[modes]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#modes +[after-submission]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#after-submission +[footer-buttons]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#footer-buttons +[working-with-views]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#working-with-views +[conditional-fields]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#conditional-fields +[modal-examples]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#examples + +[add-new]: /products/microfrontend-composer/back-kit/70_events.md#add-new +[selected-data]: /products/microfrontend-composer/back-kit/70_events.md#selected-data +[require-confirm]: /products/microfrontend-composer/back-kit/70_events.md#require-confirm +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[create-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#create-data-with-file +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file +[error]: /products/microfrontend-composer/back-kit/70_events.md#error +[success]: /products/microfrontend-composer/back-kit/70_events.md#success +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/display]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---dispaly + + + + +```html + +``` + +![wizard-form-modal](img/wizard-form-modal.png) + +The Form Wizard is an extension of the [Dynamic Form Modal][bk-dynamic-form-modal] that allows to split data insertion / editing into multiple steps. +Each step consists of a form or an accordion of forms and allows to fill-in / edit a subset of the data properties. +Navigation through wizard steps is possible through buttons displayed inside the footer of the modal. +Upon reaching the last step, it is possible to submit the wizard, which signals the need for an item creation / update, with data obtained by aggregating form values from each of the wizard steps. + + +## How to configure + +For basic usage of the Form Wizard Providing a data-schema to interpret the structure of the data to handle is sufficient. +Several [customizations][data-schema] can be applied to the provided data-schema that tune how the data is handled by the component. +Particularly, but not limited to, every field supports a set of [options][form-options] specific for forms. + +Additionally, by default, the From Wizard analyzes the provided data-schema to automatically configure each step of the wizard. +All fields that are not nested objects or nested arrays are displayed as a form in the first step of the modal. +Each of the following steps is composed of a single nested object or array field, the fields of which are editable through a form. + +```json +{ + "tag": "bk-form-wizard", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "__STATE__": { + "type": "string" + }, + "name": { + "type": "string" + }, + "price": { + "type": "number" + }, + "color": { + "type": "object", + "dataSchema": { + "type": "object", + "properties": { + "red": {"type": "number"}, + "green": {"type": "number"}, + "blue": {"type": "number"} + } + } + }, + "variants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "shape": {"type": "string"}, + "size": {"type": "string"} + } + } + } + } + } + } +} +``` + +A Form Wizard configured as above results in a wizard with three steps. + - the first step displays a form with fields "_id", "\_\_STATE__", "name", "price" + - the second step displays a form with fields "red", "green", "blue" + - the third step displays an accordion of forms, each one with fields "shape", "size" + +![wizard-form-modal-accordion](img/wizard-form-modal-accordion.png) + + +The Form Wizard can be opened in two different modes, just like the [Dynamic Form Modal][modes]: + +- *insert*: submitting the form signals the need for an item creation. This mode is activated upon listening to an [add-new] event +- *edit*: submitting the form signals the need for an item creation. This mode is activated upon listening to an [selected-data] event + + +### Customize wizard steps + +Property `wizard` allows to configure each step specifying an array of objects with three properties, `keys`, `labels`, `asForm`. + +```typescript +type WizardStepSchema = { + keys: string[], + labels: { + wizardNext?: LocalizedText + wizardPrevious?: LocalizedText + wizardAddNew?: LocalizedText + stepperTitle?: LocalizedText + stepperSubtitle?: LocalizedText + accordionHeader?: LocalizedText + accordionEmptyComponent?: LocalizedText + } + asForm?: boolean +} +``` + +Each such element maps to a step of the wizard as follows: + +| property | description | +| -------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `keys` | fields to display in the step | +| `labels` | [localized labels][localized-text] with the text to show | +| `asForm` | whether to visualize nested objects as a form, or nested arrays as an accordion of forms. Step must include one field. Defaults to true. | + +If a step meets the following requirements: + - only includes one field + - the field is of type `object` or `array` and has a property `dataSchema` + - `asForm` is set to true (as per default) + +Then the field will be displayed as a form in case of an `object` field, or as an accordion of forms in case of an `array` field. + +`labels` are mapped to displayed text as follows: + +| key | description | +| ------------------------- | -------------------------------------------------------------------------------------------------------- | +| `wizardNext` | Button for going to next step | +| `wizardPrevious` | Button for going back to previous step | +| `wizardAddNew` | Button for adding a new element to an array, when displayed as an accordion | +| `wizardSubmit` | Button for submitting the form in the final step | +| `stepperTitle` | Title of the stepper component | +| `stepperSubtitle` | Subtitle of the stepper component | +| `accordionHeader` | Title of the accordion panel. An incremental is automatically added as panels are added to the accordion | +| `accordionEmptyComponent` | Text to display when the accordion is empty | + +### Dynamic Context + +Analogously to the [Dynamic Form Modal][bk-dynamic-form-modal], several properties of the Wizard Form allow [dynamic configurations]. +By default, such properties are parsed with [handlebars], injecting the current state of the whole wizard as context through key `values`, and the state of the current step through key `step`, as well as other information. + +```typescript +{ + values: Record // aggregated values of all steps + step: Record // values of current step + currentUser: Record // information on currently logged user, if available +} +``` + +### After Submission + +The Form Wizard supports properties `onSuccess` and `onFail`, that allow to append extra tasks to be executed after the successful or unsuccessful submission of the wizard, just like the [Dynamic Form Modal][after-submission]. + +Extra context key `step` is available in [context](#dynamic-context) injected into `onSuccess` and `onFail` actions: + +```typescript +{ + currentUser: Record + values: Record + step: Record + response: Record +} +``` + +where `step` is the state of the form of the current step, `values` is the aggregated values of all steps, `response` contains an object representation of the content of the payload of the [success] event linked to the submission request. + +### Footer Buttons + +By deafult, the footer of the modal rendered by Form Wizard includes the following buttons: + - two buttons for navigating through the wizard steps, + - a button to add a new form to an accordion of forms, in case the current step includes a single field of type array of objects, + - in case the current step is the last step of the wizard, a submit button. This can be used for signaling the need to add or edit an item in CRUD collection, depending on the operating [mode][modes]. + +#### Extra buttons + +Other than the default buttons included in the modal footer, extra buttons can be specified to be included in the modal footer, using property `actions`, just like the [Dynamic Form Modal][footer-buttons]. + +Extra buttons are added to the footer of the modal for each step of the wizard. + +#### Omitting submit button + +It is possible to omit the default submission button by setting property `omitSubmit` to true. + +### Confirmation dialog on save and on close + +It is possible to ask for confirmation on close and/or on save, and also customize the confirmation dialog texts. +This is achieved with property `requireConfirm`, analogously to the [Dynamic Form Modal][bk-dynamic-form-modal]. + + +### Integrate custom labels + +Just like the [Dynamic Form Modal][bk-dynamic-form-modal], custom labels can be specified as [localized text][localized-text], controlling copies within the Form Wizard. Additionally, extra custom labels can be [specified for each wizard step](#customize-wizard-steps). + + +### Working with Views + +Analogously to the [Dynamic Form Modal][working-with-views], the Wizard Form is designed to be able to interact with [Mia-Platform CRUD Service views][writable-views]. + +### Conditional Fields + +Properties `conditionalOptions` and `conditionalValues` can be used to set-up custom form behavior that is conditional to the current state of the wizard, just like for the [Dynamic Form Modal][conditional-fields]. + + +### Locale + +The texts of the Form Wizard can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + create: { + title: LocalizedText + ctaLabel: LocalizedText + unsavedChangesContent: LocalizedText + saveChangesContent: LocalizedText + wizardNext?: LocalizedText + wizardPrevious?: LocalizedText + wizardAddNew?: LocalizedText + stepperTitle?: LocalizedText + stepperSubtitle?: LocalizedText + accordionHeader?: LocalizedText + accordionEmptyLabel?: LocalizedText + } + update: { + title: LocalizedText + ctaLabel: LocalizedText + unsavedChangesContent: LocalizedText + saveChangesContent: LocalizedText + wizardNext?: LocalizedText + wizardPrevious?: LocalizedText + wizardAddNew?: LocalizedText + stepperTitle?: LocalizedText + stepperSubtitle?: LocalizedText + accordionHeader?: LocalizedText + accordionEmptyLabel?: LocalizedText + }, + form: { + validationMessages:{ + default: LocalizedText, + required: LocalizedText, + enum: LocalizedText, + whitespace: LocalizedText, + date:{ + format: LocalizedText, + parse: LocalizedText, + invalid: LocalizedText + }, + types:{ + string: LocalizedText, + method: LocalizedText, + array: LocalizedText, + object: LocalizedText, + number: LocalizedText, + date: LocalizedText, + boolean: LocalizedText, + integer: LocalizedText, + float: LocalizedText, + regexp: LocalizedText, + email: LocalizedText, + url: LocalizedText, + hex: LocalizedText, + file: LocalizedText + }, + string:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + number:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText + }, + array:{ + len: LocalizedText, + min: LocalizedText, + max: LocalizedText, + range: LocalizedText, + unique: LocalizedText + }, + pattern:{ + mismatch: LocalizedText + } + }, + datePicker: { + lang: { + locale: LocalizedText, + placeholder: LocalizedText, + rangePlaceholder: { + start: LocalizedText, + stop: LocalizedText + }, + today: LocalizedText, + now: LocalizedText, + backToToday: LocalizedText, + ok: LocalizedText, + clear: LocalizedText, + month: LocalizedText, + year: LocalizedText, + timeSelect: LocalizedText, + dateSelect: LocalizedText, + monthSelect: LocalizedText, + yearSelect: LocalizedText, + decadeSelect: LocalizedText, + monthBeforeYear: 'true' | 'false', + previousMonth: LocalizedText, + nextMonth: LocalizedText, + previousYear: LocalizedText, + nextYear: LocalizedText, + previousDecade: LocalizedText, + nextDecade: LocalizedText, + previousCentury: LocalizedText, + nextCentury: LocalizedText + }, + timePickerLocale:{ + placeholder: LocalizedText + } + }, + filePicker:{ + drawerTitle: LocalizedText, + filePickerTitle: LocalizedText, + dragAndDropCaption: LocalizedText, + ctaLabel: LocalizedText + }, + objectEditor:{ + editorView: LocalizedText, + tableView: LocalizedText + }, + editor:{ + editorView: LocalizedText, + rawView: LocalizedText + }, + htmlEditor: { + preview: LocalizedText, + html: LocalizedText + }, + geopoint:{ + latitude: LocalizedText, + longitude: LocalizedText, + phLatitude: LocalizedText, + phLongitude: LocalizedText + }, + element: LocalizedText, + elements: LocalizedText, + true: LocalizedText, + false: LocalizedText + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +Configuration examples for the [Dynamic Form Modal][modal-examples] also apply to the Form Wizard. + +### Example: Default Wizard Steps + +A Form Wizard configured like the following: + +```json +{ + "tag": "bk-form-wizard", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "__STATE__": { + "type": "string" + }, + "name": { + "type": "string" + }, + "price": { + "type": "number" + }, + "color": { + "type": "object", + "dataSchema": { + "type": "object", + "properties": { + "red": {"type": "number"}, + "green": {"type": "number"}, + "blue": {"type": "number"} + } + } + }, + "variants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "shape": {"type": "string"}, + "size": {"type": "string"} + } + } + } + } + } + } +} +``` +results in a wizard with three steps. + - the first step displays a form with fields "_id", "\_\_STATE__", "name", "price" + - the second step displays a form with fields "red", "green", "blue" + - the third step displays an accordion of forms, each one with fields "shape", "size" + + +### Example: Customize Wizard Steps + +A Form Wizard configured like the following: + +```json +{ + "tag": "bk-form-wizard", + "properties": { + "wizard": [ + { + "keys": [ + "name", + "color" + ], + "labels": { + "stepperTitle": { + "en": "Name & Color", + "it": "Nome & Colore" + } + } + }, + { + "keys": [ + "variants" + ], + "labels": { + "stepperSubtitle": { + "en": "Final step", + "it": "Ultimo step" + }, + "wizardAddNew": { + "en": "Add new variant", + "it": "Aggiungi nuova variante" + }, + "accordionHeader": { + "en": "Variant", + "it": "Variante" + } + } + } + ], + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "color": { + "type": "object", + "dataSchema": { + "type": "object", + "properties": { + "red": {"type": "number"}, + "green": {"type": "number"}, + "blue": {"type": "number"} + } + } + }, + "variants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "shape": {"type": "string"}, + "size": {"type": "string"} + } + } + } + } + } + } +} +``` + +results in a wizard with two steps: + - the first step displays a form with fields "name", "color". Note that "color" is **not** displayed as a separate form, but rather as a default object field - which consists of a text editor + - the second step displays an accordion of forms, each one with fields "shape", "size" + +Note that custom labels are specified for both steps. + +## API + +### Properties & Attributes + +| Property | Attribute | Type | Default | Description | +|-------------------------------|-----------------------------------|--------------------------------------------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------| +| `rootElementSelector` | `root-element-selector` | string | - | Selector to specify where the container should be appended | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | Data schema describing the fields of the collection to filter | +| `wizard` | - | [WizardStepSchema](#customize-wizard-steps) | - | Array of options for setting up the wizard steps. A default wizard is utilized is not specified | +| `width` | - | string \| number | - | Width of the modal | +| `height` | - | string \| number | - | Height of the modal | +| `omitSubmit` | `omit-submit` | boolean | false | Whether or not to include the default submit button | +| `actions` | - | [ButtonWithClose](#buttonwithclose)[] \| `{insert: ButtonWithClose[]; select: ButtonWithClose[]}` | - | Actions added as buttons to the footer | +| `liveSearchItemsLimit` | `live-search-items-limit` | number | 10 | Max items to fetch on regex live search | +| `customLabels` | - | [CustomLabels](#customlabels) \| `{insert: CustomLabels, update: CustomLabels}` | - | Custom localized texts shown as title and CTA button label | +| `requireConfirm` | - | boolean \| [RequireConfirmOpts](#requireconfirmopts) \| `{onSave: RequireConfirmOpts, onSave: RequireConfirmOpts}` | false | Whether or not the component should request confirmation before closing and/or before saving | +| `onSuccess` | - | [Action][action][] \| `{insert: Action[], update: Action[]}` | - | Action executed after successful submit | +| `onFail` | - | [Action][action][] \| `{insert: Action[], update: Action[]}` | - | Action executed after failing submit | +| `lookupQueries` | - | [LookupQueries](#lookupqueries) | - | Extra queries when fetching options for lookup fields in [views](#working-with-views) | +| `conditionalOptions` | - | [ConditionalOption](#conditionaloption)[] | - | Allows specifying dynamic conditions for form-options (hidden / disabled / readonly) to be applied | +| `conditionalValues` | - | [Condition](#condition)[] | - | Allows specifying dynamic conditions for resetting field | +| `fileFieldsPreview` | `file-fields-preview` | boolean | - | Enables preview of uploaded files in drag-n-drop file fields | +| `enableSubmitOnFormUntouched` | `enable-submit-on-form-untouched` | boolean | - | Allows submitting an unedited form | +| `basePath` | - | string | - | The URL base path to which to send HTTP requests, used when fetching options for lookup field in [views](#working-with-views) | + +#### ButtonWithClose + +```typescript +type ButtonWithClose = Partial & { + closeAfter?: boolean +} +``` +where BkButton references the properties of the [Button][bk-button] component. + +#### RequireConfirmOpts + +```typescript +type RequireConfirmOpts = boolean | { + cancelText?: LocalizedText + okText?: LocalizedText + content?: LocalizedText + title?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +#### CustomLabels + +```typescript +type CustomLabels = { + title?: LocalizedText + ctaLabel?: LocalizedText + saveChangesContent?: LocalizedText + unsavedChangesContent?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +#### LookupQueries + +```typescript +type LookupQueries = { + [property: string]: Record | Record[] +} +``` + +#### ConditionalOption + +```typescript +type ConditionalOption = { + property: string + query: Record + option: RHDOptions +} + +type RHDOptions = { + hidden?: boolean; + hiddenOnUpdate?: boolean; + hiddenOnInsert?: boolean; + } & { + readOnly?: boolean; + readOnlyOnUpdate?: boolean; + readOnlyOnInsert?: boolean; + } & { + disabled?: boolean; + disabledOnUpdate?: boolean; + disabledOnInsert?: boolean; + } +``` + +#### Condition + +```typescript +type Condition = { + property: string + query: Record +} +``` + +### Listens to + +| event | action | +|-------|--------| +| [add-new] | opens the modal to create a new item, potentially applying default fields from data schema or data provided in the payload of the event | +| [selected-data] | opens the modal to edit a selected item, filling in its fields from the data provided in the payload of the event | +| [nested-navigation-state/push] | updates internal representation of the current navigation path by adding one step. The wizard is disabled if the user navigated inside a nested field, and renders a single form with fields of the visualized nested object. | +| [nested-navigation-state/back] | updates internal representation of the current navigation path by removing the specified number of steps. The wizard is disabled if the user navigated inside a nested field, and renders a single form with fields of the visualized nested object. | +| [nested-navigation-state/display] | updates internal representation of the current navigation and closes the modal. The wizard is disabled if the user navigated inside a nested field, and renders a single form with fields of the visualized nested object. | +| [success] | notifies correct data update as a result of form submission. Payload holds the response of the associated HTTP call and is accessible by action in `onSuccess` property via `response` keyword. | +| [error] | notifies that something went wrong during form submission. Payload holds the response of the associated HTTP call and is accessible by action in `onFail` property via `response` keyword. | + +### Emits + + +| event | description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| configurable event | properties such as `onFail`, `onSuccess` or `actions` allow to emit custom events | +| [require-confirm] | triggered when trying to close the modal with unsaved data. `requireConfirm` property allows to customize this behavior | +| [create-data] | requests data creation | +| [update-data] | requests data update | +| [create-data-with-file] | requests data creation and file upload | +| [update-data-with-file] | requests data update and file upload | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/370_gallery.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/370_gallery.md new file mode 100644 index 0000000000..f949211d70 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/370_gallery.md @@ -0,0 +1,606 @@ +--- +id: gallery +title: Gallery +sidebar_label: Gallery +--- + + + + + + +[handlebars]: https://handlebarsjs.com/guide/expressions.html + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic-configurations]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration +[helpers]: /products/microfrontend-composer/back-kit/40_core_concepts.md#helpers + +[actions]: /products/microfrontend-composer/back-kit/50_actions.md + +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[selected-data-bulk]: /products/microfrontend-composer/back-kit/70_events.md#selected-data-bulk +[selected-data]: /products/microfrontend-composer/back-kit/70_events.md#selected-data + +[bk-footer]: /products/microfrontend-composer/back-kit/60_components/320_footer_&_item_state.md +[bk-bulk-actions]: /products/microfrontend-composer/back-kit/60_components/70_bulk_actions_button.md + + + +```html + +``` + +![bk-gallery](img/bk-gallery.png) + +The Gallery allows to visualize image files within an adaptive grid, as well as other data. + +Each item of the grid is composed of: + - readonly data + - title + - subtitle + - thumbnail + - preview + - actions (buttons, action menu, clickable image) + +The thumbnail is immediately visible in the item, while the preview is displayed inside a [modal](#preview-modal). + +The Gallery listens to [display-data] event to retrieve the data to visualize. Each element of the dataset is mapped to one grid item. + +## How to configure + +The Gallery component should be provided with a value for property `thumbnailSource` that describes the [path](#xpath) to reach the URL of the image to display +within the data item. + +```json +{ + "tag": "bk-gallery", + "properties": { + "thumbnailSource": "image.url" + } +} +``` + +### Appearance + +#### Gallery Items + +Gallery items are placed into a grid, which adapts to the screen size. + +Each of the Gallery item can be configured in size using properties `itemHeight` and `itemWidth`, controlling height and width respectively. + +If `itemHeight` is not specified, items adapt their height to their content. + +Property `itemWidth` supports both numeric values (these are interpreted as pixels) or "small", "medium", "large". +This property controls the attempted width of each Gallery item, but may vary slightly due to the adaptive nature of the grid. + +`gutter` property can be used to control the spacing around each Gallery item. + +#### Preview Modal + +Unless property `disableExpand` is set to true, the preview image of an item can be visualized inside a modal. +The modal can be configured in size using `modalWidth` and `modalHeight`, and a title can be specified with `modalTitle` (if not specified, the item title is used). + +### Data + +Each Gallery item allows to visualize an image (thumbnail), a preview within a modal (preview) and two types of text (title and subtitle). + +The properties that control how each item sets these options are: +- `thumbnailSource` +- `previewSource` +- `titleSource` +- `subTitleSource` + +If not specified, the `previewSource` is set to be equal to `thumbnailSource`. + +Upon listening to a [display-data] event, the Gallery component uses these properties to render one item per data row. + +The properties `titleSource`, `subTitleSource`, `thumbnailSource`, and `previewSource` accept either a string or an object with keys `path` and `default`. + +When set as a string, these properties should indicate the path within the data source from which to extract the required information. + +Alternatively, if an object is used, the `path` key guides the property to the relevant data, while the `default` key provides a value to display if the path points to undefined values. + +Additionally, `thumbnailSource` and `previewSource` also support key `template`. This is used to interpolate the extracted value within a string, through keyword `file`. + +For instance, the following are all valid configurations for `thumbnailSource`: + +```json +{ + "thumbnailSource": { + "path": "document.url", + "default": "default/file.jpg", + "template": "full/{{file}}" + } +} +``` + +```json +{ + "thumbnailSource": { + "path": "document.url", + "default": "default/file.jpg", + } +} +``` + +```json +{ + "thumbnailSource": "document.url" +} +``` + +### Dynamic Context + +The Gallery supports properties that allow [dynamic configurations][dynamic-configurations]. +By default, such properties are parsed with [handlebars], injecting the following context: + +Each action in the Gallery component has access to the following input data: +```typescript +{ + thumbnail: ..., // source for thumbnail image of the item + preview: ..., // source for preview image of the item + title: ..., // title of the item + subTitle: ..., // subtitle of the item + context: ... // all data fields of Gallery item + ... // all data fields of Gallery item +} +``` + +### Actions + +`onImageClick`, `onTitleClick`, `onSubTitleClick` and `actions` properties allow to add [Back-kit Actions][actions] to the Gallery. + +#### Callbacks + +Properties `onImageClick`, `onTitleClick`, `onSubTitleClick` are expected to follow the [Back-kit Action][actions] interface. +Their callbacks are executed upon clicking to the thumbnail, the title or the subtitle respectively. + +The Gallery supports [dynamic configurations][dynamic-configurations] in these properties. +They are parsed with [handlebars], injecting the [context](#dynamic-context) of the Gallery. + +#### Buttons & Actions menu + +Property `actions`, on the other hand, is an array of objects that have keys: `iconId`, `content`, `danger`, `action`. + +The first two entries of `actions` are rendered as buttons (thus, a value for `iconId` should be specified). +The rest of the actions are rendered inside a popup menu within each Gallery item. + +[Dynamic configurations][dynamic-configurations] is available in `actions` property. +In particular, the `action` key of each entry of `actions` property is parsed with [handlebars], injecting the [context](#dynamic-context) of the Gallery. + +```json +{ + "actions": [ + { + "iconId": "fas fa-users", + "action": { + "type": "http", + "config": { + "url": "/url", + "method": "POST", + "body": { + "field1": "{{thumbnail}}", // <- the source of the thumbnail image + "field2": "{{name}}" // <- the "name" field of the data entry associated to the Gallery item + } + } + } + } + ] +} +``` + +### Checkbox + +Each item can be selected through a checkbox, unless `disableSelection` property is set to true. + +Selecting emits a [selected-data-bulk] event with all selected items. + +Components like the [Footer][bk-footer] or the [Bulk Actions][bk-bulk-actions] react to [selected-data-bulk] events. + + +### Locale + +The texts of the Gallery can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + modalClose: LocalizedText + expandTitle: LocalizedText + actionsMenuTitle: LocalizedText + brokenFile: LocalizedText + absentFile: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +### Example: Basic Usage + +The most basic way to use the Gallery component to visualize a dataset is to set properties `thumbnailSource`, `previewSource`, `titleSource`, `subTitleSource`. + +A Gallery configured like the following: + +```json +{ + "tag": "bk-gallery", + "properties": { + "thumbnailSource": "avatar.url", + "previewSource": "profileImageUrl", + "titleSource": "name", + "subTitleSource": "description" + } +} +``` + +that receives a dataset like: + +```json +[ + { + "name": "Bruce", + "description": "I like football!", + "avatar": { + "fileName": "avatar1.jpg", + "url": "/avatar/avatar1.jpg" + }, + "profileImageUrl": "/profile/profile1.jpg" + }, + { + "name": "Emily", + "description": "Nature enthusiast!", + "avatar": { + "fileName": "avatar2.png", + "url": "/avatar/avatar2.png" + }, + "profileImageUrl": "/profile/profile2.jpg" + } +] +``` + +Then the Gallery displays two items, + +one with: + - title equal to "Bruce" + - subTitle equal to "I like football!" + - thumbnail equal to `/avatar/avatar1.jpg` + - preview equal to `/profile/profile1.jpg` + +and the second one with; + - title equal to "Emily" + - subTitle equal to "Nature enthusiast!" + - thumbnail equal to `/avatar/avatar2.png` + - preview equal to `/profile/profile2.jpg` + +### Example: Basic Usage + +Assuming the following configuration for the Gallery component: + +```json +{ + "tag": "bk-gallery", + "properties": { + "titleSource": "objField.arrField.[0]", + "subTitleSource": "objField.stringField", + "thumbnailSource": "document" + } +} +``` + +Upon receiving notification of the following data being fetched: + +```json +[ + { + "objField": { + "arrField": [ + "test" + ], + "stringField": "foo" + }, + "document": "some/path.jpg" + } +] +``` + +The Gallery renders a single item with + - title equal to "test" + - subTitle equal to "foo" + - thumbnail equal to "some/path.jpg" + - preview equal to "some/path.jpg" + +Since `previewSource` is not specified, the preview is same as the thumbnail. + +### Example: Gallery with default values + +Properties `titleSource`, `subTitleSource`, `thumbnailSource`, `previewSource` can be set to an object with `path` and `default` keys. +Key `path` is used to reach the desired data within the fields of the data element associated to the Gallery item, +while `default` provides a fallback value in case the path is not resolved. + +For instance, a Gallery configured like: +```json +{ + "tag": "bk-gallery", + "properties": { + "titleSource": "objField.arrField.[0]", + "subTitleSource": "objField.stringField", + "thumbnailSource": "document", + "previewSource": { + "path": "objField.preview", + "default": "default/file.jpg" + } + } +} +``` + +That renders the following simplified data: +```json +[ + { + "objField": { + "arrField": [ + "test" + ], + "stringField": "foo" + }, + "document": "some/path.jpg" + } +] +``` + +results is a single item with + - title equal to "test" + - subTitle equal to "foo" + - thumbnail equal to "some/path.jpg" + - preview equal to "default/file.jpg" + + +### Example: Gallery with complex image source + +Properties `thumbnailSource`, `previewSource` can be set to an object with a `path`, `default`, `template` keys. + - `path` is used to reach the desired data within the fields of the data element associated to the Gallery item + - `default` provides a fallback value in case the path is not resolved + - `template` interpolates the extracted value within a string, through keyword `file` + +For instance, a Gallery configured like: +```json +{ + "tag": "bk-gallery", + "properties": { + "thumbnailSource": { + "path": "document", + "default": "default/file.jpg", + "template": "full/{{file}}" + } + } +} +``` + +That renders the following simplified data: +```json +[ + { + "objField": { + "arrField": [ + "test" + ], + "stringField": "foo" + }, + "document": "some/path.jpg" + } +] +``` + +results in a single item having thumbnail equal to "full/some/path.jpg". + +In case `path` is unresolved, `default` is utilized. Key `default` is **not** interpolated inside `template`. + +For instance, assuming the same input data and configuration: +```json +{ + "tag": "bk-gallery", + "properties": { + "thumbnailSource": { + "path": "unk", + "default": "default/file.jpg", + "template": "full/{{file}}" + } + } +} +``` + +the resulting `thumbnail` is "default/file.jpg" and **not** "full/default/file.jpg + + +### Example: Add callback to clickinging image + +The Gallery allows to specify [Back-kit Actions][actions] to be executed upon clickinging a Gallery image, title, or subtitle. + +For instance, the following configuration for the Gallery: + +```json +{ + "tag": "bk-gallery", + "properties": { + "thumbnailSource": "image.url", + "onImageClick": { + "type": "event", + "config": { + "events": { + "label": "selected-data", + "payload": "{{rawObject context}}" + } + } + } + } +} +``` + +with the following underlying data: + +```json +[ + { + "name": "Roasted Chicken", + "description": "Very tasty!", + "calories": 650 + }, + { + "name": "Salad", + "description": "Healthy dish", + "calories": 150 + }, + +] +``` + +renders two Gallery items that, upon being clicked on its thumbnail, emit a [selected-data] event with payload equal to the object representation of its associated data element. + +Clicking on the image of the first element, the Gallery emits a [selected-data] event with payload: + +```json +{ + "name": "Roasted Chicken", + "description": "Very tasty!", + "calories": 650 +} +``` + +:::info +[rawObject][helpers] is a helper keyword that prevents "context" from being stringified in the payload of the event. +::: + + +### Example: Action with dynamic context + +The Gallery allows to insert buttons to its items to perform custom [actions]. + +For instance, the following configuration for the Gallery: + +```json +{ + "tag": "bk-gallery", + "properties": { + "thumbnailSource": "image.url", + "actions": [ + { + "iconId": "fas fa-users", + "action": { + "type": "http", + "config": { + "url": "/add-recipe", + "method": "POST", + "body": { + "image": "{{thumbnail}}", + "name": "{{name}}" + } + } + } + } + ] + } +} +``` + +with the following underlying data: + +```json +[ + { + "image": { + "name": "chicken.jpg", + "url": "file-storage/chicken.jpg", + }, + "name": "Roasted Chicken", + "description": "Very tasty!" + } +] +``` + +renders one Gallery item with a button that, upon clicking, executes a POST call to the endpoint `/add-recipe`, with body: + +```json +{ + "image": "file-storage/chicken.jpg", + "name": "Roasted Chicken" +} +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ------------------ | ------------------- | -------------------------------------------------- | -------- | -------------------------------------------------------------------------------- | +| `thumbnailSource` | - | TemplateXPath | - | source path to thumbnail image | +| `previewSource` | - | TemplateXPath | - | source path to preview image (if not specified, `thumbnailSource` is used) | +| `titleSource` | - | [XPath](#xpath) | - | source path to title text | +| `subTitleSource` | - | [XPath](#xpath) | - | source path to subtitle text | +| `disableSelection` | `disable-selection` | boolean | false | whether to disable the possibility to select Gallery items | +| `actions` | - | [GalleryAction](#galleryaction) \| GalleryAction[] | - | available actions per Gallery item | +| `onImageClick` | - | [Action][actions] | - | action to execute on image click | +| `onTitleClick` | - | [Action][actions] | - | action to execute on title click | +| `onSubTitleClick` | - | [Action][actions] | - | action to execute on subtitle click | +| `disableExpand` | `disable-expand` | boolean | false | whether to disable the possibility of viewing the image inside a modal (preview) | +| `modalWidth` | `modal-width` | number \| string | - | width of the preview modal | +| `modalHeight` | `modal-height` | number \| string | - | height of the preview modal | +| `modalTitle` | `modal-title` | string | - | title of the preview modal (if not specified, the item title is used) | +| `gutter` | `gutter` | number | 20 | gutter of Gallery items (vertical and horizontal spacing among Gallery items) | +| `primaryKey` | `primary-key` | string | "_id" | key used for indexing Gallery items | +| `itemHeight` | `item-height` | number \| string | - | height of Gallery items. If not specified, items adapt to their content | +| `itemWidth` | `item-width` | number \| "small" \| "medium" \| "large" | "medium" | attempted width of Gallery items | + + +#### XPath + +```typescript +type XPath = string | { + path?: string + default?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +#### TemplateXPath + +```typescript +type TemplateXPath = XPath | { + path?: string + default?: LocalizedText + template: string +} +``` + +where [XPath](#xpath) is either a string or an object with keys `path` and `default` +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +#### GalleryAction + +```typescript +type GalleryAction = { + iconId?: string, + content?: string, + danger?: boolean, + action: Action +} +``` + +### Listens to + +| event | action | +| -------------- | ------------------------ | +| [display-data] | receives data to display | + + +### Emits + +| event | action | +| -------------------- | ----------------------------------------------------------------------------------------------------------- | +| configurable event | properties like `actions`, `onImageClick` allow the Gallery to emit custom events | +| [selected-data-bulk] | notifies about a change in the items selected through checkboxes | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/380_import_modal.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/380_import_modal.md new file mode 100644 index 0000000000..f69952629d --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/380_import_modal.md @@ -0,0 +1,94 @@ +--- +id: import_modal +title: Import Modal +sidebar_label: Import Modal +--- + + + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md + +[import-data]: /products/microfrontend-composer/back-kit/70_events.md#import-data +[import-data/user-config]: /products/microfrontend-composer/back-kit/70_events.md#import-data---user-config + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + + + +```html + +``` + +The Import Modal renders a modal to allow the user to signal the need for a data import to be performed on a collection. + +## How to configure + +The Import Modal does not require any particular configuration. + +```json +{ + "tag": "bk-import-modal" +} +``` + +The body of the rendered modal is a form that allows the user to select what parameters should be appended to the import data request. These include: + - the file with the data to be imported + - what encoding should be used ("utf8", "ucs2", ...) to parse the file, in case this is of type CSV + - what delimiter should be used (comma or semicolon) to parse the file, in case this is of type CSV + - what escape character should be used to parse the file, in case this is of type CSV + +Supported file extensions are: `.ndjson`, `.json`, `.csv` + + +Upon submitting the Import Modal, this signals the need to import data with the specified options. +A component like the [CRUD Client][bk-crud-client] could pick up on this request and trigger data import (as long as backend services includes an instance of the [CRUD Service][crud-service] of version 6.9.0 or higher). + +### Locale + +The texts of the Import Modal can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + modalTitle: LocalizedText + file: LocalizedText + fileRequired: LocalizedText + encoding: LocalizedText + encodingPlaceholder: LocalizedText + delimiter: LocalizedText + delimiterCommaOption: LocalizedText + delimiterSemicolonOption: LocalizedText + separator: LocalizedText + okButton: LocalizedText + cancelButton: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ------------------ | ------------------------- | ---------------- | ------- | --------------------------------------------------------------------- | +| `method` | - | string | - | HTTP method for import request. Can be 'POST' or 'PATCH' | + +### Listens to + +| event | action | +| ------------- | --------------------- | +| [import-data] | prompts modal opening | + +### Emits + +| event | description | +| ------------------------- | --------------------------------------------------------- | +| [import-data/user-config] | notifies the bus of user config for next import data task | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/390_layout.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/390_layout.md new file mode 100644 index 0000000000..930cc45eb2 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/390_layout.md @@ -0,0 +1,776 @@ +--- +id: layout +title: Layout +sidebar_label: Layout +--- + + + + + + + + + + +[micro-lc]: https://github.com/micro-lc/micro-lc +[RequestInit]: https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules_typedoc_node_modules_typescript_lib_lib_dom_d_.requestinit.html + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[http-action]: /products/microfrontend-composer/back-kit/50_actions.md#rest-calls + + + +![layout](img/bk-layout.png) + +```html + +``` + +Displays a menu, analogous to the [micro-lc] (version 2.0.0+) menu, which allows to navigate amongst plugins. + + +:::caution +The Layout component is not supported by [micro-lc] version `<2.0.0.` `micro-lc` version 2.0.0+ (or a custom rendering engine) should be used. +::: + + +:::info +Since version 1.5.0, the collapse button is not inside the sidebar anymore but it is a floating button on the right bottom part of it as you can see from the images below. +::: + + +## How to configure + +The Layout can be configured in a number of ways. To include items to the menu, `menuItems` property should be specified. + +```json +{ + "tag": "bk-layout", + "properties": { + "menuItems": [ + { + "id": "orders", + "label": { + "en": "Orders", + "it": "Ordini" + }, + "type": "application" + }, + { + "id": "riders", + "label": { + "en": "Riders", + "it": "Rider" + }, + "type": "application" + } + ] + } +} +``` + +### Mode + +Four modes are available, controlling how the menu is rendered. Generally, the Layout is composed of a top-bar and a side-bar + +- `fixedSideBar` + - the top-bar includes components such as the logo and the user-menu + - the side-bar includes the menu items. The side-bar can be collapsed, but is always visible +- `overlaySideBar` + - the top-bar includes components such as the logo and the user-menu + - the side-bar includes the menu items. The side-bar becomes visible and is hidden through a CTA +- `leftMenu` + - the whole menu is included in the side-bar, the top-bar is not rendered +- `topBar` + - the whole menu is included in the top-bar, the side-bar is not rendered + +#### Fixed side bar + +![layout-fixedSideBar](img/bk-layout-fixedSideBar.png) + +#### Overlay side bar + +![layout-overlaySideBar](img/bk-layout-overlaySideBar.png) + +#### Left menu + +![layout-leftMenu](img/bk-layout-leftMenu.png) + +#### Top bar + +![layout-topBar](img/bk-layout-topBar.png) + + +### Search bar + +It is possible to add a search bar within the side bar setting the `showSearchBar` to `true` and it is available for every mode except the `topBar`. + +The search is made comparing the searched value with the localized label of the menu item and with the tags, if specified. The search does not consider the upper case letters. + +An [example](#search-bar) is available + +### Logo + +An image can be rendered as a logo using property `logo`, which is an object with keys: +- `altText`: alt-text of the image +- `onClickHref`: link to which to navigate when the logo is clicked +- `url`: + - if `url` is initialized to a string, represents the URL of the image to use as logo + - if `url` is initialized to an object with keys `path` and (optionally) `default`, the logo source is retrieved by applying `path` (in JavaScript notation) to the current user's object-like representation. The user information is obtained during bootstrap using property `userInfoUrl` as endpoint. An [example](#dynamic-logo) is available. + +### Help Menu + +Property `helpMenu` accepts an object with key `helpHref`. The Layout uses it to render a button which redirects to a help page. + +### User Menu + +The Layout fetches information about the currently logged user by calling the endpoint specified in property `userInfoUrl`. + +A user-menu can be rendered inside Layout, by configuring property `userMenu`. The user menu allows to log-out and displays information about the logged user. The menu trigger can be configured using the property `userMenuTrigger` that accepts `hover` or `click` as value. + +`userMenu` accepts keys: +- `logout`: object with keys `url`, `method`, `redirectUrl` representing the call to execute to log-out +- `userPropertiesMapping`: maps properties of the currently logged user to keys `name` and `avatar`, which are displayed within the user-menu + +An [example](#example-user-information) is available. + +:::caution +Property `userInfoUrl` is available inside `userMenu` but is deprecated. Instead, apply property `userInfoUrl` directly to the properties of Layout. + +For instance, from: +```json +{ + "tag": "bk-layout", + "properties": { + "userMenu": { + "userInfoUrl": "/user-info" + } + } +} +``` + +to + +```json +{ + "tag": "bk-layout", + "properties": { + "userInfoUrl": "/user-info" + } +} +``` +::: + +### Head + +The tab title and the fav icon can be specified with property `head`, which accepts an object with keys `favIconUrl`, `title`. + +### Menu Items + +Items in the menu. These can be of two types, `href` or `application`: +- `href` menu items behave like links, navigating to a configurable page upon click +- `application` pages navigate to a plugin + +Multiple menu items can be grouped into recursive structures, `categories` (collapsible) and `groups` (non-collapsible). + +All types of menu item have internationalized labels [LocalizedText][localized-text]. + +#### Href + +```typescript +interface HrefMenuItem { + /** Link's destination */ + href: string + + /** Icon of the menu item */ + icon?: string + + /** Unique identifier of the href */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Specifies where to open the linked document */ + target?: '_blank' | '_self' | '_parent' | '_top' + + /** Type of the item: hyperlink to another page */ + type: 'href' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig + + /** Tags used for search */ + tags?: string[] +} +``` + +#### Application + +```typescript +interface ApplicationMenuItem { + /** Icon to visualize */ + icon?: string + + /** Unique identifier of the corresponding micro-lc application */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Identifiers of micro-lc other applications that also correspond to the item */ + selectedAlsoOn?: string[] + + /** Type of the item: micro-lc application */ + type: 'application' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig + + /** Tags used for search */ + tags?: string[] +} +``` + +#### Category + +```typescript +interface CategoryMenuItem { + /** Menu items included in the category */ + children?: MenuItem[] + + /** Icon to visualize */ + icon?: string + + /** Unique identifier of the category */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Type of the item: collapsible sub-menu */ + type: 'category' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig + + /** Tags used for search */ + tags?: string[] +} + +``` + +#### Group + +```typescript +interface GroupMenuItem { + /** Menu items included in the group */ + children?: MenuItem[] + + /** Unique identifier of the group */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Type of the item: non-collapsible group of items */ + type: 'group' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig + + /** Tags used for search */ + tags?: string[] +} +``` + +#### Badges + +The `badge` property can be used to specify an extra value to be displayed next to the label within the corresponding item menu. + +If `badge` is of type `HttpConfig`, it specifies the parameters of a REST call that is used by the Layout at bootstrap time to fetch the data to display. + +Type `HttpConfig` is a subset of the supported configuration for [Http Actions][http-action], accpeting keys + - `url`: url to call + - `method`: REST method to use + - `body`: body to attach to the call + - `config`: extra configurations, such as headers + + +### Locale + +The texts of the Layout can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + collapse: LocalizedText + logout: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +### Example: Display a menu + +The following configuration for the Layout component + +```json +{ + "tag": "bk-layout", + "properties": { + "mode": "fixedSideBar", + "menuItems": [ + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faChartBar" + }, + "id": "dashboards-analytics", + "label": "Analytics", + "type": "application" + }, + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faPaperPlane" + }, + "id": "ordersList", + "label": { + "en": "Orders", + "it": "Ordini" + }, + "type": "application", + "badge": { + "url": "/v2/orders/count?_st=PUBLIC,DRAFT", + "method": "GET" + } + }, + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faUsers" + }, + "id": "usersCategory", + "label": "Users", + "type": "category", + "badge": "3", + "children": [ + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faBiking" + }, + "id": "ridersList", + "label": "Riders", + "type": "application", + "badge": {} + }, + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faUserTag" + }, + "id": "customersList", + "label": "Customers", + "type": "application" + } + ] + }, + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faAppleAlt" + }, + "id": "food-collections", + "label": "Food Collections", + "type": "application" + } + ], + "head": { + "favIconUrl": "https://www.mia-platform.eu/static/img/favicon/apple-icon-60x60.png", + "title": "Frontend" + } + } +} +``` + +renders a menu with items structured as follows (assuming english as browser language): + +``` +- Analytics +- Orders +- Users + - Riders + - Customers +``` + +### Example: Search Bar + +With the following configuration a search bar is visualized at the top of the side bar. + +- The `riders` menu item will be matched to any string that contains a part or all of `fattorini` (from tags prop) and `riders`. +- The `ordersList` menu item will be matched to any string that contains a part or all of `ordinazioni` (from tags prop) and `orders`. +- The `category` menu item will be matched to any string that contains a part or all of `category`. + +```json +{ + "tag": "bk-layout", + "properties": { + "mode": "fixedSideBar", + "showSearchBar": "true", + "menuItems": [ + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faPaperPlane" + }, + "id": "ordersList", + "label": { + "en": "Orders", + "it": "Ordini" + }, + "type": "application", + "badge": { + "url": "/v2/orders/count?_st=PUBLIC,DRAFT", + "method": "GET" + }, + "tags": ["ordinazioni"] + }, + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faUsers" + }, + "id": "usersCategory", + "label": "Users", + "type": "category", + "badge": "3", + "children": [ + { + "icon": { + "library": "@fortawesome/free-solid-svg-icons", + "selector": "faBiking" + }, + "id": "ridersList", + "label": "Riders", + "type": "application", + "badge": {}, + "tags": ["fattorini"] + } + ] + } + ] + } +} +``` + + +### Example: Dynamic Logo + +With the following configuration + +```json +{ + "tag": "bk-layout", + "properties": { + "userInfoUrl": "/user-info", + "logo": { + "altText": "Logo", + "url": { + "path": "companyImg", + "default": "./default-logo.png" + } + } + } +} +``` +and assuming the data fetched from `/user-info` is + +```json +{ + "name": "Sarah Cyprus", + "companyImg": "https://logos.test/img/logo-1.png", + "role": "admin" +} +``` + +a Layout is rendered with a logo image having source "https://logos.test/img/logo-1.png". + +While with data fetched from `/user-info` having no "companyImg" key, like + +```json +{ + "name": "Sarah Cyprus", + "role": "admin" +} +``` +a Layout is rendered with a logo image having source "./default-logo.png", specified as default inside the `logo` property. + +### Example: User information + +Assuming an instance of a Layout component to be configured like + +```json +{ + "tag": "bk-layout", + "properties": { + "userInfoUrl": "/user-info", + "userMenu": { + "logout": { + "method": "POST", + "url": "/logout" + }, + "userPropertiesMapping": { + "image": "avatar" + } + }, + } +} +``` + +and assuming the data fetched from `/user-info` is + +```json +{ + "name": "Sarah Cyprus", + "image": "https://logos.test/img/avatar-1.png", + "role": "admin" +} +``` + +then the user menu rendered by the Layout is composed of the label "Sara Cyprus" and the avatar image with source "https://logos.test/img/avatar-1.png". + +The value to use for the avatar is mapped to the "image" key of the user information through `userPropertiesMapping` field of `userMenu` property. + +Loggin out can be performed from the user-menu, which performs a POST call to endpoint "/logout". + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| --------------- | --------------- | ------------------------ | ---------------- | --------------------------------------------------- | +| userInfoUrl | user-info-url | string | - | URL called in GET to retrieve user data | +| mode | mode | [Mode](#mode) | "overlaySideBar" | controls how the menu is visualized | +| logo | - | [Logo](#logo) | - | logo to be visualized in the menu | +| menuItems | - | [MenuItem](#menuitems)[] | - | describes the items in the menu | +| helpMenu | - | [HelpMenu](#helpmenu) | - | controls the help button on the menu | +| userMenu | - | [UserMenu](#usermenu) | - | controls the user information section of the menu | +| userMenuTrigger | - | `hover` \| `click` | "hover" | controls the user menu trigger | +| head | - | [Head](#head) | - | controls tab visualization options | +| sideBarWidth | side-bar-width | number | 200 | Width of the sidebar in pixels, if applicable | +| collapsedWidth | collapsed-width | number | 80 | Width of collapsed sidebar in pixels, if applicable | +| showSearchBar | - | boolean | false | Whether to show search bar | + + +#### Mode +```typescript +type Mode = 'fixedSideBar' | 'overlaySideBar' | 'leftMenu' | 'topBar' +``` + +#### Logo + + +```typescript +type Logo { + /** Alternative text to display if the logo is not found */ + altText?: string + + /** Link to navigate to when the logo is clicked */ + onClickHref?: string + + /** URL of the logo image, or path to get it from user-info */ + url?: string | { + path: string + default?: string + } +} +``` + +#### MenuItems + +```typescript +type MenuItem = HrefMenuItem | ApplicationMenuItem | CategoryMenuItem | GroupMenuItem + +interface HrefMenuItem { + /** Link's destination */ + href: string + + /** Icon of the menu item */ + icon?: string + + /** Unique identifier of the href */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Specifies where to open the linked document */ + target?: '_blank' | '_self' | '_parent' | '_top' + + /** Type of the item: hyperlink to another page */ + type: 'href' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig +} + +interface ApplicationMenuItem { + /** Icon to visualize */ + icon?: string + + /** Unique identifier of the corresponding micro-lc application */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Identifiers of micro-lc other applications that also correspond to the item */ + selectedAlsoOn?: string[] + + /** Type of the item: micro-lc application */ + type: 'application' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig +} + +interface CategoryMenuItem { + /** Menu items included in the category */ + children?: MenuItem[] + + /** Icon to visualize */ + icon?: string + + /** Unique identifier of the category */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Type of the item: collapsible sub-menu */ + type: 'category' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig +} + +interface GroupMenuItem { + /** Menu items included in the group */ + children?: MenuItem[] + + /** Unique identifier of the group */ + id: string + + /** Label of the menu item */ + label?: LocalizedText + + /** Type of the item: non-collapsible group of items */ + type: 'group' + + /** Data to display next to the item label or http configuration to fetch it */ + badge?: string | HttpConfig +} + +interface GroupMenuItem { + /** Url to call */ + url: string + + /** Rest method to use */ + method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' + + /** Body to attach to the call */ + body?: Record | string | null + + /** Extra configuration, such as headers */ + config?: Omit +} + +type HttpConfig = { + /** URL to call */ + url: string + /** REST method to call */ + method: HttpMethods + /** body of the REST call */ + body?: Record | string | null + /** further configuration */ + config?: Omit +} + +type HttpClientConfig = Omit & { + /* search params to apply to the call */ + params?: string | Record | string[][] | URLSearchParams + /* wether or not the result should be sent back without any transformation (by default, response is either sent back as text or an object). If true, `downloadAsFile` is ignored. */ + raw?: boolean + /* whether the result should be downloaded as file. Only supported for POST and GET calls. */ + downloadAsFile?: boolean +} +``` + +Where: +- [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings +- [RequestInit] refers to the standard Typescript interface + + +#### HelpMenu + +```typescript +type HelpMenu { + /** Link to the help page */ + helpHref: string +} +``` + +#### UserMenu + +```typescript +type UserMenu { + /** Configuration needed to perform user logout */ + logout?: { + /** Method used to perform the call to the URL specified in the 'url' property */ + method?: 'GET' | 'POST' + + /** URL to be redirected to after the logout. When missing, if the logout call replies with a redirect, then it will be followed */ + redirectUrl?: string + + /** URL called to log out the user. The method used is the one specified in the 'method' property */ + url?: string + } + + + /** @deprecated URL called in GET to retrieve user data */ + userInfoUrl: string + + /** Mapping between the properties returned from the user info URL call and the ones expected by the component */ + userPropertiesMapping?: Record +} +``` + +#### Head + +```typescript +type Head { + /** Url of the fav icon */ + favIconUrl?: string + + /** Title of the tab */ + title?: string +} +``` + + +### Listens to + +None + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/400_layout_container.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/400_layout_container.md new file mode 100644 index 0000000000..3849d740e9 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/400_layout_container.md @@ -0,0 +1,344 @@ +--- +id: layout_container +title: Layout Container +sidebar_label: Layout Container +--- + + + + + +[element-composer]: https://micro-lc.io/1.x/docs/core_plugins/#microlc-element-composer +[shadow dom]: https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM + +[event-bus]: /products/microfrontend-composer/back-kit/10_overview.md#events + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-calendar]: /products/microfrontend-composer/back-kit/60_components/130_calendar.md +[bk-tabs]: /products/microfrontend-composer/back-kit/60_components/530_tabs.md +[bk-layout-swap]: /products/microfrontend-composer/back-kit/60_components/410_layout_swap.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + +[layout/change]: /products/microfrontend-composer/back-kit/70_events.md#layout---change + + + +```html + +``` + +:::caution +Using `@micro-lc/composer@^2` and `@micro-lc/orchestrator@^2` as rendering engine and micro-frontend orchestrator, +the [Layout Swap][bk-layout-swap] should be used instead of the Layout Container. +::: + +This component is meant to allow multiple configurations to live within the same plugin by: + +1. re-using `back-kit` components without letting functionalities (mostly clients') trump each other +2. render multiple layouts together like a page with table, then a card detail, then another table and so on +3. condensate plugins into a single one + +A simple instance would be a user which might want to explore multiple details connected with its user but persisted on different entities. + +Since a backend resource, like a database collection/table, is mostly mapped 1:1 on a Microfrontend Composer plugin using a single client, like the [CRUD Client][bk-crud-client], it is recommendable to use different plugins to render different collections. +For those cases falling outside the previous scope a layout that can be switched might come in handy. + + +By reproducing an [element-composer]-compatible configuration, the Layout Container provides a wrapper for different configurations wired to one or many [event-bus] instances. +Such configurations are switched whenever the Layout Container receives to the request of switching to a new layout, via a [layout/change] event. + +## How to configure + +The Layout Container should be provided with the `content` property, specifying the configurations of the layouts to orchestrate. + +```json +{ + "tag": "bk-layout-container", + "properties": { + "content": { + "$default": { + ... // first plugin + }, + "currentBasket": { + ... // second plugin + } + } + } +} +``` + +The `$default` key is not mandatory but is reserved and marks the layout to render on landing. +The Layout Container also allows to specify the default layout through property `currentLayout`. + +### Event bus + +Each layout has a dedicated [EventBus][event-bus] instance which has the same name of the configuration key. +This is by default injected to all components of the layout. + +To configure this behavior the key `busDiscriminator` is available. + +This defaults to `$inherit` and takes the `EventBus` of its parent. Specifying a different value spawns a new `EventBus`. + +### Disable shadow dom + +Adding the attribute `disable-shadow-dom` allows to disable the [shadow dom] for the Layout Container, +which can be useful when it has to embed children which bubble events up to the document root such as the [Calendar][bk-calendar]. + +:::caution +`disable-shadow-dom` needs be passed as an empty attribute to the Layout Container, and **not** as property. For instance: + +```json +{ + "tag": "bk-layout-container", + "attributes": { + "disable-shadow-dom":"" + }, + "properties": { + "content": { + "$default": { + ... // first plugin + }, + "currentBasket": { + ... // second plugin + } + } + } +} +``` +::: + +## Examples + +### Example: Merging two plugins into one + +Let's then suppose we have a customer, a list of their previous purchases and a list of their current basket items. + +We could use different plugins. For previous purchases it would look like: + +```json +// previous-purchases.json +{ + "$ref": { + "ppSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "items": {"type": "array"} + } + } + }, + "content": { + "type": "row", + "content": [ + { + "tag": "bk-table", + "properties": { + "dataSchema": {"$ref": "ppSchema"} + } + }, + { + "tag": "bk-crud-client", + "properties": { + "dataSchema": {"$ref": "ppSchema"} + } + } + ] + } +} +``` + +while current basket would look like: + +```json +// current-basket.json +{ + "$ref": { + "cbSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "description": {"type": "string"}, + "price": {"type": "number"} + } + } + }, + "content": { + "type": "row", + "content": [ + { + "tag": "bk-table", + "properties": { + "dataSchema": {"$ref": "cbSchema"} + } + }, + { + "tag": "bk-crud-client", + "properties": { + "dataSchema": {"$ref": "cbSchema"} + } + } + ] + } +} +``` + +If the UI should instead include two tables in a page that can be visually swapped by a set of buttons or tabs, +wrapping both configurations in the Layout Container does the job. + +```json +// single-plugin.json +{ + "$ref": { + "ppSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "items": {"type": "array"} + } + }, + "cbSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "description": {"type": "string"}, + "price": {"type": "number"} + } + } + }, + "content": { + "tag": "bk-layout-container", + "properties": { + "content": { + "$default": {/* first plugin */}, + "currentBasket": {/* second plugin */} + } + } + } +} +``` + +### Example: switch layout using a button + +The [Button][bk-button] can be used to switch to a different layout: + +```json +{ + "tag": "bk-button", + "properties": { + "content": "View Orders", + "action": { + "type": "event", + "config": { + "label": "layout/change", + "payload": { + "layout": "orders" + } + } + } + } +}, +{ + "tag": "bk-button", + "properties": { + "content": "View Riders", + "action": { + "type": "event", + "config": { + "label": "layout/change", + "payload": { + "layout": "riders" + } + } + } + } +}, +{ + "tag": "bk-layout-container", + "properties": { + "content": { + "riders": {...}, + "orders": {...} + } + } +} +``` + +### Example: switch layout using tabs + +The [Tabs][bk-tabs] can be used to navigate between layouts: + +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "riders", + "title": "Riders", + "event": { + "label": "layout/change", + "payload": { + "layout": "riders" + } + } + }, + { + "key": "customers", + "title": "Customers", + "event": { + "label": "layout/change", + "payload": { + "layout": "customers" + } + } + } + ] + } +}, +{ + "tag": "bk-layout-container", + "properties": { + "content": { + "riders": {...}, + "orders": {...} + } + } +} +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ------------------ | -------------------- | ------------------- | ------- | ------------------------------------------------------------------- | +| `content` | - | [Content](#content) | - | layouts configuration | +| `disableShadowDom` | `disable-shadow-dom` | boolean | false | disable the shadow dom as render root (only use as empty attribute) | +| `currentLayout` | `current-layout` | string | - | default layout to view on landing | + +#### Content +```typescript +type Content = Record | Record +type LayoutNode = { + attributes?: Record + busDiscriminator?: string | string[] + content?: LayoutNode | LayoutNode[] + properties?: Record + tag?: string + type?: string +} +``` + +### Listens to + +| event | action | +| --------------- | ------------------------------------------------------------------------------ | +| [layout/change] | requires the connection of the layout which is referenced in the event payload | + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/40_atlas_dashboard.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/40_atlas_dashboard.md new file mode 100644 index 0000000000..c8b99ec4ee --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/40_atlas_dashboard.md @@ -0,0 +1,128 @@ +--- +id: atlas_dashboard +title: Atlas Dashboard +sidebar_label: Atlas Dashboard +--- + + + + + + +[marketplace]: /runtime-components/overview_marketplace.md +[mongodb-atlas]: https://www.mongodb.com/atlas/database + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema + +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query + + + + +```html + +``` +![dashboard](img/bk-atlas-dashboard.png) + +The Atlas Dashboard embeds a read-only dashboard from [`MongoDB Atlas`][mongodb-atlas]. +The Atlas Dashboard embeds of a dashboard from `MongoDB Atlas` which displays data (or filtered data when alongside a filtering component). + + +## How to configure + +The Atlas Dashboard should be provided with properties: + - `baseUrl`: URL to reach the dashboard to visualized + - `dashboardId`: id of the dashboard to visualize + + +```json +{ + "tag": "bk-atlas-dashboard", + "properties": { + "baseUrl": "/mongo-db/project-1", + "dashboardId": "dashboard-orders" + } +} +``` + +### Authentication + +To embed an authenticated dashboard, an authentication service must be reachable by the Atlas Dashboard. +Properties `apiKey` and `authEndpoint` are used by the Atlas Dashboard to perform authentication. + +For instance, service `atlas-dashboard-authentication` is available in [Mia Platform Marketplace][marketplace] as an authentication backend solution. + +### Filters + +The Atlas Dashboard component listens to filtering events in order to replicate the applied filters to the visualized dashboard. + +The Atlas Dashboard component listens to filtering events to synchronize applied filters with the displayed dashboard. +This synchronization is achieved by monitoring [change-query] events and relies on a [data-schema] that defines the structure of the data, which must be provided to the Atlas Dashboard. + +When the component detects a `change-query` event, it processes the event payload's `search`, `filters`, and `characteristic` keys, converting them into queries compatible with the `MongoDB Atlas` service. +Subsequently, a new call to the service is made, leading to the re-rendering of the dashboard with the updated filters. + +```json +{ + "tag": "bk-atlas-dashboard", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "baseUrl": "/mongo-db/project-1", + "dashboardId": "dashboard-orders", + "name": { + "type": "string" + } + } + } + } +} +``` + +## Known issues + +### Flickering size + +It could happen that the component keeps resizing. This is due to scaling problems of the embedded `Mongo Atlas` `iframe`. +This is a known issue of Mongo Atlas, which can be temporarily fixed adding some padding to the component: + +```json +{ + "tag": "bk-atlas-dashboard", + "attributes": { + "style": "padding: 0.5px" + }, + "properties": { + "baseUrl": "/mongo-db/project-1", + "dashboardId": "dashboard-orders" + } +} +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| -------------- | --------------- | -------------------------------------------- | ------------- | ------------------------------------------------------------------------------------- | +| `apiKey` | `api-key` | string | - | apikey to call the authentication route from a trusted entity. Leave empty if not set | +| `authEndpoint` | `auth-endpoint` | string | - | endpoint for the dashboard authentication | +| `background` | `background` | string | "transparent" | background color of the dashboard. Possible values are color hex code, CSS color name | +| `baseUrl` | `base-url` | string | - | base URL of the embedded dashboard | +| `dashboardId` | `dashboard-id` | string | - | dashboard id of the embedded dashboard | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data-schema describing the fields of the collection | + +### Listens to + +| event | action | +| -------------- | -------------------------------- | +| [change-query] | applies filters to its dashboard | + + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/410_layout_swap.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/410_layout_swap.md new file mode 100644 index 0000000000..f834377e3a --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/410_layout_swap.md @@ -0,0 +1,372 @@ +--- +id: layout_swap +title: Layout Swap +sidebar_label: Layout Swap +--- + + + + + +[micro-lc]: https://micro-lc.io/docs +[event-bus-prop]: https://micro-lc.io/docs/guides/applications/compose/#eventbus + +[layout/change]: /products/microfrontend-composer/back-kit/70_events.md#layout---change + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-tabs]: /products/microfrontend-composer/back-kit/60_components/530_tabs.md +[bk-layout-container]: /products/microfrontend-composer/back-kit/60_components/400_layout_container.md +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-calendar]: /products/microfrontend-composer/back-kit/60_components/130_calendar.md + + + +:::caution +works only with [`@micro-lc/composer@^2` and `@micro-lc/orchestrator@^2`][micro-lc] +::: + +```html + +``` + +The Layout Swap allows swapping between different document fragments / compose configurations + +The use case this component addresses is when two or more configurations live in the same +page but they need to be rendered conditionally, using another component to swap them, such as the [Tabs][bk-tabs] +or the [Button][bk-button]. + +At any time, all components of all layouts are included in the page. + +The Layout Swap allows to hide the components of all layouts but one. +The visible layout can be switched via the event [layout/change]. + +:::caution +this component, due to the fact it must be loaded in advance, is bundled separately at `/bk-layout-swap.esm.js` +::: + +## How to configure + +A `content` should be specified for Layout Swap. Note that `content` is **not** a property of the Layout Swap. + +```json +{ + "tag": "bk-layout-swap", + "properties": { + "layout": "table" + }, + "content": [ + { + "tag": "div", + "attributes": { + "slot": "table" + }, + "content": { + ... + } + }, + { + "tag": "div", + "attributes": { + "slot": "calendar" + }, + "content": { + ... + } + } + ] +} +``` + +Each layout must be a unique HTML element with a `slot` property set to the layout it represents. +The content of the layout stays inside the relative HTML element. + +The resulting configuration is equivalent to the following HTML snippet: + +```html + +
+ +
+
+ +
+
+``` + +Property `layout` controls the default layout to make visible by default. + +### Difference with Layout Container + +There are differences between the [Layout Container][bk-layout-container] and this component: + +1. the inner elements are never in shadow DOM -> `disable-shadow-dom` is not needed +2. there's no composing on layouts after the initialization +3. this component does not handle the communication layer of components. `eventBus` is injected by the composer on each component. To isolate components the property [eventBus][event-bus-prop] must be tuned locally for each component. An [example](#example-event-bus) is available showing how to handle multiple `eventBus`. + +## Examples + +### Example: Basic usage + +The use case this component addresses is when two or more configurations live in the same +page but they need to be rendered conditionally, using another component - such as the [Tabs][bk-tabs] +or the [Button][bk-button] to swap them. + +For instance, to swap between a table view like + +```json +[ + { + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "name": {"type": "string"} + } + } + } + } +] +``` + +and a calendar component + +```json +[ + { + "tag": "bk-calendar" + } +] +``` + +It is possible to use [Button][bk-button]s, both firing the `layout/change` event, with the payload `layout: table` and `layout: calendar` to reach either layout. + +```json +[ + { + "tag": "bk-button", + "properties": { + "content": "Go to Table", + "action": { + "type": "event", + "config": { + "events": { + "label": "layout/change", + "payload": { + "layout": "table" + } + } + } + } + } + }, + { + "tag": "bk-button", + "properties": { + "content": "Go to Calendar", + "action": { + "type": "event", + "config": { + "events": { + "label": "layout/change", + "payload": { + "layout": "calendar" + } + } + } + } + } + } +] +``` + +This structure can be inserted within a Layout Swap. + +When a `layout/change` event is fired the Layout Swap shows only the matching branch amongst its direct children according to the `slot` attribute. +The initial layout is controlled either by the `layout` property or the `bootstrap-layout` attribute. + +The configuration looks like this: + +```json +{ + "tag": "bk-layout-swap", + "properties": { + "layout": "table" + }, + "content": [ + { + "tag": "div", + "attributes": { + "slot": "table" + }, + "content": { + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"} + } + } + } + } + }, + { + "tag": "div", + "attributes": { + "slot": "calendar" + }, + "content": { + "tag": "bk-calendar" + } + } + ] +} +``` + +### Example: Handle communication with multiple event-bus + +Let's say we have two layouts with different CRUD clients and we'd like to scope them on different channels + +- a couple of [Button][bk-button]s must have the same bus of the Layout Swap to swap layouts +- a [Table][bk-table] must talk with an instance of a [CRUD Client][bk-crud-client] +- a [Calendar][bk-calendar] must talk with another instance of a CRUD Client + +That summarizes to + +```json +{ + { + "tag": "bk-button", + "properties": { + "content": "Go to Table", + "action": { + "type": "event", + "config": { + "events": { + "label": "layout/change", + "payload": { + "layout": "table" + } + } + } + } + } + }, + { + "tag": "bk-button", + "properties": { + "content": "Go to Calendar", + "action": { + "type": "event", + "config": { + "events": { + "label": "layout/change", + "payload": { + "layout": "calendar" + } + } + } + } + } + }, + { + "tag": "bk-crud-client", + "properties" { + "reflectToUrl": false, + "eventBus": "eventBus.pool.table", + "basePath": "/table-base-path", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"} + } + } + } + }, + { + "tag": "bk-crud-client", + "properties" { + "reflectToUrl": false, + "eventBus": "eventBus.pool.calendar", + "basePath": "/calendar-base-path", + "dataSchema": { + "type": "object", + "properties": { + "title": {"type": "string"}, + "startDate": {"type": "string", "format": "data-time"}, + "endDate": {"type": "string", "format": "data-time"} + } + } + } + }, + { + "tag": "bk-layout-swap", + "properties": { + "layout": "table" + }, + "content": [ + { + "tag": "div", + "attributes": { + "slot": "table" + }, + "content": { + "tag": "bk-table", + "properties": { + "eventBus": "eventBus.pool.table", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"} + } + } + } + } + }, + { + "tag": "div", + "attributes": { + "slot": "calendar" + }, + "content": { + "tag": "bk-table", + "properties": { + "eventBus": "eventBus.pool.calendar" + } + } + } + ] + } +} +``` + +Notice how the `eventBus` property is used to appropriately scope communication channels between components. + +:::info +`reflectToUrl` property is used to prevent the CRUD Client instance from writing to the URL at the same time, +which may cause clashing. +::: + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| -------- | ------------------ | ------ | ------- | --------------------------------------------------------- | +| `layout` | `bootstrap-layout` | string | - | default layout to view on landing and then current layout | + +### Listens to + +| event | action | +| --------------- | ------------------------------------------------------------------------------ | +| [layout/change] | requires the connection of the layout which is referenced in the event payload | + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/420_list.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/420_list.md new file mode 100644 index 0000000000..3b9e377358 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/420_list.md @@ -0,0 +1,141 @@ +--- +id: list +title: List +sidebar_label: List +--- + + + + + + +[lookups]: /products/microfrontend-composer/back-kit/30_page_layout.md#lookups-deprecated +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data + + + +```html + +``` + +![bk-simple-list](img/bk-simple-list.png) + +The List displays a list of primitive elements (strings, numbers, ...) or [lookup fields][lookups]. + + +## How to configure + +Property `datasourceKey` should be provided in the List configuration, matching one of the fields of the underlying data. + +Upon receiving newly fetched data (via a [display-data] event), the List component extracts the value of the field indicated by `datasourceKey` from the first data entry. + +```json +{ + "tag": "bk-simple-list", + "properties": { + "datasourceKey": "products" + } +} +``` + +### Title + +The List title is configurable via the property `label`, which is expected to be either a sting, a [localized object][localized-text], or an object with the following fields: + +| property | type | description | +| -------- | ------------------------------- | --------------------------------------- | +| title | [LocalizedText][localized-text] | title of the list (h1) | +| subtitle | LocalizedText | subtitle (h2) displayed below the title | +| badge | LocalizedText | badge displayed right of the title | +| icon | string | icon displayed left of the title | + +## Examples + +With the following configuration, the List renders the field `items` of the retrieved data. + +```json +{ + "tag": "bk-simple-list", + "properties": { + "label": { + "icon": "fas fa-building", + "title": {"en": "Conversation", "it": "Conversazione"}, + "badge": {"en": "Awaiting", "it": "In Attesa"}, + "subtitle": {"en": "This is a conversation", "it": "Questa è una conversazione"} + }, + "datasourceKey": "products" + } +}, +``` + +If the data looks like: + +```json +[ + { + "name": "Company 1", + "products": [ + "Blue Pants", "Red Shirt", "Gray Socks" + ] + }, + { + "name": "Company 2", + "products": [ + "Green Shoes" + ] + } +] +``` + +the rendered data by the List can be represented by an array as: + +```json +[ + ["Blue Pants"], + ["Red Shirt"], + ["Gray Socks"] +] +``` + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ----------------------------- | ---------------- | -------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------- | +| `datasourceKey` | `datasource-key` | string | - | the object key that will be used to pick the data to show. | +| `customMessageOnAbsentLookup` | - | [LocalizedText][localized-text] | - | override lookup value in case lookup is not resolved due to lack of data | +| `label` | - | LocalizedText \| [HeaderProps](#headerprops) | - | header of the list. | +| `height` | `height` | string \| number | - | max height of the body of the list before. Overflowing data is accessible through vertical scrolling | + + +#### HeaderProps + +```typescript +type HeaderProps = { + title: LocalizedText + subtitle: LocalizedText + badge: LocalizedText + icon: string +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +### Listens to + +| event | action | +| -------------- | ------------------------------------ | +| [display-data] | retrieved data to display | +| [loading-data] | choose when to show the list spinner | + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/430_loading_animation.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/430_loading_animation.md new file mode 100644 index 0000000000..06cde196b8 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/430_loading_animation.md @@ -0,0 +1,58 @@ +--- +id: loading_animation +title: Loading Animation +sidebar_label: Loading Animation +--- + + + + + +[mlc-loading-animation]: https://micro-lc.io/add-ons/components/mlc-loading-animation + + + +:::caution +this component, due to the fact it must be loaded in advance, is bundled separately at `/bk-loading-animation.esm.js` +::: + +```html + +``` + +The Loading Animation to display a loading animation until one of its children has finished loading. + +This component is analogous to `mlc-loading-animation` from [micro-lc][mlc-loading-animation]. + +## How to configure + +Property `primaryColor` should be specified. + +```json +{ + "tag": "bk-loading-animation", + "properties": { + "primaryColor": "#43a056" + } +} +``` + + +## API + +### Properties & Attributes + +| Property | Attribute | Type | Description | +| -------------- | --------------- | ------ | ------------------------------------------------------------------------------------------------------------ | +| `primaryColor` | `primary-color` | string | Color of the animation (it can be Hex, 8-digit Hex, RGB, RGBA HSL, HSLA, HSV HSVA, or CSS color name string) | + +### Listens to + +None + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/440_navigation_back_arrow.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/440_navigation_back_arrow.md new file mode 100644 index 0000000000..8f9b173c7b --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/440_navigation_back_arrow.md @@ -0,0 +1,57 @@ +--- +id: navigation_back_arrow +title: Navigation Back Arrow +sidebar_label: Navigation Back Arrow +--- + + + + + + +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push + + + +```html + +``` + +The Navigation Back Arrow renders a button with left arrow icon, which upon clicking notifies the request to go back one step in the nesting path. The Navigation Back Arrow is only visible in nested pages. + +![navigation-back-arrow](img/bk-navigation-back-arrow.png) + +## How to configure + +The Navigation Back Arrow component does not require any configuration. + +```json +{ + "tag": "bk-navigation-back-arrow" +} +``` + +## API + +### Properties & Attributes + +None + +### Listens to + + +| event | action| +|-------|--------| +|[nested-navigation-state/push][nested-navigation-state/push]|updates internal representation of the current navigation path by adding one step| +|[nested-navigation-state/back][nested-navigation-state/back]|updates internal representation of the current navigation path by removing the specified number of steps| + +### Emits + + +| event | description | +|-------|-------------| +|[nested-navigation-state/back][nested-navigation-state/back]|notifies to go back one step in the navigation path| diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/450_notification_center.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/450_notification_center.md new file mode 100644 index 0000000000..4bbc1d0514 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/450_notification_center.md @@ -0,0 +1,426 @@ +--- +id: notification_center +title: Notification Center +sidebar_label: Notification Center +--- + + + + + + +[anchor]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a +[replace]: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace +[pushState]: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState +[history]: https://developer.mozilla.org/en-US/docs/Web/API/History + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[bk-state-adapter]: /products/microfrontend-composer/back-kit/60_components/510_state_adapter.md + +[add-filter]: /products/microfrontend-composer/back-kit/70_events.md#add-filter + + + +```html + +``` + +![notification-center](img/bk-notification-center.png) + +The Notification Center allows to handle notifications. It works by dealing with a backend source with a simple REST API interface. + +The Notification Center expects to be linked to a dataset of notifications like: + +```typescript +type Notification = { + _id: string + creatorId: string + createdAt: string + title: string + readState?: boolean + content?: string + onClickCallback?: CallbackHref +} + +type CallbackHref = { + content: content: string | {url: string, data: any}; +} +``` + +`onClickCallback` field in retrieved notifications allows to controls the navigation destination upon [clicking the notification](#click-strategies). + +## How to configure + +The base endpoint form which to retrieve notifications should be provided using property `endpoint`. +Property `endpoint` defaults to "/api/v1/bk-notification-center". + +```json +{ + "tag": "bk-notification-center", + "property": { + "endpoint": "/notifications" + } +} +``` + +### Backend communication + +The Notification Center needs a backend service to retrieve and interact with notifications. +Backend base endpoint can be configured using the `endpoint` property, defaults to "/api/v1/bk-notification-center". + +Following is a description of the endpoints called by the component that should be exposed by the service. + +#### GET - `/own` + +This endpoint should return the list of paged notifications that the currently logged-in user should visualize. The notifications +should be ordered by creation date descending. + +##### Query Parameters + +Query parameters `skip` and `limit` help querying the notification pagination. +These can be configured using properties `limitQueryParam`, `skipQueryParam`, `limit`. + +```json +{ + "type": "object", + "properties": { + "limit": { + "description": "Limits the number of documents, max 200 elements, minimum 1", + "type": "integer", + "minimum": 1 + }, + "skip": { + "description": "Skip the specified number of documents", + "type": "integer", + "minimum": 0 + } + }, + "required": ["skip", "limit"] +} +``` + +##### Response + +```json +{ + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "anyOf": [ + {"type": "string"}, + {"type": "object"} + ] + }, + "content": { + "anyOf": [ + {"type": "string"}, + {"type": "object"} + ] + }, + "readState": { + "type": "boolean" + }, + "createdAt": { + "type": "string" + }, + "onClickCallback": { + "kind": { + "type": "string", + "enum": [ + "href" + ] + }, + "content": { + "type": "string" + } + } + }, + "required": [ + "title", + "createdAt" + ] + } +} +``` + +#### PATCH - `/read-state/:notificationId` + +This endpoint should change the read state of a specific notification given its id. + +##### Body + +```json +{ + "type": "object", + "properties": { + "readState": { + "type": "boolean" + } + } +} +``` + +#### PATCH - `/read-state/own` + +This endpoint should change the read state of all the notifications that the currently logged-in user can retrieve. + +```json +{ + "type": "object", + "properties": { + "readState": { + "type": "boolean" + } + } +} +``` + +### Click strategies + +Clicking on a notification within the Notification Center may trigger a navigation event. + +The property `clickStrategy` controls what navigation method should be executed (`href`, `replace`, `push`). +The specified navigation method uses as input arguments the value of the field [`onClickCallback`](#notification-object) of the clicked notification. + +An on-click-strategy correspond to what happens when a notification is clicked. +- `default` and `href` create an invisible [anchor] and click it +- `replace` triggers [window.location.replace][replace] +- `push` pushes onto [window.history][history] stack + +The value of `onClickCallback` field in a clicked notification is used as input arguments for the triggered navigation method. + +Consequently, for any value of `clickStrategy`, the type of `onClickCallback` can be a string. + +Additionally, if `clickStrategy` is `push`, `onClickCallback` may also be an object with keys `url` and `data`, corresponding to the main arguments of the [window.history.pushState][pushState] method. The value of `data` is injected into the state of the destination page through a key set by property `pushStateKey`. An associated example is shown [below](#example-navigate-to-a-page-and-emit-an-event). + +Further control over the navigation behavior is provided by property `allowExternalHrefs`, controlling whether or not browsing to external external web pages and href is allwed when `clickStrategy` is `default`, `href` or `replace`. + +### Custom labels + +Property `locales` enables the user to apply custom [localized labels][localized-text] within the webcomponent. +Availabe keys are: + +- `title` +- `loadingButton` +- `dateFormat` +- `errorMessage` +- `noNotification` +- `readAll` +- `reload` +- `backOnTop` + +Not all keys need to be specified. An [example](#example-custom-labels) is available. + +To each key, it is possible to attach either a string value (which overrides any browser language settings) +or a localized string given by a key/value map such as + +```javascript +{ + en: "English Translation", + 'en-AU': "English Translation", + zh: "中文翻译", + ... +} +``` + +### Resource fetching mode + +The Notification Center can be configured to automatically fetch new notifications using property `mode`. Available values are: +- `polling` +- `default` +- `none` + +If set to `default` or `none`, data is **not** fetched automatically. + +If `polling`, the Notification Center attempts fetches new data every 10 seconds. The property `pollingFrequency` can be used to tune the fetching frequency (in milliseconds). + +### Locale + +The texts of the Notification Center can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + title: LocalizedText + loadingButton: LocalizedText + dateFormat: LocalizedText + noNotification: LocalizedText + errorMessage: LocalizedText + readAll: LocalizedText + reload: LocalizedText + backOnTop: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +## Examples + +### Example: navigate to a page on notification click + +A Notification Center instance configured like: + +```json +{ + "tag": "bk-notification-center", + "properties": { + "clickConfig": "href" + } +} +``` + +upon clicking on a notification like: + +```json +{ + "_id": "notificaiton-112", + "title": "New Order", + "onClickCallback": "/orders" +} +``` + +navigates to url "/orders" + +### Example: navigate to a page and emit an event (interaction with State Adapter) + +When `clickConfig` is set to `push`, the Notification Center may be used in conjunction with a component such as the [State Adapter][bk-state-adapter], +which consumes the page state to emit custom events. + +For instance, given two plugins located at "/plugin-1" and "/plugin-2" where: + +- "/plugin-1" includes an instance of the Notification Center like: + + ```json + { + "tag": "bk-notification-center", + "properties": { + "endpoint": "/notifications", + "clickConfig": "push", + "pushStateKey": "notification-center-state" + } + } + ``` + +- "/plugin-2" includes an instance of the State Adapter like: + + ```json + { + "tag": "bk-state-adapter", + "properties": { + "configMap": { + "notification-center-state": "add-filter" + } + } + } + ``` + +clicking on a notification in "/plugin-1" like: + +```json +{ + "onClickCallback": { + "url": "/plugin-2", + "data": { + "property": "lastname", + "operator": "equal", + "value": "Smith" + } + } +} +``` + +triggers navigation to "/plugin-2". Once there an event with label [add-filter] and payload + +```json +{ + "property": "lastname", + "operator": "equal", + "value": "Smith" +} +``` + +is emitted by the State Adapter. + +### Example: Custom labels + +The following is a valid configuration, in which the default title of the Notification Center is overwritten. + +```json +{ + "tag": "bk-notification-center", + "properties": { + "locales": { + "title": { + "en": "Notification center title", + "it": "Titolo centro notifiche" + } + } + } +} +``` + +The other component labels are set to their default values. + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +|----------------------|------------------------|------------------------------------------------|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| +| `endpoint` | `endpoint` | string | "/api/v1/bk-notification-center" | API endpoint for HTTP calls | +| `headers` | - | `{ [x: string]: string; }` | `{}` | headers included in any HTTP request | +| `limit` | `limit` | number | 10 | controls pagination limit while fetching notifications | +| `locales` | - | [PartialTranslations](#partialtranslations) | {} | key-value list to customize components default labels | +| `clickStrategy` | `click-strategy` | [ClickStrategies](#clickstrategies) | "default" | strategy to implement upon clicking a notification | +| `limitQueryParam` | `limit-query-param` | string"limit" | the query parameter which controls notification pagination page size while fetching data | +| `skipQueryParam` | `skip-query-param` | string | "skip" | the query parameter which controls notification pagination skip while fetching data | +| `pushStateKey` | `push-state-key` | string | "bk-notification-center" | the key used to scope the content callback context in `window.history.state` when `clickStrategy` is "push" | +| `allowExternalHrefs` | `allow-external-hrefs` | string | false | when true, notification links can browse to external web pages and href are not checked to ensure they are relative to self-website | +| `mode` | `mode` | [ResourceFetchingMode](#resourcefetchingmode) | "default" | strategy to implement for automatically fetching notifications | +| `pollingFrequency` | `pollingFrequency` | number | 10000 | frequency of notifications automatic fetching (in milliseconds), if mode is set to `polling` | + +#### ClickStrategies + +```typescript +enum ClickStrategies = + 'default' | + 'href' | + 'replace' | + 'push' +``` +#### PartialTranslations + +```typescript +type PartialTranslations = { + title?: LocalizedText + loadingButton?: LocalizedText + dateFormat?: LocalizedText + errorMessage?: LocalizedText + noNotification?: LocalizedText + readAll?: LocalizedText + reload?: LocalizedText + backOnTop?: LocalizedText +} +``` + +#### ResourceFetchingMode + +```typescript +enum ResourceFetchingMode = + 'polling' | + 'default' | + 'none' +``` + +### Listens to + +None + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/460_notifications.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/460_notifications.md new file mode 100644 index 0000000000..4504ce2e9e --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/460_notifications.md @@ -0,0 +1,330 @@ +--- +id: notifications +title: Notifications +sidebar_label: Notifications +--- + + + + + + +[events]: /products/microfrontend-composer/back-kit/10_overview.md#events + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[actions]: /products/microfrontend-composer/back-kit/50_actions.md +[http-actions]: /products/microfrontend-composer/back-kit/50_actions.md#rest-calls + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-gallery]: /products/microfrontend-composer/back-kit/60_components/370_gallery.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-notifications]: /products/microfrontend-composer/back-kit/60_components/460_notifications.md + +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[success]: /products/microfrontend-composer/back-kit/70_events.md#success +[error]: /products/microfrontend-composer/back-kit/70_events.md#error + + + +![notifications](img/bk-notifications.png) + +```html + +``` + +The Notifications displays toast notifications about events happening on the [EventBus][events] according to the maps provided as properties. + +Whenever a notification is received of a successful or failed HTTP request, +the Notifications looks for the triggering event of the request within the keys of its `successEventMap` map or its `errorEventMap` map. +If the keys is found, the corresponding value is used to populate the state of a toast notification which is then rendered. + +It is also possible to show notifications whenever a specified request is received - that is, whenever an event with a certain label is listened. + +## How to configure + +The Notifications should have at least one property between `successEventMap`, `errorEventMap` and `customEventMap`. + +```json +{ + "tag": "bk-notifications", + "properties": { + "successEventMap": { + "create-data": { + "title": { + "en": "Data was created correctly!", + "it": "Dato creato correttamente!" + }, + "content": { + "en": "The data has been created correctly", + "it": "I dati sono stati creati correttamente" + }, + "type": "success" + } + } + } +} +``` + +Whenever a component notifies of a successful or failed HTTP request, +the Notifications looks for the triggering event of the request within the keys of its `successEventMap` map or its `errorEventMap` map. +If the keys is found, the corresponding value is used to populate the state of a toast notification which is then rendered. + +Technically, properties `successEventMap` and `errorEventMap` map the `triggeredBy` field from the `meta` of [success] and [error] events to notification properties. +Field `triggeredBy` includes the label of the event that triggered the HTTP request to which the `success` / `error` event is associated. + +When a `success` or `error` event is received with `triggeredBy` field included in one of these two maps, a toast notification is rendered with state set to the corresponding notification properties. +An [example](#example-notifications-for-crud-operations) is available. + +It is also possible to show notifications whenever an event with a certain label is listened. +To achieve this, property `customEventMap` can be utilized. +This works analogously to `successEventMap` and `errorEventMap`, but notification properties are mapped to event labels instead of the `triggeredBy` fields. +An [example](#example-notifications-from-generic-events) is available. + +Each notification can be configured with the following properties: + +| property | type | description | +| -------- | ------------------------------------------- | ------------------------------------------------------------ | +| title | [LocalizedText][localized-text] | localized text to be used as notification title | +| content | LocalizedText | localized text to be used as notification content | +| type | "success" \| "error" \| "info" \| "warning" | enum of possible notification styling (i.e. icons, color...) | + + +### Locale + +### Locale + +The texts of the Notifications can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + infoTitle: LocalizedText + successTitle: LocalizedText + warningTitle: LocalizedText + errorTitle: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +It is possible to interpolate the title and content of the notification with the field of the HTTP response. + +For example: + +```json +{ + "tag": "bk-notifications", + "properties": { + "successEventMap": { + "create-data": { + "title": { + "en": "Data was created correctly with id:{{_id}}!", + "it": "Dato creato correttamente con id: {{_id}}!" + }, + "content": { + "en": "The data has been created correctly", + "it": "I dati sono stati creati correttamente" + }, + "type": "success" + } + } + } +} +``` + +In the case of an error type notification, the interpolation must have the keyword error before the field of the response, such as `{{error.status}}`. + +Example of error response: + +```json +{ + "status": 404, + "message": "Not found" +} +``` + +To interpolate the status you have to use `{{error.status}}`, to interpolate the error message you have to use: `{{error.message}}`. + +## Examples + +### Example: notifications for CRUD operations + +Some components automatically emit [success] and [error] events to notify the result of a generic action. +For instance, the [CRUD Client][bk-crud-client] reacts to events like [create-data] and [update-data] by performing REST calls against a configurable endpoint. +Depending on the outcome of such a call, the CRUD Client then emits a [success] or [error] event, holding in its `meta` the name of the triggering event, inside field `triggeredBy`. + +With a configuration like the following, +```json +{ + { + "tag": "bk-notifications", + "properties": { + "successEventMap": { + "create-data": { + "title": "Data correctly created!", + "content": "The data has been created correctly", + "type": "success" + } + }, + "errorEventMap": { + "create-data": { + "title": "Data not created", + "content": "An error occurred while creating data", + "type": "error" + } + } + } + }, + { + "tag": "bk-crud-client", + "properties": { + "basePath": "/base-path", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"} + } + } + } + } +} +``` + +when a `create-data` event is emitted: + + 1) the CRUD Client performs a POST call to "/base-path" + 2) assuming the call to be successful, the CRUD Client emits a `success` event with `meta`: + + ```json + { + "triggeredBy": "create-data" + } + ``` + + 3) the Notifications component reacts listens to the event, comparing the value of `triggeredBy` to the keys of its `successEventMap`. + A notification is displayed with state specified in the value of the first matching key: + + ```json + { + "title": "Data correctly created!", + "content": "The data has been created correctly", + "type": "success" + } + ``` + +### Example: notifications for specific events + +The Notifications can be configured to listen to specific events and display notifications when received, through the property `customEventMap`. + +The following configurations displays a notification everytime a [display-data] event is received. + +```json +{ + "tag": "bk-notifications", + "properties": { + "customEventMap": { + "display-data": { + "title": "Data updated", + "content": "The dataset has been updated", + "type": "info" + } + } + } +} +``` + +### Example: notifications for Back-kit Actions + +Components that allow to configure [Back-kit Actions][actions], such as [Button][bk-button] or [Gallery][bk-gallery], may integrate with the [Notifications][bk-notifications]. + +Some actions trigger a [success] or [error] event based on their result (for instance, [actions of type `http`][http-actions]). +In such cases, it is possible to specify the `triggeredBy` key in the action configuration, which is injected into the meta field of such events. This value is then matched by the Notifications with its properties `successEventMap` and `errorEventMap`. + +On the other hand, actions that emit events can be mapped to notifications leveraging property `customEventMap`. + +In the following configuration, a Button component is configured to perform an HTTP call, and the Notifications to alert on the request outcome. + +```json +{ + { + "tag": "bk-notifications", + "properties": { + "successEventMap": { + "data-fetch": { + "title": "Data correctly fetched!", + "content": "The data has been fetch correctly", + "type": "success" + } + }, + "errorEventMap": { + "data-fetch": { + "title": "Data not fetched", + "content": "An error occurred while fetching data", + "type": "error" + } + } + } + }, + { + "tag": "bk-button", + "properties": { + "content": "Get Orders", + "action": { + "type": "http", + "config": { + "url": "/orders", + "method": "GET", + "triggeredBy": "data-fetch" // <---- field `triggeredBy` is injected into success/error event + } + } + } + } +} +``` + +The `triggeredBy` field of the action configuration is injected by actions into the [success] / [error] event that is emitted to notify the outcome of the HTTP request. + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ---------------------- | ------------------------ | -------------------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `customEventMap` | - | [NotificationsMap](#notificationsmap) | - | map containing the labels of any event that should be notified to the related notification properties | +| `duration` | `duration` | number | - | lingering time for the notification in seconds | +| `errorEventMap` | - | [NotificationsMap](#notificationsmap) | - | map containing the labels of any event that triggered an [error] that should be notified to the related notification properties | +| `location` | - | "topRight" \| "topLeft" \| "bottomRight" \| "bottomLeft" | "topRight" | corner location where the notification should be displayed | +| `rootElementSelectors` | `root-element-selectors` | string | - | selector to specify where the notification should be appended | +| `successEventMap` | - | [NotificationsMap](#notificationsmap) | - | map containing the labels of any event that triggered a [success] that should be notified to the related notification properties | + + +#### NotificationsMap + +```typescript +type NotificationsMap { + [key: string]: { + title?: LocalizedText + content?: LocalizedText + type?: 'success' | 'info' | 'error' | 'warning' + } +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + +### Listens to + +| event | action | +| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | +| [success] | displays a notification if the `triggeredBy` field contained in the `meta` of the event has been mapped in the `successEventMap` property | +| [error] | displays a notification if the `triggeredBy` field contained in the `meta` of the event has been mapped in the `errorEventMap` property | +| configurable event | displays a notification on any event mapped in the `customEventMap` property | + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/470_pagination.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/470_pagination.md new file mode 100644 index 0000000000..e2711c66f7 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/470_pagination.md @@ -0,0 +1,112 @@ +--- +id: pagination +title: Pagination +sidebar_label: Pagination +--- + + + + + + + + +[nested-data-flow]: /products/microfrontend-composer/back-kit/80_examples/20_nested_data.md#nested-fields-in-the-table-and-forms + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[count-data]: /products/microfrontend-composer/back-kit/70_events.md#count-data +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/display]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---display + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + + + + +```html + +``` + +![pagination](img/bk-pagination.png) + +The Pagination displays pagination navigation tools to query pages of a dataset. +It allows moving backward and forward between pages, skipping to the first and last pages, and adjusting the current pagination size. +Additionally, it displays a counter showing the current page and the total number of pages. +It shows the current page and total elements in a given dataset while interacting with dynamic filters. + +The Pagination communicates with other components by providing pagination parameters for data retrieval. +It achieves this by injecting keys `pageNumber` and `pageSize` into the payload of a [change-query] event, which is emitted upon interacting with the component. +Components such as the [CRUD Client][bk-crud-client] can listen to this event and use the provided pagination parameters to fetch new data accordingly. + +Furthermore, the Pagination component listens to [count-data] events, which relay information about the size of the currently viewed dataset, to update its state. + +In cases where the signaled **data count is negative**, the Pagination adjusts its view. In this scenario, only tasks such as navigating between pages and modifying the pagination size can be performed. +Additionally, no information is provided about the currently viewed page or the total number of pages. + +In case the request to visualize or navigate [nested data][nested-data-flow] is received, the Pagination notifies other components on what slice of data should be visualized according to its state. + +## How to configure + +For its most basic usage, the Pagination does not require any particular configuration. + +```json +{ + "tag": "bk-pagination" +} +``` + +Properties `pageSize` and `pageSizeOptions` are available to configure the default value and the selectable options for pagination size. + +Property `showPagesCount` controls whether or not to display the current page and the total number of pages. If set to `false`, the next button goes to the next pages even if there are no data anymore. The component will be displayed like in the following image: + +![pagination](img/bk-pagination-buttonsOnly.png) + +### Locale + +The texts of the Pagination can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + prev_page: LocalizedText + next_page: LocalizedText + lastPage: LocalizedText + firstPage: LocalizedText + itemsPerPage: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ----------------- | ----------- | -------- | ----------------- | ---------------------------------------------------------- | +| `pageSize` | `page-size` | number | 25 | number of data items per page | +| `pageSizeOptions` | - | number[] | [10, 25, 50, 100] | available page sizes | +| `showPagesCount` | - | boolean | true | whether or not to display the current page and the total number of pages | + +### Listens to + +| event | action | +| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| [loading-data] | sets internal loading state | +| [count-data] | notifies the size of the currently viewed dataset | +| [nested-navigation-state/push] | updates internal representation of the current nesting path by adding one step. Emits [nested-navigation-state/display] with slice of data to display | +| [nested-navigation-state/back] | updates internal representation of the current nesting path by removing the specified number of steps. Emits [nested-navigation-state/display] with slice of data to display | + +### Emits + +| event | description | +| --------------------------------- | ------------------------------------------------------------- | +| [change-query] | requires data filtered according with the current pagination | +| [nested-navigation-state/display] | in case of nested data, notifies the slice of data to display | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/480_pdf_viewer.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/480_pdf_viewer.md new file mode 100644 index 0000000000..c8643e14c4 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/480_pdf_viewer.md @@ -0,0 +1,54 @@ +--- +id: pdf_viewer +title: Pdf Viewer +sidebar_label: Pdf Viewer +--- + + + + + + +[show-in-viewer]: /products/microfrontend-composer/back-kit/70_events.md#show-in-viewer + + + +```html + +``` + +![pdf-viewer](img/bk-pdf-viewer.png) + +allows to visualize PDF files in the browser through an `iframe` which embeds the default browser PDF viewer. +While the Pdf Viewer is capable of previewing various file types, it is recommended to restrict its use primarily to the visualization of PDF files. + +Upon listening to the [show-in-viewer] event, the Pdf Viewer retrieves the URL of the file to preview from the event payload and shows it. + +## How to configure + +The Pdf Viewer does not require any configuration. + +```json +{ + "tag": "bk-pdf-viewer" +} +``` + +## API + +### Properties & Attributes + +None + +### Listens to + +| event | action | +| ---------------- | -------------------- | +| [show-in-viewer] | opens PDF in browser | + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/490_refresh_button.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/490_refresh_button.md new file mode 100644 index 0000000000..c80f788405 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/490_refresh_button.md @@ -0,0 +1,55 @@ +--- +id: refresh_button +title: Refresh Button +sidebar_label: Refresh Button +--- + + + + + + +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query + + + +```html + +``` + +The Refresh Button renders a button that, on click, notifies the request to refresh some resource. + +![refresh-button](img/bk-refresh-button.png) + +## How to configure + +The Refresh Button does not require any configuration + +```json +{ + "tag": "bk-refresh-button" +} +``` + +## API + +### Properties & Attributes + +None + +### Listens to + + +| event | action | emits | on error | +|-------|--------|-------|----------| +|[loading-data][loading-data]|sets internal loading state| - | - | + +### Emits + +| event | description | +|-------|-------------| +|[change-query][change-query]|requires refresh without modifying current `CRUD` query by attaching an empty payload| diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/500_search_bar.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/500_search_bar.md new file mode 100644 index 0000000000..8c3f15a964 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/500_search_bar.md @@ -0,0 +1,272 @@ +--- +id: search_bar +title: Search Bar +sidebar_label: Search Bar +--- + + + + + + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[lookups]: /products/microfrontend-composer/back-kit/30_page_layout.md#lookups +[exclude-from-search]: /products/microfrontend-composer/back-kit/30_page_layout.md#excluding-properties-from-free-search +[format]: /products/microfrontend-composer/back-kit/30_page_layout.md#formats +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-crud-lookup-client]: /products/microfrontend-composer/back-kit/60_components/170_crud_lookup_client.md +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md + +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[search-lookups-found]: /products/microfrontend-composer/back-kit/70_events.md#search-lookups-found +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[search-lookups]: /products/microfrontend-composer/back-kit/70_events.md#search-lookups + + + +```html + +``` + +![search-bar](img/bk-search-bar.png) + +Allows data filtering by matching a text string + +Search bar allows to filter data against text using a regex. +Special regex characters (`( ) [ ] { } + - ^ * $ \ ? / | .`) are sanitized within the input. + +Upon search, the Search Bar notifies that data should be queried by matching its fields against the input string. +Technically, the Search Bar emits a [change-query] event, injecting the submitted text in the payload event with key "search". + +## How to configure + +For its most basic usage, no particular configuration is required by the Search Bar. + +```json +{ + "tag": "bk-search-bar" +} +``` + +### Lookup fields + +If `searchLookups` property is true, upon search the Search Bar requests the submitted text to also be matched against [lookups and multi-lookup][lookups] fields, which is achieved by emitting a [search-lookups] event. +A component like the [Lookup CRUD Client][bk-crud-lookup-client] could listen to this event and propagated fetched lookup values that match the searched text. + +[excludeFromSearch][exclude-from-search] as `false` in their schema are also searched. +The text value is compared against the `lookupFields` specified in the `lookupOptions` in the schema. + +:::warning +Searching lookup fields could be computationally heavy. +The number of searchable lookups should be kept to the needed minimum and search-bar properties such as `liveSearchItemsLimit` and `autoSearchMinInput` should be configured carefully. +For this reason, components such as the [Lookup CRUD Client][bk-crud-lookup-client] only perform text searches on lookup fields that have [excludeFromSearch][exclude-from-search] set to `false` in the provided [data-schema]. +::: + +### Tuning automatic search + +The Search Bar supports automatic search - that is, search is automatically submitted by typing into the input field of the component. + +The following properties can be used to tune automatic search: + - `searchDebounce`: milliseconds before the search is automatically submitted after the user has stopped typing + - `autoSearchMinInput`: minimum number of characters of the input value before the search is automatically submitted + +### Locale + +The texts of the Search Bar can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + placeholder: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +### Example: Basic Search + +For instance, with the Search Bar configured like: +```json +{ + "tag": "bk-search-bar" +} +``` +submitting for search the entry "example" triggers the emission of a [change-query] event with payload + + +```json +{ + "search": "example" +} +``` + +A component such as the [CRUD Client][bk-crud-client] might listen to such event, and trigger data fetching with regex filters against all [searchable][exclude-from-search] fields. + +### Example: Interaction with CRUD Client + +With a configuration that includes both a Search Bar and a CRUD Client like: + +```json +{ + "tag": "bk-search-bar" +}, +{ + "tag": "bk-crud-client", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "surname": { "type": "string" }, + "email": { "type": "string", "excludeFromSearch": true } + } + } + } +} +``` + +if the user submits a text search with input "example" using the Search Bar, a `change-query` event is emitted with payload: + +```json +{ + "search": "example" +} +``` + +triggering a data fetching call by the CRUD Client with query: + +```json +{ + "$or": [ + { "name": { "$regex": ".*example.*", "$options": "i" } }, + { "surname": { "$regex": ".*example.*", "$options": "i" } } + ] +} +``` + +The CRUD Client excludes "email" from the query because of the `excludeFromSearch` flag specified in the corresponding data-schema field. + +Note that the CRUD Client performs case-insensitive searches. + +### Example: Limitations + +In components designed to visualize data, such as the [Table][bk-table], some data might be displayed differently than the corresponding value in the database. +In such cases, it is important to notice that using the Search Bar with the [CRUD Client][bk-crud-client] fails to perform searches against the displayed value, +that are instead performed against the actual values, as stored in the database. +This limitation [does not apply to lookup fields](#lookup-fields), which might be searchable using a component like the [Lookup CRUD Client][bk-crud-lookup-client]. + +For example, assuming a backend collection to have a `weekDay` field which can have values: "0", "1", "2", "3", "4", and a configuration with a Search Bar, a CRUD Client, a Table having [enum fields][format] such as: +```json +{ + "tag": "bk-search-bar" +}, +{ + "tag": "bk-crud-client", + "properties": { + "dataSchema": { + "weekDay": { + "type": "string", + "enum": [ + {"id": "0", "label": "Monday"}, + {"id": "1", "label": "Tuesday"}, + {"id": "2", "label": "Wednesday"}, + {"id": "3", "label": "Thursday"}, + {"id": "4", "label": "Friday"} + ] + } + } + } +}, +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "weekDay": { + "type": "string", + "enum": [ + {"id": "0", "label": "Monday"}, + {"id": "1", "label": "Tuesday"}, + {"id": "2", "label": "Wednesday"}, + {"id": "3", "label": "Thursday"}, + {"id": "4", "label": "Friday"} + ] + } + } + } +} +``` + +The Table displays inside its rows the data it received by the CRUD Client, but visualizes the enum field `weekDay` using the corresponding `label` key. +For instance, if the CRUD Client fetches and propagates data like: +```json +[ + {"weekDay": "0"}, + {"weekDay": "1"} +] +``` +the Table renders a table with two rows, having a `weekDay` column with entries "Monday" instead of "0" and "Tuesday" instead of "1", as specified in the `enum` property of the data-schema: + +```json +[ + ["Monday"], + ["Tuesday"] +] +``` + +Using the Search Bar to search for the values displayed in the Table ("Monday", "Tuesday", ...) fails, since ultimately the search is performed by the CRUD Client against the actual stored value. + +Searching for "mon" triggers the Search Bar to emit a [change-query] event with payload: +```json +{ + "search": "mon" +} +``` +The CRUD Client listens to the event and fetches data with a query like: +```json +{ + "weekDay": { + "$regex": ".*mon.*", "$options": "i" + } +} +``` +which returns no data, since "mon" does not match any of the stored values of `weekDay` ("0", "1", "2", "3", "4"). + +## API + +### Properties & Attributes + + +| property | attribute | type | default | description | +| ---------------------- | ------------------------- | ------------------------------- | ------- | ---------------------------------------------------------------------------------------------- | +| `autoSearchMinInput` | `auto-search-min-input` | number | 2 | min length of input string before performing automatic search | +| `liveSearchItemsLimit` | `live-search-items-limit` | number | 100 | max items to fetch on regex live search | +| `placeholder` | - | [LocalizedText][localized-text] | - | placeholder of the search bar input | +| `searchDebounce` | `search-debounce` | number | 0 | milliseconds to wait before performing an automatic search. If 0, automatic search is disabled | +| `searchLookups` | `search-lookups` | boolean | false | whether or not to perform search on lookups. If true, a component such as the [Lookup CRUD Client][bk-crud-lookup-client] should be included in the plugin | + +### Listens to + + +| event | action | +| ------------------------------ | ---------------------------------------------------------------------------------------------------- | +| [loading-data] | sets internal loading state | +| [nested-navigation-state/back] | keeps track of navigation steps | +| [nested-navigation-state/push] | keeps track of navigation steps | +| [search-lookups-found] | includes lookup values searched against text search. Triggers the emission of a [change-query] event | + +### Emits + + +| event | description | +| ---------------- | ----------------------------------------------------- | +| [change-query] | requires data filtered according with the typed input | +| [search-lookups] | notifies to search lookups against a text | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/50_auto_refresh.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/50_auto_refresh.md new file mode 100644 index 0000000000..04ab69a26c --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/50_auto_refresh.md @@ -0,0 +1,112 @@ +--- +id: auto_refresh +title: Auto Refresh +sidebar_label: Auto Refresh +--- + + + + + + + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-query + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + + + +```html + +``` + +![auto-refresh](img/bk-auto-refresh.png) + +The Auto Refresh component allows refreshing some resources with the selected interval. + +It renders a label-like dorpdown button. The label of the button informs on the refresh frequency. +The dropdown menu opens upon hovering on the button and allows to select a new refresh interval. + +The refreshing happens by emitting a [change-query] event with an empty payload every interval. +A component like the [CRUD Client][bk-crud-client] could. + +## How to configure + +For its most basic usage, the Auto Refresh component does not require any configuration. + +```json +{ + "tag": "bk-auto-refresh" +} +``` + +By default, the Auto Refresh enables users to select the refresh interval for data requests, with options of 5, 10, 30, or 60 seconds. The initial refresh interval is initially set to 0, indicating that data refresh is not requested. + +It is possible to set the interval options and a default interval using the `intervals` and `initialInterval` properties. Both of these properties are interpreted in seconds. + + +```json +{ + "tag": "bk-auto-refresh", + "properties": { + "intervals": [10, 30, 60, 120], + "initialInterval": 10 + } +} +``` + +### Locale + +The texts of the Auto Refresh can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + refreshRate: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +The following configuration + +```json +{ + "tag": "bk-auto-refresh", + "properties": { + "intervals": [10, 30, 60, 120], + "initialInterval": 10 + } +} +``` + +requests data refresh every 10 seconds, and can be set to 10, 30, 60, 120 seconds. + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ----------------- | ------------------ | -------- | --------------- | ------------------------------ | +| `intervals` | - | number[] | [5, 10, 30, 60] | a list of intervals in seconds | +| `initialInterval` | `initial-interval` | number | 0 | initial interval value | + +### Listens to + +| event | action | +| -------------- | --------------------------- | +| [loading-data] | sets internal loading state | + +### Emits + +| event | description | +| -------------- | ------------------------------------------------------------------------------------------ | +| [change-query] | requires data refresh without modifying current `CRUD` query by attaching an empty payload | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/510_state_adapter.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/510_state_adapter.md new file mode 100644 index 0000000000..6e5d05661e --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/510_state_adapter.md @@ -0,0 +1,142 @@ +--- +id: state_adapter +title: State Adapter +sidebar_label: State Adapter +--- + + + + + +[push-state]: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState + +[plugin-navigation]: /products/microfrontend-composer/back-kit/80_examples/30_plugin_navigation.md + +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[add-new]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query + + + +```html + +``` + +The State Adapter allows injecting the `window` state into the payload of various events, emitted upon connecting to the DOM. +Window state can be set, for example, using the [push-state][push-state] method. + +Since the State Adapter allows to emit events upon landing to the new page, it is often used in the context of plugin navigation, as explained in the [dedicated section][plugin-navigation]. + +## How to configure + +Upon connection, the State Adapter consumes the current `window` state. + +The State Adapter initially searches for data within the window state that is associated with a key matching the value of `initKey`. If the data retrieved in this way forms an array of events, the State Adapter emits these events. + +Additionally, the `configMap` property and the window state are combined, resulting in an object that contains label-payload pairs, where the label is extracted from `configMap` and the payload comes from the `window` state. The State Adapter emits these pairs as events. + +```json +{ + "tag": "bk-state-adapter", + "properties": { + "initKey": "__INITIAL_KEY__", + "configMap": { + "__KEY_1__": "loading-data" + } + } +} +``` + +## Examples + +Given the following configuration of the State Adapter: + +```json +{ + "tag": "bk-state-adapter", + "properties": { + "initKey": "key_0", + "configMap": { + "key_1": "loading-data", + "key_2": "add-new" + } + } +} +``` + +and assuming the window state to be: + +```json +{ + "key_0": [ + { + "label": "change-query", + "payload": {"pageSize": 10} + } + ], + "key_1": { + "loading": true + }, + "key_2": { + "foo": "bar" + } +} +``` + +upon connection,the State Adapter emits: + +- a [change-query][change-query] event such as: + +```json +{ + "label": "change-query", + "payload": { + "pageSize": 10 + } +} +``` + +- a [loading-data][loading-data] event such as: + +```json +{ + "label": "loading-data", + "payload": { + "loading": true + } +} +``` + +- an [add-new][add-new] event such as: + +```json +{ + "label": "add-new", + "payload": { + "foo": "bar" + } +} +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +|-------------|------------|----------------------------|-------------|-------------------------------------------------------------------------| +| `configMap` | - | `{[name: string]: string}` | {} | map to configure the adapter casting object properties to events labels | +| `debounce` | `debounce` | number | 500 | delay for initial event emission | +| `initKey` | `init-key` | string | "__BK_INIT" | key for events to emit once upon connection | + +### Listens to + +This component listens to no event. + +### Emits + +| event | description | +|-------|-------------| +|configurable event|generic event based on its `configMap` property| diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/520_table.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/520_table.md new file mode 100644 index 0000000000..e6f0f7ce71 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/520_table.md @@ -0,0 +1,1684 @@ +--- +id: table +title: Table +sidebar_label: Table +--- + + + + + + +[handlebars]: https://handlebarsjs.com/ +[handlebars-syntax]: https://handlebarsjs.com/guide/expressions.html +[fontawesome]: https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=regular,solid&m=free +[events]: /products/microfrontend-composer/back-kit/10_overview.md#events +[TinyColor]: https://github.com/bgrins/TinyColor + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[nested-schemas]: /products/microfrontend-composer/back-kit/80_examples/20_nested_data.md +[visualization-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#visualization-options + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic-configurations]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration +[inline-queries]: /products/microfrontend-composer/back-kit/40_core_concepts.md#inline-queries +[rawObject]: /products/microfrontend-composer/back-kit/40_core_concepts.md#rawObject +[rawObjectOrEmptyStr]: /products/microfrontend-composer/back-kit/40_core_concepts.md#rawObjectOrEmptyStr +[template-configMap]: /products/microfrontend-composer/back-kit/40_core_concepts.md#template---configMap + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-dynamic-form-modal]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md +[bk-breadcrumbs]: /products/microfrontend-composer/back-kit/60_components/60_breadcrumbs.md +[bk-pagination]: /products/microfrontend-composer/back-kit/60_components/470_pagination.md + +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/display]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---display +[delete-data]: /products/microfrontend-composer/back-kit/70_events.md#delete-data +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[selected-data]: /products/microfrontend-composer/back-kit/70_events.md#selected-data +[selected-data-bulk]: /products/microfrontend-composer/back-kit/70_events.md#selected-data-bulk +[download-file]: /products/microfrontend-composer/back-kit/70_events.md#download-file +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[lookup-data]: /products/microfrontend-composer/back-kit/70_events.md#lookup-data +[duplicate-data]: /products/microfrontend-composer/back-kit/70_events.md#duplicate-data +[require-confirm]: /products/microfrontend-composer/back-kit/70_events.md#require-confirm + + + +```html + +``` + +![table](img/bk-table.png) + +The Table displays a dataset in rows and columns according to a given [data-schema]. +An actions column can be configured to add extra functionalities. + +The Table listens to the [display-data] event to initialize its form. + +By clickinging on a row, the Table issues a request to prompt the user with a way of editing/visualizing the corresponding item - ie, emits a [selected-data] event. +A component like the [Dynamic Form Modal][bk-dynamic-form-modal] could act upon such request. + +By default, rows can be selected through a checkbox. When this happens, the Table notifies it by emitting a [selected-data-bulk] event. + +## How to configure + +The Table needs to be provided with a [data-schema] in order to understand the structure of the dataset to render + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "surname": {"type": "string"} + } + } + } +} +``` + +### Object and Array Fields + +While rendering an array or an object from a compliant [data-schema] (either `array` or `object` key type), multiple options are available + +#### Object + +The Table can render object fields in various ways, depending on the field description in the provided [data-schema]. + +1. When no extra key is explicitly set, the object renders either as `{...}` or `{}` depending on whether there are keys or not. +2. When a data-schema is set to the object field description, the Table triggers [nested visualization](#nested-data) of objects. +3. When the object field is specified to have `format` equal to "localized-text", the object must be interpreted as a [localized string][localized-text]. The Table will render the proper language key according with browser settings. +4. When the object field is set to have specific [visualization-options], the Table renders the field accordingly. + In particular, the `template` key of the visualization-options is useful with object fields, as it interpolates an [handlebars] template using the current cell context. + ```json + { + "user": { + "type": "object", + "visualizationOptions": { + "template": "{{name}} {{surname}}" + } + } + } + ``` + Hence if datum is given by + ```json + { + "name": "john", + "surname": "does" + } + ``` + and template is `"{{name}} {{surname}}"`, then the table renders `john doe`. + +An [example](#example-object-visualization) is available showcasing how a Table can be configured to display object data. + +#### Array + +The Table can render array fields in various ways, depending on the field description in the provided [data-schema]. + +1. When no extra key is explicitly set, the array informs about the number of elements contained within the array. +2. When a data-schema is set to the object field description, the Table triggers [nested visualization](#nested-data) of arrays. +3. When the array field is set to have specific [visualization-options], the Table renders the field accordingly. + - The `joinDelimiter` key of the visualization-options joins the array elements using the given delimiter as argument of `Array.prototype.join` + ```json + { + "users": { + "type": "array", + "visualizationOptions": { + "joinDelimiter": "," + } + } + } + ``` + - The `template` key of the visualization-options interpolates an [handlebars] template using the current cell context. + ```json + { + "users": { + "type": "array", + "visualizationOptions": { + "template": "{{[0]}} {{[1]}}" + } + } + } + ``` + Hence if datum is given by + ```json + [ + "Ding", "Magnus", "Ian" + ] + ``` + and template is `{{[0]}}, {{[1]}}, ...`, then the table renders `Ding, Magnus, ...`. + +An [example](#example-array-visualization) is available showcasing how a Table can be configured to display array data. + +### Nested Data + +By default, the Table is responsive to emitted requests for showing [nested data][nested-schemas]. +Namely, the Table listens to events: + - [nested-navigation-state/push], which notifies the request to navigate into a nested field + - [nested-navigation-state/back], which notifies the request to navigate back one or multiple steps from a nested field + - [nested-navigation-state/display], which notifies the request to display the data inside a nested field + +Upon receiving these events, the Table updates itself to show the details of the currently displayed nested field. + +This behavior can be disabled by setting property `allowNavigation` to false. + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "name": {"type": "string"}, + + "spouse": { + "type": "object", + "dataSchema": { // <-- nested data-schema, for spouse object + "type": "object", + "properties": { + "mame": {"type": "string"}, + "address": {"type": "string"} + } + } + }, + + "children": { + "type": "array", + "items": { // <-- nested data-schema, for children array + "type": "object", + "properties": { + "firstName": {"type": "string"}, + "dateOfBirth": {"type": "string", "format": "date"} + } + } + } + } + } + } +} +``` + +The Table allows to emit [nested-navigation-state/push] events by clicking on cells that contain nested objects or arrays, +as long as a nested schema is provided for the corresponding field. +If a component such as the [Pagination][bk-pagination] receives such requests, a [nested-navigation-state/display] event is emitted, +triggering the Table to update itself and display the nested data. + +By default, the Table renders a button in the action column in nested visualizations, if the field is not readonly, which allows to request the object represented by the corresponding row to be deleted. +To remove the default actions rendered by the Table in nested visualization, [`navigationRowAction` property](#configuring-nested-actions-via-navigationrowactions) should be set to: +```json +{ + "kind": "icons", + "actions": [] +} +``` + +:::caution +Components such as the [Breadcrumbs][bk-breadcrumbs] and the [Pagination][bk-pagination] should always be included in the plugin when navigation is enabled. +::: + +### Display Path + +Property `displayedDataPath` enables to display a nested array of an element of the received data. +It consists of the path to the desired object, like: `data.[0].orders`. +The first key is always `data`. + +Upon listening to a [display-data] event, which lists fetched data, the Table uses property `displayDataPath` to reach an array field, and attempts to display that field according to the provided data-schema. +Therefore, the data-schema must describe the field reached by `displayDataPath`, rather than the all the fields of the underlying collection. + +```json +{ + "tag": "bk-table", + "properties": { + "displayedDataPath": "data.[0].orders", // -> enters `orders` field of first data item + "dataSchema": { // -> data-schema of `orders` field + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "price": { + "type": "number" + } + } + } + } +} +``` + +Refer to the provided [example](#example-visualize-one-elements-array-field-displayeddatapath) for further details. + +### Dynamic Context + +Several properties of the Table allow [dynamic configurations][dynamic-configurations]. +By default, such properties are parsed with [handlebars], injecting the the following data as context: + + - `args`: an array with the arguments of a table cell: + - value: containing the value of the cell + - record: an object representation of the corresponding row + - index: a number with the index of the corresponding row into the table + - `currentUser`: an object with the logged user's data + - `headers`: an object containing the headers + +All the above parameters can be dynamically interpolated into properties that allow dynamic configurations through handlebars. + +### Web Component into cells + +The Table allows to insert a generic web-component into the the cells of a specific column by defining, in the data-schema description of the corresponding field, all the web-components properties inside the [visualization-options]. + +Refer to the [below example](#example-web-component-inside-cells) for an example of configuration. + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "label": "Name as Button", + "visualizationOptions": { + "tag": "my-button", + "properties": { + "content": "Click Me!" + } + } + } + } + } + } +} +``` + +Dynamically mounted components are automatically injected with the property `eventBus`, which is the [communication channel][events] shared by components. +This allows mounted components to communicate with other components by events emission. + +The Table supports [dynamic configurations][dynamic-configurations] in dynamically mounted components properties, providing access in its configuration to its [context](#dynamic-context). + +An [example](#example-dynamic-web-component-post-call-with-row-as-body) is available showing how to configure a Table to include a button inside a cell that performs a POST request with the corresponding row as body, as well as an [example](#example-dynamic-web-component-disable-button-depending-on-row-value) to include a button that is active or disabled based on the value of a within in the corresponding row. + + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "label": "Name as Button", + "visualizationOptions": { + "tag": "my-button", + "properties": { + "content": "{{args.[0]}}" // the value of the `name` field is injected as property to the component + } + } + } + } + } + } +} +``` + +### Actions + +The Table allows to configure an actions column. +Configurable buttons or generic components are rendered inside the actions columns, and can be controlled through properties `rowActions`, `customActions`, `navigationRowActions`. + +#### Configuring actions via `rowActions` + +Each action specified through property `rowActions` is rendered as a button inside the action cell of each row of the table. + +Actions configured this way can either + - emit an event, or + - perform an POST call + +in both cases, the payload/body is set to an object representation of the corresponding row. + + +Property `rowActions` accepts an object with keys `kind` and `actions`. + +| property | type | values | description | +| --------- | ------ | -------------- | ---------------------------------- | +| `kind` | string | "icons", "cta" | how to display the action triggers | +| `actions` | array | - | available actions | + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"} + } + }, + "rowActions": { + "kind": "icons", + "actions": [ + { + "kind": "event", + "danger": "true", + "content": "duplicate-data", + "label": "Duplicate Data", + "icon": "far fa copy", + "meta": {}, + "requireConfirm": false + } + ] + } + } +} +``` + +Each entry of key `actions` is mapped to a call to action and rendered as a button. + +| property | type | values | description | +| ---------------- | ----------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `kind` | string | `httpPost`, `event` | when `event` fires an event in the `eventBus`, otherwise performs a `POST` request with the content of the row as body | +| `danger` | boolean | `true`, `false`, undefined | set danger mode on action. Defaults to false | +| `content` | string | - | when `event` it is the label of the [events] to emit, otherwise the `POST` request destination href | +| `label` | string | - | a label to render with the row action button | +| `icon` | string | - | [Fontawesome fas or far icon][fontawesome] | +| `meta` | object | - | the `meta` of the event when `kind` is `event` | +| `requireConfirm` | object or boolean | - | signals the need to prompt user confirmation before executing the action. Defaults to false | + +An [example](#example-action-with-rowactions) is available to showcase how to configure `rowActions` property in the Table. + +If the key `requireConfirm` is undefined or set to false, the corresponding CTA does not expect user confirmation before execution. +When set to true, the CTA indicates the need for user confirmation before execution. This is achieved by emitting a [require-confirm] event. +Additionally, the property `requireConfirm` can be configured as an object to request specific labels to be associated with the confirmation prompt presented to the user. +This is achieved by emitting a [require-confirm] event, injecting the specified object into the event payload, and involves specifying the following keys: + +| property | type | values | description | +| ------------ | ------ | ------ | ----------------------------------------------- | +| `cancelText` | object | - | Cancel button [localized label][localized-text] | +| `content` | object | - | Localized label used as content of the modal | +| `okText` | object | - | Confirm button localized label | +| `title` | object | - | Localized label used as title of the modal | + +Keys `content` and `title` support interpolation via [handlebars] using the current row values with resolved lookups. +For instance, the following is a valid entry for key "content": +``` +Confirmation needed before deleting item: {{name}}. Continue? +``` +where `{{name}}` is resolved with the content of field "name" in the row corresponding to the clicked row. + +#### Configuring actions via `customActions` + +Property `customActions` allows to mount web-components inside the action column of the Table. + +```json +{ + { + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"} + } + }, + "customActions": [{ + "tag": "bk-button", + "properties": { + "content": "My button" + } + }] + } + } +} +``` + +Property `customActions` shape is either an `array` of `tag`-`properties` pairs or an `array` of nested custom actions, as per the following schema: + +```json +{ + "type": "array", + "oneOf": [ + { + "type": "object", + "properties": { + "tag": "string", + "properties": { + "type": "object" + } + } + }, + { + "type": "object", + "properties": { + "keys": { + "type": "array", + "items": { + "type": "string" + } + }, + "customActions": { + "type": "object", + "properties": { + "tag": "string", + "properties": { + "type": "object" + } + } + } + } + } + ] +} +``` + +In the first case, each element of the array is a `tag`-`properties` pair, respectively representing the html tag of the component to mount and its properties. + +| property | type | values | description | +| ------------ |------------------------| ------ | -------------------------------------- | +| `tag` | string | string | custom component to mount | +| `properties` | `{[key: string]: any}` | object | properties injected into the component | + +It is often useful mounting the [Button][bk-button] components inside the actions columns of the Table because of its flexibility. + +An [example](#example-action-with-customactions) is available to showcase how to configure `customActions` property in the Table. + + +The Table supports [dynamic configurations][dynamic-configurations] in the `properties` field of web-components mounted this way, providing access in its configuration to its [context](#dynamic-context). + +An [example](#example-disable-an-action-if-a-field-is-empty) is available to show how dynamic configurations can be integrated with `customActions` property. + +[Nested navigation][nested-schemas] does not preserve `customActions`. +To configure `customActions` in nested navigation mode the second type of `customActions` allowed by the JSON schema above is helpful. + +A full configuration [example](#example-actions-in-nested-table-with-customactions) is available to show how `customActions` can be used to set CTAs inside a Table in a nested view. + +```json +{ + "customActions": [ + { + "keys": [], + "customActions": [ // <-- Table actions before entering nested data + { + "tag": "bk-button", + "properties": {...} + } + ] + }, + { + "keys": ["level1", "level2"], + "customActions": [ // <-- Table actions when visualizing data inside "level1.level2" + { + "tag": "bk-button", + "properties": {...} + } + ] + } + ] +} +``` + +#### Configuring nested actions via `navigationRowActions` + +The Table does not preserve actions created with `rowActions` property when is rendering [nested data][nested-schemas]. +Property `navigationRowActions` allows to specify actions available when the table is displaying nested data. + +As of now, actions created via `navigationRowActions` only allow to signal the need to edit the data of the corresponding table row, +or to delete the item represented by the corresponding +Property [`customActions`](#configuring-actions-via-customactions) should be utilized in order to configure actions in nested views with a greater degree of freedom. + +`navigationRowActions` is an object such as + +| property | type | values | description | +|-----------------------|------|---------|-------------| +| `kind` | string | `cta`, `icons` | whether to display the action in form of text or icon. | +| `actions` | array of actions | any | describes the behavior of each. | + +Where each entry of `actions` represent + +| property | type | values | description | +| ------------------- | ------- | -------------------- | -------------------------------------------------------------------------------------- | +| `requireConfirm` | booelan | - | Whether or not to require confirm before executing the action | +| `danger` | boolean | - | set danger mode on action | +| `type` | string | "delete" \| "detail" | whether to request deletion or edit of the object associated to the corresponding row. | +| `disableInReadonly` | boolean | - | Whether or not to disable the action for read-only nested objects. | +| `icon` | string | string | The [fontawesome icon][fontawesome] for the button | + +```json + { + "kind": "icons", + "actions": [{ + "danger": true, + "requireConfirm": true, + "type": "delete", + "disableInReadonly": true, + "icon": "far fa-trash-can" + }] + } +``` + +Property `navigationRowAction` defaults to: + +```json +{ + "kind": "icons", + "actions": [{ + "requireConfirm": true, + "type": "delete", + "disableInReadonly": true + }] +} +``` + +which will alllow to request rows to be deleted when the displayed nested data is not read-only. + +To remove the default actions rendered by the Table in nested visualization, `navigationRowAction` should be set to: + +```json +{ + "kind": "icons", + "actions": [] +} +``` + + +### Fix columns + +Property `fixedColumns` can be used to fix columns with respect to horizontal scrolling. +It takes either a number that represents the number of columns to fix from left or an object with `left` and/or `right` keys and a number as value. + +The following are all valid configurations of `fixedColumns` property: + +```json +{ + "tag": "bk-table", + "properties": { + "fixedColumns": { + "left": 2, + } + } +} +``` + +```json +{ + "tag": "bk-table", + "properties": { + "fixedColumns": { + "right": 1 + } + } +} +``` + +```json +{ + "tag": "bk-table", + "properties": { + "fixedColumns": { + "left": 2, + "right": 1 + } + } +} +``` + +```json +{ + "tag": "bk-table", + "properties": { + "fixedColumns": 2 // equivalent to: "fixedColumns": {"left": 2} + } +} +``` + +### Highlighted rows + +It is possible to use property `highlightedRows` to map a color (expressed as a CSS-valid color string) to a [mongo-like query][inline-queries]. +The background of rows that match any of these queries is set to the corresponding color. +In particular, rows are highlighted with the color of the first matching query. + +Property `highlightedRows` should be expressed as an array of objects with keys `color` and `query`. + - the color can be expressed as the CSS valid string representation of a color, or an object with keys `r`, `g`, `b` + The following are all valid entries: + ``` + #f2e8e2 + rgb(230, 155, 114) + {r: 230, g: 155, b: 114} + ``` + Broadly speaking, `color` key supports all types supported as input by [TinyColor] library. + - the query is the object representation of a mongo-like query + +An [example](#example-highlight-rows) is available to show how to configure highlighted rows in the Table. + +:::info +Input colors are converted to their RGB representation. If an alpha channel is present, a white background is assumed. +For instance, color `rgba(255, 0, 0, 0.5)` is converted to `rgb(255, 128, 128)`. +::: + +Queries support [dynamic values][dynamic-configurations] through [handlebars notation][handlebars-syntax]. +The Table provides inline queries with [context](#dynamic-context): + - `args`: an array with row arguments: + - first element and second element both have an object containing the row content + - third element stores the number with the cell index within the table rows + - `currentUser`: an object with the logged user's data + - `headers`: an object containing the headers + +An [example](#example-highlight-rows-comparing-fields-between-them) is available to show how to leverage dynamic configuration when configuring highlighted rows in the Table. + +### Browse on row click + +The property `browseOnRowSelect` allows to navigate to a specified link when a table row is clicked, overriding the default behavior. +`browseOnRowSelect` accepts an object such as + +```json +{ + "href": "destination/url", + "target": "_self", + "query": { + "id": "{{data._id}}" + }, + "navigationType": "push" +} +``` + +| property | type | values | description | +| ---------------- |------------------------| ------------------------- | ------------------------------------------------- | +| `href` | string | - | link reference. Only relative links are accepted. | +| `target` | string | - | where to open the href. Defaults to "_self" | +| `query` | `{[key: string]: any}` | - | query parameters | +| `navigationType` | string | "push", "replace", "href" | method used for navigation if target is "_self" | + +Where `navigationType` values are mapped to navigation methods as follows: + +| value | method | +| --------- | ------------------------- | +| `push` | `window.history.push` | +| `replace` | `window.history.replace` | +| `href` | `window.location.replace` | + + +### File Fields + +Fields that have type `array` or `object` and format `file` contain metadata information about one or multiple files stored in file storage service. +Property `openFileInViewerRegex` allows to control how the Table interacts such file fields. + +`openFileInViewerRegex` is either a string, an array of strings, or an object that maps a string to one between "view" and "download". +```typescript +type FileInViewerRegex = string | string[] | { + [regex: string]: "view" | "download" +} +``` + +`openFileInViewerRegex` represents a set of regex expressions, which are matched against the name of the files stored in file cells. +If one matches, the corresponding cell becomes clickable and the file is requested to be opened inside a viewer (default) or is requested to be downloaded. +Both actions are achieved by emitting a [download-file] event, injecting key `showInViewer` to the meta of the event to control whether to download or visualize the file. + +### Locale + +The texts of the Table can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + actionsTitle?: LocalizedText + element?: LocalizedText + elements?: LocalizedText + moreActions?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +### Example: Object Visualization + +Assuming an instance of the Table configured like: + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "object", + "format": "localized-text" + }, + "book": { + "type": "object", + "visualizationOptions": { + "template": "{{code}} - {{price}} $" + } + } + } + } + } +} +``` + +displaying data like: + +```json +[ + { + "name": "Deledda", + "description": { + "en": "Nobel prize winner in 1926", + "it": "Vincitrice del premio nobel nel 1926" + }, + "book": { + "code": "cv-432", + "name": "Canne al vento", + "price": 10 + }, + }, + { + "name": "Hesse", + "description": { + "en": "Nobel prize winner in 1946", + "it": "Vincitore del premio nobel nel 1946" + }, + "book": { + "code": "st-123", + "name": "Steppenwolf", + "price": 12 + } + } +] +``` + +assuming the browser language to be English, then the rendered data can be represented by an array as: + +```json +[ + ["Deledda", "Nobel prize winner in 1926", "cv-432 - 10 $"], + ["Hesse", "Nobel prize winner in 1946", "st-123 - 12 $"] +] +``` + +### Example: Array Visualization + +Assuming an instance of the Table configured like: + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "colors": { + "type": "array", + "visualizationOptions": { + "template": "{{[0]}}, {{[1]}} and more" + } + }, + "sizes": { + "type": "object", + "visualizationOptions": { + "joinDelimiter": "," + } + } + } + } + } +} +``` + +displaying data like: + +```json +[ + { + "name": "Pants", + "colors": ["black", "blue", "gray"], + "sizes": ["s", "m", "l", "xl"] + }, + { + "name": "Shirt", + "colors": ["red", "yellow", "blue", "brown"], + "sizes": ["m", "xl"] + } +] +``` + +then the rendered data can be represented by an array as: + +```json +[ + ["name", "colors", "sizes"], // table header + ["Pants", "black blue and more", "s, m, l, xl"], + ["Shirt", "red yellow and more", "m, xl"] +] +``` + +### Example: Web Component inside cells + +An instance of the Table configured like the following: + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "label": "Name as Button", + "visualizationOptions": { + "tag": "bk-button", + "properties": { + "content": "Click Me!" + } + } + } + } + } + } +} +``` + +mounts a [Button][bk-button] component inside each cell of the "name" column, injected with the specified properties. + +### Example: Dynamic Web Component (POST call with row as body) + +Given the following configuration for an instance of the Table: + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "label": "CTA", + "visualizationOptions": { + "tag": "bk-button", + "properties": { + "content": "{{currentUser.name}}", + "action": { + "type": "http", + "config": { + "method": "POST", + "url": "/path?{{args.[1].id}}={{args.[1]}}", + "body": "{{rawObject args.[1]}}", + "config": { + "headers": "{{rawObject headers}}" + } + } + } + } + } + } + } + } + } +} +``` + +And this (simplified) [context](#dynamic-context): + +- args + ```json + ["Column Name", {"id": "row-id"}, 4] + ``` + +- currentUser + ```json + { "name": "Bob" } + ``` + +- headers + ```json + { "content-type": "application/json" } + ``` + +Then the above configuration is equivalent to: + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "label": "CTA", + "visualizationOptions": { + "tag": "bk-button", + "properties": { + "content": "Bob", + "action": { + "type": "http", + "config": { + "method": "POST", + "url": "/path?row-id=4", + "body": { + "id": "row-id" + }, + "config": { + "headers": { + "content-type": "application/json" + } + } + } + } + } + } + } + } + } + } +} +``` + +which renders a table in which cells of column "name" include a [Button][bk-button] that perform a POST call. +The Button properties depend on the data in the the clicked row. + +:::info +[rawObject][rawObject] is a helper keyword that prevents "values" from being stringified in the body of the request. +::: + +### Example: Dynamic Web Component (disable button depending on row value) + +It is possible to provide a [`template`-`configMap` pair][template-configMap] instead of a value for a property. +In such cases, the value of the property is taken from the configMap using template as key (or `$default`, if the template does not match any `configMap` key). + +For instance, the following configuration: +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "label": "CTA", + "visualizationOptions": { + "tag": "bk-button", + "properties": { + "content": "Abort order", + "disabled": { + "template": "{{currentUser.role}}", + "configMap": { + "Superadmin": false, + "Admin": false, + "$default": true + } + } + } + } + } + } + } + } +} +``` +renders a table in which cells of column "name" include a [Button][bk-button] that is always disabled unless the current user has property `role` set to "Admin" or "Superadmin". + +### Example: visualize one element's array field (`displayedDataPath`) + +In this example, the Table displays the value of the `orders` array field of the first element received. + +```json +{ + "tag": "bk-table", + "properties": { + "displayedDataPath": "data.[0].orders", // -> enters `orders` field of first data item + "dataSchema": { // -> data-schema of `orders` field + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "price": { + "type": "number" + } + } + } + } +} +``` + +Upon listening to a [display-data] event, which lists fetched data, the Table uses property `displayDataPath` to reach the "orders" field of the first element, and attempts to display that field according to the provided data-schema. +Therefore, entries of "orders" are expected to have string field "name" and numeric field "price". + +If the payload of the `display-data` event were to be: + +```json +{ + "data": [ + { + "_id": "id-1", + "orders": [ + {"name": "clock", "price": 100}, + {"name": "pants", "price": 50}, + ] + }, + { + "_id": "id-2", + "orders": [ + {"name": "shirt", "price": 20} + ] + } + ] +} +``` + +then the data rendered by the Table is: + +```json +[ + {"name": "clock", "price": 100}, + {"name": "pants", "price": 50} +] +``` + +### Example: Action with `rowActions` + +A Table component configured like the following: + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"} + } + }, + "rowActions": { + "kind": "icons", + "actions": [ + { + "kind": "event", + "content": "duplicate-data", + "label": "Duplicate Data", + "icon": "far fa copy" + } + ] + } + } +} +``` + +renders an action column which includes a button that, upon being clicked, emits a [duplicate-data] event with an object representation of the corresponding row injected as payload. + +### Example: Action with `customActions` + +A Table component configured like the following: + +```json +{ + { + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "name": {"type": "string"} + } + }, + "customActions": [{ + "tag": "bk-button", + "properties": { + "content": "Cancel order", + "action": { + "type": "http", + "config": { + "url": "/cancel-order", + "method": "POST", + "body": "{{rawObject args.[1]}}" + } + } + } + }] + } + } +} +``` + +renders an action column which includes a [Button][bk-button] that, upon being clicked, emits a POST call to a URL `/cancel-order` with an object representation of the corresponding row as body. + +:::info +[rawObject][rawObject] is a helper keyword that prevents "values" from being stringified in the body of the request. +::: + +In particular, assuming data like: + +```json +[ + { + "_id": "id-1", + "name": "PC" + }, + { + "_id": "id-2", + "name": "Mouse" + }, + { + "_id": "id-3", + "name": "Smart phone" + } +] +``` + +the rendered Table includes an action "Cancel order" in each row. +Clicking on the action of the first row triggers a POST request with body: + +```json +{ + "_id": "id-1", + "name": "PC" +} +``` + +### Example: Actions in nested table with `customActions` + +Assuming a Table to be configured like the following: + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "articles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "details": { + "type": "object", + "dataSchema": { + "type": "object", + "properties": { + "code": {"type": "string"}, + "fragile": {"type": "boolean"} + } + } + } + } + } + } + } + }, + "customActions": [ + { + "keys": [], + "customActions": [ + { + "tag": "bk-button", + "properties": { + "content": "Cancel order", + "action": { + "type": "http", + "config": { + "url": "/cancel-order", + "method": "POST", + "body": "{{rawObject args.[1]}}" + } + } + } + } + ] + }, + { + "keys": ["articles", "details"], + "customActions": [ + { + "tag": "bk-button", + "properties": { + "content": "Refresh", + "action": { + "type": "http", + "config": { + "url": "/order/{{args.[1].code}}", + "method": "GET" + } + } + } + } + ] + } + ] + } +} +``` + +The action with button `Cancel order` appears on the home of the nested setup. +All other nesting level have no `customAction` but the `details` reached from `articles` which instead displays a button with label `Refresh`. + +In particular, assuming data like: + +```json +[ + { + "_id": "id-1", + "": [ + { + "name": "Pants", + "details": { + "code": "order-123", + "fragile": false + } + }, + { + "name": "Sweater", + "details": { + "code": "order-456", + "fragile": false + } + } + ] + }, + { + "_id": "id-2", + "": [ + { + "name": "Vase", + "details": { + "code": "order-987", + "fragile": true + } + } + ] + } +] +``` + +the rendered Table can be represented by the following array: + +```json +[ + ["_id", "articles"], // Table header + ["id-1", "2 Elements"], + ["id-2", "1 Element"], +] +``` +At this stage, an action "Cancel order" is available. + +Clicking on the first cell of the "articles" column, the user requests visualization of the corresponding nested data. +The Table complies to such request by re-rendering and showing: + +```json +[ + ["name", "details"], // Table header + ["Pants", "{...}"], + ["Sweater", "{...}"], +] +``` +At this stage, no action is available. + +Clicking on the second cell of the "details" column, the Table re-renders and shows: + +```json +[ + ["code", "fragile"], // Table header + ["order-456", "X"] +] +``` +At this stage, an action "Refresh" is available. With the above from the example, the action would trigger a GET call to "/order/order-456". + + +### Example: Disable an action if a field is empty + +The following example showcases how a [Button][bk-button] can be mounted inside the Table action column with `customActions`, +and disabled based on whether or not the value of a cell of a specific column in the corresponding row is defined. + +The configuration leverages the [`rawObjectOrEmptyStr`][rawObjectOrEmptyStr] custom helper, as well as the [`template`-`configMap`][template-configMap] interface. + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "avatar": {"type": "object", "format": "file"} + } + }, + "customActions": [ + { + "tag": "bk-button", + "properties": { + "content": "Download Avatar Image", + "disabled": { + "template": "{{rawObjectOrEmptyStr args.[1].avatar}}", + "configMap": { + "": true, + "$default": false + } + }, + "action": { + "type": "file-download", + "config": { + "url": "/order/{{args.[1]._id}}/avatar" + } + } + } + } + ] + } +} +``` + +This configuration of the Table component renders a table which mounts a [Button][bk-button] component as action button, +which is always enabled unless field "avatar" of the corresponding row is empty. + +### Example: Disable default actions in nested table + +To remove the default actions rendered by the Table in [nested visualization](#nested-data), `navigationRowAction` property should be set to: + +```json +{ + "kind": "icons", + "actions": [] +} +``` + +For instance, the following configuration renders a Table that does not include the default data actions associated to [nested visualizations](#nested-data). + +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "articles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"} + } + } + } + } + }, + "navigationRowActions": { + "kind": "icons", + "actions": [] + } + } +} +``` + + +### Example: Highlight rows + +Assuming the following configuration for the Table: + +```json +{ + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "severity": { + "type": "string", + "enum": ["High", "Medium", "Low"] + }, + "pets": { + "type": "array" + } + } + }, + "highlightedRows": [ + { + "color": "#ff0000", + "query": {"severity": "High"} + }, + { + "color": "blue", + "query": {"pets.0": {"$exists": true}} + } + ] + } +} +``` + +Table rows with field `severity` equal to "High" will have a red (`#ff0000`) background color, +while rows with array field `pets` having at least one element will have their background color set to blue. + +### Example: Highlight rows comparing fields between them + +Assuming the following configuration for the Table: + +```json +{ + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "payed": { + "type": "number" + }, + "owed": { + "type": "number" + } + } + }, + "highlightedRows": [ + { + "color": "yellow", + "query": {"email": "{{currentUser.emailAddress}}"} + }, + { + "color": "green", + "query": {"payed": {"$gte": "{{rawObject args.[1].owed}}"}} + } + ] + } +} +``` + +Table rows with field `email` equal to the `emailAddress` field of the logged user will be highlighted with a yellow color, +while rows with field `payed` larger than field `owed`, will be set to green color. + +### Example: Make the table as height as the parent container + +To make the table as height as the parent container, `fitParentContainer` property must be set to true and the `bk-table` component should have the correct style to make it as height as needed. + +:::info +Please remember that `maxLines` and `fitParentContainer` properties cannot be used at the same time. If both are set, only `maxLines` will be used. +::: + +```json +{ + "content": [ + { + "properties": { + ..., + "fitParentContainer": true + }, + "tag": "bk-table", + "attributes": { "style": "flex-grow: 1" } + } + ], + "tag": "div", + "attributes": { "style": "display: flex; flex-direction: column" } +} +``` + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +|-------------------------------|--------------------------------|--------------------------------------------------------|----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| +| `allowNavigation` | `allow-navigation` | boolean | true | when `true`, it is possible to navigate to nested objects and arrays if a dataSchema is specified | +| `browseOnRowSelect` | - | [ClickPayload](#clickpayload) | - | if set, a click on a row will navigate you to another location | +| `customActions` | - | [CustomAction](#customactions)[] | - | list of custom components, rendered in the action column | +| `customMessageOnAbsentLookup` | - | [LocalizedText][localized-text] | - | override lookup value in case lookup is not resolved due to lack of data | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data schema describing the fields of the collection to display | +| `disableRowClick` | `disable-row-click` | boolean | false | when `true`, a click on a row does not trigger an event | +| `disableRowSelection` | `disable-row-selection` | boolean | false | when `true`, checkbox in the first column will not be displayed | +| `disableRowSelectionChange` | `disable-row-selection-change` | boolean | false | when `true`, selecting a row through the checkbox in the first column does not trigger an event | +| `initialSortDirection` | - | "descend" \| "ascend" | - | initial sorting direction to use when component bootstraps | +| `initialSortProperty` | `initial-sort-property` | string | - | initial property to sort on when component bootstraps, it must be used with `initialSortDirection`. | +| `loadingOnStart` | `loading-on-start` | boolean | true | whether the table should be in loading state on connection | +| `maxLines` | `max-lines` | number | - | force lines that will be displayed together. It can't be used with `fitParentContainer` | +| `fitParentContainer` | `fit-parent-container` | boolean | false | Make the table fit the parent container height. It can't be used with `maxLines` | +| `navigationRowActions` | - | [NavigationDataActions](#navigationdataactions) | `{"kind": "icons", "actions": [{ "requireConfirm": true, "type": "delete", "disableInReadonly": true}]}` | actions in nested objects. | +| `openFileInViewerRegex` | - | [FileInViewerRegex](#fileinviewerregex) | - | regex expressions, matched against file values to request a preview of the file or for it to be downloaded. | +| `resizableColumns` | `resizable-columns` | boolean | false | whether the table columns can be resized. When `true`, columns can be resized from the table header | +| `rowActions` | - | [DataActions](#dataactions) | - | list of actions to render per row | +| `showArrayPopover` | `show-array-popover` | boolean | false | whether to display a popup on mouse-over on array cells, showing their value. Not available for arrays of objects or arrays of arrays. | +| `fixedColumns` | - | number \| `{'left': number; 'right': number}` | - | either the number of columns to fix from left or an object containing how many columns to fix from left and/or right | +| `displayedDataPath` | - | string | - | specify an object path as datasource for displayed data | +| `highlightedRows` | - | [QueryStyleRule](#querystylerule) \| QueryStyleRule[] | - | highlights rows matched by a mongo-like queries | + +#### ClickPayload + +```typescript +type ClickPayload = { + /** Link reference, either relative starting with '/' or absolute */ + href?: string + /** Where to open the href. Defaults to _self */ + target?: LinkTarget + /** Query params appended to href */ + query?: Record + + navigationType?: 'push', 'replace', 'href' +} + +type LinkTarget = '_blank' | '_self' | '_parent' | '_top' | string +``` + +#### CustomActions + +```typescript +type CustomActions = ComponentTemplate[] | Array<{ + keys?: string[]; customActions?: ComponentTemplate[] +}> + +type CustomComponents = { + tag: string + properties: Record +} + +``` + +#### NavigationDataActions + +`navigationRowActions` is an object of type `NavigationDataActions`, which is an object such as + +```typescript +type NavigationDataActions = { + kind: 'icons' | 'cta', + actions: { + type: delete | detail, + danger?: true, + requireConfirm?: boolean | RequireConfirmOpts, + disableInReadonly?: boolean, + icon?: string + }[] +} +``` + +#### FileInViewerRegex + +```typescript +type FileInViewerRegex = string | string[] | { + [regex: string]: "view" | "download" +} +``` + +#### DataActions + +```typescript +type DataActions = { + kind: 'icons' | 'cta' + actions: DataCustomActions[] +} + +type DataCustomActions = { + kind: 'icons' | 'cta' + content: string + meta?: Record + requireConfirm?: RequireConfirmOpts | boolean +} + +type RequireConfirmOpts = { + cancelText?: LocalizedText + content?: LocalizedText + okText?: LocalizedText + title?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +#### QueryStyleRule + +```typescript +type QueryStyleRule = { + color: ColorInput + query: Query +} +``` + +Where: + - `ColorInput` can be expressed as the CSS valid string representation of a color (for instance, `#f2e8e2` or `rgb(230, 155, 114)`), or an object such as `{r: 230, g: 155, b: 114}`. + Broadly speaking, `color` key supports all types supported as input by [TinyColor] library. + - `Query` is the object representation of a [mongo-like query][inline-queries] + + +### Listens to + +| event | action | +| --------------------------------- | -------------------------------------------------------------------------------------------------------- | +| [loading-data] | sets internal loading state | +| [lookup-data] | receives lookup data | +| [display-data] | receives data to display, deselects items by emitting a [selected-data-bulk] | +| [nested-navigation-state/push] | updates internal representation of the current navigation path by adding one step | +| [nested-navigation-state/back] | updates internal representation of the current navigation path by removing the specified number of steps | +| [nested-navigation-state/display] | updates internal representation of the data to display in navigation | + +### Emits + +| event | description | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| configurable event | [actions](#actions) or [custom web components](#web-component-into-cells) can be used to emit custom events | +| [require-confirm] | triggered when trying to submit the form accordingly to property `requireConfirm` | +| [change-query] | requires data sorting according with the sorted property | +| [download-file] | requires a file to be previewed or downloaded | +| [selected-data] | notifies about the click on a row | +| [selected-data-bulk] | notifies about a change in the rows selected through the checkboxes in the first column | +| [nested-navigation-state/push] | notifies to add a step in the navigation path | +| [nested-navigation-state/display] | notifies data to display (emitetd upon column sorting) | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/530_tabs.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/530_tabs.md new file mode 100644 index 0000000000..3bd24d9186 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/530_tabs.md @@ -0,0 +1,456 @@ +--- +id: tabs +title: Tabs +sidebar_label: Tabs +--- + + + + + + +[handlebars]: https://handlebarsjs.com/guide/expressions.html + +[events]: /products/microfrontend-composer/back-kit/10_overview.md#events +[filters]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filters +[filter-operators]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filter-operators +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic-configuration]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[change-layout]: /products/microfrontend-composer/back-kit/70_events.md#change-layout + + + +```html + +``` + +![tabs](img/bk-tabs.png) + +The Tabs component offers a fixed set of [filters], presented as tabs. Each tab is associated to a list of filters. +By default, selecting a tab triggers a request to replace the filters associated with the previously selected tab and apply the filters of the newly selected tab during data retrieval. +To achieve this behavior, the Tabs component injects the chosen filters into the payload of a [change-query] event, utilizing the `characteristic` key. + +## How to configure + +The Tabs component requires property `tabs` to be configured with an array of objects, where each entry is mapped to a tab. + +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "pending", + "title": "Pending", + "filters": [ + { + "property": "status", + "operator": "equal", + "value": "Pending" + }, + ] + }, + { + "key": "preparing", + "title": "Preparing", + "filters": [ + { + "property": "status", + "operator": "equal", + "value": "Preparing" + } + ] + } + ] + } +} +``` + +Each entry of `tabs` property is an object which supports keys: + - `key`: the id of the tab + - `title`: the [localized label][localized-text] associated to the tab + - `order`: the tab order number + - `filters`: array of [filters](#filters-configuration) that will be applied when the tab is opened + - `event`: event launched when the tab is opened + +### Filters + +The Tabs component allows to assign [filters] to each rendered tab using the `filters` key in the entries of the `tabs` property. + +Each filter is composed of an object with keys + - `property`: id of the field to use for the filter + - `operator`: [filter operator][filter-operators] to use for the filter + - `value`: input value to be compared in each data element against the value of the specified property, using to the specified operator + +The `value` key supports [dynamic configurations][dynamic-configuration], allowing both access to information about the currently logged user and to perform basic time arithmetic. + +#### Dynamic Filters: accessing Current User + +The Tabs component allows [dynamic configurations][dynamic-configuration] through [handlebar notation][handlebars]. +The provided dynamic context is the information of the current user using key `currentUser`. + +For instance: +```json +{ + "properties": { + "tabs": [ + { + "key": "currentuser", + "title": "Current User", + "filters": [ + { + "property": "name", + "operator": "equal", + "value": "{{currentUser.name}}" + } + ] + } + ] + } +} +``` + +#### Dynamic Filters: time-based filters + +When filtering by a date field, it is possible to set the `value` of the filter to the keyword `$today`, which represents the current date. +Furthermore, it is also possible to perform basic arithmetic operations on date values by setting value to an object with keys: + + - `value`: the base value (`$today` keyword is supported) + - `offset`: number representing how much to add / subtract from the `value` + - `operation`: whether to add or subtract the `offest` to the `value` + - `unit`: unit of measure of the `offset`. Accepted values are: 'year', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond' + +### Emitting custom Events + +It is possible to associate the opening of a tab to the emission of a configurable event. +When entries of `tabs` property have their key `event` populated, selecting the tab triggers the emission of such event instead of the default request to update the data filtering query. + + +## Examples + +### Example: Basic Usage + +Assuming the Tabs component to be configured like: + +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "pending", + "title": { + "en": "Pending", + "it": "In attesa" + }, + "filters": [ + { + "property": "status", + "operator": "equal", + "value": "Pending" + } + ] + }, + { + "key": "preparing", + "title": { + "en": "Preparing", + "it": "In preparazione" + }, + "filters": [ + { + "property": "status", + "operator": "equal", + "value": "Preparing" + } + ] + } + ] + } +} +``` + +upon connection to the page, the first tab is automatically selected, resulting in the emission of a [change-query] event with payload + +```json +{ + "characteristic": { + "property": "status", + "operator": "equal", + "value": "Pending" + } +} +``` + +Upon selecting the second tab, a [change-query] event with the following payload is emitted: + +```json +{ + "characteristic": { + "property": "status", + "operator": "equal", + "value": "Pending" + } +} +``` + +A component like the [CRUD Client][bk-crud-client] could listen to such events. + +### Example: Dynamic access to user information + +The Tabs component allows [dynamic configurations][dynamic-configuration] through [handlebar notation][handlebars]. + +For instance, given the following configuration: + +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "currentuser", + "title": "Current User", + "filters": [ + { + "property": "nickname", + "operator": "equal", + "value": "{{currentUser.username}}" + } + ] + } + ] + } +} +``` + +assuming the currently logged user to be representable with the following object: + +```json +{ + "name": "Sara", + "surname": "Smith", + "username": "sara_smith_123" +} +``` + +selecting the tab in the example triggers the emission of a [change-query] event with payload: + +```json +{ + "characteristic": [ + { + "property": "nickname", + "operator": "equal", + "value": "sara_smith_123" + } + ] +} +``` + +### Example: Time based filters + +When filtering by a date, it is possible to use the special keyword in the value key `$today`, which represents the current date. +For example: +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "ordered", + "title": "Ordered", + "filters": [ + { + "property": "orderedAt", + "operator": "less", + "value": "$today" + } + ] + } + ] + } +} +``` + +It is also possible to perform basic arithmetic operations on date values. +For example, a Tab component configured like the following: +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "old", + "title": "Old Orders", + "filters": [ + { + "property": "orderedAt", + "operator": "less", + "value": { + "value": "$today", + "offset": 1, + "unit": "month", + "operation": "subtract" + } + } + ] + } + ] + } +} +``` +emits the request to fetch data for which the date of the "orderedAt" field is previous to one month before the current date. + +Time based operations are also available in case of filters with operator `between`, in which the `value` should be an array. +For instance: + +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "recent", + "title": "Recently Ordered", + "filters": [ + { + "property": "orderedAt", + "operator": "between", + "value": [ + { + "value": "$today", + "offset": 1, + "unit": "week", + "operation": "subtract" + }, + "$today" + ] + } + ] + } + ] + } +} +``` +emits a request to fetch data for which the value of "orderedAt" field is a date included between one week ago and the current date. + +### Example: Custom Event + +The Tabs component can be used to emit custom events **instead of** the default [change-query] event. +For instance, assuming the Tabs component to be configured like: + +```json +{ + "tag": "bk-tabs", + "properties": { + "tabs": [ + { + "key": "orders", + "title": { + "en": "Orders", + "it": "Ordini" + }, + "event": { + "label": "change-layou", + "payload": { + "layout": "riders-layout" + } + } + }, + { + "key": "customers", + "title": { + "en": "Customers", + "it": "Clienti" + }, + "filters": [ + { + "label": "change-layout", + "payload": { + "layout": "customers-layout" + } + } + ] + } + ] + } +} +``` + +upon connection to the page, the first tab is automatically selected, resulting in the emission of a [change-layout] event with payload + +```json +{ + "layout": "riders-layout" +} +``` + +Upon selecting the second tab, a [change-layout] event with the following payload is emitted: +```json +{ + "layout": "customers-layout" +} +``` + +## API + +### Properties & Attributes + + +| property | attribute | type | default | description | +| -------- | --------- | ------------- | ------- | ----------------------------- | +| `tabs` | - | [Tab](#tab)[] | - | array with tabs configuration | + +#### Tab + +```typescript +type Tab = { + title: LocalizedText + filters?: ConfigurableTabFilter[] + event?: Partial + order?: number + key: string +} + +type ConfigurableTabFilter = { + operator: FilterOperator + property: string + value: string | number | boolean | any[] | DateOptions +} + +type DateOptions = { + value: string + offset: number + operation: 'add' | 'subtract' + unit: 'day' | 'week' | 'month' | 'year' | 'hour' | 'minute' | 'second' | 'millisecond' +} +``` + +where + - [LocalizedText][localized-text] is either a string or an object that maps languages acronyms to strings + - [FilterOperator][filter-operators] is one of the supported filter operators + - [Event][events] is the object representation of an event, thus an object with keys `label`, `payload`, `meta` + +### Listens to + +| event | action | +| ------------------------------ | -------------------------------------------------------------------------------------------------------- | +| [nested-navigation-state/push] | updates internal representation of the current navigation path by adding one step | +| [nested-navigation-state/back] | updates internal representation of the current navigation path by removing the specified number of steps | + +### Emits + + +| event | description | +| -------------------- | --------------------------------------------- | +| configurable event | custom events can be emitted on tabs opening | +| [change-query] | requests filtering on dataset | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/540_title.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/540_title.md new file mode 100644 index 0000000000..58bb5c603b --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/540_title.md @@ -0,0 +1,57 @@ +--- +id: title +title: Title +sidebar_label: Title +--- + + + + + + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + + + +```html + +``` + +![title](img/bk-title.png) + +The Title renders a header title. + +## How to configure + +The title text should be specified using `content` property. [Localized objects][localized-text] are supported. + +```json +{ + "tag": "bk-title", + "properties": { + "content": { + "en": "Products list", + "it": "Listat dei prodotti" + } + } +} +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| --------- | --------- | ------------------------------- | ------- | ----------------- | +| `content` | - | [LocalizedText][localized-text] | - | localized content | + +### Listens to + +None + +### Emits + +None diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/550_url_parameters_adapter.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/550_url_parameters_adapter.md new file mode 100644 index 0000000000..6e4eb7436a --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/550_url_parameters_adapter.md @@ -0,0 +1,191 @@ +--- +id: url_parameters_adapter +title: URL Parameters Adapter +sidebar_label: URL Parameters Adapter +--- + + + + + +[window-location]: https://developer.mozilla.org/en-US/docs/Web/API/Window/location + +[plugin-navigation]: /products/microfrontend-composer/back-kit/80_examples/30_plugin_navigation.md + +[url-mask]: /products/microfrontend-composer/back-kit/40_core_concepts.md#extracting-data-from-url---urlmask +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query + + + +```html + +``` +The URL Parameters Adapter allows to emit events upon connecting to the DOM, based on the value of the URL. + +One common way of using the URL Parameters Adapter component is to fetch only one data element from a collection, +retrieving its ID from the URL, as explained in [Plugin Navigation][plugin-navigation] dedicated section. + +## How to configure + +Upon connection, the URL Parameters Adapter attempts to match the window URL against the given mask in property [urlMask][url-mask]. +If it fails, it will redirect according to the provided property `redirectUrl`. Otherwise it will attempt to emit the matched content as payload of an event using its property `eventLabel` as label of the event, which defaults to `change-query`. + +```json +{ + "tag": "bk-url-parameters", + "properties": { + "urlMask": "/order-details/:_id", + "redirectTo": "/order-list" + } +} +``` + +### Use different masks for pathname and search + +By default, the same mask is applied to both the `pathname` and the `search` sections of the [URL][window-location]. However, different ones can be specified: + +```json +{ + "tag": "bk-url-parameters", + "properties": { + "urlMask": { + "pathname": "/order-details/:_id", + "search": "\\?pageNumber=:pNumber" + } + } +} +``` + +### Ignoring wildcards + +Wildcards (`(.*)`) can be used in `urlMask`. These match any string and is included in the payload of the emitted event with numeric keys. +If property `excludeWildcards` is true, matches coming from wildcards are excluded from the payload of the event. + +```json +{ + "tag": "bk-url-parameters", + "properties": { + "urlMask": "/order-details/(.*)/:_id", + "excludeWildcards": true + } +} +``` + +## Examples + +### Example: Basic usage + +With such configuration for the URL Parameters Adapter: +```json +{ + "tag": "bk-url-parameters", + "properties": { + "urlMask": "/order-details/:_id" + } +} +``` + +Assuming the URL to be "/order-details/test-id", then the URL Parameters Adapter emits the following [change-query][change-query] event, upon connection to the DOM: + +```json +{ + "label": "change-query", + "payload": { + "_id": "test-id" + } +} +``` + +### Example: Pathname / search + +With such configuration for the URL Parameters Adapter: +```json +{ + "tag": "bk-url-parameters", + "properties": { + "urlMask": { + "pathname": "/order-details/:_id", + "search": "\\?pageNumber=:pNumber" + } + } +} +``` +Assuming the URL to be "/order-details/first-id?pageNumber=25", then the URL Parameters Adapter emits the following event: +```json +{ + "label": "change-query", + "payload": { + "_id": "first-id", + "pNumber": "25" + } +} +``` + +### Example: Wildcards + +With such configuration for the URL Parameters Adapter: +```json +{ + "tag": "bk-url-parameters", + "properties": { + "excludeWildcards": true, + "urlMask": "/order-details/(.*)/:_id" + } +} +``` +Assuming the URL to be "/order-details/first-id/second-id", then the URL Parameters Adapter emits the following [change-query][change-query] event: + +```json +{ + "label": "change-query", + "payload": { + "_id": "second-id" + } +} +``` + +If `excludeWildcards` property is not explicitly set to true: +```json +{ + "tag": "bk-url-parameters", + "properties": { + "urlMask": "/order-details/(.*)/:_id" + } +} +``` +the following event is emitted: +```json +{ + "label": "change-query", + "payload": { + "0": "first-id", // wildcard matches are included in the event payload through numeric keys + "_id": "second-id" + } +} +``` + +## API + +### Properties & Attributes + + +| property | attribute | type | default | description | +| ------------------ | ------------------- | ------------------- | -------------- | ------------------------------------------------------------------------------------------- | +| `waitTime` | `wait-time` | number | 500 | wait time before initialization event, in milliseconds | +| `urlMask` | `url-mask` | [UrlMask][url-mask] | - | url mask to apply to the current path to extract dynamic parameters | +| `eventLabel` | `event-label` | string | 'change-query' | label of the event that will be dispatched as result | +| `redirectUrl` | `redirect-url` | string | - | optional parameter that contains the url to redirect when urlMask does not completely match | +| `excludeWildcards` | `exclude-wildcards` | boolean | false | whether or not matches from wildcards (`(.*)`) should be excluded from event payload | + +### Listens to + +This component listens to no event. + +### Emits + +| event | description | +| ------------------ | ------------------------------------------------------------------------------- | +| configurable event | generic event based on its properties ([change-query][change-query] by default) | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/60_breadcrumbs.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/60_breadcrumbs.md new file mode 100644 index 0000000000..10397c54da --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/60_breadcrumbs.md @@ -0,0 +1,144 @@ +--- +id: breadcrumbs +title: Breadcrumbs +sidebar_label: Breadcrumbs +--- + + + + + + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema + +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data + + + +```html + +``` + +![breadcrumbs](img/bk-breadcrumbs.png) + +The Breadcrumbs provide a visual representation of the the current nesting path, and allows to go back to any nesting level. + +## How to configure + +The Breadcrumbs component should be supplied with a [data-schema] containing field labels from the underlying data. +These labels are used to display the nesting path in the provided visual representation. + +```json +{ + "tag": "bk-breadcrumb", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "colors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "r": {"type": "number"}, + "g": {"type": "number"}, + "b": {"type": "number"} + } + } + } + } + } + } +} +``` + + +## Examples + +A Breadcrumbs component configured like: + +```json +{ + "tag": "bk-breadcrumb", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "product": { + "type": "object", + "label": { + "en": "Product", + "it": "Prodotto" + }, + "dataSchema": { + "type": "object", + "properties": { + "colors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "r": {"type": "number"}, + "g": {"type": "number"}, + "b": {"type": "number"} + } + } + } + } + } + } + } + } + } +} +``` + +upon receiving two [nested-navigation-state/push] events with payload including `selectedKey` property like: + +```json +{ + "selectedKey": "product" +} +``` +and +```json +{ + "selectedKey": "colors" +} +``` + +(which notify the request to enter the visualization of nested field `product` and nested field `colors` respectively), +and assuming the browser language setting to be set to english, + +visualizes a nesting path that can be represented by a string like: +``` +/Product/Colors +``` + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ------------ | ----------- | -------------------------------------------- | ------- | -------------------------------------------------------------- | +| `dataSchema` | - | [ExtendedJSONSchema7Definition][data-schema] | - | data schema describing the fields of the collection to display | +| `showHome` | `show-home` | boolean | true | toggles visualization of a "home" icon at breadcrumbs 0-level | + +### Listens to + +| event | action | +| ------------------------------ | ---------------------------------------------------------------------------------------- | +| [nested-navigation-state/push] | updates the representation of the nesting path by adding one step | +| [nested-navigation-state/back] | updates the representation of the nesting path by removing the specified number of steps | +| [display-data] | attempts to recreate current nesting path with new data. If fails, goes back to 0-level | + +### Emits + +| event | description | +| ------------------------------ | --------------------------------------------------------------------- | +| [nested-navigation-state/back] | notifies to go back the specified number of steps in the nesting path | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/70_bulk_actions_button.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/70_bulk_actions_button.md new file mode 100644 index 0000000000..d38a689fad --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/70_bulk_actions_button.md @@ -0,0 +1,158 @@ +--- +id: bulk_actions_button +title: Bulk Actions Button +sidebar_label: Bulk Actions Button +--- + + + + + +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md +[bk-gallery]: /products/microfrontend-composer/back-kit/60_components/370_gallery.md + +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[DataSchema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[select-data-bulk]: /products/microfrontend-composer/back-kit/70_events.md#select-data-bulk +[bulk-update]: /products/microfrontend-composer/back-kit/70_events.md#bulk-update + + + +```html + +``` + +The Bulk Actions Button allows to notify when it is required to alter the value of a `boolean` or `enum` field across multiple items using a bulk operation, by first selecting the field to update and subsequently the target value, both using popup menus. + +1. The component initially scans the `dataSchema` property to identify properties amenable to modification. It focuses on properties with `enum` key or `boolean` data types. +2. When components such as the [Table][bk-table] or the [Gallery][bk-gallery] notify that items have been selected, the Bulk Actions Button becomes visible. The Bulk Actions Button keeps as state an internal representation of the selected items. +3. Interaction with the component is facilitated through the left-hand side of the component, represented by three dots. This UI allows users to choose the specific property to be modified. +4. Following the selection of a property, the component assesses whether the chosen property holds the same value across all selected items. If uniform, the common value is displayed alongside the property name. If not, the property name is accompanied by '*various*' to denote inconsistency. +5. Value Selection: Users can now also engage with the right-hand side of the component to select the value intended for assignment to the chosen property. +6. Upon value selection, the component notifies the request to perform the necessary data update operations to other components. + +## How to configure + +Basic usage of the Bulk Actions Button requires a data-schema to be provided, describing the fields of the received data. + +```json +{ + "tag": "bk-bulk-button", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "isMarried": {"type": "boolean"}, + "dayOff": { + "type": "string", + "enum": ["Mon", "Tue", "Wed", "Thu", "Fri"] + } + } + } + } +} +``` + + +### Confirmation dialog on selected value + +It is possible to require for confirmation to be prompted before requesting value bulk update. To opt-in to this behavior, `requireConfirm` property is available. + +#### 1. Boolean type + +Property `requireConfirm` can be set as `true` to require the default dialog box text. + +#### 2. Object of type RequireConfirmOpts + +Property `requireConfirm` can be configured so to require custom text inside the dialog box. + +```json +{ + "tag": "bk-bulk-actions", + "properties": { + "requireConfirm": { + "content": { + "it": "Verrà creato un nuovo elemento, procedere?", + "en": "A new element will be created, continue?" + }, + "title": "Confirmation Required" + } + } +} +``` + +### Locale + +The texts of the Bulk Actions Button can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + confirmationContent?: LocalizedText + chooseProperty?: LocalizedText + chooseValue?: LocalizedText + noValue?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## Examples + +With such configuration for the Bulk Actions Button: +```json +{ + "tag": "bk-bulk-actions", + "properties": { + "dataSchema": { + "name": {"type": "string"}, + "isMarried": {"type": "boolean"}, + "dayOff": { + "type": "string", + "enum": ["Mon", "Tue", "Wed", "Thu", "Fri"] + } + }, + "requireConfirm": true + } +} +``` +it is possible to notify the request to update in bulk either the `isMarried` or the `dayOff` field in all selected items. Before issuing the request, a dialog box is prompted to the user. + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +| ---------------- | --------- | ---------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `requireConfirm` | - | boolean \| [RequireConfirmOpts](#requireconfirmopts) | false | whether or not the button should ask for confirmation before requesting to update all the selected data with the chosen value | +| `dataSchema` | - | [DataSchema][DataSchema] | - | data-schema describing the fields of the collection | + +#### RequireConfirmOpts + +```typescript +type RequireConfirmOpts = { + cancelText?: LocalizedText; // cancel button text + okText?: LocalizedText; // ok button text + content?: LocalizedText; // the content text + title?: LocalizedText; // the title text +} +``` + +where [LocalizedText][localized-text] can be either simple strings or objects containing the language acronymous key and the text as value. + +### Listens to + +| event | action | +| ------------------------------------ | ------------------------------ | +| [select-data-bulk][select-data-bulk] | keeps track of user selections | + +### Emits + + +| event | description | +| -------------------------- | ------------------------------------------------------------------------------- | +| [bulk-update][bulk-update] | notifies the client to update more items at the same time with a specific value | diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/80_bulk_delete_button.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/80_bulk_delete_button.md new file mode 100644 index 0000000000..3d32803f46 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/80_bulk_delete_button.md @@ -0,0 +1,90 @@ +--- +id: bulk_delete_button +title: Bulk Delete Button +sidebar_label: Bulk Delete Button +--- + + + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[state-pattern]: /runtime-components/plugins/crud-service/10_overview_and_usage.md#state-transitions + +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md +[bk-gallery]: /products/microfrontend-composer/back-kit/60_components/370_gallery.md +[bk-confirmation-modal]: /products/microfrontend-composer/back-kit/60_components/160_confirmation_modal.md + +[require-confirm]: /products/microfrontend-composer/back-kit/70_events.md#require-confirm +[delete-data]: /products/microfrontend-composer/back-kit/70_events.md#delete-data +[selected-data-bulk]: /products/microfrontend-composer/back-kit/70_events.md#selected-data-bulk +[localized-text]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n + + + +```html + +``` + +This component renders a button that allows to request deletion of multiple items at the same time in a bulk operation. + +## How to configure + +The Bulk Delete Button does not require any configuration. + +```json +{ + "tag": "bk-bulk-delete" +} +``` + + + + +### How it works + +1. The component begins in a disabled state, rendering it unresponsive to user interactions +2. When components such as the [Table][bk-table] or the [Gallery][bk-gallery] notify that items have been selected, the Bulk Delete Button becomes active. The Bulk Delete Button keeps as state an internal representation of the selected items. +3. Upon clicking, the component requests a confirmation dialog box to be spawned +4. Upon confirmation, a notification for the requests of bulk deletion of selected items is emitted + +Note that the Bulk Delete Button always asks for confirmation before issuing a request for data deletion. Therefore, a component such as the [Confirmation Modal][bk-confirmation-modal] should be included in the plugin. + + + +### Locale + +The texts of the Bulk Delete Button can be customized through the property `customLocale`, which accepts an object shaped like the following: + +```typescript +type Locale = { + content?: LocalizedText + confirmationContent?: LocalizedText +} +``` + +where [LocalizedText][localized-text] is either a string or an object mapping language acronyms to strings. + + +## API + +### Properties & Attributes + +None + +### Listens to + +| event | action | +|-------|--------| +|[selected-data-bulk][selected-data-bulk]|keeps track of user selections to activate the button| + +### Emits + +| event | description | +|-------|-------------| +|[require-confirm][require-confirm]|opens a dialog to ask for confirmation| +|[delete-data][delete-data]|deletes selected data| diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/90_button.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/90_button.md new file mode 100644 index 0000000000..e4e2a38db6 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/90_button.md @@ -0,0 +1,770 @@ +--- +id: button +title: Button +sidebar_label: Button +--- + + + + + +[handlebars]: https://handlebarsjs.com/guide/expressions.html +[window-location]: https://developer.mozilla.org/en-US/docs/Web/API/Window/location + +[nested-schemas]: /products/microfrontend-composer/back-kit/80_examples/20_nested_data.md + +[helpers]: /products/microfrontend-composer/back-kit/40_core_concepts.md#helpers +[url-mask]: /products/microfrontend-composer/back-kit/40_core_concepts.md#extracting-data-from-url---urlmask +[localization]: /products/microfrontend-composer/back-kit/40_core_concepts.md#localization-and-i18n +[dynamic-configurations]: /products/microfrontend-composer/back-kit/40_core_concepts.md#dynamic-configuration +[rawobject]: /products/microfrontend-composer/back-kit/40_core_concepts.md#rawobject + +[action]: /products/microfrontend-composer/back-kit/50_actions.md +[action-hooks]: /products/microfrontend-composer/back-kit/50_actions.md#action-chaining + +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md +[bk-gallery]: /products/microfrontend-composer/back-kit/60_components/370_gallery.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-confirmation-modal]: /products/microfrontend-composer/back-kit/60_components/160_confirmation_modal.md + +[require-confirm]: /products/microfrontend-composer/back-kit/70_events.md#require-confirm +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[success]: /products/microfrontend-composer/back-kit/70_events.md#success +[error]: /products/microfrontend-composer/back-kit/70_events.md#error +[cancel]: /products/microfrontend-composer/back-kit/70_events.md#cancel +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[delete-data]: /products/microfrontend-composer/back-kit/70_events.md#delete-data +[loading-data]: /products/microfrontend-composer/back-kit/70_events.md#loading-data +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[selected-data-bulk]: /products/microfrontend-composer/back-kit/70_events.md#selected-data-bulk +[selected-data]: /products/microfrontend-composer/back-kit/70_events.md#selected-data + + + +```html + +``` + + + +The Button component renders a generic button that can be configured to execute some action upon clicking. + +## How to configure + +The behavior upon clicking is defined by property `action`, which can be configured to perform the following tasks, or a combination of them: + - push events into the event-bus + - perform HTTP requests + - redirect to another page + - upload / download files + - copy data into clipboard + +Property `action` can be configured following the [Back-kit Action][action] interface. + +### Action + +The `action` property allows to configure a [Back-kit Action][action] that should be implemented by the rendered button upon clicking. + +Each action in the component is executed with the following [context](#context): +```typescript +{ + pathnameParams: ..., // parameters extracted from pathname part of URL. Requires `urlMask` property to be specified. + searchParams: ..., // parameters extracted from search part of URL. Requires `urlMask` property to be specified. + currentUser: ..., // data relative to the current user. + selectedData: ..., // currently selected data. Requires `bulkButton` property to be true. + selectedParents: ..., // history of parents through which the user has navigated to get to the current view + context: ... // extra context set by mounting component +} +``` +which allows for dynamic configurations through [handlebars syntax][handlebars]. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Register to race", + "action": { + "type": "http", + "config": { + "url": "/race", + "method": "POST", + "body": { + "id": "{{currentUser.id}}", + "nickname": "{{currentUser.nickname}}" + } + } + } + } +} +``` + + +#### Context + +[Dynamic configuration][dynamic-configurations] is possible when defining how the button should react to being clicked. Namely, the entry of the `action` property are parsed with [handlebars][handlebars] before being converted into callbacks, with the following properties injected as context: + +- `currentUser`, contains information about the current user, for example name and email. + +- `pathnameParams`, contains information about the pathname of the current URL. This is only available upon correctly configuring a value for property [urlMask][url-mask].\ +`pathnameParams.params` includes the result of the match between the `urlMask` property and the [pathname][window-location] of the URL, while `pathnameParams.path` holds the full pathname.\ +It contains the property `params` with the keys specified in the `urlMask` and the property `path` with the full query parameters string. + ```json + { + "params": { + "id": "order-id-1" + }, + "path": "/order-details/order-id-1" + } + ``` + +- `searchParams` contains information about the URL query parameters. This is only available upon correctly configuring a value for property [urlMask][url-mask].\ `searchParams.params` includes the result of the match between the `urlMask` property and the [query][window-location] of the URL, while `searchParams.path` holds the full query as a string.\ +It contains the property `params` with the keys specified in the `urlMask` and the property `path` with the full query parameters string. + ```json + { + "params": { + "sort": "ascending", + "color": "red" + }, + "path": "?sort=ascending&color=red" + } + ``` + +- `selectedData`, contains an array of objects representation of the selected data. Requires the property `bulkButton` to be true, operating the button to operate in [bulk mode](#bulk-button). Selected data is then accessible in dynamic configuration through key `selectedData`. + ```json + { + selectedData: [ + { + "name": "Sara", + "dateOfBirth": { + "day": "30", + "month": "May", + "year": "1994" + } + }, + { + "name": "Dave", + "dateOfBirth": { + "day": "21", + "month": "September", + "year": "1956" + } + } + ] + } + ``` +Most of the times, `selectedData` is used in conjunction with [rawObject helper][rawobject], like `{{rawObject selectedData}}`, which signals to the Button that the selected data should not stringified but rather kept as array. For instance, to inject the selected data items into the body of a POST call, `{{rawObject selectedData}}` should be used. + + +- `selectedParents`, contains an array with all the [nesting layers][nested-schemas] which were navigated. + +- extra context. The Button supports extra context, which could be set by the user using `context` property, or, most of the times, by a parent component that mounts the Button. For instance, the [Table][bk-table] component renders a table that may include instances of the Button component as action buttons. The Table provides the mounted Buttons with an object representation of the corresponding row, which can then be used in action configuration via keywork `args.[1]`. + + +### Require Confirmation + +It is possible to ask for confirmation before executing an action emitting a [require-confirm][require-confirm] event, and nesting the desired action in the payload of the event. This approach requires a component such as the [Confirmation Modal][bk-confirmation-modal] to be included in the plugin. + +```json +{ + "tag": "bk-button", + "properties": { + "action": { + "type": "event", + "config": { + "events": { + "label": "require-confirm", // -> this opens the confirmation dialog-box + "payload": { + "configOk": { // -> this is the OK button of the confirmation dialog-box + "tag": "bk-button", + "properties": { + "content": "Confirm", + "action": { + ... // -> action to be executed, for which a confirmation should be requested + } + } + } + } + } + } + } + } +} +``` + +:::warning +When wrapping the action inside a `require-confirm` event in this way properties `loadingOnAction` and `disableOnAction` should not be set to true, as the button will enter loading / disabled status without ever leaving it. +::: + +### Bulk button + +It is possible to create a button that keeps in state selected items by setting `bulkButton` property to true. +By setting `bulkButton` property to true, the Button keeps an internal representation of items selected through components such as the [Table][bk-table]. +Selected data can then be [referenced in actions](#context) using `selectedData`. +Most of the times, `selectedData` should be used in configurations with [rawObject][helpers] helper keyword, `{{rawObject selectedData}}`. +`rawObject` prevents the referenced data from being stringified during the dynamic value resolution step. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Register to List", + "bulkButton": true, + "action": { + "type": "http", + "config": { + "url": "/v2/users/", + "method": "POST", + "body": "{{rawObject selectedData}}" + } + } + } +} +``` + +### Loading / disable on action + +Properties `loadingOnAction` and `disableOnAction` put the button in loading/disabled state when an action of type `event`, `http`, `file-upload` is executed. +The button exits loading/disabled status once any result event is received about the outcome of the action. Result events are: [success][success], [error][error], [cancel][cancel]. + +```json +{ + "tag": "bk-button", + "properties": { + "loadingOnAction": true, + "action": { + "type": "http", + "config": { + "url": "/orders-count", + "method": "GET" + } + } + } +} +``` + +For actions of type `http` and `file-upload`, result events are emitted by the Button itself. This virtually ensures that the Button exists loading/disabled state, +provided a response is received. +However, for actions of type `event`, result events are not emitted by the Button itself, but rather rely on other components to do so - typically client components, like the [Crud Client][bk-crud-client]. Generally, clients emit result events after performing HTTP requests. + +Consequently, in order to avoid entering loading/disabled status without ever leaving it, a Button that emits events should only use `loadingOnAction` or `disableOnAction` if a following result event is eventually triggered - that is, if the button sends events that trigger an HTTP call from clients. +For instance, [create-data][create-data], [update-data][update-data], [delete-data][delete-data] eventually trigger the CRUD client to emit result events, allowing the Button to exit loading/disabled state. + +## Examples + +### Example: Basic Usage + +The Button can be configured to execute multiple types of [Back-kit Actions][action], and [combine them][action-hooks]. + +Example of a Button that executes as HTTP call: +```json +{ + "tag": "bk-button", + "properties": { + "content": "Count Orders", + "loadingOnAction": true, + "action": { + "type": "http", + "config": { + "url": "/orders-count", + "method": "GET" + } + } + } +} +``` + +Example of a Button that notifies the need for item creation via event: +```json +{ + "tag": "bk-button", + "properties": { + "content": "Create New Item", + "action": { + "type": "event", + "config": { + "events": { + "label": "add-new", + "payload": {} + } + } + } + } +} +``` + +Example of a Button that navigates to a given `href`: +```json +{ + "tag": "bk-button", + "properties": { + "content": "Go To Customers", + "action": { + "type": "href", + "config": { + "href": "/cutomers-list" + } + } + } +} +``` + +Example of a Button that performs an HTTP call and, in case of successful response, navigates to a given `href`: +```json +{ + "tag": "bk-button", + "properties": { + "content": "Count orders and go to customers", + "action": { + "type": "http", + "config": { + "url": "/orders-count", + "method": "GET" + } + }, + "hooks": { + "onSuccess": { + "type": "href", + "config": { + "href": "/cutomers-list" + } + } + } + } +} +``` + +### Example: Use Data from URL + +The Button component can use `urlMask` property to extract information from the current page URL, and inject it as [context](#context) when resolving dynamic references from its action configuration. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Add to chart", + "urlMask": "/order-details/:id", + "action": { + "type": "http", + "config": { + "url": "/chart", + "method": "POST", + "body": { + "id": "{{pathnameParams.params.id}}" + } + } + } + } +} +``` +The resulting component is a button that, on click, performs a POST request to "/chart", with body containing information extracted from the current page URL and from the information of the currently logged user. +Assuming the URL to be "/order-details/order-id-1", then body of the POST request will be: +```json +{ + "id": "order-details-1" +} +``` + +#### Pathname vs Query + +It is also possible to specify different masks for pathname and query portions of the URL. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Add To Chart", + "urlMask": { + "pathname": "order-details/:id", + "search": "\\?color=:myColor" + }, + "action": { + "type": "http", + "config": { + "url": "/chart", + "payload": { + "orderId": "{{pathnameParams.params.id}}", + "color": "{{searchParams.params.myColor}}" + } + } + } + } +} +``` +Assuming the URL to be "/order-details/order-id-1?color=red", then body of the POST request will be: +```json +{ + "orderId": "order-details-1", + "color": "red" +} +``` + +### Example: Inside Table + +One common use case of the Button component is to be used as action buttons inside other components, such as the [Table][bk-table] component. +The Table renders all action buttons in every rows of the table, and injects the object representation of the corresponding row as extra [context](#context) for the Button, retrievable via the `args.[1]` keyword, which can be used when configuring the action via [handlebars][handlebars]. + +```json +{ + "args.[1]": {...}, // Corresponding row of the table + "args.[2]": ..., // Index of the row of the table +} +``` + +The following configuration renders a Button component which, on click, notifies the need to visualize / allow editing of the details of the corresponding row. +Technically: emits a [selected-data][selected-data] event with the corresponding table row as payload. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Edit", + "action": { + "type": "event", + "config": { + "events": { + "label": "selected-data", + "payload": "{{rawObject args.[1]}}" + } + } + } + } +} +``` + +:::info +[rawObject][helpers] is a helper keyword that prevents selected items from being stringified in the payload of the event. +::: + +The following button downloads a file from an endpoint that depends on the value of the `imageUrl` field of the corresponding table row: +```json +{ + "tag": "bk-button", + "properties": { + "content": "Download Image", + "action": { + "type": "file-download", + "config": { + "url": "/files/{{rawObject args.[1].imageUrl}}" + } + } + } +} +``` + +### Example: Nested objects + +The Button provides [context](#context) to retrieve information on the navigated nested objects through keywork `selectedParents`, which can thus be used within [handlebars][handlebars] to configure the Button action. + +Assuming a collection with three levels of nesting is being displayed in a component that allows navigating nesting objects (like the [Table][bk-table] component) + +``` +companies + - employees + - projects +``` + +```json +{ + "companies": { + "type": "array", + "items": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "employees": { + "type": "array", + "items": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "projects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": {"type": "string"}, + "description": {"type": "string"} + } + } + } + } + } + } + } + } + } +} +``` + +When navigating to the third nesting level (entering "projects"), `selectedParents` holds information about both the parent company and the parent employee. + +``` json +{ + "selectedParents.[0]": {...}, // selected company + "selectedParents.[1]": {...}, // selected employee +} +``` + +When at the "employees" nesting level, a Button for removing an employee from a company could be configured as: +```json +{ + "tag": "bk-button", + "properties": { + "content": "Remove from Company", + "action": { + "type": "http", + "config": { + "method": "DELETE", + "url": "/v2/companies/{{selectedParents.[0]._id}}/employees/{args.[1]._id}" + } + } + } +} +``` + +`selectedParents.[0]._id` is the _id field of company that was selected in the first nesting step, while `args.[1]._id` is how to [access the "_id" field of a row](#inside-table) in the Table component. + +### Example: Require confirmation + +The following button allows the user to upload a file to "/files" endpoint. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Confirm", + "action": { + "type": "file-upload", + "config": { + "url": "/files" + } + } + } +} +``` + +to require confirmation for this action, it should be wrapped in the payload of event [require-confirm][require-confirm]: + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Upload File", + "action": { + "type": "event", + "config": { + "events": { + "label": "require-confirm", // -> this opens the confirmation dialog-box + "payload": { + "content": "Are you sure you want to upload a new file?", // -> this is the message displayed by the dialog-box + "configOk": { // -> this is the OK button of the confirmation dialog-box: the "main action" delegated to this button + "tag": "bk-button", + "properties": { + "content": "Confirm", + "action": { + "type": "file-upload", + "config": { + "url": "/files" + } + } + } + } + } + } + } + } + } +} +``` + +If a component such as the [Confirmation Modal][bk-confirmation-modal] is included in the plugin, it will react to the [require-confirm][require-confirm] event emitted by the button on click, using the `configOk` key in the payload to determine what action should be executed upon confirmation. + +### Example: Bulk operations + +When items are selected in components such as the [Table][bk-table] or the [Gallery][bk-gallery], a Button with `bulkButton` property set to true will provide access to selected items in its configuration through the `selectedData` keywork. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Register to List", + "bulkButton": true, + "action": { + "type": "http", + "config": { + "url": "/v2/users/", + "method": "POST", + "body": "{{rawObject selectedData}}", + } + } + } +} +``` + +:::info +[rawObject][helpers] is a helper keyword that prevents selected items from being stringified in the body of the request. +::: + +### Example: Deselect items after action + +When items are selected in components such as the [Table][bk-table] or the [Gallery][bk-gallery], executing a bulk action from the Button might not trigger items de-selection. +It is possible to deselect them by piping a [change-query][change-query] event with an empty payload after the main action, using actions [hooks][action-hooks]. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Register to List", + "bulkButton": true, + "action": { + "type": "http", + "config": { + "url": "/v2/users/", + "method": "POST", + "body": "{{rawObject selectedData}}", + }, + "hooks": { + "onFinish": { + "type": "event", + "config": { + "events": { + "label": "change-query", + "payload": {} + } + } + } + } + } + } +} +``` + +### Example: Enter loading/disabled state during action + +```json +{ + "tag": "bk-button", + "properties": { + "loadingOnAction": true, + "action": { + "type": "http", + "config": { + "url": "/orders-count", + "method": "GET" + } + } + } +} +``` +Upon clicking the rendered button: + 1. the Burron enters loading state + 2. the Burron performs the http POST request + 3. the Burron emits a [success][success] or [error][error] event, depending on the result of the call + 4. the Burron dismisses loading state after listening to the result event emitted by itself in the previous step + +### Example: Loading with action chaining + +A Button can be configured to execute multiple using [action hooks][action-hooks]. The following example shows a Button that chains two actions on click: + - sends an GET request to "/order-metadata" + - then, once a response is received, emits a [create-data][create-data] event. + +Properties `loadingOnAction` and `disableOnAction` cause the Button to enter loading/disabled state once for each chained action of type `events`, `http`, `file-upload`. + +```json +{ + { + "tag": "bk-button", + "properties": { + "content": "Count orders and create data", + "loadingOnAction": true, + "action": { + "type": "http", + "config": { + "url": "/order-metadata", + "method": "GET" + }, + "hooks": { + "onFinish": { + "type": "event", + "config": { + "events": { + "label": "create-data", + "payload": { + "name": "New Order", + "price": 150 + } + } + } + } + } + } + } + } +} +``` + +with such configuration, if the [CRUD Client][bk-crud-client] component is included in the plugin, the Button enters loading state twice when clicked, once for each chained action. +The full flow can be broken down as follows. Upon clicking: + + 1. the Button enters loading state + 2. the Button performs the http POST request + 3. the Button emits a [success][success] or [error][error] event, depending on the result of the call + 4. the Button dismisses loading state after listening to the result event emitted by itself on step 3 + 5. the Button emits an event with label `create-data` and specified payload, and parallely newly enters loading state + 6. the CRUD Client listens to the `create-data` event, which triggers its own flow to create a new item + 7. the CRUD Client emits a [success][success] or [error][error] event depending on the result of the item creation + 8. the Button dismisses loading state after listening to the event emitted by the CRUD Client on step 8 + +The Button thus enters and dismisses loading state twice. + +Please note that, in the case of actions of type `http`, the button itself emits a result event (step 3). As a consequence, the button's loading state will be appropriately terminated once a response is received. +On the contrary, actions of type `event` prompt a result event to be emitted from a distinct component (step 7). This implies that the button's successful exit from the loading state hinges on the reactions of other components to the event that is emitted. Therefore, when configuring the button's action, extra caution should be exercised. + + +## API + +### Properties & Attributes + +| property | attribute | type | default | description | +|----------|-----------|------|---------|-------------| +|`content`| - |[LocalizedText][localization]|{}|button content | +|`danger`|`danger`|boolean| - |danger flag | +|`disableOnAction`|`disable-on-action`|boolean|false|configures the button to be disabled while action is in progress | +|`disabled`|`disabled`|boolean|false|button disabled property | +|`iconId`|`icon-id`|string| - |defines which icon should be rendered into the button, if this property is not defined or doesn't match any icon no icon will be rendered | +|`iconPlacement`| - |"default" \| "left" \| "right"|"default"|defines where icon should be rendered, either left or right defaulting on left | +|`listenToLoadingData`|`listen-to-loading-data`|boolean|false|configures the button to be loading when trigger by a loading-data event | +|`loading`|`loading`|boolean|false|button loading property | +|`loadingDebounce`|`loading-debounce`|number|400|min time in milliseconds between loading swaps (when less it doesn't trigger `loading` rendering) | +|`loadingOnAction`|`loading-on-action`|boolean|false|configures the button to be loading while action is in progress | +|`navigationStrategy`| - |"disable" \| "hide"| - |determines the button behavior upon navigating nested objects. Allowed values are 'disable' and 'hide'. By default, the button does not react to navigation events. | +|`shape`|`shape`|string|'round'|button shape property. One of: 'default', 'circle', 'round' | +|`type`|`type`|string|'primary'|button type property. One of: 'primary', 'ghost', 'dashed', 'link', 'text', 'default' | +|`urlMask`|`url-mask`|[UrlMask][url-mask]|''|url mask to apply to the current path to extract dynamic parameters | +|`action`| - |[Action][action]| - | schema describing How to configure onClick event | +|`bulkButton`| - | boolean | false | whether to use it as a bulk button or not. If set to true, it listens to selected-data-bulk event | + +### Listens to + +| event | description | +|-------|-------------| +|[loading-data][loading-data]|enters loading state if property `listenToLoadingData` is set to true| +|[selected-data-bulk][selected-data-bulk]|keeps track of user selections if property `bulkButton` is set to true| +|[nested-navigation-state/back][nested-navigation-state/back]|keeps track of navigation steps| +|[nested-navigation-state/push][nested-navigation-state/push]|keeps track of navigation steps| + +### Emits + +| event | description | +|-------|-------------| +|configurable event|generic event configurable through the event type configuration| +|[error][error]|contains error messages for an http event| +|[success][success]|notifies a successful http request| diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/_category_.json b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/_category_.json new file mode 100644 index 0000000000..56132c1fca --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Components" +} diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-add-filter-button.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-add-filter-button.png new file mode 100644 index 0000000000..df06d4e473 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-add-filter-button.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-add-new-button.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-add-new-button.png new file mode 100644 index 0000000000..b9f2f65034 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-add-new-button.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-atlas-dashboard.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-atlas-dashboard.png new file mode 100644 index 0000000000..4be4a0947d Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-atlas-dashboard.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-auto-refresh.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-auto-refresh.png new file mode 100644 index 0000000000..c0eb46f9a2 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-auto-refresh.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-breadcrumbs.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-breadcrumbs.png new file mode 100644 index 0000000000..d49d8437f4 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-breadcrumbs.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-calendar.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-calendar.png new file mode 100644 index 0000000000..938bee2425 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-calendar.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-card.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-card.png new file mode 100644 index 0000000000..3ef054d402 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-card.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-chip.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-chip.png new file mode 100644 index 0000000000..9b770f653b Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-chip.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-confirmation-modal.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-confirmation-modal.png new file mode 100644 index 0000000000..2357bd8084 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-confirmation-modal.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-dropdown.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-dropdown.png new file mode 100644 index 0000000000..c58b2c5ca2 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-dropdown.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-export-modal.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-export-modal.png new file mode 100644 index 0000000000..b361c73c93 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-export-modal.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-filter-drawer.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-filter-drawer.png new file mode 100644 index 0000000000..efa9fccfb6 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-filter-drawer.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-footer.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-footer.png new file mode 100644 index 0000000000..ed4f5ecf4b Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-footer.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-card.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-card.png new file mode 100644 index 0000000000..9b92ce0cdd Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-card.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-drawer.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-drawer.png new file mode 100644 index 0000000000..f94b911e5a Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-drawer.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal-object-as-editor.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal-object-as-editor.png new file mode 100644 index 0000000000..3417a57664 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal-object-as-editor.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal-object-as-table.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal-object-as-table.png new file mode 100644 index 0000000000..5752201f58 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal-object-as-table.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal.png new file mode 100644 index 0000000000..596945070a Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-form-modal.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-gallery.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-gallery.png new file mode 100644 index 0000000000..d4f1ae2c17 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-gallery.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-fixedSideBar.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-fixedSideBar.png new file mode 100644 index 0000000000..5480cae1af Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-fixedSideBar.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-leftMenu.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-leftMenu.png new file mode 100644 index 0000000000..d58c5395d3 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-leftMenu.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-overlaySideBar.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-overlaySideBar.png new file mode 100644 index 0000000000..610d03bc03 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-overlaySideBar.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-topBar.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-topBar.png new file mode 100644 index 0000000000..f783811752 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout-topBar.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout.png new file mode 100644 index 0000000000..7b1371a327 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-layout.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-navigation-back-arrow.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-navigation-back-arrow.png new file mode 100644 index 0000000000..89b2e7aab6 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-navigation-back-arrow.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-notification-center.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-notification-center.png new file mode 100644 index 0000000000..d4b4d3fb4f Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-notification-center.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-notifications.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-notifications.png new file mode 100644 index 0000000000..33424fc188 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-notifications.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pagination-buttonsOnly.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pagination-buttonsOnly.png new file mode 100644 index 0000000000..a811b838f3 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pagination-buttonsOnly.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pagination.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pagination.png new file mode 100644 index 0000000000..458bb85dc4 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pagination.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pdf-viewer.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pdf-viewer.png new file mode 100644 index 0000000000..4f8b60b778 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-pdf-viewer.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-refresh-button.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-refresh-button.png new file mode 100644 index 0000000000..d752164f32 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-refresh-button.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-search-bar.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-search-bar.png new file mode 100644 index 0000000000..2074ba7597 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-search-bar.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-simple-list.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-simple-list.png new file mode 100644 index 0000000000..19987b28ac Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-simple-list.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-table.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-table.png new file mode 100644 index 0000000000..953baf92ec Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-table.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-tabs.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-tabs.png new file mode 100644 index 0000000000..cf26cb603c Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-tabs.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-title.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-title.png new file mode 100644 index 0000000000..614c1c34c4 Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/bk-title.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/card-header.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/card-header.png new file mode 100644 index 0000000000..405fb8a99a Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/card-header.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/wizard-form-modal-accordion.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/wizard-form-modal-accordion.png new file mode 100644 index 0000000000..b0314a974b Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/wizard-form-modal-accordion.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/wizard-form-modal.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/wizard-form-modal.png new file mode 100644 index 0000000000..f6fbfccecc Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/60_components/img/wizard-form-modal.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/70_events.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/70_events.md new file mode 100644 index 0000000000..363b5d290c --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/70_events.md @@ -0,0 +1,1227 @@ +--- +id: events +title: Back-Kit Events +sidebar_label: Events +--- + + + +[files-service]: /runtime-components/plugins/files-service/configuration.mdx +[file]: https://developer.mozilla.org/en-US/docs/Web/API/File + + + +`Events` are data structures sent into a communication channel to enable `event-driven` component behavior. They extend an `any` object and they come as + +```typescript +type Event = { + label: string + payload: P + meta?: M +} +``` + +where `label` is a unique string identifying the event such as `"create-data"` or `"delete-file"`, `payload` contains transactional data and `meta` other data with extra information like what action triggered this event, a transaction ID if there's any and so on. + +To create a new `event` within `src/events` there's a `factory` method which is a generic function that takes the `P` and `M` types with the `label` + +```typescript +export function factory

( + label: string, options: FactoryOptions = {} +): Factory { + ... +} +``` + +This function generates a function with hybrid prototype that contains: + +1. an **event generator** +2. a **predicate** `.is(` to check whether an event was made with the current generator +3. a **label** which returns the generator and its spawned events label + +for instance + +```typescript +const addNew = factory>('add-new') + +const addNewEvent = addNew({}) + +expect(addNew.is(addNewEvent)).toBeTruthy() +expect(addNew.label).toStrictlyEqual('add-new') +``` + +There's also the concept of a `register` which automatically adds event is on factory call the constant + +``` typescript +const REGISTERED = true +``` + +is provided. In that case, `src/events/eventRegister.ts` exports an `eventBuilderRegister` map that contains only registered event generators. It has an `.add(` method which is `idempotent` on a factory with the same label already contained in the register. + +An `eventBus` conforming event is an object like + +```typescript +{ + label: string, + payload: object, + meta: object, +} +``` + +- `label` is a unique event identifier. Standard Back-kit events are always kebab-case idiomatic strings, +- `payload` is an object, possibly empty, +- `meta` helps to keep track of transaction states or enhance event scoping. Meta is not required and its value might be an empty object. + +For instance an `upload-file` event looks like: + +```typescript +{ + label: "upload-file", + payload: { + file: { + lastModified: 1627457290180, + lastModifiedDate: "Wed Jul 28 2021 09:28:10 GMT+0200 (Central European Summer Time)", + name: "file.pdf", + size: "9090", + type: "application/json", + uid: "rc-upload-1630930409639-3" + } + }, + meta: { + transactionId: "97de9662-70aa-48a0-bdee-25113fc66c8f" + } +} +``` + + +## A + +### Add Filter + +delivers data to add a new filter + + +- Label: `add-filter` +- Payload: + +```typescript +{ + operator: + | "equal" + | "exists" + | "notEqual" + | "greater" + | "greaterEqual" + | "less" + | "lessEqual" + | "regex" + | "includeSome" + | "includeAll" + | "includeExactly" + | "notIncludeAny" + | "between" + | "notBetween" + | "hasLengthEqual" + | "hasLengthGreaterEqual" + | "hasLengthLessEqual" + property: string + value: string | number | boolean | any[] + applied?: boolean + name: string +} +``` + +- Meta: + +```typescript +{ + hash: string +} +``` + +### Add New + +notifies adding a new item + + +- Label: `add-new` +- Payload: + +```typescript +{ + [key: string]: any +} +``` + +### Add New External + +notifies adding a new item on an external collection + + +- Label: `add-new-external` +- Payload: + +```typescript +{ + [key: string]: any +} +``` + + + +## B + +### Bulk update - Boolean and Enums + +allows to modify enums or boolean values from an array of items + + +- Label: `bulk-update` +- Payload: + +```typescript +{ + data: { + [key: string]: any + }[] + changes: { + [key: string]: string | boolean + }[] +} +``` + + + +## C + +### Cancel + +notifies operation abort via a given transactionId + + +- Label: `event-bus-cancel` +- Payload: + +```typescript +{} +``` + +- Meta: + +```typescript +{ + transactionId: string +} +``` + +### Change Filter + +delivers data on an edited filter + + +- Label: `change-filter` +- Payload: + +```typescript +{ + operator: + | "equal" + | "notEqual" + | "greater" + | "greaterEqual" + | "less" + | "lessEqual" + | "regex" + | "includeSome" + | "includeAll" + | "includeExactly" + | "notIncludeAny" + | "between" + | "hasLengthEqual" + | "hasLengthGreaterEqual" + | "hasLengthLessEqual" + property: string + value: string | number | boolean | any[] + applied?: boolean + name: string +} +``` + +### Change Query + +requires a modification of the currently viewed dataset (filtering, sorting, paging) + + +- Label: `change-query` +- Payload: + +```typescript +{ + characteristic?: string + pageNumber?: number + pageSize?: number + search?: string + sortDirection?: SortDirection + sortProperty?: string + filters?: { + operator: + | "equal" + | "notEqual" + | "greater" + | "greaterEqual" + | "less" + | "lessEqual" + | "regex" + | "includeSome" + | "includeAll" + | "includeExactly" + | "notIncludeAny" + | "between" + | "hasLengthEqual" + | "hasLengthGreaterEqual" + | "hasLengthLessEqual" + property: string + value: string | number | boolean | any[] + applied?: boolean + name: string + }[] +} +``` + +### Close Modal + +closes a modal + + +- Label: `close-modal` +- Payload: + +```typescript +{ + modalId: string +} +``` + +- Meta: + +```typescript +{ + sessionId?: string +} +``` + +### Count Data + +sends count and pagination of current dataset + + +- Label: `count-data` +- Payload: + +```typescript +{ + total: number + pageSize: number + pageNumber: number +} +``` + +### Create Data + +notifies the request for creation of a new item and carries its value + + +- Label: `create-data` +- Payload: + +```typescript +{ + [key: string]: any +} +``` + +### Create Data With File + +create data that have one or more files within their properties, + the current file property is set into meta + + +- Label: `create-data-with-file` +- Payload: + +```typescript +{ + data: { + [key: string]: any + } +} +``` + +- Meta: + +```typescript +{ + property: string +} +``` + + + +## D + +### Delete Data + +notifies the request for deletion of an item + + +- Label: `delete-data` +- Payload: + +```typescript +{ + [key: string]: any +} +| { + [key: string]: any +}[] +``` + +### Delete File + +notifies that a given file, identified by its unique id, must be deleted + + +- Label: `delete-file` +- Payload: + +```typescript +{ + file: string +} +``` + +- Meta: + +```typescript +{ + transactionId: string +} +``` + +### Deleted File + +notifies that a given file was deleted, carries a transaction ID to rollback + + +- Label: `deleted-file` +- Payload: + +```typescript +{ + [key: string]: any +} +``` + +- Meta: + +```typescript +{ + transactionId: string +} +``` + +### Display Data + +carries a dataset + + +- Label: `display-data` +- Payload: + +```typescript +{ + data: any +} +``` + +### Download File + +notifies that a given file must be downloaded. Payload could be either the file identifier or a structure that contains it. In the latter case, the object property to find the file must be set into the meta. It carries transaction ID to rollback. Allows to request in-browser view of the file. + + +- Label: `download-file` +- Payload: + +```typescript +{ + file?: string + [key: string]: any +} +``` + +- Meta: + +```typescript +{ + transactionId?: string + property?: string + showInViewer?: boolean | "skip-checks" +} +``` + +### Downloaded File + +notifies that a given file was downloaded, carries a transaction ID to rollback + + +- Label: `downloaded-file` +- Payload: + +```typescript +{ + file: string +} +``` + +- Meta: + +```typescript +{ + transactionId: string +} +``` + +### Duplicate Data + +notifies the request for duplication of an item and carries its value + + +- Label: `duplicate-data` +- Payload: + +```typescript +{ + [key: string]: any +} +``` + + + +## E + +### Error + +notifies a generic error event + + +- Label: `error` +- Payload: + +```typescript +{ + error: any +} +``` + +- Meta: + +```typescript +{ + triggeredBy: string + transactionId: string +} +``` + +### Export Data + +raised when the export button is clicked + + +- Label: `export-data` +- Payload: + +```typescript +{} +``` + +### Export Data - Request Config + +prompts for export configuration payload + + +- Label: `awaiting-for-export-configuration` +- Payload: + +```typescript +{ + total?: number + selected?: number + columns: { + label: string + value: T + }[] +} +``` + +- Meta: + +```typescript +{ + transactionId?: string +} +``` + +### Export Data - User Config + +sends user configuration payload to perform export + + +- Label: `export-user-config` +- Payload: + +```typescript +{ + exportType: "json" | "csv" | "html" | "xlsx" + csvSeparator?: "COMMA" | "SEMICOLON" + filters: "all" | "filtered" | "selected" + columns: string[] + columnName: "id" | "label" + dateFormat: string + timezone: string +} +``` + +- Meta: + +```typescript +{ + transactionId?: string +} +``` + + + +## F + +### Fetch Files + +notifies to requests to fetch files + + +- Label: `fetch-files` +- Payload: + +```typescript +{ + limit?: string | number + page?: string | number + dateFrom?: string +} +``` + +- Meta: + +```typescript +{ + transactionId?: string +} +``` + +### Fetched Files + +carries result of files fetching operation + + +- Label: `fetched-files` +- Payload: + +```typescript +{ + files: { + [key: string]: unknown + }[] +} +``` + +- Meta: + +```typescript +{ + transactionId?: string +} +``` + +### Filter + +notifies opening of UI component that handles form creation + + +- Label: `filter` +- Payload: + +```typescript +{} +``` + + + +## H + +### Http Delete + +notifies the request for permanent deletion of an item + + +- Label: `http-delete` +- Payload: + +```typescript +{ + [key: string]: any +} +| { + [key: string]: any +}[] +``` + + + +## I + +### Import Data + +raised when the import button is clicked + + +- Label: `import-data` +- Payload: + +```typescript +{} +``` + +### Import Data - User Config + +sends user configuration payload to perform import + + +- Label: `import-data/user-config` +- Payload: + +```typescript +{ + file: File + encoding?: "utf8" | "ucs2" | "utf16le" | "latin1" | "ascii" | "base64" | "hex" + delimiter?: string + escape?: string +} +``` + + + +## L + +### Layout Change + +requires a layout change from `bk-layout-container` + + +- Label: `layout-change` +- Payload: + +```typescript +{ + layout: string +} +``` + +### Link File To Record + +sends file upload data + + +- Label: `link-file-to-record` +- Payload: + +```typescript +{ + data: { + [key: string]: any + } +} +``` + +- Meta: + +```typescript +{ + property: string +} +``` + +### Loading Data + +notifies whether dataset is loading or not. + It also advices that a dataset may be inbound + + +- Label: `loading-data` +- Payload: + +```typescript +{ + loading: boolean +} +``` + +### Lookup Data + +carries lookup data information and dataset + + +- Label: `lookup-data` +- Payload: + +```typescript +{ + [key: string]: any[] +} +``` + +- Meta: + +```typescript +{ + dataOrigin?: string +} +``` + +### Lookup Live Found + +fired when options for a Select form input are found + + +- Label: `lookup-live-found` +- Payload: + +```typescript +{ + [key: string]: any[] +} +``` + +### Lookup Live Searching + +fired upon searching on a Select form input + + +- Label: `lookup-live-searching` +- Payload: + +```typescript +{ + property: string + input: string +} +``` + +- Meta: + +```typescript +{ + limit: number + input: { + [key: string]: any[] + } + currentValues?: any[] + keys?: string[] +} +``` + + + +## N + +### Nested Navigation State - Display + +displays data or a slice of data + + +- Label: `display-state` +- Payload: + +```typescript +Array<{ + data: Record[] + from?: number + to?: number + sort?: number[] +}> +``` + +- Meta: + +```typescript +{ + keys?: string[] +} +``` + +### Nested Navigation State - Go Back + +goes back an arbitrary number of levels of nesting + + +- Label: `back-state` +- Payload: + +```typescript +{ + steps?: number +} +``` + +### Nested Navigation State - Push + +adds a new level of nesting + + +- Label: `push-state` +- Payload: + +```typescript +{ + data: Record[] + origin: Record + selectedKey?: string +} +``` + + + +## O + +### Open Modal + +opens a modal + + +- Label: `open-modal` +- Payload: + +```typescript +{ + modalId: string +} +``` + +- Meta: + +```typescript +{ + sessionId?: string +} +``` + + + +## R + +### Require Confirm + +Signals that a certain action requires confirmation to be performed + + +- Label: `require-confirm` +- Payload: + +```typescript +{ + cancelText?: LocalizedText + content?: LocalizedText + okText?: LocalizedText + onCancel?: () => {} + onOk?: () => {} + title?: LocalizedText + configOk?: { + tag: string + properties?: Record + children?: string | ReactNode + } + configCancel?: { + tag: string + properties?: Record + children?: string | ReactNode + } +} +``` + + + +## S + +### Search Lookups + +notifies that all lookups having `excludeFromSearch` set to false should be searched against a value + + +- Label: `search-lookups` +- Payload: + +```typescript +{ + input: string +} +``` + +- Meta: + +```typescript +{ + limit: number +} +``` + +### Search Lookups Found + +fired when values from a text search for lookups are found + + +- Label: `search-lookups-found` +- Payload: + +```typescript +{ + [key: string]: any[] +} +``` + +- Meta: + +```typescript +{ + input: string +} +``` + +### Selected Data + +notifies that a single datum has been selected from a dataset + + +- Label: `selected-data` +- Payload: + +```typescript +{ + data: { + [key: string]: any + } +} +``` + +### Selected Data Bulk + +notifies data selection in a dataset + + +- Label: `selected-data-bulk` +- Payload: + +```typescript +{ + data: Array<{ + [key: string]: any + }> +} +``` + +### Show In Viewer + +notifies the request for starting/updating the visualization of a PDF file + + +- Label: `show-in-viewer` +- Payload: + +```typescript +{ + show: boolean + url: string +} +``` + +### Submit Form - Request + +requests submission of form + + +- Label: `submit-form-request` +- Payload: + +```typescript +{} +``` + +- Meta: + +```typescript +{ + openingEvent: string + formId: string +} +``` + +### Submit Form - Success + +notifies correct submission of form + + +- Label: `submit-form-success` +- Payload: + +```typescript +{} +``` + +- Meta: + +```typescript +{ + transactionId?: string +} +``` + +### Success + +notifies a successful action + + +- Label: `success` +- Payload: + +```typescript +{} +``` + +- Meta: + +```typescript +{ + triggeredBy: string + transactionId: string +} +``` + + + +## U + +### Update Data + +notifies the request for creation of a new item and carries its value + + +- Label: `update-data` +- Payload: + +```typescript +{ + [key: string]: any +} +| { + [key: string]: any +}[] +``` + +- Meta: + +```typescript +{ + transactionId: string +} +``` + +### Update Data With File + +update data that have one or more files within their properties, +the current file property is set into meta + + +- Label: `update-data-with-file` +- Payload: + +```typescript +{ + data: { + [key: string]: any + } +} +``` + +- Meta: + +```typescript +{ + property: string +} +``` + +### Update State Bulk + +updates multiple data state (__STATE__ or _st) in a dataset + + +- Label: `update-state-bulk` +- Payload: + +```typescript +{ + rows: any[] + newState: string +} +``` + +### Upload File + +requests the upload of a file and carries its data. + + +- Label: `upload-file` +- Payload: + +```typescript + +``` + +### Uploaded File + +returns file upload metadata, typically when storing on an external service like [files-service] + + +- Label: `uploaded-file` +- Payload: + +```typescript +{ + _id: string + name: string + file: string + size: number + location: string +} +``` + +### Using Form Container + +notifies that a form container with given ID is currently in use + + +- Label: `using-form-container` +- Payload: + +```typescript +{ + id: string +} +``` diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/10_file_management.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/10_file_management.md new file mode 100644 index 0000000000..fa829b7c93 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/10_file_management.md @@ -0,0 +1,467 @@ +--- +id: file_management +title: File Management +sidebar_label: File management +--- + + + +[files-service]: /runtime-components/plugins/files-service/configuration.mdx +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[file-interface]: https://developer.mozilla.org/en-US/docs/Web/API/File +[xmlhttprequest]: https://developer.mozilla.org/docs/Web/API/XMLHttpRequest +[syntax]: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept + +[actions]: /products/microfrontend-composer/back-kit/50_actions.md +[action-hooks]: /products/microfrontend-composer/back-kit/50_actions.md#action-chaining + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-gallery]: /products/microfrontend-composer/back-kit/60_components/370_gallery.md +[bk-file-client]: /products/microfrontend-composer/back-kit/60_components/290_file_service_client.md +[bk-file-manager]: /products/microfrontend-composer/back-kit/60_components/260_file_manager.md +[bk-dynamic-form-modal]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md +[bk-dynamic-form-drawer]: /products/microfrontend-composer/back-kit/60_components/200_dynamic_form_drawer.md +[bk-file-picker-drawer]: /products/microfrontend-composer/back-kit/60_components/270_file_picker_drawer.md +[bk-file-picker-modal]: /products/microfrontend-composer/back-kit/60_components/280_file_picker_modal.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[create-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#create-data-with-file +[update-data-with-file]: /products/microfrontend-composer/back-kit/70_events.md#update-data-with-file +[upload-file]: /products/microfrontend-composer/back-kit/70_events.md#upload-file +[uploaded-file]: /products/microfrontend-composer/back-kit/70_events.md#uploaded-file +[create-data]: /products/microfrontend-composer/back-kit/70_events.md#create-data +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#update-data + + + +In Back-Kit library upload and management of files related to records is handled by three components that interact together: + +- [File Service Client][bk-file-client] +- [File Manager][bk-file-manager] +- a data manipulation component that allows to interact with file fields, for instance: + - [Form Dynamic Drawer][bk-dynamic-form-drawer] + - [Form Dynamic Modal][bk-dynamic-form-modal] + - [File Picker Drawer][bk-file-picker-drawer] + - [File Picker Modal][bk-file-picker-modal] + + +These components are designed to interact with [Mia Platform's Files Service][files-service], particularly the File Service Client operates as a client for the service. + +## File Fields + +In addition to acting as a file storage service, the Files Service manages a collection of the [CRUD Service][crud-service], where metadata related to file storage is stored.\ +A typical CRUD Service collection associated with a Files Service would include fields like: + +```json +{ + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, + "size": { + "type": "number" + }, + "location": { + "type": "string" + } +} +``` + +Back-Kit components that handle data from CRUD Service collections and interact with file fields expect values of file fields to be in an object (or an array of objects) following the schema mentioned above. + +File properties can be specified in the [data schema][data-schema] as: + +``` json +{ + "type": "object", + "format": "file" +} +``` +or +``` json +{ + "type": "array", + "format": "file" +} +``` + +## File Upload with a Back-Kit Action + +It is possible to upload a file using a [Back-Kit Action][actions] of type `file-upload`. + +This enables the user to pick a file from the local file system through the native upload dialog of the browser, +which is injected in the body of a `POST` called using [XMLHTTPRequest][xmlhttprequest] facility. + +Any component that implement the `Back-Kit Action` interface, for instance the [Button][bk-button] component, can be configured to perform a `file-upload` action. + +Configuring the `file-upload` action to call the endpoint of a [Files Service][files-service] is possible. + +An [example](#example-visualize-files) is available in which the [Gallery][bk-gallery] is used in conjunction with the [Button][bk-button] to visualize the [CRUD Service][crud-service] collection linked to a Files Service instance. + +## File Upload with form components + +Once a file property is specified in the data schema and its form field is modified (e.g., using a Dynamic Form Drawer), the following routine is followed: + + 1. The Dynamic Form Drawer notifies that a data item should be created/updated containing file fields (i.e., triggers a [create-data-with-file] or an [update-data-with-file] event). The emitted event provides information on which fields include files that should be uploaded. + 2. The File Manager handles the above event and requests the upload of each file to a storage service by firing an [upload-file] event for each file. + 3. The File Service Client processes the `upload-file` event by making HTTP calls to the Files Service to request the storage of the files. Upon success, the Files Service provides a response containing storage metadata about the newly uploaded file. The File Service Client then fires an [uploaded-file] event, containing this metadata. + 4. The File Manager listens for `uploaded-file` events and maintains a copy of the data item created or updated by the Dynamic Form Drawer in step 1, replacing the values of file fields with the returned storage metadata information. + 5. Once all files have been uploaded and the data item has been appropriately updated, the File Manager proceeds to request data creation/update by emitting a [create-data] or an [update-data] event. The payload sent in this event contains the fully edited data items, ensuring that the file fields now include the file storage metadata provided in step 3 instead of the actual file. + + +The process is exemplified [below](#example-upload-file-using-form-component). + +:::caution +Upon failure while uploading one file, any new file that was being uploaded in the same transaction will be deleted, even if already uploaded, +since the final create/update of the record will not be performed +::: + +:::caution +By design, any file that is unlinked from the record when updating an entry, isn't deleted from the file-service +::: + +## Custom Metadata + +File fields may present a data-schema. This is used to describe the fields that are included in the field, and allows to specify custom fields other than the [default storage metadata information](#file-fields). + +Components like the [Form Dynamic Drawer][bk-dynamic-form-drawer], the [Form Dynamic Modal][bk-dynamic-form-modal], the [File Picker Drawer][bk-file-picker-drawer], the [File Picker Modal][bk-file-picker-modal] allow to visualize and edit metadata fields of type string. + + +``` json +{ + "type": "object", + "format": "file", + "dataSchema": { + "type": "object", + "properties": { + "ownerId": { + "type": "string" + } + } + } +} +``` + +``` json +{ + "type": "array", + "format": "file", + "items": { + "type": "object", + "properties": { + "ownerId": { + "type": "string" + } + } + } +} +``` + +## Examples + +### Example: Upload a file using form components + +Assuming a plugin to include the following components: + +- a [Dynamic Form Drawer][bk-dynamic-form-drawer] + ```json + { + "tag": "bk-dynamic-form-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "image": { + "type": "object", + "format": "file" + } + } + } + } + } + ``` + +- a [File Manager][bk-file-manager] + ```json + { + "tag": "bk-file-manager" + } + ``` + +- a [File Service Client][bk-file-client] like + ```json + { + "tag": "bk-file-client", + "properties": { + "basePath": "/files", + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "image": { + "type": "object", + "format": "file" + } + } + } + } + } + ``` + +- a [CRUD Client][bk-crud-client] like + ```json + { + "tag": "bk-crud-client", + "properties": { + "basePath": "/v2/customers", + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "image": { + "type": "object", + "format": "file" + } + } + } + } + } + ``` + +The Dynamic Form Drawer allows the user to request the creation of a new data item, specifying values for fields "name" and "image". Upon submission, it emits an [create-data-with-file] event.\ +The payload of such event could look like: + +```json +{ + "name": "Alexander", + "image": ... // profile.jpg +} +``` + + +Field "image" stores the a [File][file-interface] object uploaded by the user. + + +The meta of the event: +```json +{ + "property": "image" +} +``` + +indicating what property within the event payload includes the file to upload to a storage service. + + +The File Manager listens to the event, retrieves the file to upload using the event payload and meta, and fires an [upload-file] event with payload like: + +```json +{ + "file": ... // profile.jpg +} +``` + +signaling the need to upload the file to a storage service. + +The File Service Client handles `upload-file` events, and consequently performs HTTP requests to a backend instance of [Mia Platform's Files Service][files-service]. + +Following up on the example, the File Service Client emits a POST call to the endpoint "/files" (as specified in the `basePath` property) +with a multipart body that includes the file to upload, like: + +``` +------WebKitFormBoundary5gRZNaxFPGnBKUaI +Content-Disposition: form-data; name="file"; filename="profile.jpg" +Content-Type: image/jpg + + +------WebKitFormBoundary5gRZNaxFPGnBKUaI-- +``` + +Assuming the POST to be successful and the Files Service to respond with the storage metadata of the uploaded file, +then the File Service Client notifies the correct upload of the file by emitting an [uploaded-file] event, +injecting the received response in its payload, like: + +```json +{ + "_id": "fileId7212704772008143", + "file": "profile.jpg", + "location": "/v2/files/download/profile.jpg", + "name": "profile.jpg", + "size": 3992 +} +``` + +The File Manager listens to the `uploaded-file` event, using its payload to update the content of the received data from the initial `create-data-with-file` event.\ +The resulting object is injected in the payload of an [create-data] event, like: + +```json +{ + "name": "Alexander", + "image": { + "_id": "fileId7212704772008143", + "file": "profile.jpg", + "location": "/v2/files/download/profile.jpg", + "name": "profile.jpg", + "size": 3992 + } +} +``` + +The CRUD Client listens to such an event, triggering a POST call to be performed to the [CRUD Service][crud-service], requesting the creation of the data item. + +### Example: Visualize Files + +It is possible to visualize the [CRUD Service][crud-service] collection of image files linked to a [Files Service][files-service] instance using a [Gallery][bk-gallery], a [CRUD Client][bk-crud-client], and a [Button][bk-button]. + +Assuming the Files Service to be reachable at "/files" and the CRUD Service collection to be: + +```json +{ + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, + "size": { + "type": "number" + }, + "location": { + "type": "string" + } +} +``` + +And the components to be configured like: + +- Gallery: + ```json + { + "tag": "bk-gallery", + "properties": { + "thumbnailSource": "location", + "titleSource": "name", + "subTitleSource": "file" + } + } + ``` + +- CRUD Client: + ```json + { + "tag": "bk-crud-client", + "properties": { + "basePath": "/files", + "dataSchema": { + "type": "object", + "properties": { + "_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, + "size": { + "type": "number" + }, + "location": { + "type": "string" + } + } + } + } + } + ``` + +- Button: + ```json + { + "tag": "bk-button", + "properties": { + "content": "Upload File", + "iconId": "UploadOutlined", + "action": { + "type": "file-upload", + "config": { + "url": "/files/" + } + } + } + } + ``` + +The Gallery renders an item for each entry of the collection, retrieving the image source form the "location" field, and displaying the fields "name" and "file" in the footer. + +The Button allows to perform a file upload operation towards "/files/". Doing so, the Files Service stores the file to a storage service, while adding a new entry to the CRUD Service collection. + +The CRUD Client is included to fetch the items of the collection to visualize. + +:::info +In order to automatically reload the plugin after uploading the file, an `onSuccess` [hook][action-hooks] can be used to chain a page refresh upon successful file upload. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Upload File", + "iconId": "UploadOutlined", + "action": { + "type": "file-upload", + "config": { + "url": "/files" + }, + "hooks": { + "onSuccess": { + "type": "event", + "config": { + "events": "change-query" + } + } + } + } + } +} +``` + +Emitting an empty [change-query] event is equivalent to refreshing the page if the CRUD Client is included in the configuration. +::: + +:::info +To ensure that only image files can be uploaded by the user through the `file-upload` action, field `accept` is available. Property `accept` follows the [syntax] that is used by the `input` html-element. + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Upload File", + "iconId": "UploadOutlined", + "action": { + "type": "file-upload", + "config": { + "url": "/files", + "accept": "image/png, image/jpeg" + } + } + } +} +``` +::: diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/20_nested_data.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/20_nested_data.md new file mode 100644 index 0000000000..9f628e9bbd --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/20_nested_data.md @@ -0,0 +1,624 @@ +--- +id: nested_data +title: Nested Data +sidebar_label: Nested data +--- + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[schema-formats]: /products/microfrontend-composer/back-kit/30_page_layout.md#formats +[form-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#form-options + +[bk-form-modal]: /products/microfrontend-composer/back-kit/60_components/350_form_modal.md +[bk-form-drawer]: /products/microfrontend-composer/back-kit/60_components/340_form_drawer.md +[bk-dynamic-form-modal]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md +[bk-dynamic-form-drawer]: /products/microfrontend-composer/back-kit/60_components/200_dynamic_form_drawer.md +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md +[bk-pagination]: /products/microfrontend-composer/back-kit/60_components/470_pagination.md +[bk-breadcrumbs]: /products/microfrontend-composer/back-kit/60_components/60_breadcrumbs.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-add-new-button]: /products/microfrontend-composer/back-kit/60_components/20_add_new_button.md +[bk-add-filter-button]: /products/microfrontend-composer/back-kit/60_components/10_add_filter_button.md +[bk-tabs]: /products/microfrontend-composer/back-kit/60_components/530_tabs.md +[bk-filter-drawer]: /products/microfrontend-composer/back-kit/60_components/300_filter_drawer.md +[bk-filters-manager]: /products/microfrontend-composer/back-kit/60_components/310_filters_manager.md + +[table-actions]: /products/microfrontend-composer/back-kit/60_components/520_table.md#actions + +[nested-navigation-state/push]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---push +[nested-navigation-state/back]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---back +[nested-navigation-state/display]: /products/microfrontend-composer/back-kit/70_events.md#nested-navigation-state---dispaly +[update-data]: /products/microfrontend-composer/back-kit/70_events.md#update-data +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data + + + +Some Back-Kit components are designed to handle nested data - that is, fields of type object or array of objects that specify a [data-schema]. +These components have a dedicated modality that allows the user to interact with nested data. +It is possible to request to enter or exit a nested field, allowing the user to navigate across nesting layers. + +```json +{ + "parent": { + "type": "object", + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "lastname": { + "type": "string" + } + } + } + }, + "children": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "dateOfBirth": { + "type": "string", + "format": "date" + }, + "school": { + "type": "string" + }, + "toys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": ["Sport", "Action Figure", "Table Game"] + }, + "price": { + "type": "number" + } + } + } + } + } + } + } +} +``` + +Nested data schemas support the same options that can be specified for a top level data schema. + +## Nested Fields in the Table and Forms + +Fields of type object or array that have a data-schema and no specific [format][schema-formats] are handled in a specific modality by components such as the [Table][bk-table], the [Dynamic Form Drawer][bk-dynamic-form-drawer], the [Dynamic Form Modal][bk-dynamic-form-modal], the [Form Modal][bk-form-modal], the [Form Drawer][bk-form-drawer]. + +The Table component allows to interact with cells corresponding to nested fields by clicking on them. +Doing so, the Table uses the schema of the field to interpret the data inside the cell, and re-renders itself to display that data. + +Analogously, the label of nested fields inside a Dynamic Form Drawer or Dynamic Form Modal is clickable. +Doing so has the same effect as clicking on the corresponding cell in the table. + +Components like the Table, the Dynamic Form Drawer, the Dynamic Form Modal keep an internal representation of the each nested field that was requested to be visualized, +and update their properties accordingly. + +From a technical point of view, clicking on a Table cell or a form label associated to nested data emits a [nested-navigation-state/push] event, which signals the request to enter the visualization of the nested data in question. + +The payload of the event includes information such as: + - the nested data + - the object that contains the nested data + - the id of the field with the nested data + - the index of the entered data within the array that includes it (if the nested field is an object, 0 is used) + - whether the entered nested data is an object or an array + - whether of not the nested data is to be considered read-only + +For instance: + ```json + { + "data": [{"name": "Bruce"}, {"name": "Will"}], + "origin": [ + {"floor": "0", "room": "100", "people": []}, + {"floor": "1", "room": "200", "people": [{"name": "Bruce"}, {"name": "Will"}]}, + {"floor": "1", "room": "201", "people": [{"name": "Robert"}]} + ], + "selectedKey": "people", + "rowIndex": 1, + "isObject": false, + "readonly": false + } + ``` + +While form components listen to `nested-navigation-state/push` events to determine how to update their properties in order to allow the user to interact with nested data, the Table also listens to event [nested-navigation-state/display], which also includes information on what portion of the nested data should be visualized. +This is to ensure that data pagination is also applied to nested data, consistently with the "first level" dataset. +The [Pagination][bk-pagination] component emits `nested-navigation-state/display` events as a reaction to `nested-navigation-state/push` events. + +:::caution +The [Pagination][bk-pagination] component should be included in the plugin in order to correctly visualize nested data with the [Table][bk-table]. +::: + +### Editing nested data + +Nested data can be edited by [Table][bk-table] and form components. + +Form components like the [Dynamic Form Drawer][bk-dynamic-form-drawer], the [Dynamic Form Modal][bk-dynamic-form-modal], the [Form Modal][bk-form-modal], the [Form Drawer][bk-form-drawer] allow to interact with nested data in the same way as "regular" data. + +Upon editing or creating a new value inside a nested field, the form components require, via an [update-data] event, the nested field to be edited within the corrensponding "starting" item of the collection. + +The Table allows editing nested data via [action buttons][table-actions]. +By default, the Table renders an action to delete a row of data inside a nested field. +This action triggers an [update-data] event, the nested field of the "starting" collection data item is requested to be updated. + +The `update-data` events are listened by components like the CRUD Client, which perform an HTTP request to a [CRUD Service][crud-service] to update the data item. If the request is successful, the CRUD Client emits a [display-data] event to propagate the newly updated data. + +This would normally trigger the Table to render such data, loosing this way the nested data visualization. +To avoid this behavior, the [Breadcrumbs][bk-breadcrumbs] component should be included in the page. +It listens to the `display-data` event, and consequently emits [nested-navigation-state/push] events to restore the nested visualization with the newly updated data. + +It is possible to add the `keepPageCount` property to the `bk-crud-client` component, set to true. It tries to stay on the current page after a successful CRUD operation. + +:::caution +The [Pagination][bk-pagination] and the [Breadcrumbs][bk-breadcrumbs] components should be included in the plugin configuration for the [Table][bk-table] component to work properly while editing nested fields. +::: + +An example of how nested data can be edited with a form component and a Table is [available](#example-editing-nested-data). + +## Limitations: filtering + +Nested data filtering is not currently supported by Back-Kit components. + +Thus, whenever the visualization of nested data is requested via a [nested-navigation-state/push] event: + - the [Add Filter Button][bk-add-filter-button] is disabled, + - the [Tabs][bk-tabs] components are not rendered, + - filtering components should not be used, like the [Filter Drawer][bk-filter-drawer] or the [Filters Manager][bk-filters-manager]. + +## Read-only nested data + +The payload of the [nested-navigation-state/push] event includes information on whenter the entered field is to be considered as read-only. +Several Back-Kit components are designed to handle read-only nested data. + +- the [Add New Button][bk-add-new-button] is disabled +- form components, like the [Dynamic Form Drawer][bk-dynamic-form-drawer], the [Dynamic Form Modal][bk-dynamic-form-modal], are opened in read-only mode +- the [Table][bk-table] default delete row action is not displayed + +To specify a property to be treated as read-only, the dedicated [form option][form-options] key `readOnly` should be used. + +Object and arrays that are nested inside a read-only field are also treated as read-only in the context of nested data navigation, even though they might not be explicitly specified as read-only in the [data schema][data-schema]. +For instance, in the following schema, the array `children` is specified to be read-only, therefore the array `toys` will also be treated as read-only: + +```json +{ + "parent": { + "type": "object", + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "lastname": { + "type": "string" + } + } + } + }, + "children": { + "type": "array", + "formOptions": { + "readOnly": true // "children" is read-only + }, + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "dateOfBirth": { + "type": "string", + "format": "date" + }, + "school": { + "type": "string" + }, + "toys": { // "toys" is not specified to be read-only, but it is considered as such since it belongs to a read-only field ("children") + "type": "array", + "items": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": ["Sport", "Action Figure", "Table Game"] + }, + "price": { + "type": "number" + } + } + } + } + } + } + } +} +``` + + +## Examples + +### Example: Entering nested data + +Assuming a dataset to have items: + +```json +[ + { + "difficulty": "medium", + "ingredients": [ + { + "name": "Chicken", + "calories": 500 + }, + { + "name": "Potatoes", + "calories": 600 + }, + { + "name": "Olive Oil", + "calories": 20 + } + ] + }, + { + "difficulty": "easy", + "ingredients": [ + { + "name": "Lettuce", + "calories": 90 + }, + { + "name": "Olive Oil", + "calories": 20 + } + ] + } +] +``` + +and a the following components to be included in the page: + +- a [Table][bk-table] + ```json + { + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "difficulty": { + "type": "string", + "enum": ["hard", "medium", "easy"] + }, + "ingredients": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "calories": { + "type": "number" + } + } + } + } + } + } + } + } + ``` + +- a [Pagination][bk-pagination] + ```json + { + "tag": "bk-pagination" + } + ``` + +then the rendered table can be represented by an array as: + +```json +[ + ["difficulty", "ingredients"] + ["medium", "3 Elements"], + ["easy", "2 Elements"] +] +``` + +:::info +By default, the Table renders array fields as a counter of the number of elements in the array. +::: + +The cells of the column corresponding to the "ingredients" field are clickable. + +Clicking on the first cell causes the Table to notify that the visualization of the corresponding nested data should be activated. +This corresponds to emitting a [nested-navigation-state/push] event with payload: +```json +{ + "data": [ + {"name": "Chicken","calories": 500}, + {"name": "Potatoes", "calories": 600}, + {"name": "Olive Oil", "calories": 20} + ], + "origin": { + "difficulty": "medium", + "ingredients": [ + {"name": "Chicken","calories": 500}, + {"name": "Potatoes", "calories": 600}, + {"name": "Olive Oil", "calories": 20} + ] + }, + "selectedKey": "ingredients", + "rowIndex": 0, + "isObject": false, + "readonly": false +} +``` + +the Pagination component listens to `nested-navigation-state/push` events, and notifies what portion of the nested data should be visualized. +Pagination component handles pagination of nested data as well, other than that of "regular" data. +Assuming the currently selected page-size to be 25 (which is the default value), the Pagination component emits a [nested-navigation-state/display] event with payload: +```json +{ + "data": [ + {"name": "Chicken","calories": 500}, + {"name": "Potatoes", "calories": 600}, + {"name": "Olive Oil", "calories": 20} + ], + "from": 0, + "to": 25, +} +``` + +Signaling that the first 25 elements of the specified nested data should be visualized - thus the whole data in this case. +The Table listens to the `nested-navigation-state/display` event and updates the rendered data: + +```json +[ + ["Chicken","500"], + ["Potatoes", "600"], + ["Olive Oil", "20"] +] +``` + +### Example: Editing Nested Data + +Assuming a dataset to have items: + +```json +[ + { + "difficulty": "medium", + "ingredients": [ + { + "name": "Chicken", + "calories": 500 + }, + { + "name": "Potatoes", + "calories": 600 + }, + { + "name": "Olive Oil", + "calories": 20 + } + ] + } +] +``` + +and a the following components to be included in the page: + +- a [Table][bk-table] + ```json + { + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "difficulty": { + "type": "string", + "enum": ["hard", "medium", "easy"] + }, + "ingredients": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "calories": { + "type": "number" + } + } + } + } + } + } + } + } + ``` + +- a [Dynamic Form Modal][bk-dynamic-form-modal] with the same data-schema as the Table + ```json + { + "tag": "bk-dynamic-form-modal", + "properties": { + "dataSchema": { + ... // like bk-table + } + } + } + ``` + +- a [Breadcrumbs][bk-breadcrumbs] component + ```json + { + "tag": "bk-breadcrumbs", + "properties": { + "dataSchema": { + ... // like bk-table + } + } + } + ``` + +- a [Pagination][bk-pagination] component + ```json + { + "tag": "bk-pagination" + } + ``` + +- a [CRUD Client][bk-crud-client] component + ```json + { + "tag": "bk-breadcrumbs", + "properties": { + "dataSchema": { + ... // like bk-table + } + } + } + ``` + + +and assuming the Table to be currently rendering the "ingredients" nested field + +```json +[ + ["name", "calories"] // table header + ["Chicken","500"], + ["Potatoes", "600"], + ["Olive Oil", "20"] +] +``` + +then clicking on the second row opens the Dynamic Form Modal, which allows the user to edit the fields. +Assuming the field to decrease the "calories" field to 450 and submit, then the Dynamic Form Modal emits an [update-data] event with payload: + +```json +{ + "ingredients": [ + { + "name": "Chicken", + "calories": 500 + }, + { + "name": "Potatoes", + "calories": 450 // <-- updated data + }, + { + "name": "Olive Oil", + "calories": 20 + } + ] +} +``` + +Notice how the whole "ingredients" field is sent as payload of the event. +The [CRUD Client][bk-crud-client] might be included in the page and perform an HTTP request to update the data item in question. + +If the data is correctly updated, the CRUD Client fetches the newly updated data and propagates it through a [display-data] event. + +```json +// payload of the display-data event +{ + "data": [ + { + "difficulty": "medium", + "ingredients": [ + { + "name": "Chicken", + "calories": 500 + }, + { + "name": "Potatoes", + "calories": 450 + }, + { + "name": "Olive Oil", + "calories": 20 + } + ] + }, + ... + ] +} +``` + +The Breadcrumbs listens to the `display-data`, and consequently emits a [nested-navigation-state/push] to restore the previous visualization. +```json +// payload of the nested-navigation-state/push +{ + "data": [ + {"name": "Chicken", "calories": 500}, + {"name": "Potatoes", "calories": 450}, + {"name": "Olive Oil", "calories": 20} + ] +} +``` + +the Pagination component listens to this event and informs the Table on what portion of the nested data should be rendered, with a [nested-navigation-state/display] event. Assuming the current page size to be 25 (default), then the whole nested field is rendered: + +```json +// payload of the nested-navigation-state/display +{ + "data": [ + {"name": "Chicken","calories": 500}, + {"name": "Potatoes", "calories": 450}, + {"name": "Olive Oil", "calories": 20} + ], + "from": 0, + "to": 25, +} +``` + +corresponding to the Table rendering: +```json +[ + ["name", "calories"] // table header + ["Chicken", "500"], + ["Potatoes", "450"], + ["Olive Oil", "20"] +] +``` + +:::info +Notice how the Pagination and the Breadcrumbs components are both needed when updating nested data. +::: + +By default, the Table renders an action to delete a data row inside nested field. +Clicking the action of the first row, for instance, emits an `update-data` event with payload: + +```json +{ + "ingredients": [ + { + "name": "Potatoes", + "calories": 450 + }, + { + "name": "Olive Oil", + "calories": 20 + } + ] +} +``` + +requesting to update the "ingredients" field of data item, and triggering a new cycle of events like the one described above. diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/30_plugin_navigation.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/30_plugin_navigation.md new file mode 100644 index 0000000000..4ba8907b49 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/30_plugin_navigation.md @@ -0,0 +1,219 @@ +--- +id: plugin_navigation +title: Plugin Navigation +sidebar_label: Plugin navigation +--- + + + +[window.history.push]: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState +[window.history.replace]: https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState + +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query + +[bk-url-parameters]: /products/microfrontend-composer/back-kit/60_components/550_url_parameters_adapter.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-crud-lookup-client]: /products/microfrontend-composer/back-kit/60_components/170_crud_lookup_client.md +[bk-state-adapter]: /products/microfrontend-composer/back-kit/60_components/510_state_adapter.md +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md + +[afterFinishEvents]: /products/microfrontend-composer/back-kit/60_components/340_form_drawer.md#after-submission + + + +Microfrontend Composer is a set of micro-frontend plugins. An orchestrator of micro-frontends should provide a mechanism for page/plugin navigation. + +In this regard `Back-Kit` provides a set of `webcomponents` which can handle navigation main features given that the micro-frontend orchestrator is +actively listening the [pushState][window.history.push] / [replaceState][window.history.replace] events. + +Let's take on a real life example. Two separate plugins represent a main "collection", rendered with a table and http-client to fetch data, and a "detail" overview, +made with a card and an http-client which probably requires filtering on data to fetch. + +![Push State](img/push-state.png) + +A button is clicked to navigate to the detail plugin. + +Since the orchestrator cannot use a `location.href` otherwise it would be reloaded making the operation anti-pattern, we could use the `history` API provided by the browser. On click we provide all information needed to change plugin. + +1. a context of data we would like to carry along (i.e. the unique `id` of the detail we're navigating to) +2. the relative url (possibly with queries) + +The micro-frontend orchestrator will provide plugin swapping capabilities by replacing the sandboxed document +in which is mounting plugins and the browser will + +1. modify the URL string +2. insert the data context into `window.history.state` + +`Back-Kit` provides two components that are suitable to handle the landing on a new plugin. + +## URL Parameters Adapter + +The [URL Parameters Adapter][bk-url-parameters] provides a URL mask to separate the plugin URL (handled by the micro-frontend orchestrator) and the rest of the pathname useful to scope the detail plugin + +```json +{ + "tag": "bk-url-parameters", + "properties": { + "urlMask": "/detail/:id", + "redirectUrl": "/collection" + } +} +``` + +and if the `:id` key is not found it may prevent further navigation and push back. +This component listens to the `window.location.href` only + +### Interplay with CRUD Client and CRUD Lookup Client + +While The [URL Parameters Adapter][bk-url-parameters] sends a [change-query] event with payload `{id: ""}`, the `change-query` subscribers which are the [CRUD Client][bk-crud-client] and the [CRUD Lookup Client][bk-crud-lookup-client] will permanently modify their http fetching query by including a default search parameters formed as `?...&id=&...`.\ +This URL editing will scope the entire page providing the concept of a "detail" layout with respect to the "collection" layout centered on a table. + +## State Adapter + +The [State Adapter][bk-state-adapter] provides the capability to inject `pushState` data into the `EventBus` like if the user already performed some operations. + +If the button clicked on the "collection" plugin provides a special key `__BK_INIT` (whose name is configurable), its all content will be parsed to the `EventBus` + +```javascript +window.history.state = { + __BK_INIT: [ + { + label: "add-new", + payload: { + detailId: "624ecd5642247867845498fb" + } + } + ] +} +``` + +in the previous example `EventBus` will pipe an `add-new` event with the given `detailId` payload. The corresponding action on a [Button][bk-button] embedded into the "collection" plugin would be + +```json +{ + "tag": "bk-button", + "properties": { + "content": "Add new item", + "action": { + "type": "push", + "config": { + "url": "/detail", + "state": { + "__BK_INIT": [ + { + "label": "add-new", + "payload": {"detailId": ""} + } + ] + } + } + } + } +} +``` + +## Example - food delivery + +Suppose you have food delivery orders listed in the main "collection" using a table. +The main table expects a field named `orderId` as primary table index. A form is used to create a new +order + +```json +// orders-list.json + +{ + { + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "orderId": { "type": "string" } + } + } + } + }, + { + "tag": "bk-add-new-button" + }, + { + "tag": "bk-form-drawer", + "properties": { + "dataSchema": "", + "afterFinishEvents": { + "data": { + "__BK_INIT": [ + { + "label": "add-new", + "payload": {"orderId": "{{response.orderId}}"} + } + ] + }, + "url": "/order-details/{{response.orderId}}" + } + } + } +} +``` + +On form submission, if the creation POST is, successful a context is provided with the HTTP response context to the [afterFinishEvents]. + +According to the configuration shown above a `pushState` is called and navigation to `/order-details/` is handled by the micro-frontend orchestrator. + +On landing onto `order-details` plugin, we should focus on the following config + +```json +// order-details.json + +{ + { + "tag": "bk-url-parameters", + "properties": { + "eventLabel": "change-query", + "urlMask": "/order-details/:_id", + "redirectUrl": "/orders-list" + } + }, + { + "tag": "bk-state-adapter" + }, + { + "tag": "bk-form-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "orderId": { "type": "string" } + } + } + } + } +} +``` + +The [URL Parameters Adapter][bk-url-parameters] will attempt current URL matching against the given mask. If it fails it will +redirect according to the provided property. + +Otherwise it will attempt to send the matched content to the `EventBus` using a property called +`eventLabel` which defaults to [change-query]. + +Hence, let's suppose we land on `/order-details/624ecd5642247867845498fb`, The URL Parameters Adapter will +send a `change-query` event with payload + +```javascript +const payload = { + _id: "624ecd5642247867845498fb" +} +``` + +where `_id` is taken from the `urlMask` configuration. + +Meanwhile, The [State Adapter][bk-state-adapter] awaits a given delay timeout and then checks the `window.history.state` +which was injected when `pushState` was called and if it finds a key `__BK_INIT` (which is overridable) +and then pipe the array content to the `EventBus`. + +According to the incoming config the `EventBus` will receive an `add-new` event with payload +given by `{orderId: "624ecd5642247867845498fb"}`. + +The form drawer into the "details" plugin will then open by subscribing the `add-new` event and +thus using the body to prefill the `orderId` field. diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/40_lookups.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/40_lookups.md new file mode 100644 index 0000000000..a7745e1eab --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/40_lookups.md @@ -0,0 +1,376 @@ +--- +id: lookups +title: Lookup fields - Working with writable views +sidebar_label: Lookups +--- + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[writable-views]: /runtime-components/plugins/crud-service/50_writable_views.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema +[visualization-options]: /products/microfrontend-composer/back-kit/30_page_layout.md#visualization-options + +[rawobject]: /products/microfrontend-composer/back-kit/40_core_concepts.md#rawobject +[deprecated-lookups]: /products/microfrontend-composer/back-kit/30_page_layout.md#lookups-deprecated + +[bk-dynamic-form-modal]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md +[bk-dynamic-form-card]: /products/microfrontend-composer/back-kit/60_components/190_dynamic_form_card.md +[bk-dynamic-form-drawer]: /products/microfrontend-composer/back-kit/60_components/200_dynamic_form_drawer.md +[bk-form-modal]: /products/microfrontend-composer/back-kit/60_components/350_form_modal.md +[bk-form-card]: /products/microfrontend-composer/back-kit/60_components/330_form_card.md +[bk-form-drawer]: /products/microfrontend-composer/back-kit/60_components/340_form_drawer.md +[bk-crud-lookup-client]: /products/microfrontend-composer/back-kit/60_components/170_crud_lookup_client.md +[bk-table]: /products/microfrontend-composer/back-kit/60_components/520_table.md + +[modal-lookup-queries]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#lookupqueries +[modal-conditional-fields]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#conditional-fields +[modal-writable-views]: /products/microfrontend-composer/back-kit/60_components/210_dynamic_form_modal.md#writable-views + + + +[Mia-Platform CRUD Service][crud-service] allows to create [writable views][writable-views]. +Views are virtual collections that encapsulate the results derived from aggregation pipelines. Their primary function revolves around presenting data obtained from one collection within the contextual framework of a main collection, which is referred to as the "source". Normally, views are read-only, but since version 6.9.0 of the `CRUD Service`, editing a view will automatically reflect changes to the original collection. + +"Lookup fields" are those fields within views that reference data from a collection different to the original one. +Components such as the [Dynamic Form Modal][bk-dynamic-form-modal] are geared to [work with such fields][modal-writable-views]. + +Lookup fields can be configured in the [data-schema] by defining fields of type `object` or `array` and format `lookup`. +The [Dynamic Form Modal][bk-dynamic-form-modal], [Dynamic Form Drawer][bk-dynamic-form-drawer], [Dynamic Form Card][bk-dynamic-form-card] components render these as select fields, for which options are fetched using the `/lookup` route provided by `CRUD Service` views. +Each option fetched like this is expected to be an object, and should have at least a `label` field, which is used as display value inside the form, and a `value` field which is used as unique identifier for such option. + +:::caution +Setting up lookup fields using the [Crud Lookup Client][bk-crud-lookup-client] in conjunction with one between [Dynamic Form Modal][bk-dynamic-form-modal] or [Dynamic Form Drawer][bk-dynamic-form-drawer] or [Dynamic Form Card][bk-dynamic-form-card] is **deprecated** since version 1.4.0 of Back-Kit components.\ +Documentation on previous way of configuring lookup fields is available [here][deprecated-lookups]. +::: + +## Lookup fields display in the Table + +[Table][bk-table] normally shows lookup array fields cells as a placeholder, holding a counter of the elements in the array. + +However, if internal content is meant to be shown in-place, it is possible to `join` its values and print it as a string. + +This is achieved by specifying a `joinDelimiter` key in the [visualization options][visualization-options] of the [data-schema]. An empty string is allowed. +The `label`s of the array entries are joined with the specified string in `joinDelimiter`. + +```json +{ + "visualizationOptions": { + "joinDelimiter": "" + } +} +``` + +Lookup fields of type object are also displayed as a placeholder by default in table cells. +Property `template` in the [visualization options][visualization-options] of the [data-schema] can be used to specify a custom visualization. For instance: + +```json +{ + "visualizationOptions": { + "joinDelimiter": "{{label}}" + } +} +``` + +For an example, see [below](#example-showing-lookup-fields-in-the-Table). + +## Migrating to writable views from previous lookups + +Starting from version 1.4.0 of Back-Kit, lookup fields should be handled through [CRUD Service][crud-service] feature of [writable views][writable-views]. + +In particular, the [Dynamic Form Modal][bk-dynamic-form-modal], [Drawer][bk-dynamic-form-drawer], [Card][bk-dynamic-form-card] components do not listen to events triggered by the [Crud Lookup Client][bk-crud-lookup-client], but rather fetch lookup options directly by calling the `/lookup` route, that the Crud Service makes available for writable views. + +The Crud Lookup Client component is therefore deprecated, as well as: +- the [Form Modal][bk-form-modal], which should be replaced by the Dynamic Form Modal, +- the [Form Drawer][bk-form-drawer], which should be replaced by the Dynamic Form Drawer, +- the [Form Card][bk-form-card], which should be replaced by the Dynamic Form Card. + +[Data-schema][data-schema] key `lookupOptions` is also deprecated, and ignored by the new form components. + +The Dynamic Form Modal, Drawer, Card can be configured in a way to cover features that were previously configured using `lookupOptions`. + +- `lookupQueries` + + `lookupQueries` should **not** be specified inside `lookupOptions` in the data-schema, but rather as a [property of the form component][modal-lookup-queries], which maps each lookup field to additional queries to append to the call to fetch options. + + An [example](#example-setting-up-extra-queries-to-fetch-lookup-options) is available showing how to configure the property `lookupQueries` of the Dynamic Form Modal. + +- `lookupDeps` + + Property `lookupDeps` of `lookupOptions` is used to specify a dependency between a lookup field and other fields within the form. + The Dynamic Form Modal, Drawer, Card, instead, handle [dependencies among fields][modal-conditional-fields] through properties `conditionalOptions` and `conditionalValues`. + + An [example](#example-specifying-lookup-dependencies) is available showing how to use properties `conditionalValues` and `lookupQueries` of the Dynamic Form Modal to set up lookup fields that depend on other fields of the form. + + +## Examples + +### Example: Submitting writable views with a form component + +The following example shows a configuration of the Dynamic Form Modal designed to interact with writable views: + +```json +{ + "tag": "bk-dynamic-form-modal", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "rider": {"type": "object", "format": "lookup"} + } + }, + "basePath": "/orders-view" + } +} +``` +- being "rider" an `object` field with `lookup` format, it is rendered as a select field inside the form +- options for "rider" select field are dynamically fetched from `/orders-view/lookup/rider` + +### Example: Showing lookup fields in the Table + +Specifying a `joinDelimiter` key in the [data-schema]'s [visualization options][visualization-options] of a lookup array field causes the [Table][bk-table] to show the content of the field in-place inside the corresponding cell. + +A Table configured like: +```json +{ + "tag": "bk-table", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "dishes": { + "type": "array", + "format": "lookup" + }, + "riders": { + "type": "array", + "format": "lookup", + "visualizationOptions": { + "joinDelimiter": ", " + } + }, + "customer": { + "type": "object", + "format": "lookup", + "visualizationOptions": { + "template": "{{label}}" + } + } + } + } + } +} +``` + +with data like: +```json +[ + { + "name": "Sarah", + "dishes": [ + {"value": "id-dish-1", "label": "Omelette"}, + {"value": "id-dish-9", "label": "Veggie Burger"}, + ], + "riders": [ + {"value": "id-rider-1", "label": "Alejandro"}, + {"value": "id-rider-2", "label": "Susanna"}, + ], + "customer": { + "value":"id-customer-1", "label": "Marco" + } + }, + { + "name": "Bruce", + "dishes": [ + {"value": "id-dish-7", "label": "Hamburger"}, + {"value": "id-dish-5", "label": "Coconut"}, + {"value": "id-dish-10", "label": "Cheesecake"}, + ], + "riders": [ + {"value": "id-rider-4", "label": "Simon"} + ], + "customer": { + "value":"id-customer-12", "label": "Kevin" + } + } +] +``` + +renders a table which can be represented by an array like: +```json +[ + ["name", "dishes", "riders", "customer"], // header + ["Sarah", "2 Elements", "Alejandro, Susanna", "Marco"], + ["Bruce", "3 Elements", "Simon", "Kevin"] +] +``` + +### Example: Setting up extra queries to fetch lookup options + +A Dynamic Form Modal configured like the following +```json +{ + "tag": "bk-dynamic-form-modal", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "dishes": {"type": "array", "format": "lookup"} + } + }, + "basePath": "/orders", + "lookupQueries": { + "dishes": { + "calories": { + "$lt": 300 + } + } + } + } +} +``` +fetches options for field "dishes" from `orders/lookup/dishes` with the additional condition that "calories" field of dishes collection should be lower than 300, expressed in the query parameters of the request. + +Dynamic queries are also available: +```json +{ + "tag": "bk-dynamic-form-modal", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "maxCalories": {"type": "number"}, + "dishes": {"type": "array", "format": "lookup"} + } + }, + "basePath": "/orders", + "lookupQueries": { + "dishes": { + "calories": { + "$lt": "{{rawObject maxCalories}}" // rawObject can be used to prevent numeric values from being stringified + } + } + } + } +} +``` +in this case, form field "maxCalories" is used to dynamically compute the additional query to use when fetching options for "dishes" lookup field. + +:::info +In the previous example, [`rawObject` helper][rawobject] is used to avoid numeric values from being stringified +::: + +### Example: Specifying lookup dependencies + +```json +{ + "tag": "bk-dynamic-form-modal", + "properties": { + "basePath": "/orders", + "dataSchema": { + "type": "object", + "properties": { + "state": { + "type": "object", + "format": "lookup" + }, + "city": { + "type": "object", + "format": "lookup" + } + } + }, + "conditionalValues": [ + { + "property": "city", + "query": { + "city.stateId": { + "$eq": "{{state.value}}" + } + } + } + ], + "lookupQueries": { + "city": { + "stateId": { + "$eq": "{{state.value}}" + } + } + } + } +} +``` + +- `conditionalValues` property ensures that the "city" field is automatically reset any time the selected "state" field does not correspond to the "stateId" of the selected value for "city" +- `lookupQueries` properties ensures that only options having "stateId" equals to the selected value for "state" are fetched for field "city" + +For instance, a valid configuration could be: + +```json +{ + "state": { + "value": "italy", + "label": "Italy" + }, + "city": { + "value": "milan", + "stateId": "italy", + "label": "Milan" + } +} +``` + +editing the "state" field triggers the "city" field to be reset. For instance: + +```json +{ + "state": { + "value": "france", + "label": "France" + }, + "city": {} +} +``` + +since `state.value` no longer equals `city.stateId`, the "city" field is reset, due to the confition expressed in `conditionalValues`. + +At this point, due to the specified `lookupQueries` property, HTTP calls to fetch options for the "city" field are performed to `/orders/lookup/city` with the following query paramters: + +```json +{ + "stateId": { + "$eq": "france" + } +} +``` +which might return options like: +```json +[ + { + "value": "paris", + "label": "Paris", + "stateId": "france" + }, + { + "value": "lione", + "label": "Lione", + "stateId": "france" + } +] +``` +limiting therefore the available options to be coherent with the specified condition in `conditionalValues`. + +:::info +This example features the [Dynamic Form Modal][bk-dynamic-form-modal]. However, the [Dynamic Form Drawer][bk-dynamic-form-drawer] and the [Dynamic Form Card][bk-dynamic-form-card] could be configured in the same way to obtain the same result. +::: + +:::info +Notice that field "stateId" should be included in the values returned for the "city" field. This can be achieved through proper configuration of the aggregation pipeline that is used to build the underlying [writable view][writable-views]. +Components [Dynamic Form Modal][bk-dynamic-form-modal], [Dynamic Form Drawer][bk-dynamic-form-drawer], [Dynamic Form Card][bk-dynamic-form-card] always carry in their internal representation of the form values the whole lookup object, although only the label is displayed. +This is why, in the example, `conditionalValues` may reference the "stateId" key in the value of the "city" field. +::: diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/50_data_import_export.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/50_data_import_export.md new file mode 100644 index 0000000000..a0676fa33c --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/50_data_import_export.md @@ -0,0 +1,290 @@ +--- +id: data_import_export +title: Data Import / Export +sidebar_label: Data import export +--- + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md +[export-service]: /runtime-components/plugins/export-service/10_overview.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema + +[actions]: /products/microfrontend-composer/back-kit/50_actions.md + +[bk-button]: /products/microfrontend-composer/back-kit/60_components/90_button.md +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-export]: /products/microfrontend-composer/back-kit/60_components/110_crud_export.md +[bk-export-client]: /products/microfrontend-composer/back-kit/60_components/120_crud_export_client.md +[bk-export-modal]: /products/microfrontend-composer/back-kit/60_components/250_export_modal.md +[bk-import-modal]: /products/microfrontend-composer/back-kit/60_components/380_import_modal.md + +[export-data]: /products/microfrontend-composer/back-kit/70_events.md#export-data +[import-data]: /products/microfrontend-composer/back-kit/70_events.md#import-data + + + + +Back-kit components offer components to interact with backend solutions that perform import or export of data. + +## Data Export + +To perform data export, Back-kit provides clients for the following backend solutions: + - [Mia Platform CRUD Service][crud-service] export functionality + - [Mia Platform Export Service][export-service] + +### Data Export with CRUD Service + +To leverage the [CRUD Service][crud-service] export functionality, the [CRUD Export][bk-export] component should be included in the configuration. + +The [CRUD Export][bk-export] requires two properties to be configured for its most basic usage: + - `basePath`, which is the targeted endpoint for performing data export + - a [data-schema], which provides information on the structure of the data of the associated CRUD Service collection + +```json +{ + "tag": "bk-export", + "properties": { + "basePath": "/v2/orders/export", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"} + } + } + } +} +``` + +To initiate the export, an [export-data] event must be emitted. Several Back-kit components allow to emit customizable events. + +Following is an [example](#example-trigger-crud-export-data-with-a-button) of how the CRUD Service export can be achieved combining the CRUD Export and a [Button][bk-button]. + + +### Data Export with Export Service + +To leverage the [Export Service][export-service] export functionality, the following components should be included in the configuration: + +- The [CRUD Export Client][bk-export-client], which must be configured with: + - a `basePath`, which is the endpoint of the Export Service for performing data export + - a `exportInternalUrl`, which is the endpoint of the CRUD collection of which to perform the export + - a [data-schema], which provides information on the structure of the data of the associated CRUD Service collection + ```json + { + "tag": "bk-export-client", + "properties": { + "basePath": "/export", + "exportInternalUrl": "http://crud-service/orders/export", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } + } + ``` + +- The [Export Modal][bk-export-modal], which requires no configuration + ```json + { + "tag": "bk-export-modal" + } + ``` + +To initiate the export, an [export-data] event must be emitted. Several Back-kit components allow to emit customizable events. + +Following is an [example](#example-trigger-export-service-export-data-with-a-button) of how the Export Service can be used to export data, initiating the process with a [Button][bk-button]. + + +## Data Import + +Back-kit components allow to leverage the import API of [Mia Platform CRUD Service][crud-service]. + +To do so, the following components should be included in the configuration: + +- The [CRUD Client][bk-crud-client], which must be configured with: + - a `basePath`, which is the endpoint to reach the associated CRUD collection + - a [data-schema], which provides information on the structure of the data of the associated CRUD Service collection + + ```json + { + "tag": "bk-crud-client", + "properties": { + "basePath": "/v2/orders", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } + } + ``` + +- The [Import Modal][bk-import-modal], which requires no configuration + ```json + { + "tag": "bk-import-modal" + } + ``` + + +To initiate the import, an [import-data] event must be emitted. Several Back-kit components allow to emit customizable events. + +Following is an [example](#example-trigger-data-import-data-with-a-button) of how the CRUD Service import can be achieved initiating the process with a [Button][bk-button]. + +## Examples + +### Example: Trigger CRUD export data with a button + +To leverage the export functionality of the [CRUD Service][crud-service], the [CRUD Export][bk-export] component should be included in the configuration. +To initiate the export process, an [export-data] event must be emtted. + +The following snippet of configuration can be used to trigger the export using a [Button][bk-button]. + +```json +{ + "tag": "bk-button", + "properties": { + "iconId": "DownloadOutlined", + "content": { + "en": "Export", + "it": "Esporta" + }, + "action": { + "type": "event", + "config": { + "events": "export-data" + } + } + } +}, +{ + "tag": "bk-export", + "properties": { + "basePath": "/v2/orders/export", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } +} +``` + +The Button component can be configured to perform a [Back-kit Action][actions] when clicked. `Back-kit Action`s allow to perform various tasks. In this case, the button is configured to emit an `export-data` event with an empty payload. + +This event is listened by the CRUD Export component, which triggers an HTTP call to the endpoint "/v2/orders/export" following the CRUD Service export interface. + +### Example: Trigger Export Service export data with a button + +To leverage the export functionality of the [Export Service][export-service], the [CRUD Export Client][bk-export-client] and the [Export Modal][bk-export-modal] components should be included in the configuration. To initiate the export process, an [export-data] event must be emtted. + +The following snippet of configuration can be used to trigger the export using a [Button][bk-button]. + +```json +{ + "tag": "bk-button", + "properties": { + "iconId": "DownloadOutlined", + "content": { + "en": "Export", + "it": "Esporta" + }, + "action": { + "type": "event", + "config": { + "events": "export-data" + } + } + } +}, +{ + "tag": "bk-export-modal" +}, +{ + "tag": "bk-export-client", + "properties": { + "basePath": "/export", + "exportInternalUrl": "http://crud-service/orders/export", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } +} +``` + +The Button component can be configured to perform a [Back-kit Action][actions] when clicked. `Back-kit Action`s allow to perform various tasks. In this case, the button is configured to emit an `export-data` event with an empty payload. + +This event is listened by the CRUD Export Client component, which triggers the opening of the Export Modal. +The Export Modal includes a form that allows the user to configure the export parameters. +Once the form of the Export Modal is submitted, the CRUD Export Client uses its information to configure and perform an HTTP call to the Export Service, which triggers the data export. + +### Example: Trigger data import data with a button + +To leverage the import functionality of the [CRUD Service][crud-service], the [CRUD Client][bk-crud-client] and the [Import Modal][bk-import-modal] components should be included in the configuration. To initiate the import process, an [import-data] event must be emtted. + +The following snippet of configuration can be used to trigger the data import using a [Button][bk-button]. + +```json +{ + "tag": "bk-button", + "properties": { + "icon": "fas fa-upload", + "content": { + "en": "Import", + "it": "Importa" + }, + "action": { + "type": "event", + "config": { + "events": "import-data" + } + } + } +}, +{ + "tag": "bk-import-modal" +}, +{ + "tag": "bk-crud-client", + "properties": { + "basePath": "/v2/orders", + "dataSchema": { + "type": "object", + "properties": { + "_id": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } +} +``` + +The Button component can be configured to perform a [Back-kit Action][actions] when clicked. `Back-kit Action`s allow to perform various tasks. In this case, the button is configured to emit an `import-data` event with an empty payload. + +This event is triggers the opening of the Import Modal. +The Import Modal includes a form that allows the user to upload a file containing the data to import, as well as configure some parameters of the import task. +Once the form of the Import Modal is submitted, the CRUD Client uses its content to configure and perform an HTTP call to the CRUD Service, which imports the data. diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/60_data_filtering.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/60_data_filtering.md new file mode 100644 index 0000000000..88fbdce227 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/60_data_filtering.md @@ -0,0 +1,269 @@ +--- +id: data_filtering +title: Data Filtering +sidebar_label: Data filtering +--- + + + +[crud-service]: /runtime-components/plugins/crud-service/10_overview_and_usage.md + +[data-schema]: /products/microfrontend-composer/back-kit/30_page_layout.md#data-schema + +[filters]: /products/microfrontend-composer/back-kit/40_core_concepts.md#filters + +[bk-crud-client]: /products/microfrontend-composer/back-kit/60_components/100_crud_client.md +[bk-filters-manager]: /products/microfrontend-composer/back-kit/60_components/310_filters_manager.md +[bk-filter-drawer]: /products/microfrontend-composer/back-kit/60_components/300_filter_drawer.md +[bk-add-filter-button]: /products/microfrontend-composer/back-kit/60_components/10_add_filter_button.md +[bk-expanded-filters]: /products/microfrontend-composer/back-kit/60_components/240_expandable_filters.md + +[change-query]: /products/microfrontend-composer/back-kit/70_events.md#change-query +[display-data]: /products/microfrontend-composer/back-kit/70_events.md#display-data +[filter-evt]: /products/microfrontend-composer/back-kit/70_events.md#filter +[add-filter]: /products/microfrontend-composer/back-kit/70_events.md#add-filter + + + +Several Back-kit components are designed to interact with a dataset. Data should be fetched by a client component from a backend resource. + +The [CRUD Client][bk-crud-client] component is designed to interact with [Mia Platform CRUD Service][crud-service]. The CRUD Client fetches data from a collection of the CRUD Service, and propagates it to other components as payload of a [display-data] event. + +The CRUD Client fetches data by performing an HTTP request to the CRUD Service. +Particularly, its internal state holds a representation of the query that it uses to fetch data. +This is an object shaped like the payload of a [change-query][change-query] event, in which each field influences the parameters of the HTTP call that the CRUD Client executes to fetch data from the [CRUD Service][crud-service]. + +Components may signals the need to modify the way data is fetched by emitting a `change-query` event. When this happens, the CRUD Client updates its internal query to reflect the requested changes, and re-triggers data fetching with the updated configuration. + +**Using Back-kit components, data filtering happens by emitting `change-query` events that modify how the CRUD Client fetches data, by adding new filters.** + +Back-kit offers two solutions for interacting with the CRUD Client by applying filters: +1) the combination of the [Filters Manager][bk-filters-manager] and the [Filter Drawer][bk-filter-drawer] +2) the [Expandable Filters][bk-expanded-filters] + +both solutions need a component that emits a [filter][filter-evt] event to initiate the filtering process, like the [Add Filter Button][bk-add-filter-button]. + +:::tip +Each [filter][filters] is composed of the triple: + - `property`: the field to filter + - `operator`: the operator used to filter + - `value`: the value to filter for + +While the Expandable Filters component allows to apply multiple filters in one go, it does not allow the user to configure the `property` nor the `operator` associated to each filter, which are set by configuration using the `filtersConfig` property of the component. + +If the user should be allowed to set the `property` and the `operator` of each filter, the [Filter Drawer solution](#data-filtering-with-the-filter-drawer) should be used. +::: + +## Data Filtering with the Filter Drawer + +Data filtering may be achieved by including in the configuration: + +- the [CRUD Client][bk-crud-client], which must be configured with: + - a `basePath`, which is the endpoint to reach the associated CRUD collection + - a [data-schema], which provides information on the structure of the data of the associated [CRUD Service][crud-service] collection +- the [Filters Manager][bk-filters-manager] +- the [Filter Drawer][bk-filter-drawer], which should be configured with a `data-schema` +- the [Add Filter Button][bk-add-filter-button] (or any component emitting a [filter][filter-evt] event to initiate the filtering process) + +Clicking the Add Filter Button initiates the process by emitting a `filter` event. +The Filter Drawer reacts to the event by opening. The user can use the form inside the Filter Drawer to configure a new filter to apply to the underlying data. +All three of the items that identify a filter (`property`, `operator`, `value`) can be set by the user using the Filter Drawer. + +Upon submission, the Filter Drawer notifies the need to apply the new filter by emitting an [add-filter] event. +When the Filter Manager listens to such event, performs two tasks: +1) re-renders to allow user interaction with the new filter, as well as other filters previously applied this way +2) emits a [change-query] event with the updated list of events + +The CRUD Client reacts to the `change-query` event by newly fetching data from the backend with the filters, and propagating retrieved data to other components. + +An [example](#data-filtering-with-the-filter-drawer) of how to configure filtering this way is provided. + +## Data Filtering with the Expandable Filters + +Data filtering may be achieved by including in the configuration: + +- the [CRUD Client][bk-crud-client], which must be configured with: + - a `basePath`, which is the endpoint to reach the associated CRUD collection + - a [data-schema], which provides information on the structure of the data of the associated [CRUD Service][crud-service] collection +- the [Expandable Filters][bk-expanded-filters], which must be configured with: + - a [data-schema], which provides information on the structure of the data of the associated [CRUD Service][crud-service] collection + - `filtersConfig`, which describes the `property` and `operator` of each [filter][filters] that can be applied +- the [Add Filter Button][bk-add-filter-button] (or any component emitting a [filter][filter-evt] event to initiate the filtering process) + +Clicking the Add Filter Button initiates the process by emitting a `filter` event, which toggles the Expandable Filters. + +The user can use the form inside the Expandable Filters to configure filters to be applied to the underlying data. + +While the Expandable Filters component allows to apply multiple filters in one go, it does not allow the user to configure the `property` nor the `operator` associated to each filter, which are set by configuration using the `filtersConfig` property. +:::tip +If the user should be allowed to set the `property` and the `operator` of each filter, the [Filter Drawer solution](#data-filtering-with-the-filter-drawer) should be used instead. +::: + +Submitting the form of the Expandable Filters triggers the emission of a [change-query] event with the applied filters. + +The CRUD Client reacts to the `change-query` event by newly fetching data from the backend with the filters, and propagating retrieved data to other components. + +An [example](#data-filtering-with-the-expandable-filters) of how to configure filtering this way is provided. + +## Examples + +### Example: Filter data with the Filter Drawer + +The following configuration snippet shows how data fetching and filtering can be achieved by combining the following components: + - the [CRUD Client][bk-crud-client] + - the [Filters Manager][bk-filters-manager] + - the [Filter Drawer][bk-filter-drawer] + - the [Add Filter Button][bk-add-filter-button] + +```json +{ + "tag": "bk-add-new-filter" +}, +{ + "tag": "bk-filters-manager" +}, +{ + "tag": "bk-filter-drawer", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id_": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } +}, +{ + "tag": "bk-crud-client", + "properties": { + "basePath": "/v2/orders", + "dataSchema": { // <- same as `bk-filter-drawer` + "type": "object", + "properties": { + "_id_": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } +} +``` + +Clicking the Add New Button opens the Filter Drawer, which allow the user to specify one filter for each property of the data-schema. +Assuming the inserted values to be representable as: + +```json +{ + "property": "name", + "operator": "equal", + "value": "Joe", +} +``` + +And assuming the Filters Manager to already include a filter like: + +```json +{ + "property": "price", + "operator": "greater", + "value": 100 +} +``` + +Then the updated filters are the combination of the two: + +```json +{ + "property": "name", + "operator": "equal", + "value": "Joe" +}, +{ + "property": "price", + "operator": "greater", + "value": 100 +} +``` + +The [CRUD Client][bk-crud-client] chains these filters inside an `$and` `MongoDB`-like query, and retrieves filtered data. + + +### Example: Filter data with the Expandable Filters + +The following configuration snippet shows how data fetching and filtering can be achieved by combining the following components: + - the [CRUD Client][bk-crud-client] + - the [Expandable Filters][bk-expanded-filters] + - the [Add Filter Button][bk-add-filter-button] + +```json +{ + "tag": "bk-add-new-filter" +}, +{ + "tag": "bk-expanded-filters", + "properties": { + "dataSchema": { + "type": "object", + "properties": { + "_id_": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + }, + "filtersConfig": [ + { + "property": "price", + "operator": "greater" + }, + "name" // same as: `{"property": "name", "operator": "equal"}` + ] + } +}, +{ + "tag": "bk-crud-client", + "properties": { + "basePath": "/v2/orders", + "dataSchema": { // <- same as `bk-expanded-filters` + "type": "object", + "properties": { + "_id_": {"type": "string"}, + "__STATE__": {"type": "string"}, + "name": {"type": "string"}, + "price": {"type": "number"} + } + } + } +} +``` + +Clicking the Add New Button toggles the Expanded Filters, which allow the user to specify a value for filtering properties `price` and `name`. +Assuming the inserted values to be representable as: + +```json +{ + "name": "Joe", + "price": 100 +} +``` + +Then the emitted filters look like: + +```json +{ + "property": "name", + "operator": "equal", + "value": "Joe" +}, +{ + "property": "price", + "operator": "greater", + "value": 100 +} +``` + +The [CRUD Client][bk-crud-client] chains these filters inside an `$and` `MongoDB`-like query, and retrieves filtered data. diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/_category_.json b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/_category_.json new file mode 100644 index 0000000000..9fc99f39e0 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Flows" +} diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/img/push-state.png b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/img/push-state.png new file mode 100644 index 0000000000..a7d9bf2c8b Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/80_examples/img/push-state.png differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/_category_.json b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/_category_.json new file mode 100644 index 0000000000..4e77287c04 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Back Kit", + "position": 10 +} \ No newline at end of file diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/changelog.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/changelog.md new file mode 100644 index 0000000000..d599f3b501 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/changelog.md @@ -0,0 +1,1230 @@ +--- +id: changelog +title: CHANGELOG +sidebar_label: CHANGELOG +--- + +## [1.5.26] - 2026-01-28 + +## Added + +- Editor now supports tables + +## [1.5.25] - 2026-01-20 + +### Fixed + +- Fixed isPartialFormat date in bk-form-wizard + +## [1.5.24] - 2026-01-20 + +### Fixed + +- managed `formOptions.isPartialFormat` in filter parsing and export + +## [1.5.23] - 2025-11-12 + +### Changed + +- update nginx image +- update ci script +- generated image SBOM + +## [1.5.22] - 2025-10-27 + +### Fixed + +- fixed editor formatting on text paste + +## [1.5.21] - 2025-10-10 + +### Fixed + +- fixed table loops when switching from data tab to empty tab + +## [1.5.20] - 2025-07-18 + +### Fixed + +- fixed partial date format on `bk-form-wizard` component + +## [1.5.19] - 2025-07-04 + +### Fixed + +- fixed enum arrays in form wizard + +## [1.5.18] - 2025-06-06 + +### Added + +- added prop interpolation with HTTP response values in `bk-notifications` component. + +### Fixed + +- fixed `bk-table` columns when Chrome version is 136 or above. + +## [1.5.17] - 2025-05-07 + +### Fixed + +- added prop `validateForm` to custom footer button under the `actions` section for validating a form. + +## [1.5.16] - 2025-03-03 + +### Removed + +- Removed the escaping of `&` char in `editor` and `html-editor`. + +## [1.5.15] - 2025-01-31 + +### Fixed + +- fixed escaping of char `&` in `editor` and `html-editor` format. + +## [1.5.14] - 2025-01-10 + +- added format for dates and time in `isPartialFormat` mode + +## [1.5.13] - 2024-12-16 + +### Added + +- added `method` property in `bk-import-modal` to choose the HTTP method for the import request + +## [1.5.12] - 2024-12-16 + +### Fixed + +- fixed `bk-expanded-filters` `+` read from url + +## [1.5.11] - 2024-11-29 + +### Fixed + +- fixed `bk-table` visualization when inside `bk-layout-swap` + +## [1.5.10] - 2024-11-15 + +### Fixed + +- fixed query for writable views' lookup +- fixed typo in italian label on export/import delimiter option + +### Added + +- by specifing `format: date` or `format: time` and adding the flag `isPartialFormat` to true in `formOptions` it is possible to use dates and time as simple string and not ISO format. + +## [1.5.9] - 2024-10-18 + +### Added + +- `group` to components properties + +### Fixed + +- added new key `$dateNow` in handlebars to retrieve current date time in ISO format + +## [1.5.8] - 2024-10-02 + +### Fixed + +- fixed csv export option of column names as field IDs of labels + +## [1.5.7] - 2024-09-20 + +### Fixed + +- fixed validation for integer types in input form fields in bk-form-modal component +- fixed filter by special characters in bk-expanded-filters +- fixed conversion of boolean fields in csv export + +## [1.5.6] - 2024-07-12 + +### Added + +- added default export for web components package +- enriched manifests + +### Fixed + +- fixed validation error on array object fields in accordion +- fixed date picker error on array object fields in accordion form +- fixed flag allowNavigation to navigate array of objects + +## [1.5.5] - 2024-06-28 + +### Fixed + +- fixed `bk-table` fit parent on resize +- fixed half hidden tooltip in editor +- fixed error for required array of dates in forms + +## [1.5.4] - 2024-06-13 + +### Added + +- added custom events for bk-dynamic-form-modal and bk-dynamic-form-drawer + +## [1.5.3] - 2024-06-03 + +### Fixed + +- fixed logout redirect +- fixed broken link in readonly file fields + +## [1.5.2] - 2024-05-16 + +### Fixed + +- fixed duplicated options in bk-export-modal +- fixed undefined value in bk-card for boolean type + +## [1.5.1] - 2024-05-03 + +### Added + +- added the possibility to choose the date format and the time zone in `bk-export-modal` and `bk-export` can now be used with `bk-export-modal` +- added `fitParentContainer` property to `bk-table` to make the table as height as the parent container + +### Fixed + +- fixed link url generation with special characters + +## [1.5.0] - 2024-03-22 + +### Added + +- added the possibility to search between menu items in `bk-layout` and changed the collapse button. +- added `useEstimateCount` property to `bk-crud-client` and `usePagesCount` property to `bk-pagination` + +### Fixes + +- improved behavior of `bk-crud-client` and `bk-pagination` when `keepPageCount` is true. +- fixed files preview in `bk-file-client` + +## [1.4.17] - 2024-03-08 + +### Added + +- added the new format `html-editor` in dataschema for type `string`. When `html-editor` format is set, the form components show an editor to write html and see a readonly preview of it. + +## [1.4.16] - 2024-02-15 + +### Fixes + +- `bk-expanded-filters` supports `lookupDeps` option + +## [1.4.15] - 2024-02-07 + +### Fixes + +- dynamic values may include new line characters +- bk-expanded-filters allows to customize date picker locale + +## [1.4.14] - 2024-01-28 + +### Added + +- components allow to specify custom texts with `customLocale` property +- `bk-dynamic-iframe` component is available +- `bk-footer` has property `loadingOnStart`, controlling whether or not the component is initially in loading state + +### Fixes + +- `bk-dropdown` correctly displays icon specified in `iconId` +- Fixed lookup deps query in `bk-crud-lookup-client`: spaces inserted by the user in the input field are kept in query +- Fixed text-areas borders + +## [1.4.13] - 2024-01-17 + +### Added + +- `bk-export-modal` component allows to specify whether to use field ids or field labels as column names in the exported file +- `bk-crud-client` component allows to specify additional sorting property to be appended to `_s` search parameter +- client components allow to specify rerouting rules for HTTP requests + +## [1.4.12] - 2024-01-10 + +### Fixes + +- `bk-calendar` allows to open appointments details in "week" and "day" views + +## [1.4.11] - 2023-12-22 + +### Added + +- `geopointFormat` option is available in data-schema `formOptions` to configure geopoint fields interpretation by Form components (`[latitude, longitude]` vs `[longitude, latitude]`) + +## [1.4.10] - 2023-12-11 + +### Added + +- Form components provide specific field for plain string arrays and string arrays with enum +- Label localization fallbacks to english if browser language is not supported +- `bk-table` renders empty cell for undefined boolean fields +- added `userMenuTrigger` property to `bk-layout` + +### Fixes + +- `bk-wizard-form` correctly submits data that include file fields in nested objects +- `bk-form-wizard` component correctly allows custom title inside stepper +- Action buttons in Dynamic Form components correctly perform event actions +- `bk-layout` component correctly allows to scroll through menu items in `leftMenu` mode +- Form components correctly localizes read-only enum fields +- `bk-form-wizard` component holds value updates after failing validation +- `bk-form-card` and `bk-dynamic-form-card` components correctly process file fields in initial values +- `bk-form-card` components correctly enables submit button on data update + +## [1.4.9] - 2023-11-23 + +### Fixes + +- Form components do not break on relative links + +## [1.4.8] - 2023-11-22 + +### Fixes + +- Form components correctly use monaco editor component to render object / array fields +- `bk-form-wizard` component correctly handles consecutive steps with same fields +- `bk-form-wizard` component correctly holds values of hidden fields + +## [1.4.7] - 2023-11-10 + +### Added + +- `bk-crud-client` emits `count-data` and `display-data` events separately, as soon as needed data is fetched from the backend + +## [1.4.6] - 2023-11-07 + +### Fixes + +- `bk-pagination` component handles case of element count being equal to 0 + +## [1.4.5] - 2023-11-02 + +### Added + +- form components text editor allow raw HTML mode + +## [1.4.4] - 2023-10-20 + +### Added + +- Added table visualization for array properties in manifests + +### Fixes + +- `g` flag is not included in lookup searches +- styling fixes in `bk-layout` component `leftMenu` mode + +## [1.4.3] - 2023-10-12 + +### Added + +- Crud lookup client component provides access to url-mask facilities + +## [1.4.2] - 2023-10-06 + +### Fixes + +- Added boolean type to `filters.value` in `bk-tabs` manifest +- Added `oneOfGuard` to child elements of categories and groups in `bk-layout` manifest +- Added schema for `default` property of dataSchema manifest +- Calendar component sets style correctly on first render + +### Added + +- Form components allow to edit fields of format `geopoint` + +## [1.4.1] - 2023-09-22 + +### Added + +- Component `bk-calendar` supports dynamic configuration in `additionalCreatePayload` +- Component `bk-calendar` has `urlMask` property to retrieve data from URL +- Component `bk-layout` supports new layout modality `leftMenu` +- Form components support month/year navigation and selection in date fields + +### Fixes + +- Title of footer buttons in `bk-gallery` are localized +- File upload action propagates returned object in hooks +- Copy action supports dynamic configurations via handlebars +- Component `bk-form-wizard` does not reset in accordion mode on fields changes + +## [1.4.0] - 2023-08-28 + +### Fixed + +- `bk-layout` shows the user menu when `user` context is defined (when fetch request to api is successful). This fix will show an empty user `name` if not provided +- `bk-layout` manifest `userInfoUrl` was missing the mock fetch implementation +- `bk-layout` manifest `userInfoUrl.userPropertiesMapping` fixed key overwrite + +### Added + +- Support for `CRUD Service` import functionality is available through components `bk-import-modal` and `bk-crud-client` +- Support for `CRUD Service` writable views is available in components. Standard lookup fields handling is now deprecated. +- New components `bk-dynamic-form-modal`, `bk-dynamic-form-drawer`, `bk-dynamic-form-card`, `bk-form-wizard` are available. These extend the functionalities of `bk-form-modal`, `bk-form-drawer`, `bk-form-card`, which are now deprecated. + +## [1.3.18] - 2023-07-24 + +### Fixed + +- `phosphor` icons render tags such as `rect` or `circle` via `@micro-lc/iconic@1.3.1` (``) + +## [1.3.17] - 2023-07-14 + +### Fixed + +- `bk-layout` icon style back to micro-lc v1 look and feel +- `bk-layout` supports `phosphor` icons via `@micro-lc/iconic@1.3.0` + +## [1.3.16] - 2023-06-30 + +## Added + +- `bk-file-picker-modal` allows to visualize and select files that have already been uploaded (requires `Files Service` version 2.7.0 or higher) + +### Fixed + +- `bk-button` callback context is responsive to url updates +- `bk-expanded-filters` with filters parsed from URL correctly perform reset + +## [1.3.15] - 2023-06-19 + +### Added + +- Manifest of component `bk-expanded-filters` includes property `readFromUrl` +- Manifest of component `bk-file-picker-modal` is available + +## [1.3.14] - 2023-06-15 + +### Added + +- `bk-expanded-filters` optionally performs bootstrap, applying filters read from URL +- new component `bk-file-picker-modal` is available, analogous to `bk-file-picker-drawer` +- file fields support `dataSchema` and `items` properties, allowing to specify meta-data. Form components interact with `bk-file-picker-drawer` and `bk-file-picker-modal` to edit files with metadata. + +### Fixed + +- `nginx:1.24.0-alpine` vulnerability fixes in `.docker/Dockerfile` +- Nested objects/arrays are correctly updated when editing form is spawned through `customActions` property of `bk-table` +- `disbaleOnAction` property of `bk-button` correctly interacts with `bk-file-client` + +## [1.3.13] - 2023-06-01 + +### Fixed + +- fixed bug on `selectedParents` property of `bk-button` when used inside `bk-layout-container` +- fixed bug on `selectedParents` property of `bk-button` not correctly updating +- `bk-table`, form components, `bk-breadcrumbs` support `items` keyword in data-schema for arrays of objects fields + +### Added + +- query parameters of http calls are url-encoded +- new event `http-delete` is listened to by `bk-crud-client`, allowing to send DELETE requests to `CRUD Service` +- `bk-table` allows to highlight rows that match mongo-like queries through property `highlightedRows` + +## [1.3.12] - 2023-05-19 + +### Fixed + +- `bk-layout` sets `logo` when `userInfoUrl` is not specified + +## [1.3.11] - 2023-05-18 + +### Added + +- `error` events carry response in payload, if present +- item menu in `bk-layout` can display extra data next to labels using property `badge` +- `enum` property of `data-schema` support array of objects with `id`, `label` keys, enabling to specify a i18n label for enum values +- actions fo type `file-upload` support `accept` attribute, restricting accepted files +- `bk-card` allows to place footer buttons horizontally through key `buttonsLayout` in `cardSchema.footer` +- `bk-layout` supports logo source being retrieved from user information +- `bk-antd-theme-manager` supports retrieving theming information from endpoint + +### Fixed + +- `bk-confirmation-modal` injects `headers` and `credentials` into dynamically mounted buttons +- `bk-button`s with action of type `http` correctly implement `loadingOnAction` and `disableOnAction` logic +- actions of type `copy` stop event propagation by default + +## [1.3.10] - 2023-05-04 + +### Added + +- added property `selectedParents` to `bk-button` to access the history of previous navigated parents + +### Fixed + +- form components correctly localize default values of date fields + +## [1.3.9] - 2023-04-26 + +### Added + +- `reflectToUrl` property allows to control whether `bk-crud-client` reflects its state to the URL with a `window.history.pushState` +- `bk-layout-swap` performs a layout change listening to `layout/change` event. The payload of the event is the layout rendered by the component (bundled separately) + +### Fixed + +- form components correctly resolve lookups in initial values from `add-new` event payload + +## [1.3.8] - 2023-04-07 + +### Fixed + +- `bk-card` component applies `visualizationOptions` to nested objects +- `bk-search-bar` and `bk-breadcrumb` correctly update their nesting state on layout change inside `bk-layout-container` + +### Added + +- new component `bk-file-picker-modal`. `bk-file-picker-modal` and `bk-file-picker-drawer` components allows to attach meta-data to files. +- form components allows upload files using to open `bk-file-picker-modal` / `bk-file-picker-drawer` component + +## [1.3.7] - 2023-03-23 + +### Added + +- added component `bk-antd-theme-manager` and its manifest +- added component `bk-loading-animation` and its manifest (optional) +- added manifest to `bk-layout` +- `bk-loading-animation` moved to its own bundle at `/dist/bk-loading-animation.esm.js` +- http components (eg, `bk-crud-client`) has property `credentials`, which specifies credentials of http calls + +### Fixed + +- files are downloaded with correct name + +## [1.3.6] - 2023-03-09 + +### Added + +- `urlMask` properties of `bk-button` and `bk-url-parameters` allow separate masks for `pathname` and `search` fields of current URL +- actions of type `http` support methods `PATCH` and `PUT` + +### Fixed + +- `headers` property is forwarded from `bk-layout-container` into its content +- `bk-layout` adds injected headers in http-calls +- locales are correctly loaded on first plugin render +- actions of type `file-upload` call error event if http-call fails +- actions of type `href` correctly resolve dynamic configurations +- using `bk-layout-container` does not trigger extra http calls +- fields are correctly put on focus on `bk-form-modal` wizard mode +- form components do not discard "\__STATE__" field on data creation +- `bk-search-bar` keeps state on layout change + +## [1.3.5] - 2023-02-23 + +### Added + +- new component `bk-dropdown` is available +- `bk-form-modal` with `extraEndpoint` property injects a `triggeredBy` key equal to `bk-form-modal-extra-endpoint` into `success`/`error` events +- `bk-simple-list` supports `height` property, setting max-height of the list body +- new Handlebars helper `nFormat` allows to format fields of type `number` and format `currency`, specifying number of decimal places, decimal separator, group separator +- new component `bk-notification-center` is available +- `bk-filters-manager` component allows persistent filters + +### Fixed + +- `bk-expanded-filters` supports internationalized labels +- output of fields with format `editor` do not use custom `quill` classes in form components. Refer to [this issue](https://github.com/zenoamaro/react-quill/issues/553) for further details + +## [1.3.4] - 2023-02-09 + +### Added + +- fields in form can have a description in a tooltip +- new web component for auto refresh: `bk-auto-refresh` +- `bk-url-parameters` support wildcards in `urlMask`, which can be ignored with property `excludeWildcards` +- new component `bk-atlas-dashboard` is available +- `bk-card` component supports dynamic footer and buttons using `template`-`configMap` pair +- `bk-card` uses `visualizationOptions` in dataschema +- `bk-button` supports `Action`-sdk thorugh property `action`. `clickConfig` is now deprecated and will be removed in future releases, please refer to documentation for migration instructions + +### Fixed + +- `bk-form-card` resolves lookups in initial values +- lookups are correctly resolved `bk-filter-drawer` initial values +- Form components correctly support `editorHeight` property in readonly mode +- Tables inside form components render date fields correctly accordingly to `dateOptions.displayFormat` in nested data-schema +- `bk-gallery` component does not render menu icon if empty +- `bk-simple-list` header style is aligned with `bk-card` and `bk-form-card` + +## [1.3.3] - 2023-01-26 + +### Fixed + +- `bk-export` component emits success / error events +- `date` / `date-time` / `time` fields are formatted in filter names accordingly to `dateOptions.displayFormat` in data-schema +- table column minWidth is more fitted to the column title +- fields of format "editor" can be edited +- lookups are correctly resolved in filter names + +## [1.3.2] - 2023-01-18 + +### Added + +- `bk-filter-manager` has a new filter operator for dates: `notBetween` +- components support array of dates +- filters on fields having `filtersOptions.hidden` set to true can be edited through events - `bk-calendar` works after setting `filtersOptions.hidden` to true for `startDate`, `endDate` fields + +### Fixed + +- `$today` keyword in filters works correctly with every operator +- hour in date filters works correctly +- improved style of `bk-gallery` component + +## [1.3.1] - 2023-01-10 + +### Added + +- `bk-simple-list` resolves lookups +- `bk-form-card` can have a custom card header + +## [1.3.0] - 2022-23-12 + +### Added + +- new component `bk-gallery` is available + +## [1.2.3] - 2022-22-12 + +### Added + +- `bk-crud-client` can be configured to stay on current page after successful CRUD operation +- `bk-calendar` allows to specify the name of default date filters + +### Fixed + +- Form components support internationalized strings for file picker fields + +## [1.2.2] - 2022-21-12 + +### Fixed + +- Form and Calendar components support internationalized labels + +## [1.2.1] - 2022-16-12 + +### Added + +- new component `bk-layout` is available, allowing plugins layout customization + +### Fixed + +- `bk-tabs` support `between` operator with complex date filters +- lookups in forms are correctly resolved with long running queries +- default values integrate with initial values in `add-new` payload +- buttons in `bk-confirmation-modal` do not hold state from previous re-renders + +## [1.2.0] - 2022-11-17 + +### Added + +- file download with POST requests +- configurable height of object/array editor in `bk-filter-drawer`, `bk-form-drawer`, `bk-form-modal` and `bk-form-card` +- `bk-table` custom actions can be configured on a per-nested-level basis +- `bk-file-client` forwards `useOriginalName` query parameter to `files-service` (needs `files-service` 2.6.4+) +- number fields support `date-time`, `date`, `time` formats +- `sortOption` is supported in `lookupOptions`, controlling `_s` parameter when fetching lookups + +### Fixed + +- `bk-card` with default role doesn't show border +- nested objects are shown in `bk-table` component without need to include `bk-pagination` in page +- when the same date is used in a `between` filter in `bk-expanded-filters` component, the correct filter is created +- fixed infinite loading caused by non-existing file in download-file event +- `bk-table` correctly performs `pushState` and `replaceState` when `browseOnRowSelect` property has `navigationType` set to "push" or "replace" + +## [1.1.2] - 2022-11-02 + +### Fixed + +- `bk-table` correctly indexes rows if `primaryKey` property is not defined (fixes rendering errors with nested objects) +- drawers follow Ant standard styling + +### Added + +- `bk-button` enables bulk actions +- new component `bk-expanded-filter` +- `bk-table` accepts nested object path as data source + +## [1.1.1] - 2022-10-19 + +### Fixed + +- `bk-form-drawer` and `bk-form-modal` show `readOnly` dates with correct format, specified in `dateOptions` +- components keep loading until lookups aren't solved +- skip parameter (`_sk`) is reset when fetching data (unless query was triggered by pagination update) +- `bk-filter-drawer` filters of type `date` work correctly +- `bk-layout-container` supports disabling its render root as shadow dom. Useful to embed `bk-calendar`. + +### Added + +- enable `urlMask` in `bk-table` `customActions`. + +## [1.1.0] - 2022-10-05 + +### Fixed + +- `bk-form-drawer` sends events created by `dataCustomActions` with the correct payload +- regex operators are escaped in search queries +- `bk-form-drawer` fields don't enable save button when `lookupDeps` prop is used +- file fields are correctly updated inside nested fields +- `bk-form-modal` with set `extraEndpoint` correctly opens wizard mode +- search queries are correctly performed for number fields +- fixed filter drawer bugs: exists operator, monaco editor + +### Added + +- added the possibility to block a column in `bk-form-table` +- `ignoreCase` field is available in `filtersOptions`, controlling whether equality filters should be evaluated ignoring case +- custom button icon in nested tables +- complex date manipulation on `bk-tabs` filters + +### BREAKING CHANGES + +- docker image serving back-kit components moved to: `nexus.mia-platform.eu/back-kit/bk-web-components:{{BACK-KIT-VERSION}}`. How to fix: + - retrieve back-kit component from `nexus.mia-platform.eu/back-kit/bk-web-components:1.1.0` +- component `bk-calendar` uses `addFilter` event to handle data filtering. How to fix: + - make sure `bk-filters-manager` is included in the page: + + ```json + ... + { + "type": "element", + "tag": "bk-filters-manager" + } + ... + ``` + +- `bk-modal` is now `bk-old-modal`. How to fix: + - replace `bk-modal` with `bk-old-modal` in configurations +- `bk-drawer` is now `bk-old-drawer`. How to fix: + - replace `bk-drawer` with `bk-old-drawer` in configurations + +## [1.0.11] - 2022-10-05 + +### Fixed + +- `bk-form-drawer` sends events created by `dataCustomActions` with the correct payload +- `bk-form-modal` with set `extraEndpoint` correctly opens wizard mode + +### Added + +- `ignoreCase` field is available in `filtersOptions`, controlling whether equality filters should be evaluated ignoring case + +## [1.0.10] - 2022-09-21 + +### Fixed + +- fixed bug format currency +- readonly object and array fields are correctly displayed in forms + +## [1.0.9] - 2022-09-14 + +### Fixed + +- fixed export-modal bug on columns selection +- fixed ampersand visualization bug on table cells +- equal and not equal filters of properties with format "date" will not take in consideration the whole day + +### Added + +- new React component `BulkActions` +- new components `bk-bulk-delete` and `bk-bulk-actions` +- added support to `exists` operator in filters + +## [1.0.8] - 2022-09-07 + +### Fixed + +- `bk-pdf-viewer` opens under `bk-form-modal` +- when a time/date/date-time field is marked as readOnly, it doesn't display the correct date format in the form +- `bk-button` does not emit events after plugin is changed + +### Added + +- confirmation dialog on form submit: `bk-form-drawer`, `bk-form-modal` +- property `showArrayPopover` in `bk-table` allows displaying a popover on hovering array cells containing the elements of the array + +## [1.0.7] - 2022-08-03 + +### Fixed + +- `bk-filters-manager` does not display filters with properties having `filtersOptions.hidden` equals to true +- Fixed trailing comma bug in `bk-crud-client` while adding MongoDB query filters in "$and" clauses + +### Added + +- danger colors can be controlled by global CSS variables +- `bk-table` allows resizable columns using property `resizableColumns` +- title and content of confirmation modals of `bk-table` row actions can now use the content of the row via Handlebars +- `bk-file-picker` can be used to update fields of type `array` and format `file` +- new components `bk-export-client` and `bk-export-modal` +- Added `Export Service` frontend client to perform collection exports +- fields with type `number` support `currency` format + +## [1.0.6] - 2022-07-20 + +### Fixed + +- fixed border-radius issue on select component in multiselect mode +- fixed support to filters added at bootstrap time + +### Added + +- box-shadow color can be controlled by global CSS variables +- new React component `MultipleFileCell` +- `bk-table` has custom visualization for array of files +- `bk-table` allows to specify `download` or `view` mode in prop `navigationRowActions` +- added `appendTrailingSlash` property on `bk-crud-client` +- Update Files Service interface on `bk-file-client` allowing for download with actual filename in Content-Disposition header field +- `bk-form` and `bk-file-manager` support file array + +## [1.0.5] - 2022-07-06 + +### Fixed + +- `bk-table` does not render empty action column +- `bk-form-modal` correctly solves lookups in wizard mode + +### Added + +- `bk-card` display main content in a css grid structure +- `bk-modal` reduced top css rule to center the container +- actions are evenly spaced in actions column in `bk-table` +- http client supports PUT method +- `bk-filter-drawer` and `bk-filters-manager` migrated to lit components. +- `bk-crud-lookup-client` solves nested lookups +- `bk-pagination` resets pageNumber when count and current page are inconsistent +- `bk-crud-client` patch response can also be a 204 no-content +- `bk-filters-manager` supports hidden static filters + +## [1.0.4] - 2022-06-23 + +### Fixed + +- `bk-crud-client` fixed support to projections in GET / and GET /count methods + +### Added + +- new react hook `useDynamicElement` for creating components dynamically +- new react components `Stepper` and `Accordion` +- react components `Form` supports `accordion` visualization +- `bk-table` supports `danger` in `rowActions` and `navigationRowActions` +- `bk-button`/`bk-generic-button` supports http delete as `clickConfig` +- `bk-notifications` api fix +- `bk-crud-lookup-client` supports recursive lookup resolution when properly hinted by the `DataSchema` +- `bk-form-modal` supports wizard visualization + +## [1.0.3] - 2022-06-08 + +### Added + +- `bk-card` supports date with configurable formatting +- `bk-form` supports map visualization for object/array fields having format "geopoint" +- `bk-file-client` is implemented in lit +- `bk-file-manager` is implemented in lit +- `bk-file-picker-drawer` is implemented in lit +- `bk-form-card` is implemented in lit +- `bk-button` `bk-generic-button` support `file-download` type +- `bk-card` supports `EventBus` in sub-components props + `bk-button` style fixes on `type` `link` +- `bk-button` supports `danger` prop + +## [1.0.2] - 2022-05-25 + +### Added + +- `navigationType` can be specified in `bk-table` in prop `browseOnRowSelect`, specifying the desired navigation method. +- `bk-form-modal` and `bk-form-drawer` are implemented in lit +- `bk-card` footer accepts dynamic configurations with handlebars notation +- it is allowed to search numbers +- nested objects visualization supports file upload/download + +- `bk-table` has custom visualization for array of files +- `bk-table` allows to specify `download` or `view` mode in prop `navigationRowActions` + +## [1.0.1] - 2022-05-12 + +### Added + +- `Table` accepts (template, configMap) pairs in custom components properties. +- `Table` accepts `onCellClickBuilder`, building `onClick` callback for cells. +- property `customActions` in `bk-table` accepts (`template`, `configMap`) pairs for values depending on table row. +- `bk-table` accepts `openFileInViewerRegex`, determining which file cells are clickable, opening the file inside the native viewer of the browser. +- support to subsets of operators in `bk-filter-drawer` + support to `string` enum fields. +- new `bk-layout-container` component allows to render multiple configurations within the same plugin. +- `bk-tabs` migrated to lit components. +- `bk-tabs` can pipe custom events to the `EventBus`. +- date filters now support key `$today` as value, indicating the current date + +## [1.0.0] - 2022-04-22 + +### Added + +- added new component `Chip` +- building custom component inside `Table` handles undefined context in handlebars +- `Pagination` supports `buttonsOnly` modality, only displaying previous button, next button and page size menu +- property `allowNavigation` in `bk-form-card`, `bk-form-drawer` and `bk-form-modal` accepts values true, false, 'show-editor' +- `bk-button` accepts property `navigationStrategy` which allows to disable/hide the button in navigation +- key `showInViewer` in `formOptions` inside the data-schema and key `showInViewer` in `downloadFile`'s meta allow to display supported files (PDFs) inside the browser, while property `showPdfInBrowser` in `bk-file-client` is no longer needed +- added new component `bk-chip` +- `bk-crud-client` can retrieve `http` responses and append the content to the `success` event payload +- `bk-state-adapter` allows carrying some state to another plugin + new documentation on `plugin navigation` +- if a negative page total count is received, `bk-pagination` only displays previous button, next button and page-size menu, omitting current page, page total and skip all buttons + +## [0.10.7] - 2022-04-08 + +### BREAKING CHANGES + +- `lookupQueries` require a new key `propertyType` that specifies the type of the `property` field that is queried if this is not `string`. + How to fix: add a new key `propertyType` in each filter inside `lookupQueries`, with the type of the queried property. + +### Added + +- added new property `computeOptionKey` to `Form` and `Table` that allows to compute the key to use when retrieving options for `lookup`s and `multilookup`s +- `Table` supports custom components in the actions column +- `lookup`s and `multi-lookup`s fields are resolved when navigating nested objects/arrays in `bk-table`, `bk-form-drawer` and `bk-form-modal` +- `bk-table` supports custom components in the actions column via the prop `customActions` +- `lookupQueries` now support queries based on fields that are not included as properties in the `data-schema`. Key `propertyType` added to `lookupQueries`, indicating the type of the property being filtered +- `bk-tabs` supports handlebars in filters with array value +- `bk-crud-lookup-client` supports `extraLookupKeys`, which specifies extra fields to retrieve data from CRUD collections +- `bk-pagination` is now a lit component + +## [0.10.6] - 2022-04-01 + +### BREAKING CHANGES + +- `crud-client` interacts with `window.history` using `replaceState` instead of `pushState` allowing plugin navigation. (very low impact) + +### Added + +- It is now possible to specify the hiddenLabel visualization option in dataschema properties to hide the table column name. +- It is now possible to specify the sortable visualization option in dataschema properties to enable/disable the table column sort. +- Moved search-bar logic to web components +- `object` visualization template +- `bk-crud-lookup-client` now supports searchLookups event, searching lookups against a text value +- `bk-crud-client` now supports search queries on lookups +- removed `bk-search-bar` component +- `bk-file-client` can be configured to request in-browser PDF visualization instead of requesting download +- `bk-pdf-viewer` component allows to visualize PDF files in-browser +- added new `bk-search-bar` component that allows text search +- Add new web component `bk-dynamic-title` +- Add new web component `bk-list` +- Add new web component `bk-url-parameters` + +## [0.10.5] - 2022-03-17 + +### Added + +- Added new component `Generic Button` +- Added `between` filter +- Dynamic href are resolved for link add-ons. +- Added new components `NavigationBackArrow` and `Breadcrumbs` +- It is now possible to specify dynamic links for href in link addons. +- It is now possible to navigate and edit nested objects. +- `dataSchema` supports type `object` format `localized-text` and renders the object according with the browser language +- It is now possible to specify a `between` operator for date fields in filters. +- Form card component `bk-form-card` +- Subtitle for `form-modal` and `form-drawer` +- `nativeDownload` on `bk-export` enables native browser file download aliasing the export service +- Add new web component `bk-generic-button` - it handles configurable onCLick action. +- `bk-dynamic-title` component +- Add new web component `bk-navigation-nack-arrow` and `bk-breadcrumbs` to handle nested objects navigation. + +## [0.10.4] - 2022-02-21 + +### Fixed + +- Avoid FontAwesome's CSS collision + +### Added + +- fetchOptions for dependent fields is run on on-blur event + +## [0.10.3] - 2022-01-28 + +### Fixed + +- when `null` object reaches a table it is correctly printed as an italic placeholder string + +### Added + +- `Table` and `Form` now receive already resolved lookup data +- `Form` receives options and fetchOptions properties for dependent lookup and multilookup fields +- Options for lookup fields are now fetched live as the user is typing, instead of being retrieved all at once +- If key is turned on --> duplicate keeps the state. If state is passed as not undefined, creating drags it along as well +- Unresolved lookups can be set to display a custom error message on `bk-table`, `bk-form-drawer` and `bk-form-modal` +- It is now possible to specify dependencies between lookup and multilookup fields specifying `lookupDeps` inside `lookupOptions` in the dataSchema. +- It is now possible to specify `lookupAddTrailingSlash` in `lookupOptions` which controls whether or not a trailing `/` is added to the url when the lookup data is queried. Defaults to `true`. + +## [0.10.2] - 2022-01-14 + +### Fixed + +- It is now possible to paste content in `Editor` without scrolling back to the top + +### Added + +- `Form` allows to visualize `object`s and `array`s either as table or MonacoEditor, when attached to modal viewer +- `allowObjectAsTable` property/attribute added to `bk-form-modal` +- `bk-add-new-button` now accepts an initialValues prop that gets forwarded to the `add-new` event. + +## [0.10.1] - 2021-12-17 + +### Fixed + +- [Issue-38](https://git.tools.mia-platform.eu/platform/backoffice/headless-cms/-/issues/38) definitive delete sends `__STATE__` to CRUD jointly with delete by id request + +## [0.10.0] - 2021-12-10 + +### Fixed + +- `filterForm` now correctly supports live search in lookup fields +- readonly form drawer doesn't overwrite configurations/data-schema +- Query builder now starts off from a fresh query every time and creates it with the current query object, any other query parameter will be removed +- `bk-tabs` now expects every tab to have also a `key` property in tab objects, objects with no `key` property are deprecated, this is to keep consistency with links exchanged between users with different ACL rules +- `bk-form-drawer` now correctly passes language to its inner components +- `bk-filter-form` now correctly supports live search in lookup fields + +### BREAKING CHANGES + +- Tabs props now expect `defaultActiveKey` as `string` instead of `defaultActiveIndex`, `tabs` has to be provided as a `Record` instead of an array of tabs +- `using-drawer` event is now `using-form-container` + +### Added + +- Created new Editor component +- Created new format `editor` for the form +- Created modal as form container +- save is enabled on form drawer if entries are not touched and relative config is enabled +- `readOnly` and `disabled` properties can be configured separately on `form-drawer` `insert` or `update` opening mode +- Created bk-form-modal component + +## [0.9.0] - 2021-11-08 + +### Changed + +- `form` now correctly validates `fileInput` `required` prop +- date, lookup, file, and form addon properties are now automatically excluded from queries generated +by free-text search +- drawer confirmation modal before close is configurable from prop `requireConfirm` +- drawer actions is configurable for each action from prop `closeOnClick` + +### BREAKING CHANGES + +- Table maxLines has no default value + +### Added + +- Table fill parent size if no maxLines has been specified + +## [0.8.1] - 2021-10-26 + +### Fixed + +- `bk-file-manager` now correctly sends `create-data` event after uploading following a `create-data-with-file` + +### Added + +- `table` now supports `defaultSortedProp` and `defaultSortOrder` props to mark a column as already sorted when generating headers +- `bk-table` now supports `initialSortProperty` and `initialSortDirection` props to provide a bootstrap sorting order to table + +## [0.8.0] - 2021-10-22 + +### Fixed + +- `bk-form-drawer` should not overwrite default locales when merging user config + +### Changed + +- Data are now refreshed after an HTTP POST triggered by a table row action + +### Added + +- Form now supports file input fields +- `bk-form-drawer` can now accept a `readonlyOnView` prop, when true, will use a readonly form to represent the selected data +- `bk-form-drawer` now communicates with file manager to handle multiple file upload linked to a record while creating/updating a record + +## [0.7.0] - 2021-10-07 + +### BREAKING CHANGES + +- `bk-file-picker-drawer`, `bk-form-drawer`, and `bk-filter-drawer` locale labels are now lowercase + +### Added + +- When creating a new event, `bk-calendar` can now pass a configurable payload alongside with `startDate` and `endDate` +- When creating a new event, `bk-calendar` can now pass a configurable payload alongside with `startDate` and `endDate` + +## [0.6.0] - 2021-09-29 + +### Changed + +- Changed calendar component props interfaces + +### Added + +- Components use `headers` custom prop to inject headers on http clients + +## [0.5.0] - 2021-09-23 + +### Fixed + +- Lookup queries must involve only fields declared within the `dataSchama` +- Href links are limited to current page domain. no external ref allowed +- `email` text field validation did occur twice + +### Added + +- Drawer component now can render custom data actions in the header +- Confirmation ConfirmationModal component +- `bk-form-drawer` awaits a success/error on their transaction before to close. On error it stays open +- Custom actions are available on `bk-form-drawer` component +- Added `bk-confirm-modal` Confirmation ConfirmationModal component +- Custom actions now can trigger the `bk-confirm-modal` by specifying `requireConfirm` and customize the messages in the modal if provided in the object +- `bk-form-drawer` uses `bk-confirm-modal` to ask confirmation before closing if fields are touched + +## [0.4.0] - 2021-09-16 + +### Fixed + +- Filters on array properties that are not multilookup are now supported +- `bk-filter-drawer` will now wait for lookup data if there is at least one lookup property + in the data schema + +### BREAKING CHANGES + +- `bk-notification` component props were modified. Three props are now available: `successEventMap`, `errorEventMap` and `customEventMap` event maps + `crud-client` and `crud-lookup-client` changed prop name from `schema` to `dataSchema` +- Naming convention moved to `bk-`component-name even for `clients` and `file-picker-drawer` + +### Added + +- Documentation automation +- Filters marked as hidden are not written in the URL + +## [0.3.0] - 2021-09-09 + +### BREAKING CHANGES + +- Form links now have to be declared in the `properties` property of the data schema. Property `formLinks` + is no longer supported. +- Form titles and subtitles now have to be declared in the `properties` property of the data schema. + Properties `title`, `subtitle` and `subtitlePosition` of `data-schema`'s `FormOptions` are no longer supported. + +### Added + +- Properties can be hidden from FiltersForm with property `filtersOptions.hidden` in data schema. +- Table `rowActions` support `download-file` event when a file is available in row +- Table `browseOnSelectRow` supports browsing away by clicking the row +- Add-new-button `browseOnButtonClick` supports browsing away by clicking the button +- Form web-components now support custom localized labels + +## [0.2.0] - 2021-09-03 + +## [0.2.0-alpha.6] - 2021-09-02 + +### Fixed + +- Tabs now support values with `|` in them +- Patch now works on $set $unset + +## [0.2.0-alpha.5] - 2021-09-02 + +### Fixed + +- `__STATE__` property has been removed from query parameters `_q` and moved to `_st`. Conflicting `__STATE__` changes are defaulted in favour of the selected tab `__STATE__` filter +- Fixed filters on lookup-client + +### Added + +- Tabs support `currentUser` on queries + +## [0.2.0-alpha.4] - 2021-08-30 + +### Fixed + +- Table lookup and multilookup resolve +- Monaco now correctly load in prod build +- Required complex objects now properly validate + +### Changed + +- The only supported format both in input and output is now only ISO8601 in every component using dates +- Only changed values are sent to patch +- Edited form output formatting for Dates + +### Added + +- File picker now handle the download of a previously uploaded file +- On update data, `null` fields are used for the `$unset` +- From file drawer is now possible to download the previously uploaded file +- From file drawer is now possible to delete the previously uploaded file + +## [0.2.0-alpha.3] - 2021-08-23 + +### Fixed + +- Fixed date input formatting when format was date-time, time +- Live search in form lookup and multilookup field is now applied to label instead of value +- Fixed multiple lookup on same datasource +- Fixed scroll on top of the drawer when is visible +- Fixed filter duplication reload when there was a filter configured in DataSchema +- Fixed date input formatting when format was date-time, time +- Fixed multiple lookup on same datasource +- Standardized locale for drawer web components +- Aligned test general behavior for eventBus and subscription + +### Changed + +- Dependencies upgrade +- Removed matchMedia mock +- Jest default testEnvironment = 'jsdom' +- Font awesome icons as peer dependency +- Removed peerDependencies from devDependencies +- Reordered scripts +- Now form accept a React.Ref object +- Dependencies upgrade +- Removed testSetup +- At boot, the table loading spinner is activated + +### BREAKING CHANGES + +- The entry point for bk-web-components is now exposed under `/{DOCKER_IMAGE_VERSION}/bk-web-components.esm.js` path + +### Added + +- React Table component supports cell visualization on type: `object` and format: `file` +- Added filter support to array types +- Added support to includeSome/includeAll/includeExactly operators in array filters +- Form localization +- Form links target property is now configurable +- Support for readonly properties in form +- File picker component +- Inserted `lookupQueries` in `lookupOptions` +- More efficient components behavior thanks to `useMemo` and `useCallback` +- CrudQueryConverter now supports includeSome/includeAll/includeExactly array operators in filter queries +- Added delete support on file-client +- Added `file-manger` web-component - it handles transactions between `file-client` and `crud-client` + on collections having a property with format `file` +- Support for multiple queries in `and` in Tabs component. +- File picker with drawer component +- Inserted `filters` prop in `crud-lookup-client` +- The sort property in the url are managed by the table + +## [0.2.0-alpha.2] - 2021-08-05 + +### Fixed + +- Fix read only in date inputs. +- Aligned CRUD client format (string) with Calendar events format (date). + +### Added + +- Support to string formats `date-time` and `time` in form. diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/img/data_flow.jpg b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/img/data_flow.jpg new file mode 100644 index 0000000000..aa5e04899b Binary files /dev/null and b/versioned_docs/version-14.5.1/products/microfrontend-composer/back-kit/img/data_flow.jpg differ diff --git a/versioned_docs/version-14.5.1/products/microfrontend-composer/composer/10_structure.md b/versioned_docs/version-14.5.1/products/microfrontend-composer/composer/10_structure.md new file mode 100644 index 0000000000..2c163433e2 --- /dev/null +++ b/versioned_docs/version-14.5.1/products/microfrontend-composer/composer/10_structure.md @@ -0,0 +1,349 @@ +--- +id: structure +title: Frontend structure +sidebar_label: Structure +--- + + + +The Microfrontend Composer allows to configure multiple micro-lc services. The user can switch among services using the selector in the page header. + +The first section of the configurator targets the general structure of the frontend. It is divided into five tabs: + +1. [pages](#pages), where you can overview the frontend structure and quickly adding or removing pages, +2. [layout](#layout), where you can configure the frontend layout in a no-code fashion, +3. [settings](#settings), where frontend global and shared settings reside, +4. [webserver configuration](#webserver-configuration), where settings regarding the underlying server are made accessible, and +5. [translations](#translations), where you can view and edit the translations of different labels for different languages, +6. [advanced](#advanced-configuration), from which it is possible to review and edit the raw configuration. + +![First section](img/structure_first-section.png) + +## Pages + +The first tab is _Pages_, it allows you to view, create, modify, and delete the pages (i.e., [micro-lc applications](https://micro-lc.io/docs/guides/applications/)) composing your frontend. + +![Pages](img/structure_pages.png) + +### Create new page + +Clicking on the _Add new page_ button will open the page creation wizard, which will lead to the page setup thought two steps, [page details](#page-details) and [page options](#page-options). + +#### Page details + +On the first step of the wizard you will be asked to specify some basic details regarding the page. + +![Page details](img/structure_page-details.png) + +The requested fields are: + +- _page type_: the type of the new page chosen among + - [compose](https://micro-lc.io/docs/guides/applications/compose): a dynamically composed page constructed with HTML5 elements or web components following a provided configuration; + - [micro-frontend](https://micro-lc.io/docs/guides/applications/parcels): a framework-agnostic component directly managed by the orchestrator, which needs to be supplied with the assets entry point; + - [iFrame](https://micro-lc.io/docs/guides/applications/iframes): an HTML page embedded in an iframe tag with full strict encapsulation; +- _id_: the unique identifier of the page; +- _page rendering route_: the path on which the page will be rendered; +- _acl expression_: an optional [logical expression](https://micro-lc.io/add-ons/backend/middleware#acl-application) + evaluated against user's groups and permissions to determine whether they can view the page. + +#### Page options + +The second and last step is a type-specific form for page options. + +For **compose pages**, available fields are: + +- _input mode_: whether the page configuration is saved inline (_inline_ option) or in a separate file (_external_ option); +- _configurations manager endpoint_ (only if input mode is _external_): endpoint from which the configuration file can be fetched; +- _configuration source_ (only if input mode is _external_): name of the file containing the page configuration; +- _fetch config on mount_ (only if input mode is _external_): whether the configuration should be fetched at each application mount; +- _template_ (only if input mode is _external_): a [configuration template](/products/microfrontend-composer/composer/20_compose_pages.md#templates) carrying a pre-defined, pre-arranged set of components. + +![Page compose options](img/structure_page-compose-options.png) + +For **micro-frontend pages**, available fields are: + +- _entry_: a JSON object carrying information regarding the [entry points](https://micro-lc.io/docs/guides/applications/parcels#usage) of the micro-frontend; +- _properties_: a JSON object of [properties](https://micro-lc.io/docs/guides/applications/parcels#properties) to inject in the micro-frontend; +- _inject base_: a flag stating whether a `` tag has to be [injected](https://micro-lc.io/docs/guides/applications/parcels#injectbase) in the micro-frontend. + +:::tip +The editors will help you writing configurations hinting the correct properties JSON schemas. +::: + +![Page micro-frontend options](img/structure_page-micro-frontend-options.png) + +For **iFrame pages**, available fields are: + +- _source_: the URL of the page to embed; +- _source document_: an inline HTML document to embed (overriding _source_); +- _attributes_: `