Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
10 changes: 7 additions & 3 deletions common/flow.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,16 @@ interface ImportState {
classes: string[]
}

type PropertyValue = {
value: string|null,
type: "default"|"custom"
}

interface Component extends Positionable {
id: Uuid,
type: string,
name: string,
properties: {[name: string]: string|null}
properties: {[name: string]: PropertyValue}
visibleProperties?: string[]
running?: ComponentState
parentGroup?: Uuid|null
Expand Down Expand Up @@ -194,10 +199,9 @@ interface ConnectionSize {
interface Connection {
id: Uuid,
name: string|null,
errors: string[],
attributes: string[],
source: {id: Uuid, port: string|null},
sourceRelationships: {[name: string]: boolean},
sourceRelationships: string[],
destination: {id: Uuid, port: string|null},
flowFileExpiration: string,
swapThreshold: string|null,
Expand Down
1 change: 1 addition & 0 deletions examples/minifi/agent-cpp.dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM apache/nifi-minifi-cpp:latest

RUN echo "nifi.c2.enable=true" >> /opt/minifi/minifi-current/conf/minifi.properties && \
echo "nifi.c2.rest.path.base=http://c2:13405/api" >> /opt/minifi/minifi-current/conf/minifi.properties && \
echo "nifi.c2.flow.base.url=http://c2:13405/api/flows" >> /opt/minifi/minifi-current/conf/minifi.properties && \
echo "nifi.c2.rest.url=http://c2:13405/api/heartbeat" >> /opt/minifi/minifi-current/conf/minifi.properties && \
echo "nifi.c2.rest.url.ack=http://c2:13405/api/acknowledge" >> /opt/minifi/minifi-current/conf/minifi.properties && \
Expand Down
2 changes: 1 addition & 1 deletion server/src/utils/flow-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function SerializeFlow(id: string, flow: FlowObject): string {
for (const conn of flow.connections) {
const src = flow.processors.find(proc => conn.source.id === proc.id)!;
const dst = flow.processors.find(proc => conn.destination.id === proc.id)!;
const rels = Object.keys(conn.sourceRelationships).filter(rel => conn.sourceRelationships[rel]);
const rels = conn.sourceRelationships;
result += " - name: " + (conn.name ?? `${src.name}/${rels.join(",")}/${dst.name}`) + "\n";
result += " id: " + conn.id + "\n";
result += " source name: " + src.name + "\n";
Expand Down
25 changes: 7 additions & 18 deletions server/src/utils/json-flow-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function serializeProcessGroup(id: Uuid | null, flow: FlowObject): object {
}).map(conn => {
const src = findComponent(flow, conn.source.id)!;
const dst = findComponent(flow, conn.destination.id)!;
const rels = Object.keys(conn.sourceRelationships).filter(rel => conn.sourceRelationships[rel]);
const rels = conn.sourceRelationships;
return {
"position": {
"x": typeof conn.midPoint === "number" ? conn.midPoint : (conn.midPoint?.x ?? 0.0),
Expand Down Expand Up @@ -159,11 +159,11 @@ function findComponent(flow: FlowObject, id: Uuid): Component | undefined | null
flow.funnels.find(val => val.id === id);
}

function filterNullish(obj: { [key: string]: string | null }): { [key: string]: string } {
function filterNullish(obj: { [key: string]: PropertyValue }): { [key: string]: string } {
let result: { [key: string]: string } = {};
for (let key in obj) {
if (isNullish(obj[key])) continue;
result[key] = obj[key]!;
if (isNullish(obj[key].value)) continue;
result[key] = obj[key].value;
}
return result;
}
Expand Down Expand Up @@ -268,7 +268,6 @@ function deserializeProcessGroup(flow_object: FlowObject, group_id: Uuid | null,
flow_object.connections = flow_object.connections.concat(process_group_json.connections.map((conn: any) => ({
id: conn.identifier,
name: conn.name,
errors: [],
attributes: [],
source: {
id: conn.source.id,
Expand Down Expand Up @@ -362,7 +361,7 @@ function fixFlowObject(flow_object: FlowObject) {
if (processor_manifest && processor_manifest.propertyDescriptors) {
for (let property_name in processor_manifest.propertyDescriptors) {
if (!(property_name in processor.properties)) {
processor.properties[property_name] = null;
processor.properties[property_name].value = null;
}
}
}
Expand All @@ -379,22 +378,12 @@ function fixFlowObject(flow_object: FlowObject) {
if (service_manifest && service_manifest.propertyDescriptors) {
for (let property_name in service_manifest.propertyDescriptors) {
if (!(property_name in service.properties)) {
service.properties[property_name] = null;
service.properties[property_name].value = null;
}
}
}
}
for (let connection of flow_object.connections) {
const source_processor = flow_object.processors.find(processor => processor.id === connection.source.id);
if (source_processor) {
const source_manifest = flow_object.manifest.processors.find(processor_manifest => processor_manifest.type === source_processor.type);
if (source_manifest) {
for (let relationship of source_manifest.supportedRelationships) {
if (!(relationship.name in connection.sourceRelationships)) {
connection.sourceRelationships[relationship.name] = false;
}
}
}
}
connection.sourceRelationships = []
}
}
19 changes: 12 additions & 7 deletions website/src/components/connection-editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { InputField } from "../component-editor-input";
import { Toggle } from "../component-editor-toggle";
import "./index.scss"

export function ConnectionEditor(props: {model: Connection, readonly?: boolean}) {
export function ConnectionEditor(props: {model: Connection, supportedRels: string[], readonly?: boolean, errors: ErrorObject[]}) {
const flow_context = useContext(FlowContext);
const setModel = React.useMemo(()=>{
return (fn: (curr: Connection)=>Connection) => flow_context!.updateConnection(props.model.id, fn);
Expand All @@ -24,7 +24,7 @@ export function ConnectionEditor(props: {model: Connection, readonly?: boolean})
<div className="component-content">
<div className="section">
<div className="section-title">General</div>
{props.model.errors.map(err => <div key={err} className="connection-error">{err}</div>)}
{props.errors.map(err => <div key={err.message} className="connection-error">{err.message}</div>)}
<InputField name="NAME" width="100%" default={props.model.name} onChange={flow_context?.editable ? val=>setModel(curr => ({...curr, name: val})) : undefined}/>
<InputField name="FLOWFILE EXPIRATION" width="100%" default={props.model.flowFileExpiration} onChange={flow_context?.editable ? val=>setModel(curr => ({...curr, flowFileExpiration: val})) : undefined}/>
<InputField name="BACK PRESSURE COUNT THRESHOLD" width="100%" default={props.model.backpressureThreshold.count} onChange={flow_context?.editable ? val => setModel(curr => ({...curr, backpressureThreshold: {...curr.backpressureThreshold, count: val}})) : undefined}/>
Expand All @@ -33,11 +33,16 @@ export function ConnectionEditor(props: {model: Connection, readonly?: boolean})
</div>
<div className="section">
<div className="section-title">Source relationships</div>
{
Object.keys(props.model.sourceRelationships).sort().map(rel=>{
return <Toggle key={rel} marginBottom="10px" name={rel} initial={props.model.sourceRelationships[rel]} onChange={flow_context?.editable ? val => setModel(curr => ({...curr, sourceRelationships: {...curr.sourceRelationships, [rel]: val}})) : undefined} />
})
}
{[...new Set([...props.supportedRels, ...props.model.sourceRelationships])].map(rel => {
return <Toggle key={rel} marginBottom="10px" name={rel} error={props.errors.find(err => err.target === rel)?.message}
initial={props.model.sourceRelationships.includes(rel)}
onChange={flow_context?.editable ? val => setModel(curr => {
if (curr.sourceRelationships.includes(rel)) {
return {...curr, sourceRelationships: curr.sourceRelationships.filter(curr_rel => curr_rel !== rel)}
}
return {...curr, sourceRelationships: [...curr.sourceRelationships, rel]}
}) : undefined} />
})}
</div>
<div className="section">
<div className="section-title">Flow File Attributes</div>
Expand Down
20 changes: 13 additions & 7 deletions website/src/components/connection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ export function IsInside(area: {x: number, y: number, w: number, h: number, circ
return area.x - area.w/2 <= x && x <= area.x + area.w/2 && area.y - area.h/2 <= y && y <= area.y + area.h/2;
}

export function ConnectionView(props: {model?: Connection, id?: Uuid,
export function ConnectionView(props: {model?: Connection, id?: Uuid, supportedRel: string[],
from: {x: number, y: number, w: number, h: number, circular: boolean},
to: {x: number, y: number, w: number, h: number, circular: boolean}, name?: string,
midPoint?: {x: number, y: number}|number, readonly?: boolean, container?: Positionable|null,
selected?: boolean}) {
selected?: boolean, errors: ErrorObject[]}) {
const midPoint = props.model?.midPoint ?? props.midPoint;

let v_x = props.to.x - props.from.x;
Expand Down Expand Up @@ -196,7 +196,7 @@ export function ConnectionView(props: {model?: Connection, id?: Uuid,
</svg>
{
props.id === undefined ? null :
<ConnectionName id={props.id} model={props.model!} x={name_pos.x - (left - 500)} y={name_pos.y - (top - 500)} name={props.name} />
<ConnectionName id={props.id} model={props.model!} supportedRels={props.supportedRel} x={name_pos.x - (left - 500)} y={name_pos.y - (top - 500)} name={props.name} errors={props.errors} />
}
</div>
</div>
Expand Down Expand Up @@ -224,7 +224,7 @@ const usage_colors = [
{bg: "#CD0000", color: "#ffffff"},
]

function ConnectionName(props: {id: Uuid, model: Connection, x: number, y: number, name?: string}) {
function ConnectionName(props: {id: Uuid, model: Connection, supportedRels: string[], x: number, y: number, name?: string, errors: ErrorObject[]}) {
const [inline_rels, setInlineRels] = React.useState(false);
const flow_context = React.useContext(FlowContext);
const view_ref = React.useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -275,10 +275,16 @@ function ConnectionName(props: {id: Uuid, model: Connection, x: number, y: numbe

return <div ref={view_ref} className="name popout" style={{left: `${props.x}px`, top: `${props.y}px`}} onContextMenu={oncontextmenu} onMouseDown={onmousedown} onDoubleClick={ondblclick} onClick={onclick}>
{props.name ? props.name : "<unspecified>"}
{props.model?.errors.length !== 0 ? <ConnectionErrorBadge/> : null}
{props.errors.length !== 0 ? <ConnectionErrorBadge/> : null}
<div ref={inline_rel_ref} className={`inline-relationship-picker popout ${inline_rels ? 'active': ''}`} tabIndex={-1} onBlur={onblur}>
{Object.keys(props.model.sourceRelationships).map(rel => {
return <Toggle key={rel} marginBottom="10px" name={rel} initial={props.model.sourceRelationships[rel]} onChange={val => flow_context!.updateConnection(props.model.id, curr => ({...curr, sourceRelationships: {...curr.sourceRelationships, [rel]: val}}))} />
{[...new Set([...props.supportedRels, ...props.model.sourceRelationships])].map(rel => {
return <Toggle key={rel} marginBottom="10px" name={rel} error={props.errors.find(err => err.target === rel)?.message} initial={props.model.sourceRelationships.includes(rel)}
onChange={val => flow_context!.updateConnection(props.model.id, curr => {
if (curr.sourceRelationships.includes(rel)) {
return {...curr, sourceRelationships: curr.sourceRelationships.filter(curr_rel => curr_rel !== rel)}
}
return {...curr, sourceRelationships: [...curr.sourceRelationships, rel]}
})} />
})}
</div>
{props.model.size ?
Expand Down
3 changes: 3 additions & 0 deletions website/src/components/create-string-modal/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
border-radius: 3px;
outline: none;
background-color: var(--bg-color);
&:focus {
border-color: var(--highlight-blue);
}
}
.ok {
align-self: flex-end;
Expand Down
14 changes: 12 additions & 2 deletions website/src/components/create-string-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,19 @@ export function CreateStringModal(props: {text: string, onSubmit: (val: string)=
const onChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>)=>{
setPropName(e.currentTarget.value);
}, [prop_name])
return <div className="create-string">
return <div className="create-string" tabIndex={0} >
<div className="title">{props.text}</div>
<input defaultValue={prop_name} onChange={onChange} />
<input defaultValue={prop_name} onChange={onChange} autoFocus
onKeyDown={e => {
if (e.code === "Escape") {
e.stopPropagation();
openModal(null as any)
return;
}
if (e.code === "Enter") {
props.onSubmit(prop_name); openModal(null as any)
}
}}/>
<div className="ok" onClick={() => {props.onSubmit(prop_name); openModal(null as any)}}>Create</div>
</div>
}
2 changes: 1 addition & 1 deletion website/src/components/dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function Dropdown(props: {name: string, items: string[], initial?: string
</>}
</div>
<div className={`dropdown ${state.active ? "active": ""}`} tabIndex={-1} onBlur={onBlur} onFocus={onFocus}>
<div className="selected">{state.current === '' ? <span>&nbsp;</span> : state.current}
<div className="selected">{state.current === '' || state.current === null ? <span>&nbsp;</span> : state.current}
{
props.onChange ?
<div className="down-icon">
Expand Down
2 changes: 1 addition & 1 deletion website/src/components/extended-widget/ai-widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ export function AiWidget(props: {value: Component}) {
<div className="header">
<SparkleIcon size={20} />
</div>
<div className="prompt">{props.value.properties["Prompt"]}</div>
<div className="prompt">{props.value.properties["Prompt"].value}</div>
</div>
}
2 changes: 1 addition & 1 deletion website/src/components/extended-widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function ExtendedWidget(props: {value: Component}) {
props.value.visibleProperties!.map(property => {
return <div key={property} className="extended-property">
<div className="extended-property-name">{property}</div>
<div className="extended-property-value">{`${props.value.properties[property]}`}</div>
<div className="extended-property-value">{`${props.value.properties[property].value}`}</div>
</div>
})
}
Expand Down
4 changes: 2 additions & 2 deletions website/src/components/flow-editor/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
gap: 10px;
}

.open-publish, .export-btn, .rearrange-btn {
.open-publish, .export-btn, .rearrange-btn, .upgrade-manifest-btn {
padding: 8px 20px;
border-radius: 5px;
color: var(--text-inactive-color);
Expand All @@ -91,7 +91,7 @@
cursor: pointer;
}

.open-publish:hover, .export-btn:hover, .rearrange-btn:hover {
.open-publish:hover, .export-btn:hover, .rearrange-btn:hover, .upgrade-manifest-btn:hover {
color: var(--highlight-green);
background-color: var(--light-green);
border-color: var(--highlight-green);
Expand Down
Loading