contensis-cli 1.6.1-beta.21 → 1.6.1-beta.23
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/LICENSE +674 -0
- package/dist/index.js +36 -6
- package/dist/index.js.map +2 -2
- package/dist/shell.js +36 -6
- package/dist/shell.js.map +2 -2
- package/docs/copy_field_templates.md +112 -0
- package/package.json +3 -3
- package/src/commands/set.ts +4 -3
- package/src/localisation/en-GB.ts +4 -0
- package/src/services/ContensisCliService.ts +29 -3
- package/src/version.ts +1 -1
|
@@ -352,3 +352,115 @@ Or we can refer to other fields in the `entry` variable
|
|
|
352
352
|
```handlebars
|
|
353
353
|
{{entry.text}}{% if entry.heading %} - {{entry.heading}}{% endif %}
|
|
354
354
|
```
|
|
355
|
+
|
|
356
|
+
### Transforming fields inside Canvas blocks
|
|
357
|
+
|
|
358
|
+
Canvas fields contain an array of blocks (objects with `id`, `type`, `value`, `properties`). Some blocks are components (`_component` type with `properties.component`) that hold nested fields inside `value`. To transform those inner fields - for example converting a rich text field inside a component to canvas format - you need to rebuild the canvas array by iterating over the blocks and selectively transforming the ones you need.
|
|
359
|
+
|
|
360
|
+
This is done using the `capture` tag to build the output as a JSON string, then `from_json | json` to validate and minify the result.
|
|
361
|
+
|
|
362
|
+
#### Example: Convert rich text to canvas inside a component block
|
|
363
|
+
|
|
364
|
+
Given a canvas field containing a `linkedComponent` block with a `richText` field:
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"id": "5b03fe6a",
|
|
369
|
+
"type": "_component",
|
|
370
|
+
"properties": { "component": "linkedComponent" },
|
|
371
|
+
"value": {
|
|
372
|
+
"entry": [{ "sys": { "id": "abc123", "dataFormat": "entry" } }],
|
|
373
|
+
"title": "My component",
|
|
374
|
+
"richText": "<h2>Original rich text</h2>",
|
|
375
|
+
"canvas": null
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
This template converts `richText` to canvas via `html_to_canvas`, storing it in the `canvas` field. Other blocks pass through unchanged:
|
|
381
|
+
|
|
382
|
+
```handlebars
|
|
383
|
+
{% capture out %}
|
|
384
|
+
[
|
|
385
|
+
{%- for b in value -%}
|
|
386
|
+
{%- if forloop.index0 > 0 %},{% endif -%}
|
|
387
|
+
{%- if b.properties.component == "linkedComponent" -%}
|
|
388
|
+
{
|
|
389
|
+
"id": {{ b.id | json }},
|
|
390
|
+
"type": {{ b.type | json }},
|
|
391
|
+
"properties": {{ b.properties | json }},
|
|
392
|
+
"value": {
|
|
393
|
+
"entry": {{ b.value.entry | json }},
|
|
394
|
+
"title": {{ b.value.title | json }},
|
|
395
|
+
"richText": {{ b.value.richText | json }},
|
|
396
|
+
"canvas": {% if b.value.richText and b.value.richText != "" %}{{ b.value.richText | html_to_canvas | json }}{% else %}{{ b.value.canvas | json }}{% endif %}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
{%- else -%}
|
|
400
|
+
{{ b | json }}
|
|
401
|
+
{%- endif -%}
|
|
402
|
+
{%- endfor -%}
|
|
403
|
+
]
|
|
404
|
+
{% endcapture %}
|
|
405
|
+
{{ out | from_json | json }}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
#### How it works
|
|
409
|
+
|
|
410
|
+
1. `{% capture out %}` starts building the output as a JSON string
|
|
411
|
+
2. The outer `[` opens the canvas array
|
|
412
|
+
3. `{% for b in value %}` iterates over every block in the canvas
|
|
413
|
+
4. `{% if b.properties.component == "linkedComponent" %}` matches the block we want to transform
|
|
414
|
+
5. Each field in the block is mapped with `|json` to ensure valid JSON output (strings get quotes, objects serialize correctly)
|
|
415
|
+
6. The `canvas` field conditionally applies `html_to_canvas` when `richText` exists, otherwise passes the existing value through
|
|
416
|
+
7. `{% else %}` passes non-matching blocks through unchanged via `{{ b | json }}`
|
|
417
|
+
8. `{% endcapture %}` closes the string, then `{{ out | from_json | json }}` parses and re-serializes to validate the JSON
|
|
418
|
+
|
|
419
|
+
#### Why `|json` is needed on every mapped field
|
|
420
|
+
|
|
421
|
+
Without it, strings would render bare (invalid JSON: `hello` instead of `"hello"`) and objects would render as `[object Object]`. The `|json` filter handles strings, objects, arrays, nulls, and booleans correctly.
|
|
422
|
+
|
|
423
|
+
#### Handling nested component blocks
|
|
424
|
+
|
|
425
|
+
If a canvas block contains a repeatable array of sub-components, you can nest the same pattern. For example, a `nestingLinkedComponent` block has `linkedComponent[]` items, each with their own `richText` and `canvas`:
|
|
426
|
+
|
|
427
|
+
```handlebars
|
|
428
|
+
{% capture out %}
|
|
429
|
+
[
|
|
430
|
+
{%- for b in value -%}
|
|
431
|
+
{%- if forloop.index0 > 0 %},{% endif -%}
|
|
432
|
+
{%- if b.properties.component == "nestingLinkedComponent" -%}
|
|
433
|
+
{
|
|
434
|
+
"id": {{ b.id | json }},
|
|
435
|
+
"type": {{ b.type | json }},
|
|
436
|
+
"properties": {{ b.properties | json }},
|
|
437
|
+
"value": {
|
|
438
|
+
"linkedComponent": [
|
|
439
|
+
{%- for it in b.value.linkedComponent -%}
|
|
440
|
+
{%- if forloop.index0 > 0 %},{% endif -%}
|
|
441
|
+
{
|
|
442
|
+
"entry": {{ it.entry | json }},
|
|
443
|
+
"title": {{ it.title | json }},
|
|
444
|
+
"richText": {{ it.richText | json }},
|
|
445
|
+
"canvas": {% if it.richText and it.richText != "" %}{{ it.richText | html_to_canvas | json }}{% else %}{{ it.canvas | json }}{% endif %}
|
|
446
|
+
}
|
|
447
|
+
{%- endfor -%}
|
|
448
|
+
],
|
|
449
|
+
"singleLinkedComponent": {
|
|
450
|
+
"entry": {{ b.value.singleLinkedComponent.entry | json }},
|
|
451
|
+
"title": {{ b.value.singleLinkedComponent.title | json }},
|
|
452
|
+
"richText": {{ b.value.singleLinkedComponent.richText | json }},
|
|
453
|
+
"canvas": {% if b.value.singleLinkedComponent.richText and b.value.singleLinkedComponent.richText != "" %}{{ b.value.singleLinkedComponent.richText | html_to_canvas | json }}{% else %}{{ b.value.singleLinkedComponent.canvas | json }}{% endif %}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
{%- else -%}
|
|
458
|
+
{{ b | json }}
|
|
459
|
+
{%- endif -%}
|
|
460
|
+
{%- endfor -%}
|
|
461
|
+
]
|
|
462
|
+
{% endcapture %}
|
|
463
|
+
{{ out | from_json | json }}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
The same `richText` to `canvas` conversion is applied to each item in the repeatable `linkedComponent` array and to the singular `singleLinkedComponent` block.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contensis-cli",
|
|
3
|
-
"version": "1.6.1-beta.
|
|
3
|
+
"version": "1.6.1-beta.23",
|
|
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": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"package-lock": "npm i --package-lock-only --workspaces false"
|
|
26
26
|
},
|
|
27
27
|
"author": "Zengenti",
|
|
28
|
-
"license": "
|
|
28
|
+
"license": "GPL-3.0",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@action-validator/core": "^0.6.0",
|
|
31
31
|
"@inquirer/prompts": "^8.2.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"inquirer-command-prompt": "^0.1.0",
|
|
44
44
|
"keytar": "^7.9.0",
|
|
45
45
|
"lodash": "^4.17.21",
|
|
46
|
-
"migratortron": "^1.0.0-beta.
|
|
46
|
+
"migratortron": "^1.0.0-beta.89",
|
|
47
47
|
"nanospinner": "^1.2.0",
|
|
48
48
|
"node-fetch": "^2.6.7",
|
|
49
49
|
"parse-git-config": "^3.0.0",
|
package/src/commands/set.ts
CHANGED
|
@@ -35,18 +35,19 @@ Example call:
|
|
|
35
35
|
.command('renderer')
|
|
36
36
|
.description('assign a renderer to a node')
|
|
37
37
|
.argument('<"node path or id">', 'the path or id of the node to update')
|
|
38
|
-
.argument('<
|
|
38
|
+
.argument('<rendererUuidOrName>', 'the renderer uuid, id or name to assign to the node')
|
|
39
39
|
.option(
|
|
40
40
|
'--is-partial-match-root',
|
|
41
41
|
'should the renderer be used as the partial match root for the node',
|
|
42
42
|
false
|
|
43
43
|
)
|
|
44
|
-
.usage('<"node path or id"> <
|
|
44
|
+
.usage('<"node path or id"> <rendererUuidOrName>')
|
|
45
45
|
.addHelpText(
|
|
46
46
|
'after',
|
|
47
47
|
`
|
|
48
48
|
Example call:
|
|
49
|
-
> set node renderer /path 1502f64e-e9b1-436b-b62f-e273f639ecb6 --is-partial-match-root
|
|
49
|
+
> set node renderer /path 1502f64e-e9b1-436b-b62f-e273f639ecb6 --is-partial-match-root
|
|
50
|
+
> set node renderer /path my-block --is-partial-match-root\n`
|
|
50
51
|
)
|
|
51
52
|
.action(async (nodePathOrId: string, rendererId: string, opts) => {
|
|
52
53
|
await cliCommand(['set', 'node', 'renderer'], opts).CreateOrUpdateNode(
|
|
@@ -325,6 +325,10 @@ export const LogMessages = {
|
|
|
325
325
|
`[${env}] Unable to find renderer ${Logger.highlightText(
|
|
326
326
|
name
|
|
327
327
|
)} in project ${projectId}`,
|
|
328
|
+
resolved: (env: string, name: string, uuid: string) =>
|
|
329
|
+
`[${env}] Resolved renderer ${Logger.highlightText(
|
|
330
|
+
name
|
|
331
|
+
)} to uuid ${Logger.highlightText(uuid)}`,
|
|
328
332
|
created: (env: string, name: string, projectId: string) =>
|
|
329
333
|
`[${env}] Created renderer ${Logger.highlightText(
|
|
330
334
|
name
|
|
@@ -5,6 +5,7 @@ import inquirer from 'inquirer';
|
|
|
5
5
|
import fetch from 'node-fetch';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import clone from 'rfdc';
|
|
8
|
+
import type { CommanderError } from 'commander';
|
|
8
9
|
|
|
9
10
|
import { Component, ContentType, Project } from 'contensis-core-api';
|
|
10
11
|
import {
|
|
@@ -74,9 +75,9 @@ import { GetTagGroupsArgs } from 'migratortron/dist/services/TagGroupsMigrationS
|
|
|
74
75
|
let insecurePasswordWarningShown = false;
|
|
75
76
|
|
|
76
77
|
class ContensisCli {
|
|
77
|
-
static quit = (error?:
|
|
78
|
+
static quit = (error?: CommanderError) => {
|
|
78
79
|
process.removeAllListeners('exit');
|
|
79
|
-
const exitCode = error ? 1 : 0;
|
|
80
|
+
const exitCode = error?.exitCode ?? (error ? 1 : 0);
|
|
80
81
|
|
|
81
82
|
// console.info(`\nExiting contensis-cli with exit code: ${exitCode}\n`);
|
|
82
83
|
process.exit(exitCode);
|
|
@@ -2818,7 +2819,32 @@ class ContensisCli {
|
|
|
2818
2819
|
if (nodeById) existingNode = nodeById;
|
|
2819
2820
|
}
|
|
2820
2821
|
|
|
2821
|
-
//
|
|
2822
|
+
// Resolve a friendly renderer id/name to its uuid for ease of use
|
|
2823
|
+
const rendererRef = nodeUpdates.renderer?.id;
|
|
2824
|
+
if (rendererRef && !isUuid(rendererRef)) {
|
|
2825
|
+
const [, renderers] = await contensis.renderers.GetRenderers();
|
|
2826
|
+
const match = renderers?.find(
|
|
2827
|
+
r =>
|
|
2828
|
+
r.id?.toLowerCase() === rendererRef.toLowerCase() ||
|
|
2829
|
+
r.name?.toLowerCase() === rendererRef.toLowerCase()
|
|
2830
|
+
);
|
|
2831
|
+
if (match) {
|
|
2832
|
+
log.info(
|
|
2833
|
+
messages.renderers.resolved(
|
|
2834
|
+
currentEnv,
|
|
2835
|
+
rendererRef,
|
|
2836
|
+
match.uuid
|
|
2837
|
+
)
|
|
2838
|
+
);
|
|
2839
|
+
nodeUpdates.renderer.id = match.uuid;
|
|
2840
|
+
} else {
|
|
2841
|
+
log.error(
|
|
2842
|
+
messages.renderers.failedGet(currentEnv, rendererRef, currentProject)
|
|
2843
|
+
);
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2822
2848
|
if (!existingNode) {
|
|
2823
2849
|
// Build a node object to create or reject if there is not enough data
|
|
2824
2850
|
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = "1.6.1-beta.
|
|
1
|
+
export const LIB_VERSION = "1.6.1-beta.23";
|