This is a Micro-Frontend written in Angular that can render a collection of configurable widgets in the UI. All the configuration are passed by a simple JSON string or JavaScript Object.
Being a Micro-Frontend, this can be used in any web-application be it Angular, React, Vue or even simple HTML + JS page. An example of its use in a simple HTML page is given in the demo folder.
To use this Micro-Frontend, you need to first import its main.js
and style.css
files in your index.html
file of the application where you want to render the widget collection. In case of non-Angular applications, you need to import the polyfills.js
file as well.
<link rel="stylesheet" href="https://ani-json-widget-micro-frontend.surge.sh/styles.css" />
<script src="https://ani-json-widget-micro-frontend.surge.sh/polyfills.js"></script>
<script src="https://ani-json-widget-micro-frontend.surge.sh/main.js"></script>
Then use the HTML tag json-widgets
with appropriate inputs and outputs to use this.
Key | I/O | Description |
---|---|---|
jsonInput | Input | Expects a JSON string or JavaScript Object with the widget configuration and/or any network request parameters |
variables | Input | Expects a JS Object map of the variables and their values, that are automatically included in the variables of any GRAPHQL requests and are also available to be used in the widgets. |
baseURL | Input | Expects a base URL string to be appended before the url in the requests mentioned in the jsonInput |
tokens | Input | Expects a JS Object map of the tokens and their values, that can be used in the requests mentioned in the jsonInput for Authorization header. |
widgetOutput | Output | Some of the widgets can emit custom events through the widgetOutput event. |
The JSON Input Structure consists of 2 parts: the requests part(request
) and the widgets display configuration part (rows
).
Key | Type | Description |
---|---|---|
request | Object / Object[] | Contain the details of the requests that are to be made |
request.url / request[index].url | String | Specifies the url of the API calls |
request.method / request[index].method | "GRAPHQL"| "GET" | "POST" | Specifies the method of the requests. Currently it supports GraphQl and REST (GET and POST) API calls |
request.authToken / request[index].authToken | String | Specifies the Authorization header for each requests. It can either be directly set here or can take ${{tokenName}} syntax where tokenName is the name of the token in the tokens object. |
request.body / request[index].body | Object / Object[] | Contains the body of the GraphQL or REST (POST) API request. In case ofGraphQl request, the body.variables or body[index].variables object will automatically also include variables passed to the Micro-Frontend |
request | Object / Object[] | Contain the details of the requests that are to be made |
rows | Object[] | This contains the widgets configuration. Each row can contain multiple widgets OR more rows or columns, which in turn can have multiple rows or columns. |
- Each row or column can have
classes
,widgets
, or morerows
/columns
- Each widget will specify some key-value pairs:
widget
: Name of the widget typeclasses
: List of classes to be applied to the widget- And other configuration parameters related to the specific widget
- The
classes
will be bootstrap grid classes everywhere
Any string in the format ${{path.to.variable}}
will be replaced by the value of that variable from the response of the request.
Note: For arrays, both
a[0].b.c
anda.0.b.c
path notation are supported.
For Example:
In case of single request, the path can be ${{variableName}}
and the value will be the variable value from the response of the request.
In case of multiple requests, the path can be ${{0.variableName}}
and the value will be the variable value from the response of the first request.
Any string in the format #{{path.to.variable}}
will be replaced by the value of that variable from the variables
object passed to the HTML tag / Micro-Frontend.
Note: For arrays, both
a[0].b.c
anda.0.b.c
path notation are supported.
If there is variable substitution for any field, then simple JavaScript data manipulation can be done on the values.
For Example:
'Total Score : ' + (${{path.to.a.primitive.variable}} || 0)
#{{path.to.an.array}}.filter(e=>e.isValid).map(e=>e.value)
${{data.metrics.0.successRate}} ? ((${{data.metrics.0.successRate}}*100).toFixed(1) + '%')) : 'N/A'
${{data.metrics.0.pass}} ? 'Passed: ' + ${{data.metrics.0.pass}} : 'N/A'
etc.
If there is variable substitution for any field, then for complex JavaScript data manipulation, we can use JavaScript Arrow functions as a string.
For Example:
()=>{let a = ${{path.to.a.primitive.variable}}; return a}
- Sample function to convert time in Millisecond to dynamic unit:
()=>{let varMilliseconds = ${{data.foo.0.timeInMilliseconds}}; if(!varMilliseconds) return'N/A'; let seconds = Number((varMilliseconds / 1000).toFixed(1)); let minutes = Number((varMilliseconds / (1000 * 60)).toFixed(1)); let hours = Number((varMilliseconds / (1000 * 60 * 60)).toFixed(1)); let days = Number((varMilliseconds / (1000 * 60 * 60 * 24)).toFixed(1)); if (seconds < 60) { return seconds + 'Sec'; } else if (minutes < 60) { return minutes + 'Min'; } else if (hours < 24) { return hours + 'Hrs'; } else { return days + 'Days'; } }
{
"request": {
"url": "/graphql",
"method": "GRAPHQL",
"authToken": "${{xyzAuthToken}}",
"body": {
"query": "query getFoo ($inp: String!) { foo(input:$inp) {fieldName} }",
"variables": {
"inp": "123"
}
}
},
"rows": {
"classes": ["justify-content-center"],
"widgets": [
{
"widget": "widget-name",
"classes": ["col-md-6", "col-sm-12"],
"configuration1": "${{data.foo.0.fieldName}}", // Use ${{data.path}} to access the data from the response
"configuration2": "#{{externalVariableName}}", // Use #{{path}} to access the data from the variables object passed to the HTML tag / Micro-Frontend
"configuration3": "${{data.foo.0.fieldName}}.map(e=>e.value)", // You can use simple JS operation on the dynamic data
"configuration4": "()=>{ let a = ${{data.foo.0.fieldName}}; return a.length }" // For any advanced operation on the dynamic data, you can use arrow functions like this
}
]
}
}
{
"request": [
{
"url": "https://run.mocky.io/v3/db830bac-3ac3-4d97-ba85-aa13aacf5be5",
"method": "GET"
},
{
"url": "https://api.abc.com/graphql",
"method": "GRAPHQL",
"authToken": "${{xyzAuthToken}}",
"body": [
{
"query": "query getFoo ($inp: String!) { foo(input:$inp) {fieldName} }",
"variables": {
"inp": "123"
}
},
{
"query": "query { metrics { successRate pass } }"
}
]
}
],
"rows": [
{
"classes": ["justify-content-center"],
"columns": [
{
"classes": ["justify-content-center"],
"rows": [
{
"classes": ["justify-content-center"],
"widgets": [
{
"widget": "Widget 1"
}
]
},
{
"classes": ["justify-content-center"],
"widgets": [
{
"widget": "Widget 2"
}
]
}
]
},
{
"classes": ["justify-content-center"],
"widgets": [
{
"widget": "Widget 3"
},
{
"widget": "Widget 4"
}
]
}
]
},
{
"classes": ["justify-content-center"],
"widgets": [
{
"widget": "Widget 5"
}
]
}
]
}
Type | Widget | Documentation |
---|---|---|
Small Stat | small-stat |
Small Stat Docs |
Stat Graph Card | stat-graph-card |
Stat Graph Card Docs |
Line Chart | line-chart |
Line Chart Docs |
Bar Chart | bar-chart |
Bar Chart Docs |
Doughnut/Pie Chart | doughnut-pie-chart |
Doughnut/Pie Chart Docs |
Progress Chart | progress-chart |
Progress Chart Docs |