contensis-cli 1.2.0 → 1.2.1-beta.0
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 +169 -8
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/copy_field_templates.md +354 -0
- package/docs/copy_field_transformation_matrix.md +65 -0
- package/package.json +2 -2
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ or use your preferred installation method below
|
|
|
11
11
|
### Windows ([Chocolatey](https://chocolatey.org/install))
|
|
12
12
|
|
|
13
13
|
```shell
|
|
14
|
-
choco install contensis-cli
|
|
14
|
+
choco install contensis-cli
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
- [Choco package docs and source](https://github.com/contensis/cli/tree/main/installers/chocolatey)
|
|
@@ -242,6 +242,7 @@ contensis >
|
|
|
242
242
|
- [Get an entry with all of its dependents](#get-an-entry-with-all-of-its-dependents)
|
|
243
243
|
- [Get entries with a ZenQL statement](#get-entries-with-a-zenql-statement)
|
|
244
244
|
- [Choose entry fields to output](#choose-entry-fields-to-output)
|
|
245
|
+
- [Get entries using the Delivery API](#get-entries-using-the-delivery-api)
|
|
245
246
|
- [Output results to a file](#output-results-to-a-file)
|
|
246
247
|
- [Format output](#format-output)
|
|
247
248
|
- [Manage API keys](#manage-api-keys)
|
|
@@ -254,7 +255,7 @@ contensis >
|
|
|
254
255
|
- [Set role details](#set-role-details)
|
|
255
256
|
- [Disable role](#disable-role)
|
|
256
257
|
- [Remove role](#remove-role)
|
|
257
|
-
- [Manage
|
|
258
|
+
- [Manage blocks](#manage-blocks)
|
|
258
259
|
- [List blocks](#list-blocks)
|
|
259
260
|
- [Get block](#get-block)
|
|
260
261
|
- [Get block logs](#get-block-logs)
|
|
@@ -277,6 +278,12 @@ contensis >
|
|
|
277
278
|
- [Import from a file](#import-from-a-file-1)
|
|
278
279
|
- [Import entries further reading](#import-entries-further-reading)
|
|
279
280
|
- [Remove entries](#remove-entries)
|
|
281
|
+
- [Copy an entry field](#copy-an-entry-field)
|
|
282
|
+
- [Copy a simple entry field](#copy-a-simple-entry-field)
|
|
283
|
+
- [Limit entries when copying field content](#limit-entries-when-copying-field-content)
|
|
284
|
+
- [Copy a composer into a canvas field](#copy-a-composer-into-a-canvas-field)
|
|
285
|
+
- [Copy a field using a template](#copy-a-field-using-a-template)
|
|
286
|
+
- [Copy a field and save the entries as output](#copy-a-field-and-save-the-entries-as-output)
|
|
280
287
|
|
|
281
288
|
## Get started
|
|
282
289
|
|
|
@@ -706,7 +713,7 @@ Use a ZenQL statement to find entries with the `--zenql` or `-q` option, add you
|
|
|
706
713
|
website t.durden@example-dev> get entries --zenql "sys.contentTypeId = plant"
|
|
707
714
|
-------------------------------------
|
|
708
715
|
[24/07 01:52:37] [INFO] Fetching initial entries in project 'website'
|
|
709
|
-
Fetch [website] >> 100% 21 0.0s/0.0s
|
|
716
|
+
Fetch [website] >> 100% 21 0.0s/0.0s
|
|
710
717
|
|
|
711
718
|
Found 21 entries in [website]
|
|
712
719
|
--------------------------------------------
|
|
@@ -771,6 +778,16 @@ Found 12 entries in [website]
|
|
|
771
778
|
website t.durden@example-dev>
|
|
772
779
|
```
|
|
773
780
|
|
|
781
|
+
### Get entries using the Delivery API
|
|
782
|
+
|
|
783
|
+
By default all Contensis operations are performed using the Management API. Some data fields are only available to output when searching the Delivery API e.g. `sys.uri`
|
|
784
|
+
|
|
785
|
+
To include the `sys.uri` field with the entries returned from the above example, as well as adding the `sys.uri` field to the `--fields` list, we would also include the `--delivery-api` option in the `get entries` command.
|
|
786
|
+
|
|
787
|
+
```shell
|
|
788
|
+
website t.durden@example-dev> get entries --delivery-api --fields sys.uri productName colour material externalPromotion --zenql "sys.contentTypeId = pot"
|
|
789
|
+
```
|
|
790
|
+
|
|
774
791
|
### Output results to a file
|
|
775
792
|
|
|
776
793
|
Use the `--output` or `-o` option followed by the file name you wish for command output to be written to
|
|
@@ -784,10 +801,10 @@ website t.durden@example-dev> get entries --zenql "sys.contentTypeId = pot" --ou
|
|
|
784
801
|
website t.durden@example-dev>
|
|
785
802
|
```
|
|
786
803
|
|
|
787
|
-
Combine other options and mobilise your data to consume elsewhere
|
|
804
|
+
Combine other options and mobilise your data to consume elsewhere: this command will dump an entry and all of its dependents (at all link depths) to a json file creating a complete picture of the entry data and everything that is linked to it.
|
|
788
805
|
|
|
789
806
|
```shell
|
|
790
|
-
get entries
|
|
807
|
+
get entries --dependents --output aloe-complete-entry.json --id 7cf921a0-ee4f-4bd6-a3f2-0fb0fe1a2ac8
|
|
791
808
|
-------------------------------------
|
|
792
809
|
[24/07 02:16:04] [INFO] Fetching initial entries in project 'website'
|
|
793
810
|
Fetch [website] >> 100% 1 0.0s/0.0s 100000p/s
|
|
@@ -1103,9 +1120,9 @@ website t.durden@example-dev> get webhook "Slack"
|
|
|
1103
1120
|
website t.durden@example-dev>
|
|
1104
1121
|
```
|
|
1105
1122
|
|
|
1106
|
-
## Manage
|
|
1123
|
+
## Manage blocks
|
|
1107
1124
|
|
|
1108
|
-
You can manage blocks for any Contensis project using the following commands
|
|
1125
|
+
You can manage deployed blocks for any Contensis project using the following commands
|
|
1109
1126
|
|
|
1110
1127
|
### List blocks
|
|
1111
1128
|
|
|
@@ -1229,7 +1246,7 @@ website t.durden@example-dev> execute block action release contensis-website 78
|
|
|
1229
1246
|
[cli] ✅ [example-dev] Action release on contensis-website in project website requested successfully
|
|
1230
1247
|
v78 contensis-website
|
|
1231
1248
|
state: available
|
|
1232
|
-
released: [23/11/2022 01:42]
|
|
1249
|
+
released: [23/11/2022 01:42] t.durden
|
|
1233
1250
|
status:
|
|
1234
1251
|
deployment: deployed
|
|
1235
1252
|
workflow: released
|
|
@@ -1697,3 +1714,147 @@ website t.durden@example-dev>
|
|
|
1697
1714
|
```
|
|
1698
1715
|
|
|
1699
1716
|
<sup><sub>Add the `--commit` option to make the changes, be very careful using this! There is no going back</sub></sup>
|
|
1717
|
+
|
|
1718
|
+
## Copy an entry field
|
|
1719
|
+
|
|
1720
|
+
This command allows us to copy the contents of one entry field to another, this is useful if, for example - when a field is named incorrectly, or was specified originally as one field type but we would like to curate and present this content differently in future.
|
|
1721
|
+
|
|
1722
|
+
The required inputs for using `copy field` are:
|
|
1723
|
+
|
|
1724
|
+
- `contentTypeId`: the content type containing the field to copy
|
|
1725
|
+
- `fieldId`: the field id containing the source data
|
|
1726
|
+
- `destinationId`: the target field id where the data will be copied to
|
|
1727
|
+
|
|
1728
|
+
Copying field data from one field to another can only be done with fields that exist in the content type, and with the source and destination field types are metioned in the [transformation matrix](docs/copy_field_transformation_matrix.md)
|
|
1729
|
+
|
|
1730
|
+
Similar to the `import` commands, the `copy` command is safe to run again and again for testing and reviewing the output. The changes are made to the entries permanently when the `--commit` option is added.
|
|
1731
|
+
|
|
1732
|
+
### Copy a simple entry field
|
|
1733
|
+
|
|
1734
|
+
To copy the contents of one field to another use the command like this:
|
|
1735
|
+
|
|
1736
|
+
```
|
|
1737
|
+
copy field <contentTypeId> <fieldId> <destinationId>
|
|
1738
|
+
```
|
|
1739
|
+
|
|
1740
|
+
For the next example, we will copy the contents of a field called `text` into another field called `heading`, in the `contentPage` content type
|
|
1741
|
+
|
|
1742
|
+
```shell
|
|
1743
|
+
website t.durden@example-dev> copy field contentPage text heading
|
|
1744
|
+
-------------------------------------
|
|
1745
|
+
-- IMPORT PREVIEW --
|
|
1746
|
+
[07/05 16:21:40] [INFO] OK to copy contentPage[text]<string> field into contentPage[heading]<string> in website on example-dev [direct]
|
|
1747
|
+
[07/05 16:21:40] [INFO] Searching for initial entries in example-dev project 'website'
|
|
1748
|
+
[07/05 16:21:40] [INFO] Finding 2 entries in example-dev project 'website'
|
|
1749
|
+
[07/05 16:21:45] [INFO] Building 2 content entries
|
|
1750
|
+
|
|
1751
|
+
2/2 entries to migrate into [website]
|
|
1752
|
+
|
|
1753
|
+
contentTypeId status total
|
|
1754
|
+
----------------------------------------------
|
|
1755
|
+
contentPage update 2
|
|
1756
|
+
----------------------------------------------
|
|
1757
|
+
|
|
1758
|
+
id contentTypeId status updates entryTitle
|
|
1759
|
+
--------------------------------------------------------------------------------------------------------------
|
|
1760
|
+
21818721-f03e-4e8a-9982-c83212409850 contentPage update -1,+1 Content page
|
|
1761
|
+
70fa7283-cdba-462d-8cd3-a1d4b30ac2e7 contentPage update -0,+1 Test field data
|
|
1762
|
+
--------------------------------------------------------------------------------------------------------------
|
|
1763
|
+
|
|
1764
|
+
[07/05 16:21:45] [OK] Entries migration preview ready
|
|
1765
|
+
|
|
1766
|
+
[cli] ⏩ import from project website to website
|
|
1767
|
+
|
|
1768
|
+
- contentPage: 2 [existing: 100%] [needs update: 100%]
|
|
1769
|
+
- totalCount: 2
|
|
1770
|
+
|
|
1771
|
+
[cli] ✅ [example-dev] Will import 2 entries
|
|
1772
|
+
|
|
1773
|
+
[cli] ⏩ Add --commit flag to commit the previewed changes
|
|
1774
|
+
|
|
1775
|
+
website t.durden@example-dev>
|
|
1776
|
+
```
|
|
1777
|
+
|
|
1778
|
+
We can request more output for our preview by adding `--output-entries changes` option and we will see a diff of the entries that have updates applied to them.
|
|
1779
|
+
|
|
1780
|
+
### Limit entries when copying field content
|
|
1781
|
+
|
|
1782
|
+
If the number of entries to copy in a content type are too large to manage, or if we are testing the `copy field` command with a subset of entries we can supply one of the following options to limit the entries that are returned when we run the `copy field` command.
|
|
1783
|
+
|
|
1784
|
+
- `--id`: copy the field contents of one entry only
|
|
1785
|
+
- `--zenql`: provides the finest level of control over the returned entries
|
|
1786
|
+
- `--search`: limits the results with a simple keyword or phrase
|
|
1787
|
+
|
|
1788
|
+
Consult the command `copy field --help` to see all of the available options
|
|
1789
|
+
|
|
1790
|
+
### Copy a composer into a canvas field
|
|
1791
|
+
|
|
1792
|
+
, in order to transform the contents of a Composer field in an entry to a canvas field type, we achieve this by rendering each item in the Composer as simple HTML representation internally before parsing this markup and converting it to canvas then adding the output to our destination entry field, working in the same way as if we were copying the contents of a rich text field type (containing markup) to a canvas field.
|
|
1793
|
+
|
|
1794
|
+
```shell
|
|
1795
|
+
contensis t.durden@example-dev> copy field contentPage composer canvas --output-entries changes
|
|
1796
|
+
-------------------------------------
|
|
1797
|
+
-- IMPORT PREVIEW --
|
|
1798
|
+
[07/05 17:02:51] [INFO] OK to copy contentPage[composer]<objectArray> field into contentPage[canvas]<objectArray> in website on example-dev [canvas]
|
|
1799
|
+
[07/05 17:02:51] [INFO] Searching for initial entries in example-dev project 'website'
|
|
1800
|
+
[07/05 17:02:53] [INFO] Finding 1 entries in example-dev project 'website'
|
|
1801
|
+
[07/05 17:02:56] [INFO] Building 1 content entries
|
|
1802
|
+
|
|
1803
|
+
1/1 entries to migrate into [website]
|
|
1804
|
+
|
|
1805
|
+
contentTypeId status total
|
|
1806
|
+
----------------------------------------------
|
|
1807
|
+
contentPage update 1
|
|
1808
|
+
----------------------------------------------
|
|
1809
|
+
|
|
1810
|
+
id contentTypeId status updates entryTitle
|
|
1811
|
+
--------------------------------------------------------------------------------------------------------------
|
|
1812
|
+
401abeba-d47d-4975-8890-db4b07ad58c4 contentPage update -1,+1 Content page
|
|
1813
|
+
--------------------------------------------------------------------------------------------------------------
|
|
1814
|
+
|
|
1815
|
+
[07/05 17:02:56] [OK] Entries migration preview ready
|
|
1816
|
+
|
|
1817
|
+
update 401abeba-d47d-4975-8890-db4b07ad58c4 contentPage Content page
|
|
1818
|
+
diff: '{'canvas':[{'id':'<->9fef6713','type':'_paragraph'}],'</-><+>c2c69573','type':'_paragraph','value':[{'id':'2edb9251','type':'_fragment','value':'This is the page content curated in a '},{'id':'fc28bf06','properties':{'decorators':['code']},'type':'_fragment','value':'markup'},{'id':'b67233b7','type':'_fragment','value':' composer item'}]},{'id':'f13ced2f','type':'_image','value':{'asset':{'sys':{'availableLanguages':['en-GB'],'id':'e7ee357f-35b1-4315-be7a-3d0cc2ff661b','isPublished':true,'language':'en-GB','metadata':{'includeInAToZ':false,'includeInMenu':false,'includeInSearch':true,'includeInSiteMap':false,'nodeId':'e7ee357f-35b1-4315-be7a-3d0cc2ff661b'},'owner':'d.mee','projectId':'contensis','properties':{'fileId':'e7ee357f-35b1-4315-be7a-3d0cc2ff661b','filename':'swiss-army-knife-blog-image1.jpeg','filePath':'/image-library/blog-images/','fileSize':48731,'height':512,'width':357},'version':{'created':'2021-09-24T10:56:10.8000819Z','createdBy':'ServicesUser','modified':'2021-09-24T10:56:10.8000819Z','modifiedBy':'ServicesUser','published':'2021-10-04T10:05:45.9434807Z','publishedBy':'ServicesUser','versionNo':'1.0'},'versionStatus':'latest','workflow':{'id':'contensisEntryBasic','state':'versionComplete'}},'title':'Swiss Army Knife - Blog image1'}}},{'id':'867aebcd','type':'_paragraph','value':'This line was curated as plain text'},{'id':'f9e378c8','properties':{'component':'iconWithText'},'type':'_component','value':{'icon':{'sys':{'id':'7d62ee24-b36a-46c3-b49f-09b32575dfbd','language':'en-GB'}},'text':'Some text curated in a component along with my icon'}}],'</+>composer':[{'type':'markup','value':'<p>This is the page content curated in a <code>markup</code> composer item</p>'},{'type':'image','value':{'altText':'An inline image in my content page','asset':{'sys':{'id':'e7ee357f-35b1-4315-be7a-3d0cc2ff661b'}}}},{'type':'text','value':'This line was curated as plain text'},{'type':'iconWithText','value':{'icon':{'sys':{'id':'7d62ee24-b36a-46c3-b49f-09b32575dfbd'}},'text':'Some text curated in a component along with my icon'}}],'heading':'This is my content heading','text':'Content page'}
|
|
1819
|
+
|
|
1820
|
+
[cli] ⏩ import from project website to website
|
|
1821
|
+
|
|
1822
|
+
- contentPage: 1 [existing: 100%] [needs update: 100%]
|
|
1823
|
+
- totalCount: 1
|
|
1824
|
+
|
|
1825
|
+
[cli] ✅ [example-dev] Will import 1 entries
|
|
1826
|
+
|
|
1827
|
+
[cli] ⏩ Add --commit flag to commit the previewed changes
|
|
1828
|
+
|
|
1829
|
+
website t.durden@example-dev>
|
|
1830
|
+
```
|
|
1831
|
+
|
|
1832
|
+
### Copy a field using a template
|
|
1833
|
+
|
|
1834
|
+
For fine-grained control of what is rendered or copied into the target field we can supply a `--template` option with a string value that is a [LiquidJS](https://liquidjs.com/tutorials/intro-to-liquid.html) template with access to variables we can use to directly drive how the output is written into our target field
|
|
1835
|
+
|
|
1836
|
+
The syntax for applying a template with the `copy field` command is
|
|
1837
|
+
```shell
|
|
1838
|
+
copy field blog description kicker --template "<h2>{{ value }}</h2>"
|
|
1839
|
+
```
|
|
1840
|
+
in this example the `value` from `description` field will be wrapped in a `<h2>` tag before being added to the `kicker` field
|
|
1841
|
+
|
|
1842
|
+
The template must be surrounded in double-quotes and be entered (or pasted) in a single line for it to be parsed correctly with the intended command.
|
|
1843
|
+
|
|
1844
|
+
Adding a template containing html? Attributes can be wrapped in single quotes.
|
|
1845
|
+
|
|
1846
|
+
Escape characters and new lines can be introduced inside templates when calling `contensis copy field` from your system shell as a cli command. This is OS/shell dependent and does not work in the Contensis shell (due to the combined layers of command parsing)
|
|
1847
|
+
|
|
1848
|
+
Further documentation on using [templates](docs/copy_field_templates.md)
|
|
1849
|
+
|
|
1850
|
+
### Copy a field and save the entries as output
|
|
1851
|
+
|
|
1852
|
+
As we do not actually commit the output of a `copy field` command until specified we can also save the entries preview containing the new field data.
|
|
1853
|
+
|
|
1854
|
+
With the saved output we can examine the raw output of each entry containing the copied field data before we choose to load it, or we can repurpose the saved entries output for further processing.
|
|
1855
|
+
|
|
1856
|
+
Add the `--save-entries` option to the `copy field` command, remember to also include the `--output copy-entries.json` option, specifying the file where the output will be saved.
|
|
1857
|
+
|
|
1858
|
+
```shell
|
|
1859
|
+
copy field contentPage composer canvas --save-entries --output canvas-entries.json
|
|
1860
|
+
```
|
package/dist/version.js
CHANGED
|
@@ -21,7 +21,7 @@ __export(version_exports, {
|
|
|
21
21
|
LIB_VERSION: () => LIB_VERSION
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(version_exports);
|
|
24
|
-
const LIB_VERSION = "1.2.0";
|
|
24
|
+
const LIB_VERSION = "1.2.1-beta.0";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
LIB_VERSION
|
package/dist/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["export const LIB_VERSION = \"1.2.0\";\n"],
|
|
4
|
+
"sourcesContent": ["export const LIB_VERSION = \"1.2.1-beta.0\";\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
## Apply a template
|
|
2
|
+
|
|
3
|
+
If your field type is not supported in the [copy field transformation matrix](copy_field_transformation_matrix.md), or you wish to modify the output value for the field we can supply a [LiquidJS](https://liquidjs.com/tutorials/intro-to-liquid.html) template where we can make use of "tags" and "filters" available in LiquidJS to perform custom transformations on our entry field data
|
|
4
|
+
|
|
5
|
+
The result after parsing this template will become the new value for the destination field for every entry
|
|
6
|
+
|
|
7
|
+
Templates allow us to to make some very precise adjustments to the field value we will update
|
|
8
|
+
|
|
9
|
+
A number of variables are available to use in the liquid template
|
|
10
|
+
|
|
11
|
+
- `value` - the value of the source field in the entry
|
|
12
|
+
- `existing_value` - any existing value of the target field in the entry
|
|
13
|
+
- `target_value` - the value that has been prepared to go into the destination field
|
|
14
|
+
- `entry` - the entire entry object (if we need to reference another field in the entry)
|
|
15
|
+
- `field` - the content type configuration of the source field
|
|
16
|
+
- `target_field` - the content type configuration of the target field
|
|
17
|
+
|
|
18
|
+
### Examples
|
|
19
|
+
|
|
20
|
+
These are simple examples of using and chaining [LiquidJS filters](https://liquidjs.com/filters/overview.html)
|
|
21
|
+
|
|
22
|
+
- `"{{ value | capitalize }}"` will capitalise the first letter of the value
|
|
23
|
+
- `"{{ value | downcase }}"` will lowercase the entire value
|
|
24
|
+
- `"{{ value | downcase | capitalize }}"` will lowercase the entire value then capitalise the first letter
|
|
25
|
+
- `"{{ value >= 50 }}"` using logic based on a source field value we can set a boolean to true or false
|
|
26
|
+
|
|
27
|
+
Use of [LiquidJS tags](https://liquidjs.com/tags/overview.html) is also available for more complex scenarios
|
|
28
|
+
|
|
29
|
+
### Apply the template before any field transformation
|
|
30
|
+
|
|
31
|
+
Templates are parsed and rendered after field transformations have taken place and the resulting value is set on the entry as our new field's value.
|
|
32
|
+
|
|
33
|
+
A special variable is available called `source_value` (which is the same as `value`) except when used, the template is parsed and rendered *prior* to any field transformations taking place.
|
|
34
|
+
|
|
35
|
+
The result of this template when parsed will override the source field's value from each entry and this will be transformed again to the target field's type before the resulting value is set on the entry as our target field's value.
|
|
36
|
+
|
|
37
|
+
This is necessary if you wish to alter the source field value prior to any internal transformations (e.g. before we convert the value to a canvas field).
|
|
38
|
+
|
|
39
|
+
Using `source_value` means `target_value` and `value` variables are not available.
|
|
40
|
+
|
|
41
|
+
#### Examples
|
|
42
|
+
|
|
43
|
+
- `"<h1>{{ source_value }}</h1>"` allows us to surround our `source_value` with some text before it is converted into the destination field type (e.g. canvas)
|
|
44
|
+
- `"{{ source_value | remove: ".aspx" }}"` will remove any instance of `.aspx` from our source value
|
|
45
|
+
|
|
46
|
+
### Transform Composer content with a template
|
|
47
|
+
|
|
48
|
+
Because of the near infinite flexibility provided by Composer field configurations, in order to transform parts of, or the entire contents of a Composer field in an entry to another field type (except canvas which is now supported by default), we can do this by writing our own template to configure how each item in the Composer is to be "rendered" before adding the transformation result to our destination entry field.
|
|
49
|
+
|
|
50
|
+
#### Examples
|
|
51
|
+
|
|
52
|
+
If we have the following Composer content in JSON containing a number of different data types or "Composer items":
|
|
53
|
+
|
|
54
|
+
```JSON
|
|
55
|
+
[
|
|
56
|
+
{
|
|
57
|
+
"type": "text",
|
|
58
|
+
"value": "This is my plain text"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "markup",
|
|
62
|
+
"value": "<p>This is rich <em>text</em> with some <strong>styling</strong></p>"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"type": "quote",
|
|
66
|
+
"value": {
|
|
67
|
+
"source": "This is the source",
|
|
68
|
+
"text": "This is a quote"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "number",
|
|
73
|
+
"value": 123456789
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"value": false
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "location",
|
|
81
|
+
"value": {
|
|
82
|
+
"lat": 51.584151,
|
|
83
|
+
"lon": -2.997664
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"type": "list",
|
|
88
|
+
"value": [
|
|
89
|
+
"Plum",
|
|
90
|
+
"Orange",
|
|
91
|
+
"Banana"
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"type": "iconWithText",
|
|
96
|
+
"value": {
|
|
97
|
+
"icon": {
|
|
98
|
+
"sys": {
|
|
99
|
+
"id": "51639de0-a1e4-4352-b166-17f86e3558bf"
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"text": "This is my icon text"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"type": "asset",
|
|
107
|
+
"value": {
|
|
108
|
+
"sys": {
|
|
109
|
+
"id": "e798df96-1de3-4b08-a270-3787b902a580"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"type": "image",
|
|
115
|
+
"value": {
|
|
116
|
+
"altText": "A photo of Richard Saunders.",
|
|
117
|
+
"asset": {
|
|
118
|
+
"sys": {
|
|
119
|
+
"id": "bc6435eb-c2e3-4cef-801f-b6061f9cdad6"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
We could supply a template to pull out specific item types into our destination field
|
|
128
|
+
|
|
129
|
+
The example below will take the list field above and allow the content to be copied into any string type field
|
|
130
|
+
|
|
131
|
+
```handlebars
|
|
132
|
+
{% # use a "for" tag to iterate over our "value" variable (composer field) %}
|
|
133
|
+
{% for c_item in value %}
|
|
134
|
+
{% # use an "if" tag to match a composer item type of list in the composer array %}
|
|
135
|
+
{% if c_item.type == 'list' %}
|
|
136
|
+
{% # render any list from the composer field, use a "join" filter to convert the value array to a string %}
|
|
137
|
+
{{ c_item.value | join: ', ' }}
|
|
138
|
+
{% # close the "if" tag %}
|
|
139
|
+
{% endif %}
|
|
140
|
+
{% # close the "for" tag %}
|
|
141
|
+
{% endfor %}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
A short hand example similar to the above using only LiquidJS filters
|
|
145
|
+
|
|
146
|
+
Taking the `value` (a composer item array), filtering just the composer item types of 'list', mapping just the 'value' taking the `first` found 'list' and concatenating the values into a comma-separated string.
|
|
147
|
+
|
|
148
|
+
```handlebars
|
|
149
|
+
{{ value | where: 'type', 'list' | map: 'value' | first | join: ', ' }}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
So a composer field containing this JSON
|
|
153
|
+
|
|
154
|
+
```JSON
|
|
155
|
+
[{
|
|
156
|
+
"type": "list",
|
|
157
|
+
"value": [
|
|
158
|
+
"Plum",
|
|
159
|
+
"Orange",
|
|
160
|
+
"Banana"
|
|
161
|
+
]
|
|
162
|
+
}]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
becomes `Plum, Orange, Banana`
|
|
166
|
+
|
|
167
|
+
Or render the same list field data ready to copy into a Rich text or Canvas field, we are free to decorate any value with required markup so it is presented and transformed correctly.
|
|
168
|
+
|
|
169
|
+
```handlebars
|
|
170
|
+
{% for c_item in source_value %} {% if c_item.type == 'list' %}
|
|
171
|
+
<ul>
|
|
172
|
+
{% for l_item in c_item.value %}
|
|
173
|
+
<li>{{l_item}}</li>
|
|
174
|
+
{% endfor %}
|
|
175
|
+
</ul>
|
|
176
|
+
{% endif %} {% endfor %}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Transforming Composer content to Canvas
|
|
180
|
+
|
|
181
|
+
To transform the above Composer content into a Canvas field, we would need to "render" each item in the Composer that we require in the Canvas field as a very simple HTML representation, and this becomes the value we pass to the HTML parser that in turn renders the JSON that allows us to store the Canvas content in Contensis.
|
|
182
|
+
|
|
183
|
+
The same kind of theory can be applied to any source field we wish to convert to Canvas content
|
|
184
|
+
|
|
185
|
+
We must use the `source_value` variable in the template instead of `value` variable as the template needs to alter the source value and be applied _before_ the process transforms the value into Canvas
|
|
186
|
+
|
|
187
|
+
If the source field (or composer item value) is already a rich text field containing existing markup, we don't need to do any special rendering before this is parsed and converted to Canvas content
|
|
188
|
+
|
|
189
|
+
```handlebars
|
|
190
|
+
{% for c_item in source_value %}
|
|
191
|
+
{% if c_item.type == 'markup' %}{{ c_item.value }}
|
|
192
|
+
{% elsif c_item.type == 'quote' %}
|
|
193
|
+
<p>{{ c_item.value.source }}</p>
|
|
194
|
+
<blockquote>{{ c_item.value.text }}</blockquote>
|
|
195
|
+
{% elsif c_item.type == 'image' %}
|
|
196
|
+
<img src='{{ c_item.value.asset.sys.uri }}' alt='{{ c_item.value.altText }}'/>
|
|
197
|
+
{% else %}<p>{{ c_item.value | join: '</p><p>' | json }}</p>
|
|
198
|
+
{% endif %}
|
|
199
|
+
{% endfor %}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Embedding Component data in Canvas
|
|
203
|
+
|
|
204
|
+
We can curate and store Component data inline with Canvas content in the Contensis editor.
|
|
205
|
+
|
|
206
|
+
Component data will likely be encountered as part of a parent composer field when converting long-form composer-curated content to Canvas.
|
|
207
|
+
|
|
208
|
+
Following on from the examples above, we have a component in the composer data of type `iconWithText`. We need to also know the api id of the component (which can be found in the composer field definition in the Content type editor), as the component api id is often different from how it is named in the composer field.
|
|
209
|
+
|
|
210
|
+
```handlebars
|
|
211
|
+
{% for c_item in source_value %}
|
|
212
|
+
{% # ... %}
|
|
213
|
+
{% elsif c_item.type == 'iconWithText' %}
|
|
214
|
+
{{ c_item.value | canvas_component: 'iconWithText' }}
|
|
215
|
+
{% # ... %}
|
|
216
|
+
{% endif %}
|
|
217
|
+
{% endfor %}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
In the above template when we encounter a composer item with a type of `iconWithText` we can render it and apply the custom filter `canvas_component` to the composer item value, supplying the component api id as an argument to this filter
|
|
221
|
+
|
|
222
|
+
Rendering the component with the custom filter will produce an output that will allow the component (and its content) to be parsed and stored inline in Canvas field content:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
<div class='component' data-component='iconWithText' data-component-value='{"icon":{"sys":{"id":"51639de0-a1e4-4352-b166-17f86e3558bf","dataFormat":"entry","contentTypeId":"icon"}},"text":"This is my icon text"}'></div>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### Further component customisation
|
|
229
|
+
|
|
230
|
+
If you need to customise the component output for the canvas content any further, you can instead not use the suggested custom filter and render the component data as markup following the example output above.
|
|
231
|
+
|
|
232
|
+
```handlebars
|
|
233
|
+
{% for c_item in source_value %}
|
|
234
|
+
{% # ... %}
|
|
235
|
+
{% elsif c_item.type == 'iconWithText' %}
|
|
236
|
+
<div class='component' data-component='iconWithText' data-component-value='{{ c_item.value | html_encode }}'></div>
|
|
237
|
+
{% # ... %}
|
|
238
|
+
{% endif %}
|
|
239
|
+
{% endfor %}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Another custom filter `html_encode` used here is provided to help render the `data-component-value` attribute with the correct encoding to be parsed and embedded into the canvas content
|
|
243
|
+
|
|
244
|
+
#### Curate redundant components as canvas
|
|
245
|
+
|
|
246
|
+
If it is preferred for any reason, instead of embedding component data inline in the canvas content, you could stop using the component field and have the content curated, stored and rendered from regular canvas content blocks going forward.
|
|
247
|
+
|
|
248
|
+
You would use a template to render the data from each component field wrapped in simple appropriate markup so it will be represented like this within canvas content blocks in Contensis after the field data has been copied and converted to canvas.
|
|
249
|
+
|
|
250
|
+
### Embedding Entry (and asset) links in Canvas
|
|
251
|
+
|
|
252
|
+
Continuing the example above, we can embed an inline entry link from every matched composer item easily into the canvas content by applying custom filter `canvas_entry`
|
|
253
|
+
|
|
254
|
+
```handlebars
|
|
255
|
+
{% for c_item in source_value %}
|
|
256
|
+
{% # ... %}
|
|
257
|
+
{% elsif c_item.type == 'entry' %}
|
|
258
|
+
{{ c_item.value | canvas_entry }}
|
|
259
|
+
{% # ... %}
|
|
260
|
+
{% endif %}
|
|
261
|
+
{% endfor %}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Produces output similar to the HTML below which can be parsed and saved inside the canvas content
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
<a class='inline-entry' data-entry='{"sys":{"id":"eee9129e-70fc-4f70-b641-01e160af2438","dataFormat":"entry","contentTypeId":"person"}}'></a>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Another example of embedding an entry link into canvas where we could be converting existing rich text content to canvas and need to link/append a certain entry at the bottom of every entry's canvas content.
|
|
271
|
+
|
|
272
|
+
```handlebars
|
|
273
|
+
{{ source_value }}
|
|
274
|
+
{{ entry.tsAndCs | canvas_entry }}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
If we need to hard code a specific entry id into the canvas after a rich text field:
|
|
278
|
+
|
|
279
|
+
```handlebars
|
|
280
|
+
{{ source_value }}
|
|
281
|
+
{% capture link_entry %}
|
|
282
|
+
{ "sys": { "id": "eee9129e-70fc-4f70-b641-01e160af2438", "contentTypeId": "person" } }
|
|
283
|
+
{% endcapture %}
|
|
284
|
+
{{ link_entry | from_json | canvas_entry }}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
In the final output we are applying two custom filters to our `link_entry`, `from_json` allows us to use a `capture` tag and hardcode our own json, then parse this as a json object that can be read normally within the template (something which cannot be done natively in LiquidJS).
|
|
288
|
+
|
|
289
|
+
Further applying `canvas_entry` filter will convert our parsed JSON object into the markup that is valid for loading with canvas content
|
|
290
|
+
|
|
291
|
+
```handlebars
|
|
292
|
+
{{ source_value }}
|
|
293
|
+
{{ '{ "sys": { "id": "eee9129e-70fc-4f70-b641-01e160af2438", "contentTypeId": "person" } }' | from_json | canvas_entry }}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
We can achieve the same effect by applying the filter chain to a hardcoded valid JSON string
|
|
297
|
+
|
|
298
|
+
### Embedding Images in Canvas
|
|
299
|
+
|
|
300
|
+
Continuing with the composer example above, we can embed an existing image into the canvas content by applying custom filter `canvas_image`
|
|
301
|
+
|
|
302
|
+
We also need to ensure we have supplied the option to query the delivery api, as entries returned in the management api search do not contain the image uri in any image fields as the delivery api does.
|
|
303
|
+
|
|
304
|
+
```handlebars
|
|
305
|
+
{% for c_item in source_value %}
|
|
306
|
+
{% # ... %}
|
|
307
|
+
{% elsif c_item.type == 'image' %}
|
|
308
|
+
{{ c_item.value | canvas_image }}
|
|
309
|
+
{% # ... %}
|
|
310
|
+
{% endif %}
|
|
311
|
+
{% endfor %}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Produces output similar to the HTML below which can be parsed and saved inside the canvas content
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
<img src='/image-library/people-images/richard-saunders-blog-image.x67b5a698.png' altText='A photo of Richard Saunders.'/>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Images from existing, external or hardcoded content can be added to the canvas by rendering the image details out into valid markup including an `<img />` tag with a completed `src=""` attribute
|
|
321
|
+
|
|
322
|
+
### Complete composer example
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
```handlebars
|
|
326
|
+
{% for c_item in source_value %}
|
|
327
|
+
{% if c_item.type == 'markup' %}{{ c_item.value }}
|
|
328
|
+
{% elsif c_item.type == 'quote' %}
|
|
329
|
+
<p>{{ c_item.value.source }}</p>
|
|
330
|
+
<blockquote>{{ c_item.value.text }}</blockquote>
|
|
331
|
+
{% elsif c_item.type == 'iconWithText' %}{{ c_item.value | canvas_component: 'iconWithText' }}
|
|
332
|
+
{% elsif c_item.type == 'image' %}{{ c_item.value | canvas_image }}
|
|
333
|
+
{% elsif c_item.type == 'asset' or c_item.type == 'entry' %}{{ c_item.value | canvas_entry }}
|
|
334
|
+
{% elsif c_item.type == 'boolean' and c_item.value %}Boolean: Yes
|
|
335
|
+
{% else %}<p>{{ c_item.value | join: '</p><p>' | json }}</p>
|
|
336
|
+
{% endif %}
|
|
337
|
+
{% endfor %}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Concatenate multiple entry fields
|
|
341
|
+
|
|
342
|
+
We can utilise a LiquidJS template to concatenate multiple field values together and copy to a destination field
|
|
343
|
+
|
|
344
|
+
In the example below we will copy the value of the source field to the destination field but also append any existing value if it exists
|
|
345
|
+
|
|
346
|
+
```handlebars
|
|
347
|
+
{{value}}{% if existing_value %} - {{existing_value}}{% endif %}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Or we can refer to other fields in the `entry` variable
|
|
351
|
+
|
|
352
|
+
```handlebars
|
|
353
|
+
{{entry.text}}{% if entry.heading %} - {{entry.heading}}{% endif %}
|
|
354
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
## Copy field transformation matrix
|
|
2
|
+
|
|
3
|
+
Copying field data directly from one field to another can be done directly with the source and destination field types metioned in the below table
|
|
4
|
+
|
|
5
|
+
When we copy certain field types, a transformation is made to the data to make it compatible with the destination field type.
|
|
6
|
+
|
|
7
|
+
Copying a field will overwrite any data in the destination field, it will not preserve or respect any data that currently exists or has been manually entered. The destination field also needs to exist in the Content Type we are targeting.
|
|
8
|
+
|
|
9
|
+
Finer grained control of the field data transformation (including field types not supported directly) can be made using a [template](copy_field_templates.md)
|
|
10
|
+
|
|
11
|
+
| source | destination | notes |
|
|
12
|
+
| ---------------------------- | ---------------------------- | ------------------------------------------------------------------------------------- |
|
|
13
|
+
| string | string | |
|
|
14
|
+
| | stringArray | |
|
|
15
|
+
| | canvas | Content is surrounded within a paragraph block (template can alter the source value) |
|
|
16
|
+
| | richText | |
|
|
17
|
+
| | richTextArray | |
|
|
18
|
+
| | boolean | True if evaluates "truthy" (0, false or null would be false) |
|
|
19
|
+
| stringArray | stringArray | |
|
|
20
|
+
| | string | Multiples separated with newline |
|
|
21
|
+
| | canvas | ^ |
|
|
22
|
+
| | richText | ^ |
|
|
23
|
+
| | richTextArray | |
|
|
24
|
+
| richText | canvas | |
|
|
25
|
+
| | richText | |
|
|
26
|
+
| | richTextArray | |
|
|
27
|
+
| | string | |
|
|
28
|
+
| | stringArray | |
|
|
29
|
+
| richTextArray | richTextArray | |
|
|
30
|
+
| | richText | Multiples separated with newline |
|
|
31
|
+
| | canvas | |
|
|
32
|
+
| boolean | boolean | |
|
|
33
|
+
| | string | "Yes" or "No" |
|
|
34
|
+
| | stringArray | ^ |
|
|
35
|
+
| | integer | True = 1, false = 0 |
|
|
36
|
+
| | integerArray | ^ |
|
|
37
|
+
| | decimal | True = 1, false = 0 |
|
|
38
|
+
| | decimalArray | ^ |
|
|
39
|
+
| integer | integer | |
|
|
40
|
+
| | integerArray | |
|
|
41
|
+
| | decimal | |
|
|
42
|
+
| | decimalArray | |
|
|
43
|
+
| | boolean | True if evaluates "truthy" (0, false or null would be false) |
|
|
44
|
+
| decimal | decimal | |
|
|
45
|
+
| | decimalArray | |
|
|
46
|
+
| | integer | Truncate any decimal precision (e.g. 44.9 = 44) |
|
|
47
|
+
| | integerArray | ^ |
|
|
48
|
+
| | boolean | True if evaluates "truthy" (0, false or null would be false) |
|
|
49
|
+
| dateTime | dateTime | |
|
|
50
|
+
| | dateTimeArray | |
|
|
51
|
+
| image | image | |
|
|
52
|
+
| | imageArray | |
|
|
53
|
+
| imageArray | imageArray | |
|
|
54
|
+
| | image | |
|
|
55
|
+
| component | component | Source and destination component must contain the same fields |
|
|
56
|
+
| | componentArray | ^ |
|
|
57
|
+
| component.\<field type> | \<field type> | Supports the field types mentioned above |
|
|
58
|
+
| componentArray.\<field type> | \<field type> | ^ at the first position in the array |
|
|
59
|
+
| \<field type> | component.\<field type> | Adds the field to existing component object or add new component with just this field |
|
|
60
|
+
| | componentArray.\<field type> | ^ at the first position in the array |
|
|
61
|
+
| composer | canvas | Renders composer content as simple HTML and parses to canvas JSON |
|
|
62
|
+
| \<field type> | composer | Not supported |
|
|
63
|
+
| canvas | \<field type> | Not supported |
|
|
64
|
+
|
|
65
|
+
Key: ^ = as above
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contensis-cli",
|
|
3
|
-
"version": "1.2.0",
|
|
3
|
+
"version": "1.2.1-beta.0",
|
|
4
4
|
"description": "A fully featured Contensis command line interface with a shell UI provides simple and intuitive ways to manage or profile your content in any NodeJS terminal.",
|
|
5
5
|
"repository": "https://github.com/contensis/cli",
|
|
6
6
|
"homepage": "https://github.com/contensis/cli/tree/main/packages/contensis-cli#readme",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"jsonpath-mapper": "^1.1.0",
|
|
41
41
|
"keytar": "^7.9.0",
|
|
42
42
|
"lodash": "^4.17.21",
|
|
43
|
-
"migratortron": "^1.0.0-beta.
|
|
43
|
+
"migratortron": "^1.0.0-beta.50",
|
|
44
44
|
"nanospinner": "^1.1.0",
|
|
45
45
|
"node-fetch": "^2.6.7",
|
|
46
46
|
"parse-git-config": "^3.0.0",
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = "1.2.0";
|
|
1
|
+
export const LIB_VERSION = "1.2.1-beta.0";
|