Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,38 @@ Alternatively, if you don’t want the script builder GUI, you can also only dep

Running a script requires a script (either as a JSON-encoded string or as an instance of `com.swisscom.aem.tools.jcrhopper.config.Script`) and a runner (`com.swisscom.aem.tools.jcrhopper.Runner`).

#### Creating a script
#### Creating a sample script

JCR hopper scripts comprise the following:
JCR hopper sample scripts comprise the following:

- A log level that determines which log messages are sent to the run handler.
- A list of hop configs that are run against a given node. Hops can also have their own descendant pipelines of hop configs.
- A list of parameters that the script supports. Parameters always have a default value, thus passing arguments to the script runner is always optional. Each parameter also has a name, a script builder input type hint and an evaluation type that determines how the default values/arguments are to be interpreted.
- A `label` that is displayed in the dropdown for Scripts.
- A `log level` that determines which log messages are sent to the run handler.
- A `list of hop configs` that are run against a given node. Hops can also have their own descendant pipelines of hop configs.
- A `list of parameters` that the script supports. Parameters always have a default value, thus passing arguments to the script runner is always optional. Each parameter also has a name, a script builder input type hint and an evaluation type that determines how the default values/arguments are to be interpreted.

##### Inside JCR Hopper repo

Common reusable scripts could be added to JCR Hopper repo directly.

- Create a new json file with `log level` , `list of hop configs` & `list of parameters` under `/apps/jcr-hopper/script-builder/scripts/samples/` folder.
- Add an tag Entry in `/apps/jcr-hopper/script-builder/scripts/.content.xml` file for your new json and by defining user-friendly label for Sample script as `jcr:title`. Check this file on how it is added for previous sample script jsons.

##### Inside application project repo

If the Sample script is quite specific to your project needs then you can keep the script in your project repo with specific folder structure as defined below.

- Create a new json file `your-samnple-script.json` under `/apps/jcr-hopper/script-builder/scripts/{your-project-folder}` or any sub folder under it. json should contain `log level` , `list of hop configs` & `list of parameters`. Check the existing sample scripts for examples.
- Add an tag Entry in `/apps/jcr-hopper/script-builder/scripts/.content.xml` file for your new json and by defining user-friendly label for Sample script as `jcr:title`. Check this file on how it is added for previous sample script jsons.

High level structure of Script json content

```json
{
"logLevel": "info",
"hops": [],
"parameters": []
}
```

#### Configuring a builder

Expand Down
1 change: 1 addition & 0 deletions mock/script-builder.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
class="jcr-hopper-builder"
data-run-endpoint="/mock/mock-response.jsonl"
data-valid-scripting-languages='{"js": "JavaScript", "jexl": "JEXL", "groovy": "Groovy"}'
data-sample-scripts='[{"label":"Sample: Remove all minified JavaScript files","configJson":"{\n\t\"hops\": [\n\t\t{\n\t\t\t\"type\": \"nodeQuery\",\n\t\t\t\"query\": \"SELECT * FROM [cq:ClientLibraryFolder]\",\n\t\t\t\"queryType\": \"JCR-SQL2\",\n\t\t\t\"hops\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"resolveNode\",\n\t\t\t\t\t\"conflict\": \"ignore\",\n\t\t\t\t\t\"name\": \"..\",\n\t\t\t\t\t\"hops\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"childNodes\",\n\t\t\t\t\t\t\t\"hops\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"filterNode\",\n\t\t\t\t\t\t\t\t\t\"expression\": \"str:contains(node.name, \u0027.min.js\u0027)\",\n\t\t\t\t\t\t\t\t\t\"hops\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"moveNode\",\n\t\t\t\t\t\t\t\t\t\t\t\"conflict\": \"ignore\",\n\t\t\t\t\t\t\t\t\t\t\t\"newName\": \"/dev/null\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"logLevel\": \"warn\",\n\t\"parameters\": []\n}"},{"label":"Sample: Replace H1 with H2 in text components","configJson":"{\n\t\"hops\": [\n\t\t{\n\t\t\t\"type\": \"nodeQuery\",\n\t\t\t\"query\": \"SELECT * FROM [nt:unstructured] as text WHERE text.[sling:resourceType] \u003d \u0027${args.resourceType}\u0027\",\n\t\t\t\"queryType\": \"JCR-SQL2\",\n\t\t\t\"hops\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"filterNode\",\n\t\t\t\t\t\"expression\": \"str:contains(jcr:val(node, \\\"content\\\"), \\\"\u003ch1\\\")\",\n\t\t\t\t\t\"hops\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"setProperty\",\n\t\t\t\t\t\t\t\"conflict\": \"force\",\n\t\t\t\t\t\t\t\"propertyName\": \"content\",\n\t\t\t\t\t\t\t\"value\": \"str:replacePattern(str:replacePattern(jcr:val(node, \\\"content\\\"), \\\"\u003ch1\\\", \\\"\u003ch2\\\"), \\\"\u003c/h1\\\", \\\"\u003c/h2\\\")\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"logLevel\": \"warn\",\n\t\"parameters\": [\n\t\t{\n\t\t\t\"name\": \"resourceType\",\n\t\t\t\"defaultValue\": \"core/wcm/components/text/v2/text\",\n\t\t\t\"evaluation\": \"STRING\"\n\t\t}\n\t]\n}"},{"label":"Sample: Remove temporary packages created by gulp","configJson":"{\n\t\"hops\": [\n\t\t{\n\t\t\t\"type\": \"resolveNode\",\n\t\t\t\"conflict\": \"ignore\",\n\t\t\t\"hops\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"childNodes\",\n\t\t\t\t\t\"namePattern\": \"pack_*\",\n\t\t\t\t\t\"hops\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"moveNode\",\n\t\t\t\t\t\t\t\"conflict\": \"ignore\",\n\t\t\t\t\t\t\t\"newName\": \"/dev/null\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"name\": \"/etc/packages/temporary\"\n\t\t}\n\t],\n\t\"logLevel\": \"warn\",\n\t\"parameters\": []\n}"},{"label":"Sample: Update build timestamp","configJson":"{\n\t\"logLevel\": \"trace\",\n\t\"hops\": [\n\t\t{\n\t\t\t\"type\": \"resolveNode\",\n\t\t\t\"conflict\": \"throw\",\n\t\t\t\"name\": \"${args.timestampFilePath}/jcr:content\",\n\t\t\t\"hops\": [\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"declare\",\n\t\t\t\t\t\"defaultConfig\": {},\n\t\t\t\t\t\"title\": \"Declare Variables\",\n\t\t\t\t\t\"declarations\": { \"time\": \"class:forName(\\\"java.util.Calendar\\\").getInstance().time.toString()\" }\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"type\": \"setProperty\",\n\t\t\t\t\t\"conflict\": \"force\",\n\t\t\t\t\t\"propertyName\": \"jcr:data\",\n\t\t\t\t\t\"value\": \"str:replacePattern(time, \u0027[\\\\\\\\W]\u0027, \u0027-\u0027) + \u0027-\u0027 + node.session.userID\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"parameters\": [{ \"name\": \"timestampFilePath\", \"defaultValue\": \"/apps/base/clientlibs/build_timestamp.txt\", \"evaluation\": \"STRING\" }]\n}"}]'
></div>
</div>
</div>
Expand Down
5 changes: 4 additions & 1 deletion src/main/content/META-INF/vault/filter.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<workspaceFilter version="1.0">
<filter root="/apps/cq/core/content/nav/tools/jcr-hopper" />
<filter root="/apps/jcr-hopper" />
<filter root="/apps/jcr-hopper">
<exclude pattern="/apps/jcr-hopper/script-builder/scripts(/.*)?" />
<include pattern="/apps/jcr-hopper/script-builder/scripts/samples" />
</filter>
<filter root="/etc/jcr-hopper" />
</workspaceFilter>
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
class="jcr-hopper-builder"
data-run-endpoint="${info.endpoint}"
data-valid-scripting-languages="${info.validScriptingLanguages}"
data-sample-scripts="${info.sampleScripts}"
></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" ?>
<jcr:root
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:mixinTypes="granite:PublicArea"
jcr:primaryType="nt:folder"
>
<samples jcr:primaryType="nt:folder">
<add-node.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Add Node" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</add-node.json>
<add-or-replace-property.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Add or replace property" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</add-or-replace-property.json>
<batch-search-and-replace.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Batch search and replace" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</batch-search-and-replace.json>
<check-hardcoded-urls.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Check hardcoded URLs" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</check-hardcoded-urls.json>
<create-missing-jcr-content-nodes.json
jcr:mixinTypes="[mix:title]"
jcr:title="Sample: Create missing jcr:content nodes for pages"
jcr:primaryType="nt:file"
>
<jcr:content jcr:primaryType="nt:resource" />
</create-missing-jcr-content-nodes.json>
<delete-nodes.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Delete nodes" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</delete-nodes.json>
<find-component-and-page.json
jcr:mixinTypes="[mix:title]"
jcr:title="Sample: Find component and page using JOIN"
jcr:primaryType="nt:file"
>
<jcr:content jcr:primaryType="nt:resource" />
</find-component-and-page.json>
<migrate-page-template.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Migrate page template" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</migrate-page-template.json>
<migrate-resource-type.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Migrate resource type" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</migrate-resource-type.json>
<remove-deprecated-legacy-urls.json
jcr:mixinTypes="[mix:title]"
jcr:title="Sample: Remove deprecated legacy URLs"
jcr:primaryType="nt:file"
>
<jcr:content jcr:primaryType="nt:resource" />
</remove-deprecated-legacy-urls.json>
<remove-gulp-packages.json
jcr:mixinTypes="[mix:title]"
jcr:title="Sample: Remove temporary packages created by gulp"
jcr:primaryType="nt:file"
>
<jcr:content jcr:primaryType="nt:resource" />
</remove-gulp-packages.json>
<remove-min-js.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Remove all minified JavaScript files" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</remove-min-js.json>
<rename-node.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Rename node" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</rename-node.json>
<rename-property.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Rename property" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</rename-property.json>
<replace-h1-with-h2.json
jcr:mixinTypes="[mix:title]"
jcr:title="Sample: Replace H1 with H2 in text components"
jcr:primaryType="nt:file"
>
<jcr:content jcr:primaryType="nt:resource" />
</replace-h1-with-h2.json>
<update-build-timestamp.json jcr:mixinTypes="[mix:title]" jcr:title="Sample: Update build timestamp" jcr:primaryType="nt:file">
<jcr:content jcr:primaryType="nt:resource" />
</update-build-timestamp.json>
</samples>
</jcr:root>
7 changes: 6 additions & 1 deletion src/main/frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ScriptEditor } from './sections/ScriptEditor';
export const EnvironmentContext = createContext({
runEndpoint: '/',
validScriptingLanguages: {} as Record<string, string>,
sampleScripts: [] as Array<Record<string, string>>,
});
export const ScriptContext = createContext<HistoryUpdater<Script>>(null!);

Expand Down Expand Up @@ -81,7 +82,11 @@ const RootElement = styled('div')`
}
`;

export const App: FC<{ runEndpoint: string; validScriptingLanguages: Record<string, string> }> = props => {
export const App: FC<{
runEndpoint: string;
validScriptingLanguages: Record<string, string>;
sampleScripts: Array<Record<string, string>>;
}> = props => {
const initialScript = useOnce(getInitialScript);

const scriptContext = useHistoryImmutable(initialScript, current => {
Expand Down
8 changes: 6 additions & 2 deletions src/main/frontend/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ patchCoralUiCreateElement();

function init() {
const target = document.querySelector<HTMLElement>('.jcr-hopper-builder')!;
const { runEndpoint, validScriptingLanguages } = target.dataset;
const { runEndpoint, validScriptingLanguages, sampleScripts } = target.dataset;
const root = createRoot(target.parentElement!.parentElement!);
root.render(
<React.StrictMode>
<App runEndpoint={runEndpoint!} validScriptingLanguages={JSON.parse(validScriptingLanguages || '{}')}></App>
<App
runEndpoint={runEndpoint!}
validScriptingLanguages={JSON.parse(validScriptingLanguages || '{}')}
sampleScripts={JSON.parse(sampleScripts || '[]')}
></App>
</React.StrictMode>,
);
}
Expand Down
92 changes: 1 addition & 91 deletions src/main/frontend/model/samples/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,7 @@
import removeMinJs from './remove-min-js.json';
import replaceH1 from './replace-h1-with-h2.json';
import removeTempGulpPackages from './remove-gulp-packages.json';
import updateBuildTimestamp from './update-build-timestamp.json';
import findComponentAndPage from './find-component-and-page.json';
import createMissingJcrContentNodes from './create-missing-jcr-content-nodes.json';
import migrateResourceType from './migrate-resource-type.json';
import migratePageTemplate from './migrate-page-template.json';
import batchSearchAndReplace from './batch-search-and-replace.json';
import checkHardcodedUrls from './check-hardcoded-urls.json';
import removeDeprecatedLegacyUrls from './remove-deprecated-legacy-urls.json';
import deleteNodes from './delete-nodes.json';
import renameProperty from './rename-property.json';
import addOrReplaceProperty from './add-or-replace-property.json';
import addNode from './add-node.json';
import renameNode from './rename-node.json';
import valueFinder from './value-finder.json';
import changePropertyValue from './change-value.json';
import { Hop, HOP_DEFINITIONS } from '../hops';
import { Script } from '../Script';

type Sample = { label: string; config: Script };
export type Sample = { label: string; config: Script };

function suggestionFromDefinition(key: keyof typeof HOP_DEFINITIONS): Sample {
return {
Expand All @@ -34,76 +16,4 @@ export const SAMPLES: Sample[] = [
suggestionFromDefinition('declare'),
suggestionFromDefinition('each'),
suggestionFromDefinition('runScript'),
{
config: removeMinJs as Script,
label: 'Sample: Remove all minified JavaScript files',
},
{
config: replaceH1 as Script,
label: 'Sample: Replace H1 with H2 in text components',
},
{
config: removeTempGulpPackages as Script,
label: 'Sample: Remove temporary packages created by gulp',
},
{
config: updateBuildTimestamp as Script,
label: 'Sample: Update build timestamp',
},
{
config: findComponentAndPage as Script,
label: 'Sample: Find component and containing page using JOIN',
},
{
config: createMissingJcrContentNodes as Script,
label: 'Sample: Create missing jcr:content node for pages',
},
{
config: migrateResourceType as Script,
label: 'Sample: Migrate Resource Type',
},
{
config: migratePageTemplate as Script,
label: 'Sample: Migrate Page Template',
},
{
config: batchSearchAndReplace as Script,
label: 'Sample: Batch search and replace',
},
{
config: checkHardcodedUrls as Script,
label: 'Sample: Check hardcoded urls',
},
{
config: removeDeprecatedLegacyUrls as Script,
label: 'Sample: Remove deprecated legacy urls',
},
{
config: addOrReplaceProperty as Script,
label: 'Sample: Add or replace property',
},
{
config: renameProperty as Script,
label: 'Sample: Rename property',
},
{
config: valueFinder as Script,
label: 'Sample: Value Finder',
},
{
config: changePropertyValue as Script,
label: 'Sample: Change Property Value',
},
{
config: addNode as Script,
label: 'Sample: Add node',
},
{
config: renameNode as Script,
label: 'Sample: Rename node',
},
{
config: deleteNodes as Script,
label: 'Sample: Delete nodes',
},
];
Loading
Loading