Skip to content

Commit

Permalink
feat(editor): implement childNodes hop config
Browse files Browse the repository at this point in the history
  • Loading branch information
sabberworm committed Oct 10, 2024
1 parent 76f101b commit 866e151
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/main/frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const RootElement = styled('div')`
'script-editor run-controls'
'script-editor output';
grid-template-rows: min-content min-content 1fr;
grid-template-columns: 1fr 1fr;
grid-template-columns: 2fr 1fr;
.flex-spacer {
flex-grow: 1;
Expand Down
2 changes: 1 addition & 1 deletion src/main/frontend/coral/custom-elements.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ declare module 'react' {
icon?: CoralIcon;
iconsize?: CoralIconSize;
size?: 'M' | 'L';
variant?: 'cta' | 'primary' | 'quiet' | 'warning' | 'minimal';
variant?: 'cta' | 'primary' | 'quiet' | 'warning' | 'minimal' | undefined;
}
namespace JSX {
interface IntrinsicElements {
Expand Down
4 changes: 2 additions & 2 deletions src/main/frontend/model/hops/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ export const HOP_DEFINITIONS = {

export type ConflictResolutionStrategy = 'ignore' | 'force' | 'throw';

export type ActionType = keyof typeof HOP_DEFINITIONS;
export type HopType = keyof typeof HOP_DEFINITIONS;

export interface AnyHop {
type: ActionType;
type: HopType;
}
export type Hop =
| childNodes.Type
Expand Down
2 changes: 1 addition & 1 deletion src/main/frontend/sections/ScriptEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const ScriptEditor: FC = () => {
</label>
</fieldset>
<div className="script">
<Pipeline hops={script.hops} />
<Pipeline hops={script.hops} addButton={false} />
</div>
<fieldset className="parameters">
<legend>Parameters</legend>
Expand Down
2 changes: 1 addition & 1 deletion src/main/frontend/sections/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ export const Toolbar: FC = () => {
Paste
</button>
<Picker
icon="addChildPanel"
buttonLabel="Add"
title="Add Hop to Script"
buttonAttributes={{ icon: 'addChildPanel', is: 'coral-button' }}
picked={value => {
const sampleScript = SAMPLES[Number(value)]!.config;
script.hops.push(...sampleScript.hops);
Expand Down
29 changes: 26 additions & 3 deletions src/main/frontend/sections/editor/Pipeline.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
import React, { FC } from 'react';
import { Hop } from '../../model/hops';
import React, { FC, useContext } from 'react';

import { Hop, HOP_DEFINITIONS, HopType } from '../../model/hops';
import { PipelineStep } from './PipelineStep';
import { Picker } from '../../widgets/Picker';
import { ScriptContext } from '../../App';

export const Pipeline: FC<{ hops: Hop[]; addButton?: boolean }> = ({ hops, addButton = true }) => {
const scriptContext = useContext(ScriptContext);

export const Pipeline: FC<{ hops: Hop[] }> = ({ hops }) => {
return (
<>
{hops.map((hop, i) => (
<PipelineStep parentHops={hops} key={i} hop={hop} />
))}
{addButton ? (
<>
<Picker
buttonAttributes={{ className: 'add-hop' }}
buttonLabel={<coral-icon icon="addCircle"></coral-icon>}
title="Hop"
items={Object.entries(HOP_DEFINITIONS).map(([type, definition]) => [type, definition.title])}
picked={(type: HopType) => {
const hop: Hop = {
type,
...HOP_DEFINITIONS[type],
} as Hop;
hops.push(hop);
scriptContext.commit();
}}
/>
</>
) : undefined}
</>
);
};
3 changes: 3 additions & 0 deletions src/main/frontend/sections/editor/PipelineStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import React, { FC } from 'react';
import { Hop } from '../../model/hops';
import { FallbackStep } from './types/FallbackStep';
import { DeclareStep } from './types/DeclareStep';
import { ChildNodesStep } from './types/ChildNodesStep';

export const PipelineStep: FC<{ parentHops: Hop[]; hop: Hop }> = ({ parentHops, hop }) => {
switch (hop.type) {
case 'childNodes':
return <ChildNodesStep parentHops={parentHops} hop={hop} />;
case 'declare':
return <DeclareStep parentHops={parentHops} hop={hop} />;
default:
Expand Down
48 changes: 48 additions & 0 deletions src/main/frontend/sections/editor/types/ChildNodesStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { FC } from 'react';

import { Hop } from '../../../model/hops';
import { StepEditor } from '../../../widgets/StepEditor';

import { shortDescription, Type } from '../../../model/hops/childNodes';
import { Help } from '../../../widgets/Help';
import { Input } from '../../../widgets/Input';
import { Pipeline } from '../Pipeline';

export const ChildNodesStep: FC<{ parentHops: Hop[]; hop: Type }> = ({ parentHops, hop }) => {
return (
<StepEditor parentHops={parentHops} hop={hop} title={shortDescription(hop)} pipeline={<Pipeline hops={(hop.hops ??= [])} />}>
<label>
Name Pattern:{' '}
<Input value={hop.namePattern ?? ''} onChange={namePattern => (hop.namePattern = namePattern)} placeholder="*" />
</label>
<label>
Counter Name:{' '}
<Input value={hop.counterName ?? ''} onChange={counterName => (hop.counterName = counterName)} placeholder="index" />
</label>
<Help title="Child Nodes">
<h5 className="u-coral-margin">Name Pattern</h5>
<p className="u-coral-margin">
Gets all child nodes of this node accessible through the current Session that match namePattern. The pattern
may be a full name, a partial name with one or more wildcard characters (*), or a disjunction of those (using
the <code className="code font--serif">|</code> character).
</p>
<p className="u-coral-margin">
For example, <code className="code font--serif">jcr:* | myapp:report | my doc</code> will run the pipeline
actions for each accessible child node that is either called{' '}
<code className="code font--serif">myapp:report</code>, <code className="code font--serif">my doc</code>, or
whose name begins with the prefix <code className="code font--serif">jcr:</code>.
</p>
<p className="u-coral-margin">
For more information, see <a href="https://adobe.ly/2YrfG1G">Node#getNodes(String)</a>
</p>
<p className="u-coral-margin">If left empty, will return all all children of node.</p>
<h5 className="u-coral-margin">Counter Name</h5>
<p className="u-coral-margin">
Declare a counter variable with a name. When the pipeline iterates over the result set, each action in the
sub-pipeline will have access to this variable and may use it in an expression like{' '}
<code>{'${yourVariableName}'}</code>. The counter starts at 0 and is incremented by 1 every loop iteration.
</p>
</Help>
</StepEditor>
);
};
2 changes: 1 addition & 1 deletion src/main/frontend/sections/editor/types/DeclareStep.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { FC, Fragment, useContext } from 'react';
import { styled } from 'goober';

import { Hop } from '../../../model/hops';
import { StepEditor } from '../../../widgets/StepEditor';
Expand All @@ -7,7 +8,6 @@ import { ScriptContext } from '../../../App';
import { shortDescription, Type } from '../../../model/hops/declare';
import { Help } from '../../../widgets/Help';
import { Input } from '../../../widgets/Input';
import { styled } from 'goober';

const Elm = styled('fieldset')`
display: grid;
Expand Down
12 changes: 6 additions & 6 deletions src/main/frontend/widgets/Picker.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { FC, useEffect, useId, useRef } from 'react';
import React, { ButtonHTMLAttributes, FC, ReactNode, useEffect, useId, useRef } from 'react';
import { Options } from './Select';
import type { CoralIcon } from '../coral/custom-elements';

export const Picker: FC<{
items: Options;
buttonLabel: string;
icon: CoralIcon | undefined;
buttonLabel?: ReactNode;
buttonAttributes?: ButtonHTMLAttributes<HTMLButtonElement>;
title: string;
picked(value: string): void;
}> = ({ items, buttonLabel, icon, title, picked }) => {
}> = ({ items, buttonLabel, buttonAttributes, title, picked }) => {
const popoverRef = useRef<HTMLDialogElement>(null);
const selectlistRef = useRef<HTMLSelectElement>(null);
const buttonId = useId();
Expand All @@ -34,13 +34,13 @@ export const Picker: FC<{

return (
<>
<button is="coral-button" id={buttonId} {...(icon ? { icon } : {})}>
<button id={buttonId} is={buttonAttributes?.is ? buttonAttributes?.is : undefined} {...buttonAttributes}>
{buttonLabel}
</button>
<coral-popover ref={popoverRef} target={`#${CSS.escape(buttonId)}`} placement="bottom">
<coral-popover-header>{title}</coral-popover-header>
<coral-popover-content>
<coral-selectlist ref={selectlistRef}>
<coral-selectlist ref={selectlistRef} style={{ maxHeight: '50vh', overflow: 'auto', border: 'none' }}>
{items.map(([value, label, icon]) => (
<coral-selectlist-item key={value} value={value}>
{icon ? <coral-icon icon={icon} /> : undefined}
Expand Down
28 changes: 5 additions & 23 deletions src/main/frontend/widgets/StepEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,40 +131,22 @@ const Elm = styled('div')`
}
}
&.has-pipeline {
> details {
border-bottom-left-radius: 0;
}
}
.sub-pipeline {
padding-left: 2em;
margin-top: -4px;
padding-top: 4px;
border-left: solid 4px var(--accent-color);
border-radius: 0 0 0 4px;
.add-more {
> .add-hop {
display: inline-block;
margin: 16px 0 0 ~'calc(-2em - 4px)';
padding-top: 3px;
margin: 16px 0 0 calc(-2em - 4px);
background-color: var(--accent-color);
border: none;
border-radius: 0 4px 4px 4px;
color: white;
cursor: pointer;
sdx-menu-flyout-toggle {
background-color: rgba(196, 196, 196, 0.4);
display: inline-block;
padding: 4px;
i {
color: var(--contrast-color);
}
}
&:hover sdx-menu-flyout-toggle {
background-color: rgba(255, 255, 255, 0.7);
}
}
}
`;
Expand Down Expand Up @@ -225,7 +207,7 @@ export const StepEditor: FC<{ parentHops: Hop[]; hop: Hop; title: string; childr
</summary>
<div className="edit">{children}</div>
</details>
{pipeline ? <div className="pipeline">{pipeline}</div> : undefined}
{pipeline ? <div className="pipeline sub-pipeline">{pipeline}</div> : undefined}
</Elm>
);
};

0 comments on commit 866e151

Please sign in to comment.