npm package: @sintradigital/vustack
Latest version: 1.0.5

# configuration


The `Vustack` project includes a `plugins` directory that contains various plugins to extend the application (e.g., `http`, `uimessages`). Each of these can be imported and used as Vue plugins within your application.

In addition to these plugins, Vustack provides a core module that includes global configurations. This core module should also be registered as a Vue plugin in your main entry file (`main.js` or `main.ts`). Below is an example of how to include it:

```javascript
// main.js or main.ts

import Vustack from 'vustack';
app.use(Vustack, {
  "test": 243
});

```

Once included, you'll be able to access the Vustack instance via `this.$vustack` in any component. The oder plugins can be load similarly:


```javascript
// main.js or main.ts

import { http } from 'vustack/plugins/http.js'
import { uimessages } from 'vustack/plugins/uimessages.js'
app.use(uimessages);
app.use(http);
```



# routing menu



The setup provides a standard configuration for routing and menus. It operates using `vue-router`, where the necessary information for rendering the navigation menu is included within the route metadata.

The following parameters can be used in the route metadata:

| **Parameter** | **Description**                                                                                 |
|---------------|-------------------------------------------------------------------------------------------------|
| `title`       | Represents the main label of the menu item.                                                     |
| `subtitle`    | Represents a descriptive subtitle.                                                              |
| `icon`        | Specifies the icon in MDI format, such as `mdi-information`, `mdi-account`.                     |
| `enabled`     | Indicates whether the route should be included in the menu.                                     |
| `order`       | Specifies a number used to sort the menu items within the navigation tree.                      |

### Note

Currently, the menu component only supports a single-level menu. However, in the future, more complex views may be implemented, potentially including a `path` field in the metadata to build a hierarchical navigation tree.

A typical route is like this:

```javascript
const _routes=[
    {
      path: '/',
      name: 'home',
      meta:{
        enabled: true,
        title: "Home",
        icon: "mdi-information",
        subtitle: "Subtitle",
        order:1
      },
      component: () => import('../views/HomeView.vue'),
    }
    //...
    ];

```

# Vuesack Overview and components

Vuestack provides a set of data-driven components that can be extended through component inheritance. This design allows for the separation of data presentation from the data source.

## Data List Components

| **Component** | **Pagination** | **Editing**       | **Filters**             |
|---------------|----------------|-------------------|-------------------------|
| List View     | Yes            | To be tested      | To be implemented        |
| Data Table    | Yes            | To be tested      | Yes                      |

## Record View Components

| **Component**     | **Status**                                           |
|-------------------|------------------------------------------------------|
| JsonFormCommonEditor   | To be completed and integrated with the list components |
| PropertyView      | To be tested and integrated with the list components |

## Data Adapters

Vuestack includes several data adapters for fetching data:

| **Data Adapter**      | **Description**                                                                                                  |
|-----------------------|------------------------------------------------------------------------------------------------------------------|
| baseDataSource        | Implements fake methods for data access.                                                                         |
| restDataSource        | Implements the standard REST protocol, allowing the developer to define the necessary code for HTTP requests.    |
| apiStackDataSource    | Implements the ApiStack API protocol.                                                                            |

# Component Composition

By composing these components, you can configure various combinations, such as instantiating a `DataGrid` with an ApiStack connection:

```javascript

import restDataService from 'vustack/extensions/restDataService';
const _config={/* conf omitted */};

const _Base=restDataService("action",{
  axios:axios
});

const DataGrid=Vustack.compone(_Base,_DataGrid);
```

Similarly, you can define a new data source connector or extend an existing one. For example, here's a datasource with hardcoded data:

```javascript
// Example of a datasource with hardcoded data

const _Base=restDataService("action",{
  axios:axios
});

const _Override={
    methods:{
        getPagedData: async function (page,itemsPerPage,_sortBy,filters) {
            return [{id:22, name:"my", value:"value"},
                {id:23, name:"my1", value:"value1"},
                {id:24, name:"my2", value:"value2"}
            ]
        }
    }
};

const DataSource=Vustack.compone(_Base,_Override);

```

## Complete Example

Below is a complete example of including a data grid component:

```javascript
// Complete example of a data grid component inclusion

<template>
  <DataGrid labelEdit="Action" title="Applications"  :config="config">
  </DataGrid>
</template>

<script >
import _DataGrid from "vustack/components/DataGrid.vue";
import restDataService from 'vustack/extensions/restDataService';
const _config={
  paging:{
    itemsPerPage:4,
  },
  editing:{
    enabled:true
  },
  filters: {
    enabled:true,
    options:{
      filtersDef:{
        fields:[{
          name:"myfield",
          label:"My field Id",
          component :"v-text-field"
        },
        //...
        }],
      }
    },
    component: "FilterForm"
  },
  headers: [
          { key: 'myfield', title: 'My field Id' },
          { key: 'myfield2', title: 'Field2' }
        ],
};

const _Base=restDataService("action",{
  axios:axios
});

const DataGrid=Vustack.compone(_Base,_DataGrid);

export default {
  name: "DataGridView",
  components: {
    DataGrid
  },
}
</script>
```

# List View Component

The `List View` component displays paginated data from the data source. The presentation logic is entirely managed at the templating level. See the example below:

```javascript
// Example of List View templating

<ListView labelEdit="Action" title="Applications" >
    <template v-slot:itemTitle="{ item }">
      {{item.first_name}} {{item.last_name}}
    </template>
    <template v-slot:itemSubTitle="{ item }">
      {{item.email}} ({{item.gebder}})
    </template>
  </ListView>


```

If the `editing.enabled` configuration parameter is set to `true`, action components for editing and deleting records, as well as a button for adding new entries, will be displayed. The editing form should also be implemented at the templating level within the "edit" slot.


```javascript
// Example of List View templating with editing

<ListView labelEdit="Action" title="Applications" >
    //...
    <template v-slot:edit="{ editingItem }">
      XXX EDITING
    </template>
  </ListView>
```

# Data Grid Component

The `DataGrid` component can be extended through both configuration and templating. The configuration object is comprehensive and includes the following sections:

- **paging**: Settings for pagination.
- **editing**: Settings for the data entry/editing form.
- **view**: Settings for the data view form.
- **delete**: Settings for the data deletion.
- **filters**: Settings for the search filters form.
- **headers**: Settings for the data columns.
- **actions**: Settings for the actions column (edit, view, delete, and custom actions).

### Paging

| **Parameter**   | **Description**                                                        |
|-----------------|------------------------------------------------------------------------|
| `itemsPerPage`  | Number of items displayed per page by default.                         |
| `enabled`       | Pagination for the data grid cannot be disabled.                       |

### Editing

| **Parameter**   | **Description**                                                        |
|-----------------|------------------------------------------------------------------------|
| `enabled`       | If `true`, enables data editing (insert and update).                  |
| `component`     | Specifies the component to use for the entry/edit form. This can be any registered component or a path for dynamic loading. |
| `options`       | Properties that will be passed to the component.                       |



### delete

| **Parameter**   | **Description**                                                        |
|-----------------|------------------------------------------------------------------------|
| `enabled`       | If `true`, enables data deletion.                  |
| `component`     | Specifies the component to use for the entry/edit form. This can be any registered component or a path for dynamic loading. |
| `options`       | Properties that will be passed to the component.                       |


### view

| **Parameter**   | **Description**                                                        |
|-----------------|------------------------------------------------------------------------|
| `enabled`       | If `true`, enables data view.                  |
| `component`     | Specifies the component to use for the entry/edit form. This can be any registered component or a path for dynamic loading. |
| `options`       | Properties that will be passed to the component.                       |

### Filters

| **Parameter**   | **Description**                                                        |
|-----------------|------------------------------------------------------------------------|
| `enabled`       | If `true`, enables search filters.                                     |
| `component`     | Specifies the component to use for the filters form. This can be any registered component or a path for dynamic loading. |
| `options`       | Properties that will be passed to the component.                       |

## Headers

The `headers` configuration is an array defining the standard columns of the native Vuetify table component. Refer to the official documentation for all available options.

In addition to the standard headers, for each header you can include these custom attributes:

| **Parameter**   | **Description**                                                        |
|-----------------|
| `sorted`       | true if the column is pre sortered                       |
| `asc`       | contains a constant string value                       |

### Header Override
The `headerOverrides` array in the configuration allows column customization. Any column defined in the `headers` section can be overriden (you can use keys not present in the model, adding fully computed fields). 
There are three ways of extending a column:

- use a constant value
- use a render function
- use a ready to be used component


| **Parameter**   | **Description**                                                        |
|-----------------|------------------------------------------------------------------------|
| `key`       | it is the concatenation of type (`item` or `header`) and the key of the column (eg. `header.id` or`item.id`)                                    |
| `component`     | if not empty print a component. This is an object with `componentName` and `options` fields available. Options properties are passed as props to the component. The `value` attribute allows to re-define the javacript expressoin for compute a custom column value, like in the render section |
| `render`       | it is a javascript snippet with no return statement. the scope contains item,index, column, value when available. eg. `value+'fdsfsf'+item.field`                       |
| `text`       | contains a constant string value                       |


component,render, field are not mutually exclusive: the are rendered one above the other. Use only one at once if you need it.


Here a list of examples.

#### Constant value
```javascript
{
  key: "item.id",
  text: "hello worlds"
}
```
#### Render Function
```javascript
{
  key: "item.id",
  render: "value+' myconstant'"
}
```
#### Component
```javascript
{
  key: "item.id",
  component: {
      componentName:"v-alert",
      options:{
        text:"prova",
        type:"success"
      },
    }
}
```

#### Javascript function
Javascript functions are allowed inside `render` and `component.value` elements. Both of them have the following prototype. The parameters availability depends on the context (item or header).

The expression:
```javascript
"component": {
                "value":"value+' ssdfdsf'",
                "componentName": "SimpleText"
                
              }

```

is equivalent to:
```javascript
function computeValue(item,index, column, value){
  return value+' ssdfdsf';
}
```



### Default sorting

Ecco la descrizione con una tabella per i parametri:

---

### Default Sort

The `defaultSort` section is an array that contains additional sorting conditions beyond those mapped directly onto the grid columns. These conditions are static and are applied before any dynamic conditions set by the data grid. This attribute allows you to enforce default sorting rules, including sorting by non-visible columns. If sorting is applied to a column already present, the values defined in `defaultSort` take precedence (i.e., the sorting cannot be modified by the user if specified here).

#### Parameters of `defaultSort` Elements:

| Parameter | Description                        | Values                  |
|-----------|------------------------------------|-------------------------|
| `key`     | The name of the field              | Any column field name   |
| `order`   | The sorting direction              | `asc` (ascending), `desc` (descending) |

#### Example:

```json
"defaultSort": [
  {
    "key": "routeShortName",
    "order": "asc"
  }
]
```
### Actions

The actions section controls the action column in the data grid (the one that contains edit, view, delete, and custom actions).

| **Parameter** | **Description**                                                                             |
| ------------- | ------------------------------------------------------------------------------------------- |
| `addDefaults` | Defines whether the standard buttons (edit, view, delete) must be added. Default is `true`. |
| `items`       | List of additional buttons to add. Each button supports the following options:              |

#### Parameters of items
| **Parameter** | **Description**                                                             |
| ------------- | --------------------------------------------------------------------------- |
| `label`       | Text shown as a tooltip or menu label.                                      |
| `position`    | Defines button placement: `submenu` (inside a three-dots menu) or `inline`. |
| `icon`        | Material Design Icon name (e.g., `"mdi-account"`).                          |
| `action`      | Function or string name of the function to invoke.                          |
| `args`        | (Optional) Arguments to pass to the function when invoked.                  |
| `options`        | (Optional) attributes trasposed to the menu item.                  |

#### Event handling

Functions can be passed directly in the configuration.
Functions can be implemented inside the grid extension through component composition.
Alternatively, the actionClicked event can be listened to in order to handle actions globally.

#### Action example
``` js
actions: {
  addDefaults: true,
  items: [
    {
      label:"New",
      position: "submenu",
      icon:"mdi-account",
      action: function (item){
        alert("Injected");
      }
    },
    {
      label:"New2",
      icon:"mdi-account",
      action: "new2!",
      args:{
        "ccc":"ddd"
      }
    }
  ]
}
```

### Full example

Below is a complete example of a configuration:

```javascript
{
  paging:{
    itemsPerPage:4,
  },
  editing:{
    enabled:true,
    component:'JsonFormCommonEditr',
    options:{
        settingsName:'accounts'
    }
  },
  filters: {
    enabled:true,
    options:{
      filtersDef:{
        fields:[
        {
          name:"campo1",
          label:"Campo 1",
          component :"v-text-field"
        },
        {
          name:"campo2",
          label:"Campo 2",
          component :"v-switch"
        },
        {
          name:"campo3",
          label:"Campo 3",
          component :"v-select",
          options:{
            items:[12,213,123,234]
          }
        }],
      }
    },
    component: "FilterForm"
  },
  headers: [
          {
            align: 'start',
            key: 'id',
            sortable: false,
            title: 'id',
          },
          { key: 'name', title: 'Name' },
          { key: 'code', title: 'Code' },
        ],
  actions:{
    addDefaults: true,
    items:[
      {
        label:"New",
        position: "submenu",
        icon:"mdi-account",
        action: function (item){
          alert("Injected"+JSON.stringify(item));
        }
      }
    ]
  }
}
```

Moreover, you can override filters or edit component by changing the template via slots:

```javascript
<template>
  <DataGrid labelEdit="Action" title="Applications"  :config="config">
     <template v-slot:edit="{ editingItem }">
       <!-- my implementation-->
    </template>
     <template v-slot:filters="{  }">
        <!-- my implementation-->
    </template>
  </DataGrid>
</template>


```

# JsonFormCommonEditor Component


## Overview

The `JsonFormCommonEditor` component implements a JSON form within a container that provides dual visualization modes: **JSON (raw data)** and **form view**. This dual-view feature is particularly useful for debugging or technical applications. The two views, hosted in separate tabs, are synchronized and accessible, allowing users to seamlessly switch between them. The dual-mode feature is enabled via the `debug` parameter.

## Features

- **Dual view**: JSON raw data and form, synchronized in real-time.
- **Debugging support**: The dual-mode view, enabled by the `debug` parameter, helps in identifying and resolving issues efficiently.
- **Tab-based layout**: JSON and form views are presented in separate, easy-to-navigate tabs.

## Parameters

### `entity`
- The `entity` field defines the name of the form to be used. This name corresponds to the configuration files required to render the form. 
- For example, an `entity` value of `"test"` links to the following configuration files:
  - JSON Schema: `/schemas/test.json`
  - UI Schema: `/schemas/test-ui.json`

The **JSON Schema** defines the data structure, while the **UI Schema** follows the format used by the JSON Form library to describe the form's user interface.

## Documentation
For full documentation, visit: [the json form website](https://jsonforms.io/) and the [UI plugin for vuetify](https://github.com/eclipsesource/jsonforms-vuetify-renderers)

## Demo and Materials
For a demo and additional resources, visit: [Demo with examples](https://jsonforms-vuetify-renderers.netlify.app/)

## Example using dynamic component
Suppose to have the following data model:

```json
{
  "date": "2022-06-15",
  "stringDate": "2022-06",
  "stringDateFull": "2022-06-15",
  "stringYear": "324"
}

```

The config for a dynamic component:

```json
{
    "componentName": "JsonFormCommonEditor",
    "options":{
        "entity":"test",
        "debug":false
    }
}

```

The JSON Schema located at `/schemas/test.json`:

```json
{
  "type": "object",
  "properties": {
    "date": {
      "type": "string",
      "format": "date"
    },
    "stringDate": {
      "type": "string"
    },
    "stringYear": {
      "type": "string"
    },
    "stringDateFull": {
      "type": "string"
    }
  }
}

```

The UI Schema located at `/schemas/test-ui.json`:

```json
{
  "type": "Categorization",
  "elements": [
    {
      "type": "Category",
      "label": "Hide Actions",
      "elements": [
        {
          "type": "VerticalLayout",
          "elements": [
            {
              "type": "Group",
              "label": "Schema Based",
              "elements": [
                {
                  "type": "HorizontalLayout",
                  "elements": [
                    {
                      "type": "Control",
                      "scope": "#/properties/date",
                      "label": "Date",
                      "options": {
                        "dateFormat": "MM/DD/YYYY",
                        "dateSaveFormat": "YYYY-MM-DD"
                      }
                    }
                  ]
                }
              ]
            },
            //... omissis
```

note: the code abova can be inclueded in edit or view form of a datagrid or listview


## Api service


The base interface for a `DataSource` component is as follows:

```javascript
{
    getPagedData: async function (page, itemsPerPage, _sortBy, filters) {},
    getItem: async function (id, force) {},
    insert: async function (data) {},
    update: async function (data) {},
    deleteItem: async function (data) {},  
}
```

## Functionality Overview

| **Method**       | **Description**                                                                                               |
|------------------|---------------------------------------------------------------------------------------------------------------|
| `getPagedData`   | Returns a paginated list of data.                                                                            |
| `getItem`        | Returns a single item based on the `id`. If the `force` parameter is `false`, it retrieves the item from local cache if available. |
| `insert`         | Provides functionality to insert new data.                                                                   |
| `update`         | Provides functionality to update existing data.                                                              |
| `deleteItem`     | Provides functionality to delete data.                                                                        |

## Hooks by Implementation

### restDataSource

| **Hook**                 | **Description**                                                        |
|--------------------------|------------------------------------------------------------------------|
| `createListRequest`      | Creates a request for listing data.                                    |
| `createInsertRequest`    | Creates a request for inserting data.                                  |
| `createUpsertRequest`    | Creates a request for updating or inserting data (upsert).              |
| `unpackGetListRequest`   | Unpacks the request for listing data.                                  |
| `unpackGetRequest`       | Unpacks the request for retrieving a single item.                       |
| `unpackUpsertResponse`   | Unpacks the response from an upsert request.                            |

### ApiStack

| **Variable**            | **Description**                                                                                               |
|-------------------------|---------------------------------------------------------------------------------------------------------------|
| Entity Name             | The name of the entity being managed.                                                                         |
| URL                     | The URL used for the API requests. If not specified, defaults to the base configuration.                      |



# Dynamic Loading


Vustack features an automatic configuration mechanism that allows components and routes to be driven entirely by external settings.
There are now **two alternative ways** for passing configuration by javascript file or json file (loaded dynamically)

---

## 1. Json File

This approach uses **JSON static configuration files**.
The file name acts as a key for the settings being referenced. For example, specifying `"test"` will refer to the file `/settings/test.json`.

**Pros**

* Can be served as a static asset.
* Can also be fetched from a database or other backend service.
* Lightweight and simple.

**Cons**

* Cannot contain code, functions, or component inclusions.
* Limited to pure JSON structures.

**Example:**

```javascript
// Using configName with static JSON file
const _routes = [{
  path: '/dynamic',
  name: 'dynamic',
  component: DynamicComponent,
  props: {
    configName: "test"  // will load /settings/test.json
  }
}]
```

You can also read these settings programmatically:

```javascript
let config = await this.vustack.services.getSettings(this.configName);
```

### Example

```javascript
import settings from '../settings/jssettings.js'

const _routes = [{
  path: '/dynamic',
  name: 'dynamic',
  component: DynamicComponent,
  props: {
    configSource: settings
  }
}]
```

## 2. JavaScript

This approach uses **JavaScript modules (objects)** instead of plain JSON.
The configuration can therefore include **functions, computed values, or reusable structures**.

**Pros**

* Can include dynamic code and functions.
* Reusable and composable.
* Ideal when configuration needs logic.

**Cons**

* Must be bundled as part of the source code.
* Less flexible for runtime changes compared to static JSON.



### Example

```javascript
const _routes = [{
  path: '/dynamic',
  name: 'dynamic',
  component: DynamicComponent,
  props: {
    configSource: () => import('../settings/jssettings.js')
  }
}]

```

## Settings structure

 Within this file, the following properties will be present:

| **Property**     | **Description**                                              |
|------------------|--------------------------------------------------------------|
| `componentName`  | Can be either the name of a loaded component or a dynamic path. |
| `options`        | Properties to be passed to the component.                   |
| `extension`        | object that are merged with the main component (composition)                   |

## Full example

Below is a complete example demonstrating the loading of a `DataGrid` component:

```json
// Complete example of loading a DataGrid component
{
  "componentName": "DataGrid",
  "extension":["restDataService"],
  "options": {
    "config": {
      "paging": {
        "itemsPerPage": 4
      },
      "editing": {
        "enabled": true
      },
      "filters": {
        "enabled": true,
        "options": {
          "filtersDef": {
            "fields": [
              {
                "name": "routeId",
                "label": "Route Id",
                "component": "v-text-field"
              },
              {
                "name": "campo1",
                "label": "Campo 1",
                "component": "v-text-field"
              },
              {
                "name": "campo2",
                "label": "Campo 2",
                "component": "v-switch"
              },
              {
                "name": "campo3",
                "label": "Campo 3",
                "component": "v-select",
                "options": {
                  "items": [
                    12,
                    213,
                    123,
                    234
                  ]
                }
              }
            ]
          }
        },
        "component": "FilterForm"
      },
      "headers": [
        {
          "align": "start",
          "key": "id",
          "sortable": false,
          "title": "id"
        },
        {
          "key": "routeId",
          "title": "Route id"
        },
        {
          "key": "routeLongName",
          "title": "Name"
        },
        {
          "key": "routeShortName",
          "title": "Code"
        }
      ]
    }
  }
}

```


# Environments and deploy

##  Configuration

Vustack provides dynamic configuration management to facilitate flexible deployment environments for Single Page Applications (SPA). Due to the nature of SPA applications, all environment variables need to be embedded inside the application container at runtime. For example, environment variables might be:

- `VITE_TEST_VARIABLE1`
- `VITE_PROD_VARIABLE`

Where `test` and `prod` represent different environments.


The configuration of Vustack revolves around a few core options that allow for environment-specific behavior and dynamic retrieval of variables.

- Always ensure that all required environment variables are available at build-time since SPAs require them to be embedded into the container.
- Custom logic in `getVariables` allows for advanced configurations like fetching values from APIs or dynamically setting values based on conditions.

This configuration provides the flexibility needed to handle different environments and dynamic variable management for modern SPAs.

### Configurable Options



| Option           | Description                                                                                               | Default Value | Example                                                                                          |
|------------------|-----------------------------------------------------------------------------------------------------------|---------------|--------------------------------------------------------------------------------------------------|
| **envMap**       | Maps navigation URLs to specific environments. Supports regular expressions and expects `HOST:PORT` format.| N/A           | `{'localhost': 'local', 'prod.mysite.com': 'prod'}`                                               |
| **variablePrefix**| Defines the prefix for environment variables based on the tool used (Vite, Webpack, Node, etc.).           | `VITE`        | Vite: `VITE_TEST_VARIABLE`, Webpack: `WEBPACK_TEST_VARIABLE`, Node: `NODE_TEST_VARIABLE`          |
| **getVariables** | A custom function to retrieve environment variables. Supports dynamic variables and external system fetches.| N/A           | ```javascript getVariables: () => ({ VITE_API_URL: process.env.VITE_API_URL }) ```                |




    
### Example Configuration

Here is an example of how you can configure Vustack for a typical use case:

```javascript
const vustackConfig = {
  ...
  envMap: {
    'localhost': 'local',
    'dev.mysite.com': 'dev',
    'prod.mysite.com': 'production',
  },
  variablePrefix: 'VITE',
  getVariables: () => {
    return {
      VITE_LOCAL_URL: "localhost/api",
      VITE_DEV_URL: "web.server/api",
    };
  }
};

```

In this example:

- The `envMap` maps different URLs to specific environments.
- The `variablePrefix` is set to `VITE`, which would prefix all environment variables.
- The `getVariables` function retrieves the environment variables dynamically using `process.env`.