saasufy-components 3.15.2 → 3.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -31
- package/collection-browser.js +8 -2
- package/input-transformer.js +48 -0
- package/package.json +1 -1
- package/utils.js +2 -0
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ Components for Saasufy
|
|
|
19
19
|
### User input
|
|
20
20
|
- [input-provider](#input-provider)
|
|
21
21
|
- [input-combiner](#input-combiner)
|
|
22
|
+
- [input-transformer](#input-transformer)
|
|
22
23
|
|
|
23
24
|
### Authentication
|
|
24
25
|
- [log-in-form](#log-in-form)
|
|
@@ -53,40 +54,14 @@ You can apply custom CSS/styling to elements that are rendered inside a viewport
|
|
|
53
54
|
|
|
54
55
|
### Components
|
|
55
56
|
|
|
56
|
-
To use
|
|
57
|
-
|
|
58
|
-
```html
|
|
59
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/socket.js" type="module" defer></script>
|
|
60
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/app-router.js" type="module" defer></script>
|
|
61
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/collection-browser.js" type="module" defer></script>
|
|
62
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/collection-adder.js" type="module" defer></script>
|
|
63
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/collection-deleter.js" type="module" defer></script>
|
|
64
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/collection-reducer.js" type="module" defer></script>
|
|
65
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/model-input.js" type="module" defer></script>
|
|
66
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/model-text.js" type="module" defer></script>
|
|
67
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/model-viewer.js" type="module" defer></script>
|
|
68
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/input-provider.js" type="module" defer></script>
|
|
69
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/input-combiner.js" type="module" defer></script>
|
|
70
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/log-in-form.js" type="module" defer></script>
|
|
71
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/log-out.js" type="module" defer></script>
|
|
72
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/oauth-link.js" type="module" defer></script>
|
|
73
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/oauth-handler.js" type="module" defer></script>
|
|
74
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/render-group.js" type="module" defer></script>
|
|
75
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/if-group.js" type="module" defer></script>
|
|
76
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/switch-group.js" type="module" defer></script>
|
|
77
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/collection-adder-group.js" type="module" defer></script>
|
|
78
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/confirm-modal.js" type="module" defer></script>
|
|
79
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/overlay-modal.js" type="module" defer></script>
|
|
80
|
-
<script src="https://saasufy.com/node_modules/saasufy-components/download-link.js" type="module" defer></script>
|
|
81
|
-
```
|
|
57
|
+
To use a component, you just need to include the relevant `<script>` tag into the `<head>` tag of your `.html` file.
|
|
58
|
+
You can simply copy-paste the script tag provided under the `Import` section of the relevant component's documentation.
|
|
82
59
|
|
|
83
60
|
You should only add the script tags for the components which your page uses to avoid wasting bandwidth and unnecessarily delaying page load for your users.
|
|
84
|
-
|
|
85
|
-
The only exception is the `socket-provider` component which is located inside the `socket.js` file - This is because that file exposes multiple components which are used behind the scenes by other components.
|
|
86
|
-
You should always include the `socket.js` script as shown above whenever you use components which depend on data from Saasufy.
|
|
61
|
+
You should always include the `socket.js` script and create a top-level `socket-provider` component if you intend to use components which depend on data from Saasufy.
|
|
87
62
|
|
|
88
|
-
Linking the scripts directly from `saasufy.com`
|
|
89
|
-
An alternative approach is to download Saasufy components using `npm install saasufy-components` and
|
|
63
|
+
Linking the scripts directly from `saasufy.com` is the simplest way to get started as it doesn't require loading anything or hosting the scripts yourself.
|
|
64
|
+
An alternative approach is to download Saasufy components using `npm install saasufy-components` and self-host them.
|
|
90
65
|
|
|
91
66
|
### Styling
|
|
92
67
|
|
|
@@ -111,6 +86,42 @@ The following utility functions can be used anywhere inside template `{{expressi
|
|
|
111
86
|
- Format UNIX timestamp as a human-readable date: `{{date(Product.updatedAt)}}`
|
|
112
87
|
- Given an array of objects, extract the values from the specified field and join them together into a single comma-separated string: `{{joinFields(Product, 'name')}}`
|
|
113
88
|
|
|
89
|
+
### File hosting
|
|
90
|
+
|
|
91
|
+
Saasufy provides basic HTTP/HTTPS file hosting functionality with support for client-side caching (with `ETag`).
|
|
92
|
+
This is especially useful for hosting images.
|
|
93
|
+
|
|
94
|
+
To upload files to Saasufy, you first need to create a field of type `string` on a model of your choice.
|
|
95
|
+
You will then need to check/enable the `blob` constraint to tell Saasufy to treat this field as a base64 file.
|
|
96
|
+
|
|
97
|
+
After you've deployed your schema from the Saasufy dashboard, you will be able to manually add new records into your model via its `data` section.
|
|
98
|
+
Saasufy will show you a file picker next to the relevant field name which you can use to upload a file/image to Saasufy.
|
|
99
|
+
|
|
100
|
+
After adding a record to Saasufy which holds a file in one of its fields, that file can be accessed over HTTP/HTTPS via your Saasufy service's `/files` HTTP endpoint.
|
|
101
|
+
The format of the URL to link directly to a specific file/image is:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
https://saasufy.com/:serviceId/files/:modelName/:modelId/:fieldName
|
|
105
|
+
```
|
|
106
|
+
For example, if the URL for your Saasufy service (which you get after deploying your service) is `wss://saasufy.com/sid7999/socketcluster/`
|
|
107
|
+
and your file is stored inside an `Image` model with ID `58f2051c-14bc-4518-8816-ff387cfdd57e` inside a `data` field, you will be able to link to your image directly using this URL:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
https://saasufy.com/sid7999/files/Image/58f2051c-14bc-4518-8816-ff387cfdd57e/data
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
You can use it to embed images into your application using the `<img>` tag like this:
|
|
114
|
+
|
|
115
|
+
```html
|
|
116
|
+
<img src="https://saasufy.com/sid7999/files/Image/58f2051c-14bc-4518-8816-ff387cfdd57e/data" alt="My image" />
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Saasufy enforces access controls for HTTP in the same way as it does for its WebSocket protocol.
|
|
120
|
+
It's possible to block or restrict access to specific files stored on specific fields via the `Access` page under the relevant model.
|
|
121
|
+
|
|
122
|
+
If your model field's access is set to `restrict`, only authenticated users with matching permissions will be able to view/download the image/file.
|
|
123
|
+
In this case, you will need to add your user's JWT token to a cookie with the name `socketcluster.saasufyService.authToken` and it will be passed along with the request.
|
|
124
|
+
|
|
114
125
|
## Components
|
|
115
126
|
|
|
116
127
|
### app-router
|
|
@@ -609,6 +620,46 @@ The `combineFilters` function produces a combined query string (joined with `%AN
|
|
|
609
620
|
- `provider-template`: A template string within which the `{{value}}` can be injected before passing to consumers. In the case of the `input-combiner`, the value is an object wherein each key represents the unique label associated with different `input-provider` components.
|
|
610
621
|
- `debounce-delay`: The delay in milliseconds to wait before triggering a change event. This is useful to batch multiple updates together. Default is 0ms.
|
|
611
622
|
|
|
623
|
+
### input-transformer
|
|
624
|
+
|
|
625
|
+
A component which can be used to transform data from an `input-provider` component and pass the transformed data to other components (or HTML elements) via custom attributes.
|
|
626
|
+
This component can be configured to provide its data to multiple components (consumers) via custom attributes.
|
|
627
|
+
|
|
628
|
+
**Import**
|
|
629
|
+
|
|
630
|
+
```html
|
|
631
|
+
<script src="https://saasufy.com/node_modules/saasufy-components/input-transformer.js" type="module" defer></script>
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
**Example usage**
|
|
635
|
+
|
|
636
|
+
The following example shows how to bind an `input-provider` component to an `input-transformer`.
|
|
637
|
+
|
|
638
|
+
```html
|
|
639
|
+
<input-provider
|
|
640
|
+
class="dollar-input"
|
|
641
|
+
name="count"
|
|
642
|
+
type="text"
|
|
643
|
+
consumers=".cents-transformer"
|
|
644
|
+
value=""
|
|
645
|
+
placeholder="Dollars"
|
|
646
|
+
></input-provider>
|
|
647
|
+
|
|
648
|
+
<input-transformer
|
|
649
|
+
class="cents-transformer"
|
|
650
|
+
consumers=".cents-container"
|
|
651
|
+
provider-template="{{Number(value) * 100}}"
|
|
652
|
+
></input-transformer>
|
|
653
|
+
|
|
654
|
+
<div class="cents-container"></div>
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
**Attributes**
|
|
658
|
+
|
|
659
|
+
- `consumers`: This allows you to connect this `input-transformer` to other elements on your page. It takes a list of selectors with optional attributes to target. For example `.my-input:value` will find all elements with a `my-input` class and update their `value` attributes with the value of the `input-provider` component in real-time. You can specify multiple selectors separated by commas such as `.my-input,my-div` - In this case, because attribute names are not specified, values will be injected into the `value` attribute (for input elements) or into the `innerHTML` property (for other kinds of elements). The default attribute/property depends on the element type.
|
|
660
|
+
- `provider-template`: A template string within which the `{{value}}` can be injected before passing to consumers.
|
|
661
|
+
- `debounce-delay`: The delay in milliseconds to wait before triggering a change event. This is useful to batch multiple updates together. Default is 0ms.
|
|
662
|
+
|
|
612
663
|
### log-in-form
|
|
613
664
|
|
|
614
665
|
A form component which allows end-users to authenticate themselves into your app using the Saasufy blockchain or any Capitalisk-based blockchain.
|
package/collection-browser.js
CHANGED
|
@@ -139,8 +139,14 @@ class CollectionBrowser extends SocketConsumer {
|
|
|
139
139
|
let currentPageElements = this.shadowRoot.querySelector('slot[name="page-number"]').assignedElements();
|
|
140
140
|
let pageNumber = Math.floor(this.collection.meta.pageOffset / this.collection.meta.pageSize + 1);
|
|
141
141
|
for (let element of currentPageElements) {
|
|
142
|
-
if (element.nodeName === 'INPUT') {
|
|
142
|
+
if (element.nodeName === 'INPUT' || element.nodeName === 'MODEL-INPUT') {
|
|
143
143
|
element.value = pageNumber;
|
|
144
|
+
} else if (
|
|
145
|
+
element.nodeName === 'INPUT-PROVIDER' ||
|
|
146
|
+
element.nodeName === 'INPUT-COMBINER' ||
|
|
147
|
+
element.nodeName === 'INPUT-TRANSFORMER'
|
|
148
|
+
) {
|
|
149
|
+
element.setAttribute('value', pageNumber);
|
|
144
150
|
} else {
|
|
145
151
|
element.innerHTML = pageNumber;
|
|
146
152
|
}
|
|
@@ -241,7 +247,7 @@ class CollectionBrowser extends SocketConsumer {
|
|
|
241
247
|
render() {
|
|
242
248
|
let collectionType = this.getAttribute('collection-type');
|
|
243
249
|
let collectionFields = this.getAttribute('collection-fields') || '';
|
|
244
|
-
let collectionView = this.getAttribute('collection-view');
|
|
250
|
+
let collectionView = this.getAttribute('collection-view') || 'defaultView';
|
|
245
251
|
let collectionPageSize = this.getAttribute('collection-page-size');
|
|
246
252
|
let collectionViewParams = this.getAttribute('collection-view-params') || '';
|
|
247
253
|
let collectionPageOffset = this.getAttribute('collection-page-offset');
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { debouncer, updateConsumerElements } from './utils.js';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_DEBOUNCE_DELAY = 0;
|
|
4
|
+
|
|
5
|
+
class InputTransformer extends HTMLElement {
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
this.isReady = false;
|
|
9
|
+
this.debounce = debouncer();
|
|
10
|
+
}
|
|
11
|
+
connectedCallback() {
|
|
12
|
+
this.isReady = true;
|
|
13
|
+
this.render();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static get observedAttributes() {
|
|
17
|
+
return [
|
|
18
|
+
'consumers',
|
|
19
|
+
'debounce-delay',
|
|
20
|
+
'provider-template',
|
|
21
|
+
'value'
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
26
|
+
this.render();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
render() {
|
|
30
|
+
if (!this.hasAttribute('value')) return;
|
|
31
|
+
|
|
32
|
+
let value = this.getAttribute('value') || '';
|
|
33
|
+
let debounceDelay = this.getAttribute('debounce-delay');
|
|
34
|
+
debounceDelay = debounceDelay ? Number(debounceDelay) : DEFAULT_DEBOUNCE_DELAY;
|
|
35
|
+
|
|
36
|
+
if (!this.isReady) return;
|
|
37
|
+
|
|
38
|
+
let consumers = this.getAttribute('consumers');
|
|
39
|
+
if (!consumers) return;
|
|
40
|
+
|
|
41
|
+
this.debounce(async () => {
|
|
42
|
+
let providerTemplate = this.getAttribute('provider-template') || '{{value}}';
|
|
43
|
+
updateConsumerElements(consumers, value, providerTemplate);
|
|
44
|
+
}, debounceDelay);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
window.customElements.define('input-transformer', InputTransformer);
|
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -320,6 +320,8 @@ export function updateConsumerElements(consumers, value, template, sourceElement
|
|
|
320
320
|
}
|
|
321
321
|
} else if (element.nodeName === 'MODEL-INPUT') {
|
|
322
322
|
element.value = value;
|
|
323
|
+
} else if (element.nodeName === 'INPUT-TRANSFORMER') {
|
|
324
|
+
element.setAttribute('value', value);
|
|
323
325
|
} else if (element.nodeName === 'INPUT-COMBINER') {
|
|
324
326
|
element.setAttribute(
|
|
325
327
|
'value',
|