From fc4a21b3b7093026be0931903d6b60404f4833ac Mon Sep 17 00:00:00 2001 From: Grzegorz Karaluch Date: Tue, 21 Jan 2025 09:27:46 +0100 Subject: [PATCH] docs: Update the extensibility docs (#3582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update the extensibility docs * Fix remaining docs * Fix links * Fix one more link * Fix lint * Add an example to the Wizard section * Apply suggestions from code review Co-authored-by: Mateusz Wisniewski * Update docs/extensibility/170-additional-sections-wizard.md Co-authored-by: Mateusz Wisniewski * Apply suggestions from mmitoraj review Co-authored-by: Małgorzata Świeca * Add blank spaces * Rework the preset functions parameters --------- Co-authored-by: Mateusz Wisniewski Co-authored-by: Małgorzata Świeca --- docs/extensibility/100-jsonata.md | 63 +++++++ docs/extensibility/101-preset-functions.md | 87 +++++++++ docs/extensibility/110-presets.md | 37 ++++ docs/extensibility/120-resource-extensions.md | 72 +++++++ .../130-additional-sections-resources.md | 29 +++ docs/extensibility/140-static-extensions.md | 36 ++++ ...lations-section.md => 150-translations.md} | 2 +- docs/extensibility/160-wizard-extensions.md | 41 ++++ .../170-additional-sections-wizard.md | 50 +++++ ...-extensions.md => 80-custom-extensions.md} | 12 +- docs/extensibility/90-datasources.md | 59 ++++++ docs/extensibility/datasources-section.md | 65 ------- docs/extensibility/jsonata.md | 175 ------------------ docs/extensibility/presets-section.md | 37 ---- docs/extensibility/resources.md | 113 ----------- docs/extensibility/statics.md | 58 ------ docs/extensibility/wizard.md | 76 -------- 17 files changed, 481 insertions(+), 531 deletions(-) create mode 100644 docs/extensibility/100-jsonata.md create mode 100644 docs/extensibility/101-preset-functions.md create mode 100644 docs/extensibility/110-presets.md create mode 100644 docs/extensibility/120-resource-extensions.md create mode 100644 docs/extensibility/130-additional-sections-resources.md create mode 100644 docs/extensibility/140-static-extensions.md rename docs/extensibility/{translations-section.md => 150-translations.md} (97%) create mode 100644 docs/extensibility/160-wizard-extensions.md create mode 100644 docs/extensibility/170-additional-sections-wizard.md rename docs/extensibility/{custom-extensions.md => 80-custom-extensions.md} (51%) create mode 100644 docs/extensibility/90-datasources.md delete mode 100644 docs/extensibility/datasources-section.md delete mode 100644 docs/extensibility/jsonata.md delete mode 100644 docs/extensibility/presets-section.md delete mode 100644 docs/extensibility/resources.md delete mode 100644 docs/extensibility/statics.md delete mode 100644 docs/extensibility/wizard.md diff --git a/docs/extensibility/100-jsonata.md b/docs/extensibility/100-jsonata.md new file mode 100644 index 0000000000..2e1e52bf74 --- /dev/null +++ b/docs/extensibility/100-jsonata.md @@ -0,0 +1,63 @@ +# Use JSONata Expressions with Resource-Based Extensions + +## Scoping + +The primary data source of [JSONata](https://docs.jsonata.org/overview.html) expressions changes depending on where it's used. Starting with the root, it contains the whole resource, but whenever it's in a child whose parent has a **source** (in lists and details) or **path** (in forms) parameter, the scope changes to data from that source or path. + +Additionally, the scope in arrays changes to the array item. + +For example, for this resource: + +```yaml +spec: + name: foo + description: bar + items: + - name: item-name + details: + status: ok +``` + +The following definition has their scope changed as follows: + +```yaml +- source: spec.name # top level, scope is the same as a resource + +- source: spec # top level, scope is the same as a resource + children: + - source: name # parent has source=spec, therefore this refers to spec.name + +- children: + - source: spec.name # As there's no parent source here, the scope is still the resource + +- source: spec.items + children: + - source: name # parent data is an array, therefore scope changes to its item - this refers to spec.items[0].name + - source: details.status # refers to spec.items[0].details.status (same as above) + - source: details # this changes scope for its children again + children: + source: status # this refers to spec.items[0].details.status +``` + +## Common Variables + +Common variables are the primary means to bypass the default scoping. + +- **\$root** - always contains the reference to the resource, so any JSONata in the example above can always be `$root.spec.name`. +- **\$item** - refers to the most recent array item. When not in an array, it's equal to **\$root**. +- **\$items** - contains an array of references to all parent array items (with the last item being equal to **\$item**). +- **\$value** - when used in a JSONata other than **source** (for example **visibility**, but also other widget-specific formulas), contains the value returned by the source. +- **\$index** - exists in array components, refers to the index of the current item of an array. + +### Example + +```yaml +- widget: Table + source: spec.rules + visibility: $exists($value) + collapsibleTitle: "'Rule #' & $string($index + 1)" +``` + +## Data Sources + +Whenever data sources are provided, they are available as corresponding variable names. For more information, see [Configure the dataSources Section](90-datasources.md). diff --git a/docs/extensibility/101-preset-functions.md b/docs/extensibility/101-preset-functions.md new file mode 100644 index 0000000000..104761153a --- /dev/null +++ b/docs/extensibility/101-preset-functions.md @@ -0,0 +1,87 @@ +# JSONata Preset Functions for Resource-Based Extensions + +## canI (resourceGroupAndVersion, resourceKind) + +You can use the **canI** function to determine if a user has access rights to list a specified resource. The function comes with the following parameters: + +- **resourceGroupAndVersion**: Determines the first part of a resource URL following the pattern: `${resource group}/${resource version}`. +- **resourceKind**: Describes a resource kind. + +### Example + +```yaml +- path: spec.gateway + name: gateway + visibility: $not($canI('networking.istio.io/v1beta1', 'Gateway')) +``` + +## compareStrings (first, second) + +You can use this function to sort two strings alphabetically. The function comes with the following parameters: + +- **first**: Determines the first string to compare. +- **second**: Determines the second string to compare. + +### Example + +Here is an example from the [ResourceList widget](./50-list-and-details-widgets.md#resourcelist): + +```yaml +- widget: ResourceList + source: '$myDeployments()' + name: Example ResourceList Deployments + sort: + - source: '$item.spec.strategy.type' + compareFunction: '$compareStrings($second, $first)' + default: true +``` + +## matchByLabelSelector (item, selectorPath) + +You can use this function to match Pods using a resource selector. The function comes with the following parameters: + +- **item**: Describes a Pod to be used. +- **selectorPath**: Defines a path to selector labels from `$root`. + +### Example + +Example from [dataSources](90-datasources.md). + +```yaml +- podSelector: + resource: + kind: Pod + version: v1 + filter: '$matchByLabelSelector($item, $root.spec.selector)' +``` + +## matchEvents (item, kind, name) + +You can use this function to match Events using a resource selector. The function comes with the following parameters: + +- **item**: Describes an Event to be checked. +- **kind**: Describes the kind of the Event emitting resource. +- **name**: Describes the name of the Event emitting resource. + +### Example + +```yaml +- widget: EventList + filter: '$matchEvents($item, $root.kind, $root.metadata.name)' + name: events + defaultType: NORMAL + hideInvolvedObjects: true +``` + +## readableTimestamp (timestamp) + +You can use this function to convert time to readable time. The function comes with the following parameters: + +- **timestamp**: Defines a timestamp to convert. + +### Example + +```yaml +- source: '$readableTimestamp($item.lastTransitionTime)' + name: status.conditions.lastTransitionTime +``` diff --git a/docs/extensibility/110-presets.md b/docs/extensibility/110-presets.md new file mode 100644 index 0000000000..d0522019ef --- /dev/null +++ b/docs/extensibility/110-presets.md @@ -0,0 +1,37 @@ +# Configure the presets Section + +The **presets** section contains a list of objects that define which preset and template are used in the form view. If you specify a preset, it is displayed in the dropdown list along with the **Clear** option. When you select a preset, the form is filled with the values defined in the **value** property. + +## Available Parameters + +| Parameter | Required | Type | Description | +| ----------- | -------- | ------- | ------------------------------------------------------------------------------------------------ | +| **name** | **Yes** | string | A name to display on the preset's dropdown. | +| **value** | **Yes** | | It contains the fields that are set when you choose the given preset from the list. | +| **default** | No | boolean | If set to `true`, it prefills the form with values defined in **value**. It defaults to `false`. | + +## Example + +```yaml +- name: template + default: true + value: + metadata: + name: my-name + spec: + description: A set description +- name: preset + value: + metadata: + name: second-one + spec: + data: regex + description: A different description + items: + - name: item-1 + value: 10 + - name: item-2 + value: 11 + - name: item-3 + value: 5 +``` diff --git a/docs/extensibility/120-resource-extensions.md b/docs/extensibility/120-resource-extensions.md new file mode 100644 index 0000000000..a2ff23c04b --- /dev/null +++ b/docs/extensibility/120-resource-extensions.md @@ -0,0 +1,72 @@ +# Configure a Config Map for Resource-Based Extensions + +You can set up your ConfigMap to handle your UI page by adding objects to the **general** section. This section contains basic information about the resource and additional options. +You can provide all the ConfigMap data sections as either JSON or YAML. + +## Extension Version + +The version is a string value that defines in which version the extension is configured. It is stored as a value of the `busola.io/extension-version` label. If the configuration is created with the **Create Extension** button, this value is provided automatically. When created manually, use the latest version number, for example, `'0.5'`. + +> [!NOTE] +> Busola supports only the two latest versions of the configuration. Whenever a new version of the configuration is proposed, go to your Extension and migrate your configuration to the latest version. + +## Available Parameters + +| Parameter | Required | Type | Description | | | | | | +| ---------------------------------- | -------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | --- | ------ | ------------------------------------------------------------------------------------------------------------------ | --- | +| **resource** | **Yes** | | A resource defined based on the following properties: | | | | | | +| **resource.kind** | **Yes** | string | A Kubernetes resource kind. | | | | | | +| **resource.version** | **Yes** | string | A Kubernetes resource version. | **resource.group** | No | string | An API group used for all the requests. It's not provided for the Kubernetes resources in the core (legacy) group. | | +| **name** | No | string | A name used a title in the navigation and on the list screen. It defaults to its resource kind. | | | | | | +| **category** | No | string | A name of the category used for the left-hand menu. By default, it's placed in the `Custom Resources` category. | | | | | | +| **icon** | No | | A suffix of an icon name used for the left-hand menu. The default value is `customized`. You can find the list of icons [here](https://sap.github.io/fundamental-react/?path=/docs/component-api-icon--primary). | | | | | | +| **scope** | No | string | It can be `namespace` or `cluster`. It defaults to `cluster`. | | | | | | +| **urlPath** | No | string | A path fragment for this resource used in the URL. Defaults to pluralized lowercase **kind**. It is used to provide an alternative URL to avoid conflicts with other resources. | | | | | | +| **defaultPlaceholder** | No | string | It is visible in an empty text placeholder. Overridden by the widget-level **placeholder**. Defaults to `-`. | | | | | | +| **description** | No | string | It displays a custom description on the resource list page. It can contain links. If the **translations** section has a translation entry with the ID that is the same as the **description** string, the translation is used. | | | | | | +| **filter** | No | string, [JSONata](100-jsonata.md) expression | An optional JSONata [filter](https://docs.jsonata.org/higher-order-functions#filter) used to filter the resources shown at the list section property. | | | | | | +| **features** | No | boolean | An object for the features configuration. | | | | | | +| **features.actions** | No | boolean | An object for the actions configuration. | | | | | | +| **features.actions.disableCreate** | No | boolean | When set to `true`, it disables the **Create** button. It defaults to `false`. | | | | | | +| **features.actions.disableEdit** | No | boolean | When set to `true`, it disables the **Edit** button. It defaults to `false`. | | | | | | +| **features.actions.disableDelete** | No | boolean | When set to `true`, it disables the **Delete** button. It defaults to `false`. | | | | | | +| **externalNodes** | No | string | A list of links to external websites. | | | | | | +| **externalNodes.category** | No | string | A name of the category. | | | | | | +| **externalNodes.scope** | No | string | It can be `namespace` or `cluster`. It defaults to `cluster`. | | | | | | +| **externalNodes.icon** | No | string | An icon that you can choose from the [Icon Explorer](https://sdk.openui5.org/test-resources/sap/m/demokit/iconExplorer/webapp/index.html#/overview). | | | | | | +| **externalNodes.children** | No | string | A list of child nodes containing details about the links. | | | | | | +| **externalNodes.children.label** | No | string | A displayed label. | | | | | | +| **externalNodes.children.link** | No | string, [JSONata](100-jsonata.md) expression | A link to an external website. | | | | | | + +### Example + +```yaml +resource: + kind: MyResource + version: v1alpha3 + group: networking.istio.io +name: MyResourceName +category: My Category +scope: namespace +defaultPlaceholder: '- not set -' +description: See the {{[docs](https://github.com/kyma-project/busola)}} for more information. +filter: "$filter(data, function($data) {$data.type = 'Opaque'})" +features: + actions: + disableCreate: true + disableDelete: true +externalNodes: + - category: My Category + icon: course-book + children: + - label: Example Node Label + link: 'https://github.com/kyma-project/busola' + - category: My Second Category + icon: bar-chart + scope: namespace + children: + - label: Example Node Label + link: '$string($exampleResource().link)' +``` + +For more information, see [Additional Sections for Resource-Based Extensions](130-additional-sections-resources.md). diff --git a/docs/extensibility/130-additional-sections-resources.md b/docs/extensibility/130-additional-sections-resources.md new file mode 100644 index 0000000000..a5011b41ea --- /dev/null +++ b/docs/extensibility/130-additional-sections-resources.md @@ -0,0 +1,29 @@ +# Additional Sections for Resource-Based Extensions + +## Form Section + +To customize the **form** section see the [Create forms with extensibility](./40-form-fields.md) documentation. +Views created with the extensibility [ConfigMap wizard](README.md) have a straightforward form configuration by default. + +## List Section + +The **list** section presents the resources of a kind, that is, Secrets or ConfigMaps, and comes with a few predefined columns: **Name**, **Created**, and **Labels**. +If you want to add your own columns, see [Customize UI display](./30-details-summary.md) to learn how to customize both list and details views. + +## Details Section + +The **details** section presents the resource details. To customize it, see [Customize UI display](./30-details-summary.md). The default details header contains some basic information. By default, the body is empty. + +## Value Preprocessors + +Value preprocessors are used as a middleware between a value and the actual renderer. They can transform a given value and pass it to the widget, or stop processing and render it so you can view it immediately, without passing it to the widget. + +### List of Value Preprocessors + +- **PendingWrapper** - useful when value resolves to a triple of `{loading, error, data}`: + + - For `loading` equal to `true`, it displays a loading indicator. + - For truthy `error`, it displays an error message. + - Otherwise, it passes `data` to the display component. + + Unless you need custom handling of error or loading state, we recommend using **PendingWrapper**, for example, for fields that use [data sources](90-datasources.md). diff --git a/docs/extensibility/140-static-extensions.md b/docs/extensibility/140-static-extensions.md new file mode 100644 index 0000000000..3f8e783bad --- /dev/null +++ b/docs/extensibility/140-static-extensions.md @@ -0,0 +1,36 @@ +# Configure a Config Map for Static Extensions + +You can define a static extension by adding the `busola.io/extension:statics` label to the ConfigMap. You don't need the **general** section as static extensions present data that are not connected to any resource. Instead, they may use information from the page they are displayed on using the `$embedResource` variable. You can provide all the ConfigMap data sections as either JSON or YAML. + +## Extension Version + +The version is a string value that defines in which version the extension is configured. It is stored as a value of the `busola.io/extension-version` label. When created manually, use the latest version number, for example, `'0.5'`. + +> [!NOTE] +> Busola supports only the two latest versions of the configuration. Whenever a new version of the configuration is proposed, go to your Extension and migrate your configuration to the latest version. + +## Available Parameters + +| Parameter | Required | Type | Description | +| -------------------------------- | -------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| **externalNodes** | No | string | It is used to define optional links to external websites that appear in the navigation menu. | +| **externalNodes.catagory** | No | string | A name of the category. | +| **externalNodes.scope** | No | string | It can be `namespace` or `cluster`. It defaults to `cluster`. | +| **externalNodes.icon** | No | string | An icon that you can choose from the [Icon Explorer](https://sdk.openui5.org/test-resources/sap/m/demokit/iconExplorer/webapp/index.html#/overview). | +| **externalNodes.children** | No | string | a list of child Nodes containing details about the links. | +| **externalNodes.children.label** | No | string | a displayed label. | +| **externalNodes.children.link** | No | string, [JSONata](100-jsonata.md) expression | a link to an external website. | + +### Example + +```yaml +general: + externalNodes: + - category: My Category + icon: course-book + children: + - label: Example Node Label + link: 'https://github.com/kyma-project/busola' +``` + +For more information on an exemplary configuration of the `External Nodes` feature in static extensions, see the [configuration example](examples/../../../examples/statics/statics-external-nodes.yaml). diff --git a/docs/extensibility/translations-section.md b/docs/extensibility/150-translations.md similarity index 97% rename from docs/extensibility/translations-section.md rename to docs/extensibility/150-translations.md index 1c155f397b..74b3670fd2 100644 --- a/docs/extensibility/translations-section.md +++ b/docs/extensibility/150-translations.md @@ -1,4 +1,4 @@ -# _translations_ section +# Configure Translations This optional section contains all available languages formatted for [i18next](https://www.i18next.com/) either as YAML or JSON, based on their paths. When a name is provided for a widget, that value can be used as the key, and the value is the translation for a specific language. diff --git a/docs/extensibility/160-wizard-extensions.md b/docs/extensibility/160-wizard-extensions.md new file mode 100644 index 0000000000..1b736d550a --- /dev/null +++ b/docs/extensibility/160-wizard-extensions.md @@ -0,0 +1,41 @@ +# Configure a Config Map for Wizard Extensions + +You can set up your ConfigMap to handle a custom wizard by adding objects to the **general** section. This section contains basic information about the created resources and additional options. +You can provide all the ConfigMap data sections as either JSON or YAML. + +## Extension Version + +The version is a string value that defines in which version the extension is configured. It is stored as a value of the `busola.io/extension-version` label. If the configuration is created with the **Create Extension** button, this value is provided automatically. When created manually, use the latest version number, for example, `'0.5'`. + +> [!NOTE] +> Busola supports only the two latest versions of the configuration. Whenever a new version of the configuration is proposed, go to your Extension and migrate your configuration to the latest version. + +## Available Parameters + +| Parameter | Required | Type | Description | +| -------------------------------- | -------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| **externalNodes** | No | string | It is used to define optional links to external websites that appear in the navigation menu. | +| **externalNodes.catagory** | No | string | A name of the category. | +| **externalNodes.scope** | No | string | It can be `namespace` or `cluster`. It defaults to `cluster`. | +| **externalNodes.icon** | No | string | An icon that you can choose from the [Icon Explorer](https://sdk.openui5.org/test-resources/sap/m/demokit/iconExplorer/webapp/index.html#/overview). | +| **externalNodes.children** | No | string | a list of child Nodes containing details about the links. | +| **externalNodes.children.label** | No | string | a displayed label. | +| **externalNodes.children.link** | No | string, [JSONata](100-jsonata.md) expression | a link to an external website. | + +### Example + +```yaml +id: mywizard +name: Create a MyResource +resources: + myresource: + kind: MyResource + group: busola.example.com + version: v1 + myservice: + kind: MyService + group: busola.example.com + version: v1 +``` + +See [Additional Sections for Wizard Extensions](170-additional-sections-wizard.md) for more information on the available sections. diff --git a/docs/extensibility/170-additional-sections-wizard.md b/docs/extensibility/170-additional-sections-wizard.md new file mode 100644 index 0000000000..abdd0404fd --- /dev/null +++ b/docs/extensibility/170-additional-sections-wizard.md @@ -0,0 +1,50 @@ +# Additional Sections for Wizard Extensions + +## steps Section + +Each wizard consists of steps. The steps section contains their definitions. + +### Available Parameters + +| Parameter | Required | Type | Description | | +| --------------- | -------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | --- | +| **name** | **Yes** | string | The step name displayed on the step navigation and in the step header. | | +| **resource** | **Yes** | string | The default resource identifier for this step. | | +| **form** | **Yes** | string | the form definition. This is analogous to the contents of the [form section](./40-form-fields.md) of the resource extension. | | +| **description** | No | string | Additional details about the step, shown only when the step is active. | | + +## defaults Section + +The defaults section is optional. If present, not all resources must be covered. This section contains a map of default values for specific resources. It is appended to the basic skeleton resources created based on the data provided in the [general section](160-wizard-extensions.md). + +## Example + +```yaml +data: + defaults: + qqq: + spec: + string-ref: foo + subqqq: + metadata: + labels: + example: example + steps: + - name: First step + description: this is the first step + resource: qqq + form: + - id: foo + path: spec.string-ref + name: string ref + trigger: [sr] + - path: spec.double-ref.name + name: double ref name + visibility: false + overwrite: false + subscribe: + init: spec."string-ref" + sr: spec."string-ref" +``` + +For the example of usage, check the [Get started with functions](../../examples/wizard/README.md) wizard. diff --git a/docs/extensibility/custom-extensions.md b/docs/extensibility/80-custom-extensions.md similarity index 51% rename from docs/extensibility/custom-extensions.md rename to docs/extensibility/80-custom-extensions.md index ef645b8a57..a98c3ceddc 100644 --- a/docs/extensibility/custom-extensions.md +++ b/docs/extensibility/80-custom-extensions.md @@ -1,6 +1,6 @@ # Custom Extensions -Busola's custom extension feature allows you to design fully custom user interfaces beyond the built-in extensibility functionality. This feature is ideal for creating unique and specialized displays not covered by the built-in components. +With Busola's custom extension feature, you can design fully custom user interfaces beyond the built-in extensibility functionality. This feature is ideal for creating unique and specialized displays that are not covered by the built-in components. ## Getting Started @@ -15,10 +15,10 @@ EXTENSIBILITY_CUSTOM_COMPONENTS: Creating a custom extension is as straightforward as setting up a ConfigMap with the following sections: -- `data.general`: Contains configuration details -- `data.customHtml`: Defines static HTML content -- `data.customScript`: Adds dynamic behavior to your extension. +- **data.general**: Contains configuration details +- **data.customHtml**: Defines static HTML content +- **data.customScript**: Adds dynamic behavior to your extension. -Once your ConfigMap is ready, add it to your cluster, and Busola will load and display your custom UI. +Once your ConfigMap is ready, add it to your cluster. Then, Busola loads and displays your custom UI. -See this [example](./../../examples/custom-extension/README.md), to learn more. +For more information, see this [example](./../../examples/custom-extension/README.md). diff --git a/docs/extensibility/90-datasources.md b/docs/extensibility/90-datasources.md new file mode 100644 index 0000000000..2c7490570d --- /dev/null +++ b/docs/extensibility/90-datasources.md @@ -0,0 +1,59 @@ +# Configure the dataSources Section + +The optional **dataSources** section contains an object that maps a data source name to a data source configuration object. The data source name, preceded by a dollar sign `$`, is used in the **source** expression. + +Data sources are provided in all [JSONata](100-jsonata.md) formulas as functions to call. For example, `{ "source": $myRelatedResource().metadata.labels }` returns the `metadata.labels` of the related resource. + +When you provide the whole request, you can access individual resources using the `items` field, for example `{ "widget": "Table", "source": "$myRelatedResources().items" }`. + +## Available Parameters + +| Parameter | Required | Type | Description | +| -------------------------- | -------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **resource** | **Yes** | | A resource defined based on the following properties: | +| **resource.kind** | **Yes** | string | A Kubernetes resource kind. | +| **resource.version** | **Yes** | string | A Kubernetes resource version. | +| **resource.name** | No | string | A resource name. If left empty, all resources of a given type are matched. | +| **resource.group** | No | string | A Kubernetes resource group. It's not provided for the Kubernetes resources in the core (legacy) group. | +| **resource.namespace** | No | string | The name of the resource's namespace. It defaults to the original resource's namespace. If set to `null`, cluster-wide resources or resources in all namespaces are matched. | +| **ownerLabelSelectorPath** | No | | The path to original object's selector type property. For example, `spec.selector.matchLabels` for Deployment, used to select matching Pods. | +| **filter** | No | [JSONata](100-jsonata.md) expression | It allows you to write a custom matching logic. It uses the `item` variable to point to the current item of the related kind, and the `root` variable to point to the original resource. It returns a boolean value. You can also filter using the [`matchByLabelSelector` function](101-preset-functions.md#matchbylabelselectoritem-selectorpath) to see the matched Pods. To do that, provide the Pods as `$item`, and path to the labels. | + +## Examples + +```yaml +details: + body: + - widget: ResourceList + source: '$myPods()' +dataSources: + myPods: + resource: + kind: Pod + version: v1 + ownerLabelSelectorPath: spec.selector.matchLabels +``` + +```yaml +details: + body: + - widget: ResourceList + path: '$mySecrets' +dataSources: + mySecrets: + resource: + kind: Secret + version: v1 + namespace: + filter: + '$root.spec.secretName = $item.metadata.name and $root.metadata.namespace + = $item.metadata.namespace' +``` + +```yaml +podSelector: + resource: + kind: Pod + version: v1 + filter: '$matchByLabelSelector($item, $root.spec.selector)' +``` diff --git a/docs/extensibility/datasources-section.md b/docs/extensibility/datasources-section.md deleted file mode 100644 index 495e82991e..0000000000 --- a/docs/extensibility/datasources-section.md +++ /dev/null @@ -1,65 +0,0 @@ -# _dataSources_ section - -The optional **dataSources** section contains an object that maps a data source name to a data source configuration object. The data source name, preceded by a dollar sign '\$', is used in the **source** expression. - -Data sources are provided in all [JSONata](jsonata.md) formulas as functions to call. For example, `{ "source": $myRelatedResource().metadata.labels }` returns the `metadata.labels` of the related resource. - -When you provide the whole request, you can access individual resources using the `items` field, for example `{ "widget": "Table", "source": "$myRelatedResources().items" }`. - -## Data source configuration object fields - -Busola uses the following fields to build the related resource URL and filter the received data. - -- **resource**: - - **kind** - _[required]_ Kubernetes resource kind. - - **group** - Kubernetes resource group. Not provided for Kubernetes resources in the core (also called legacy) group. - - **version** - _[required]_ Kubernetes resource version. - - **namespace** - the resource's Namespace name; it defaults to the original resource's Namespace. If set to `null`, cluster-wide resources or resources in all Namespaces are matched. - - **name** - a specific resource name; leave empty to match all resources of a given type. -- **ownerLabelSelectorPath** - the path to original object's **selector** type property; for example, `spec.selector.matchLabels` for Deployment, used to select matching Pods. -- **filter** - a [JSONata](jsonata.md) function enabling the user to write a custom matching logic. It uses the following variables: - - - **item** - the current item of the related kind. - - **root** - the original resource. - - This function should return a boolean value. - You can also use the [`matchByLabelSelector` function](jsonata.md#matchbylabelselectoritem-selectorpath) to see the matched Pods. To do that, provide the Pods as `$item`, and path to the labels. - -## Examples - -```yaml -details: - body: - - widget: ResourceList - source: '$myPods()' -dataSources: - myPods: - resource: - kind: Pod - version: v1 - ownerLabelSelectorPath: spec.selector.matchLabels -``` - -```yaml -details: - body: - - widget: ResourceList - path: '$mySecrets' -dataSources: - mySecrets: - resource: - kind: Secret - version: v1 - namespace: - filter: - '$root.spec.secretName = $item.metadata.name and $root.metadata.namespace - = $item.metadata.namespace' -``` - -```yaml -podSelector: - resource: - kind: Pod - version: v1 - filter: '$matchByLabelSelector($item, $root.spec.selector)' -``` diff --git a/docs/extensibility/jsonata.md b/docs/extensibility/jsonata.md deleted file mode 100644 index 2e08c8bd90..0000000000 --- a/docs/extensibility/jsonata.md +++ /dev/null @@ -1,175 +0,0 @@ -# Jsonata preset functions for resource-based extensions - -**Table of Contents** - -- [Overview](#overview) -- [Scoping](#scoping) -- [Preset functions](#preset-functions) - - [_canI_](#caniresourcegroupandversion-resourcekind) - - [_compareStrings_](#comparestringsfirst-second) - - [_matchByLabelSelector_](#matchbylabelselectoritem-selectorpath) - - [_matchEvents_](#matcheventsitem-kind-name) - -## Overview - -This document describes how to use JSONata expressions [JSONata](https://docs.jsonata.org/overview.html) throughout the extensions. - -## Scoping - -The primary data source of JSONata expressions changes depending on where it's used. Starting with the root, it contains the whole resource, but whenever it's in a child whose parent has a **source** (in lists and details) or **path** (in forms) parameter, the scope changes to data from that source or path. - -Additionally, scope in arrays changes to the array item. - -For example, for this resource: - -```yaml -spec: - name: foo - description: bar - items: - - name: item-name - details: - status: ok -``` - -The following definition has their scope changed as follows: - -```yaml -- source: spec.name # top level, scope is the same as resource - -- source: spec # top level, scope is the same as resource - children: - - source: name # parent has source=spec, therefore this refers to spec.name - -- children: - - source: spec.name # however there's no parent source here, therefore scope is still the resource - -- source: spec.items - children: - - source: name # parent data is an array, therefore scope changes to it's item - this refers to spec.items[0].name - - source: details.status # refers to spec.items[0].details.status (same as above) - - source: details # this changes scope for it's children again - children: - source: status # so this refers to spec.items[0].details.status -``` - -## Common variables - -Common variables are the primary means to bypass the default scoping. - -- **\$root** - always contains the reference to the resource, so any JSONata in the example above can always be `$root.spec.name`. -- **\$item** - refers to the most recent array item. When not in an array, it's equal to **\$root**. -- **\$items** - contains an array of references to all parent array items (with the last item being equal to **\$item**). -- **\$value** - when used in a JSONata other than **source** (for example **visibility**, but also other widget-specific formulas), contains the value returned by the source. -- **\$index** - exists in array components, refers to the index of the current item of an array. - -#### Example - -```yaml -- widget: Table - source: spec.rules - visibility: $exists($value) - collapsibleTitle: "'Rule #' & $string($index + 1)" -``` - -## Data sources - -Whenever data sources are provided, they are available as corresponding variable names. See [data sources](datasources-section.md) section for more details. - -## Preset functions - -### canI(resourceGroupAndVersion, resourceKind) - -You can use this function to determine if a user has access rights for listing a specified resource. - -#### Function parameters - -- **resourceGroupAndVersion** - the first part of a resource URL following the pattern: `${resource group}/${resource version}`. -- **resourceKind** - resource kind. - -#### Example - -```yaml -- path: spec.gateway - name: gateway - visibility: $not($canI('networking.istio.io/v1beta1', 'Gateway')) -``` - -### compareStrings(first, second) - -You can use this function to sort two strings alphabetically. - -#### Function parameters - -- **first** - first string to compare. -- **second** - second string to compare. - -#### Example - -Here is an example from the [ResourceList widget](./50-list-and-details-widgets.md#resourcelist): - -```yaml -- widget: ResourceList - source: '$myDeployments()' - name: Example ResourceList Deployments - sort: - - source: '$item.spec.strategy.type' - compareFunction: '$compareStrings($second, $first)' - default: true -``` - -### matchByLabelSelector(item, selectorPath) - -You can use this function to match Pods using a resource selector. - -#### Function parameters - -- **item** - Pod to be used. -- **selectorPath** - path to selector labels from `$root`. - -#### Example - -Example from [dataSources](datasources-section.md). - -```yaml -- podSelector: - resource: - kind: Pod - version: v1 - filter: '$matchByLabelSelector($item, $root.spec.selector)' -``` - -### matchEvents(item, kind, name) - -You can use this function to match Events using a resource selector. - -#### Function parameters - -- **item** - Event to be checked. -- **kind** - kind of the Event emitting resource. -- **name** - name of the Event emitting resource. - -#### Example - -```yaml -- widget: EventList - filter: '$matchEvents($item, $root.kind, $root.metadata.name)' - name: events - defaultType: NORMAL - hideInvolvedObjects: true -``` - -### readableTimestamp(timestamp) - -You can use this function to convert time to readable time. - -#### Function parameters - -- **timestamp** - timestamp to convert. - -#### Example - -```yaml -- source: '$readableTimestamp($item.lastTransitionTime)' - name: status.conditions.lastTransitionTime -``` diff --git a/docs/extensibility/presets-section.md b/docs/extensibility/presets-section.md deleted file mode 100644 index 76b9e952a2..0000000000 --- a/docs/extensibility/presets-section.md +++ /dev/null @@ -1,37 +0,0 @@ -# _presets_ section - -The **presets** section contains a list of objects that define which preset and template are used in the form view. If you specify a preset, it is displayed in the dropdown list along with the **Clear** option. When you select a preset, the form is filled with the values defined in the **value** property. - -## preset configuration object fields - -- **name** - _[required]_ a name to display on the preset's dropdown, -- **value** - _[required]_ contains fields that are set when you choose this preset from the list. -- **default** - For `default` equal to `true`, it prefills form with values defined in the **value** property. Defaults to `false`. - -## Example - -```yaml -- name: template - default: true - value: - metadata: - name: my-name - spec: - description: A set description -- name: preset - value: - metadata: - name: second-one - spec: - data: regex - description: A different description - items: - - name: item-1 - value: 10 - - name: item-2 - value: 11 - - name: item-3 - value: 5 -``` - -Preset list with one entry defined as default diff --git a/docs/extensibility/resources.md b/docs/extensibility/resources.md deleted file mode 100644 index 3439a0b2fa..0000000000 --- a/docs/extensibility/resources.md +++ /dev/null @@ -1,113 +0,0 @@ -# Config Map for resource-based extensions - -**Table of Contents** - -- [Overview](#overview) -- [Extension version](#extension-version) -- [_general_ section](#general-section) -- [_form_ section](#form-section) -- [_list_ section](#list-section) -- [_details_ section](#details-section) -- [Value preprocessors](#value-preprocessors) - - [List of value preprocessors](#list-of-value-preprocessors) - -## Overview - -This document describes the required ConfigMap setup that you need to configure in order to handle your CRD UI page. -You can provide all the ConfigMap data sections as either JSON or YAML. - -## Extension version - -The version is a string value that defines in which version the extension is configured. It is stored as a value of the `busola.io/extension-version` label. If the configuration is created with the **Create Extension** button, this value is provided automatically. When created manually, use the latest version number, for example, `'0.5'`. - -> **NOTE:**: Busola supports only the two latest versions of the configuration. Whenever a new version of the configuration is proposed, go to your Extension and migrate your configuration to the latest version. - -## _general_ section - -The **general** section is required and contains basic information about the resource and additional options. - -### Item parameters - -- **resource** - _[required]_ - information about the resource. - - **kind** - _[required]_ Kubernetes kind of the resource. - - **version** - _[required]_ API version used for all requests. - - **group** - API group used for all requests. Not provided for Kubernetes resources in the core (also called legacy) group. -- **name** - title used in the navigation and on the list screen. It defaults to its resource kind. -- **category** - the name of a category used for the left-hand menu. By default, it's placed in the `Custom Resources` category. -- **icon** - suffix of an icon name used for the left-hand menu. The default value is `customized`. You can find the list of icons [here](https://sap.github.io/fundamental-react/?path=/docs/component-api-icon--primary). -- **scope** - either `namespace` or `cluster`. Defaults to `cluster`. -- **urlPath** - path fragment for this resource used in the URL. Defaults to pluralized lowercase **kind**. Used to provide an alternative URL to avoid conflicts with other resources. -- **defaultPlaceholder** - to be shown in place of an empty text placeholder. Overridden by the widget-level **placeholder**. Defaults to `-`. -- **description** - displays a custom description on the resource list page. It can contain links. If the **translations** section has a translation entry with the ID that is the same as the **description** string, the translation is used. -- **filter** - optional [JSONata](jsonata.md) [filter](https://docs.jsonata.org/higher-order-functions#filter) used to filter the resources shown at the list section property. -- **features** - an optional object for the features configuration. - - **actions** - an optional object for the actions configuration. - - **disableCreate** - when set to `true`, it disables the **Create** button. Defaults to `false`. - - **disableEdit** - when set to `true`, it disables the **Edit** button. Defaults to `false`. - - **disableDelete** - when set to `true`, it disables the **Delete** button. Defaults to `false`. -- **externalNodes** - an optional list of links to external websites. - - **category** - a category name - - **scope** - either `namespace` or `cluster`. Defaults to `cluster`. - - **icon** - an optional icon. Go to [Icon Explorer](https://sdk.openui5.org/test-resources/sap/m/demokit/iconExplorer/webapp/index.html#/overview) to find a list of the available icons. - - **children** - a list of child nodes containing details about the links - - **label** - a displayed label - - **link** - a link to an external website. You can provide a [JSONata](jsonata.md) function. - -### Example - -```yaml -resource: - kind: MyResource - version: v1alpha3 - group: networking.istio.io -name: MyResourceName -category: My Category -scope: namespace -defaultPlaceholder: '- not set -' -description: See the {{[docs](https://github.com/kyma-project/busola)}} for more information. -filter: "$filter(data, function($data) {$data.type = 'Opaque'})" -features: - actions: - disableCreate: true - disableDelete: true -externalNodes: - - category: My Category - icon: course-book - children: - - label: Example Node Label - link: 'https://github.com/kyma-project/busola' - - category: My Second Category - icon: bar-chart - scope: namespace - children: - - label: Example Node Label - link: '$string($exampleResource().link)' -``` - -## _form_ section - -To customize the **form** section see the [Create forms with extensibility](./40-form-fields.md) documentation. -Views created with the extensibility [ConfigMap wizard](README.md) have a straightforward form configuration by default. - -## _list_ section - -The **list** section presents the resources of a kind, that is, Secrets or ConfigMaps, and comes with a few predefined columns: **Name**, **Created**, and **Labels**. -If you want to add your own columns, see [Customize UI display](./30-details-summary.md) to learn how to customize both list and details views. - -## _details_ section - -The **details** section presents the resource details. To customize it, see [Customize UI display](./30-details-summary.md). The default details header contains some basic information. By default, the body is empty. - -## Value preprocessors - -Value preprocessors are used as a middleware between a value and the actual renderer. They can transform a given value and pass it to the widget; or stop processing and render it so you can view it immediately, without passing it to the widget. - -### List of value preprocessors - -- **PendingWrapper** - useful when value resolves to a triple of `{loading, error, data}`: - - - For `loading` equal to `true`, it displays a loading indicator. - - For truthy `error`, it displays an error message. - - Otherwise, it passes `data` to the display component. - - Unless you need custom handling of error or loading state, we recommend using **PendingWrapper**, for example, for fields that use [data sources](./datasources-section.md). diff --git a/docs/extensibility/statics.md b/docs/extensibility/statics.md deleted file mode 100644 index 2acd49847b..0000000000 --- a/docs/extensibility/statics.md +++ /dev/null @@ -1,58 +0,0 @@ -# Config Map for static extensions - -**Table of Contents** - -- [Overview](#overview) -- [Static extension label](#static-extension-label) -- [Extension version](#extension-version) -- [_general_ section](#general-section) -- [_injections_ section](#injections-section) - -## Overview - -This document describes the required ConfigMap setup that you need to configure to handle a static extension. -You can provide all the ConfigMap data sections as either JSON or YAML. - -## Static extension label - -To define a static extension, add the `busola.io/extension:statics` label to the ConfigMap. - -## Extension version - -The version is a string value that defines in which version the extension is configured. It is stored as a value of the `busola.io/extension-version` label. When created manually, use the latest version number, for example, `'0.5'`. - -> **NOTE:** Busola supports only the two latest versions of the configuration. Whenever a new version of the configuration is proposed, go to your Extension and migrate your configuration to the latest version. - -## _general_ section - -The **general** section is not required as static extensions present data that are not connected to any resource. Instead, they may use information from the page they are displayed on via variable `$embedResource`. - -### _externalNodes_ - -The **externalNodes** parameter allows you to define optional links to external websites that appear in the navigation menu. - -- **externalNodes** - an optional list of links to external websites. - - **category** - a category name. - - **scope** - either `namespace` or `cluster`. Defaults to `cluster`. - - **icon** - an optional icon. Go to [Icon Explorer](https://sdk.openui5.org/test-resources/sap/m/demokit/iconExplorer/webapp/index.html#/overview) to find the list of the available icons. - - **children** - a list of child Nodes containing details about the links. - - **label** - a displayed label - - **link** - a link to an external website. You can provide a [JSONata](jsonata.md) function. - -### Example - -```yaml -general: - externalNodes: - - category: My Category - icon: course-book - children: - - label: Example Node Label - link: 'https://github.com/kyma-project/busola' -``` - -To see an exemplary configuration of the `External Nodes` feature in static extensions, check the [configuration example](examples/../../../examples/statics/statics-external-nodes.yaml). - -## _injections_ section - -For more information, read the [widget injections overview](./70-widget-injection.md). diff --git a/docs/extensibility/wizard.md b/docs/extensibility/wizard.md deleted file mode 100644 index 6975d949cd..0000000000 --- a/docs/extensibility/wizard.md +++ /dev/null @@ -1,76 +0,0 @@ -# Config Map for wizard extensions - -**Table of Contents** - -- [Overview](#overview) -- [Extension version](#extension-version) -- [_general_ section](#general-section) -- [_steps_ section](#steps-section) -- [_defaults_ section](#defaults-section) - -## Overview - -This document describes the required ConfigMap setup that you need to configure in order to handle a custom wizard. -You can provide all the ConfigMap data sections as either JSON or YAML. - -## Extension version - -The version is a string value that defines in which version the extension is configured. It is stored as a value of the `busola.io/extension-version` label. If the configuration is created with the **Create Extension** button, this value is provided automatically. When created manually, use the latest version number, for example, `'0.5'`. - -> **NOTE:**: Busola supports only the two latest versions of the configuration. Whenever a new version of the configuration is proposed, go to your Extension and migrate your configuration to the latest version. - -## _general_ section - -The **general** section is required and contains basic information about the created resources and additional options. - -### Item parameters - -- **id** - _[required]_ - an identifier used to reference the wizard to trigger its opening. -- **resources** - _[required]_ - information about the resources created by the wizard. This is a key value map with values consisting of: - - **kind** - _[required]_ Kubernetes kind of the resource. - - **version** - _[required]_ API version used for all requests. - - **group** - API group used for all requests. Not provided for Kubernetes resources in the core (also called legacy) group. -- **name** - wizard window title. - -### Example - -```yaml -id: mywizard -name: Create a MyResource -resources: - myresource: - kind: MyResource - group: busola.example.com - version: v1 - myservice: - kind: MyService - group: busola.example.com - version: v1 -``` - -## _steps_ section - -Each wizard consists of steps. This section contains their definitions. - -### Item parameters - -Each step contains the following parameters: - -- **name** - _[required]_ - the name of the step displayed on the step navigation and in the step header -- **description** - extra details about the step, shown only when the step is active -- **resource** - _[required]_ - the identifier of the default resource for this step -- **form** - _[required]_ - the definition of the form - this is analogous to the contents of the [_form_ section](./40-form-fields.md) of the resource extension - -## _defaults_ section - -This section is optional; if present, not all resources must be covered. This section contains a map of default values for specific resources. It is appended to the basic skeleton resources created based on the data provided in the [_general_ section](#general-section). - -### Example - -```yaml -myresource: - spec: - enabled: true -``` - -For the example of usage, check the [Get started with functions](../../examples/wizard/README.md) wizard.