Skip to content

Commit

Permalink
Merge branch 'linked-inputs-group' of https://github.com/RunDevelopme…
Browse files Browse the repository at this point in the history
…nt/chaiNNer into linked-inputs-group
  • Loading branch information
RunDevelopment committed Jul 25, 2023
2 parents d056eea + e0b8d50 commit ec7a892
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 22 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
"react-dom": "^18.1.0",
"react-hotkeys-hook": "^3.4.6",
"react-i18next": "^12.0.0",
"react-icons": "^4.7.1",
"react-icons": "^4.10.1",
"react-markdown": "^8.0.3",
"react-query": "^3.39.3",
"react-time-ago": "^7.2.1",
Expand Down
1 change: 1 addition & 0 deletions src/common/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface JsonObject {
export type JsonValue = null | string | number | boolean | JsonObject | JsonValue[];

export type Mutable<T> = { -readonly [P in keyof T]: T[P] };
export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

export interface Size {
width: number;
Expand Down
1 change: 1 addition & 0 deletions src/common/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"openInFileExplorer": "Open in File Explorer",
"selectDirectory": "Select a directory..."
},
"extractValueIntoNode": "Extract value into node",
"file": {
"copyFileName": "Copy File Name",
"copyFullFilePath": "Copy Full File Path",
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/components/inputs/DirectoryInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { BsFolderPlus } from 'react-icons/bs';
import { MdContentCopy, MdFolder } from 'react-icons/md';
import { ipcRenderer } from '../../../common/safeIpc';
import { useContextMenu } from '../../hooks/useContextMenu';
import { useInputRefactor } from '../../hooks/useInputRefactor';
import { useLastDirectory } from '../../hooks/useLastDirectory';
import { CopyOverrideIdSection } from './elements/CopyOverrideIdSection';
import { MaybeLabel } from './InputContainer';
Expand Down Expand Up @@ -65,6 +66,8 @@ export const DirectoryInput = memo(

const displayDirectory = isConnected ? getDirectoryPath(inputType) : value;

const refactor = useInputRefactor(nodeId, input, value, isConnected);

const menu = useContextMenu(() => (
<MenuList className="nodrag">
<MenuItem
Expand Down Expand Up @@ -98,6 +101,7 @@ export const DirectoryInput = memo(
>
{t('inputs.directory.copyFullDirectoryPath', 'Copy Full Directory Path')}
</MenuItem>
{refactor}
<CopyOverrideIdSection
inputId={input.id}
nodeId={nodeId}
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/components/inputs/NumberInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
import { MdContentCopy, MdContentPaste } from 'react-icons/md';
import { areApproximatelyEqual } from '../../../common/util';
import { useContextMenu } from '../../hooks/useContextMenu';
import { useInputRefactor } from '../../hooks/useInputRefactor';
import { AdvancedNumberInput } from './elements/AdvanceNumberInput';
import { CopyOverrideIdSection } from './elements/CopyOverrideIdSection';
import { MaybeLabel } from './InputContainer';
Expand Down Expand Up @@ -50,6 +51,7 @@ export const NumberInput = memo(
const displayString = isConnected ? typeNumberString : inputString;

const { t } = useTranslation();
const refactor = useInputRefactor(nodeId, input, value, isConnected);

const menu = useContextMenu(() => (
<MenuList className="nodrag">
Expand Down Expand Up @@ -77,6 +79,7 @@ export const NumberInput = memo(
>
{t('inputs.number.paste', 'Paste')}
</MenuItem>
{refactor}
<CopyOverrideIdSection
inputId={input.id}
nodeId={nodeId}
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/components/inputs/SliderInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Input, OfKind } from '../../../common/common-types';
import { assertNever } from '../../../common/util';
import { BackendContext } from '../../contexts/BackendContext';
import { useContextMenu } from '../../hooks/useContextMenu';
import { useInputRefactor } from '../../hooks/useInputRefactor';
import { AdvancedNumberInput } from './elements/AdvanceNumberInput';
import { CopyOverrideIdSection } from './elements/CopyOverrideIdSection';
import {
Expand Down Expand Up @@ -143,6 +144,7 @@ export const SliderInput = memo(
const filled = !expr;

const { t } = useTranslation();
const refactor = useInputRefactor(nodeId, input, value, isConnected);

const menu = useContextMenu(() => (
<MenuList className="nodrag">
Expand All @@ -165,6 +167,7 @@ export const SliderInput = memo(
>
{t('inputs.number.paste', 'Paste')}
</MenuItem>
{refactor}
<CopyOverrideIdSection
inputId={input.id}
nodeId={nodeId}
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/components/inputs/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { stopPropagation } from '../../../common/util';
import { GlobalVolatileContext } from '../../contexts/GlobalNodeState';
import { typeToString } from '../../helpers/naviHelpers';
import { useContextMenu } from '../../hooks/useContextMenu';
import { useInputRefactor } from '../../hooks/useInputRefactor';
import { DragHandleSVG } from '../CustomIcons';
import { CopyOverrideIdSection } from './elements/CopyOverrideIdSection';
import { MaybeLabel } from './InputContainer';
Expand Down Expand Up @@ -82,6 +83,7 @@ export const TextInput = memo(
const displayText = isConnected ? typeText : tempText;

const { t } = useTranslation();
const refactor = useInputRefactor(nodeId, input, value, isConnected);

const menu = useContextMenu(() => (
<MenuList className="nodrag">
Expand Down Expand Up @@ -110,6 +112,7 @@ export const TextInput = memo(
>
{t('inputs.text.paste', 'Paste')}
</MenuItem>
{refactor}
<CopyOverrideIdSection
inputId={input.id}
nodeId={nodeId}
Expand Down
4 changes: 1 addition & 3 deletions src/renderer/components/inputs/props.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Type } from '@chainner/navi';
import { Input, InputKind, OfKind, SchemaId, Size } from '../../../common/common-types';

type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
import { Input, InputKind, OfKind, PartialBy, SchemaId, Size } from '../../../common/common-types';

export interface InputProps<Kind extends InputKind, Value extends string | number = never> {
readonly value: Value | undefined;
Expand Down
17 changes: 6 additions & 11 deletions src/renderer/components/outputs/DefaultImageOutput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { BsEyeFill } from 'react-icons/bs';
import { useReactFlow } from 'reactflow';
import { useContext } from 'use-context-selector';
import { EdgeData, InputId, NodeData, SchemaId } from '../../../common/common-types';
import { createUniqueId, stringifySourceHandle, stringifyTargetHandle } from '../../../common/util';
import { createUniqueId, stringifySourceHandle } from '../../../common/util';
import { GlobalContext } from '../../contexts/GlobalNodeState';
import { TypeTags } from '../TypeTag';
import { OutputProps } from './props';

const VIEW_SCHEMA_ID = 'chainner:image:view' as SchemaId;

export const DefaultImageOutput = memo(({ output, id, schema, type }: OutputProps) => {
const { selectNode, createNode, createConnection } = useContext(GlobalContext);
const { selectNode, createNode, createEdge } = useContext(GlobalContext);
const { getNodes, getEdges } = useReactFlow<NodeData, EdgeData>();

return (
Expand Down Expand Up @@ -78,15 +78,10 @@ export const DefaultImageOutput = memo(({ output, id, schema, type }: OutputProp
},
containingNode.parentNode
);
createConnection({
source: id,
sourceHandle,
target: nodeId,
targetHandle: stringifyTargetHandle({
nodeId,
inputId: 0 as InputId,
}),
});
createEdge(
{ nodeId: id, outputId: output.id },
{ nodeId, inputId: 0 as InputId }
);
}
}}
>
Expand Down
17 changes: 17 additions & 0 deletions src/renderer/contexts/GlobalNodeState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ import {
import { withoutNull } from '../../common/types/util';
import {
EMPTY_SET,
ParsedSourceHandle,
ParsedTargetHandle,
createUniqueId,
deepCopy,
deriveUniqueId,
lazy,
parseSourceHandle,
parseTargetHandle,
stringifySourceHandle,
stringifyTargetHandle,
} from '../../common/util';
import { VALID, Validity, invalid } from '../../common/Validity';
import {
Expand Down Expand Up @@ -122,6 +126,7 @@ interface Global {
animate: (nodeIdsToAnimate: Iterable<string>, animateEdges?: boolean) => void;
unAnimate: (nodeIdsToAnimate?: Iterable<string>) => void;
createNode: (proto: NodeProto, parentId?: string) => void;
createEdge: (from: ParsedSourceHandle, to: ParsedTargetHandle) => void;
createConnection: (connection: Connection) => void;
setNodeInputValue: <T extends InputValue>(nodeId: string, inputId: InputId, value: T) => void;
setNodeInputSize: (nodeId: string, inputId: InputId, value: Readonly<Size>) => void;
Expand Down Expand Up @@ -799,6 +804,17 @@ export const GlobalProvider = memo(
},
[changeEdges]
);
const createEdge = useCallback(
(from: ParsedSourceHandle, to: ParsedTargetHandle): void => {
createConnection({
source: from.nodeId,
sourceHandle: stringifySourceHandle(from),
target: to.nodeId,
targetHandle: stringifyTargetHandle(to),
});
},
[createConnection]
);

const releaseNodeFromParent = useCallback(
(id: string) => {
Expand Down Expand Up @@ -1351,6 +1367,7 @@ export const GlobalProvider = memo(
animate,
unAnimate,
createNode,
createEdge,
createConnection,
setNodeInputValue,
setNodeInputSize,
Expand Down
102 changes: 102 additions & 0 deletions src/renderer/hooks/useInputRefactor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { MenuDivider, MenuItem } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
import { CgArrowsExpandUpLeft } from 'react-icons/cg';
import { useReactFlow } from 'reactflow';
import { useContext } from 'use-context-selector';
import {
EdgeData,
Input,
InputId,
InputKind,
InputValue,
NodeData,
OutputId,
PartialBy,
SchemaId,
} from '../../common/common-types';
import { createUniqueId } from '../../common/util';
import { BackendContext } from '../contexts/BackendContext';
import { GlobalContext } from '../contexts/GlobalNodeState';

const valueNodeMap = {
number: 'chainner:utility:number' as SchemaId,
slider: 'chainner:utility:number' as SchemaId,
text: 'chainner:utility:text' as SchemaId,
directory: 'chainner:utility:directory' as SchemaId,
} as const satisfies Partial<Record<InputKind, SchemaId>>;

export const useInputRefactor = (
nodeId: string | undefined,
input: Omit<PartialBy<Input, 'id'>, 'type' | 'conversion'>,
value: InputValue,
isConnected: boolean
): JSX.Element | null => {
const { t } = useTranslation();
const { createNode, createEdge } = useContext(GlobalContext);
const { schemata } = useContext(BackendContext);
const { getNode } = useReactFlow<NodeData, EdgeData>();

const inputId = input.id;
if (nodeId === undefined || inputId === undefined) {
return null;
}

const refactoringOptions: JSX.Element[] = [];
const specificInput = input as Input;

if (
specificInput.hasHandle &&
((specificInput.kind === 'text' && !specificInput.multiline) ||
specificInput.kind === 'number' ||
specificInput.kind === 'slider' ||
specificInput.kind === 'directory')
) {
refactoringOptions.push(
<MenuItem
icon={<CgArrowsExpandUpLeft />}
isDisabled={isConnected || value === undefined}
key="extract text"
onClick={() => {
const containingNode = getNode(nodeId);
const valueNodeId = createUniqueId();

let inputIndex = 0;
if (containingNode) {
const schema = schemata.get(containingNode.data.schemaId);
inputIndex = schema.inputs.findIndex((i) => i.id === inputId);
}

createNode(
{
id: valueNodeId,
position: {
x: (containingNode?.position.x ?? 0) - 300,
y: (containingNode?.position.y ?? 0) - 30 + inputIndex * 50,
},
data: {
schemaId: valueNodeMap[specificInput.kind],
inputData: { [0 as InputId]: value },
},
nodeType: 'regularNode',
},
containingNode?.parentNode
);
createEdge(
{ nodeId: valueNodeId, outputId: 0 as OutputId },
{ nodeId, inputId }
);
}}
>
{t('inputs.extractValueIntoNode', 'Extract value into node')}
</MenuItem>
);
}

if (refactoringOptions.length === 0) return null;
return (
<>
<MenuDivider />
{refactoringOptions}
</>
);
};

0 comments on commit ec7a892

Please sign in to comment.