Merge pull request #1513 from 0xi4o/feature/sticky-notes-node
FEATURE: Sticky Note node
This commit is contained in:
commit
27f2a7f6ba
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { INode, INodeParams } from '../../../src/Interface'
|
||||||
|
|
||||||
|
class StickyNote implements INode {
|
||||||
|
label: string
|
||||||
|
name: string
|
||||||
|
version: number
|
||||||
|
description: string
|
||||||
|
type: string
|
||||||
|
icon: string
|
||||||
|
category: string
|
||||||
|
baseClasses: string[]
|
||||||
|
inputs: INodeParams[]
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.label = 'Sticky Note'
|
||||||
|
this.name = 'stickyNote'
|
||||||
|
this.version = 1.0
|
||||||
|
this.type = 'StickyNote'
|
||||||
|
this.icon = 'stickyNote.svg'
|
||||||
|
this.category = 'Utilities'
|
||||||
|
this.description = 'Add a sticky note'
|
||||||
|
this.inputs = [
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
name: 'note',
|
||||||
|
type: 'string',
|
||||||
|
rows: 1,
|
||||||
|
placeholder: 'Type something here',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.baseClasses = [this.type]
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(): Promise<any> {
|
||||||
|
return new StickyNote()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { nodeClass: StickyNote }
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||||
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M15.5 3H5a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V8.5L15.5 3Z"/>
|
||||||
|
<path d="M15 3v6h6"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 305 B |
|
|
@ -90,7 +90,7 @@ export interface INodeProperties {
|
||||||
type: string
|
type: string
|
||||||
icon: string
|
icon: string
|
||||||
version: number
|
version: number
|
||||||
category: string
|
category: string // TODO: use enum instead of string
|
||||||
baseClasses: string[]
|
baseClasses: string[]
|
||||||
description?: string
|
description?: string
|
||||||
filePath?: string
|
filePath?: string
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { Entity, Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn } from 'typeorm'
|
import { Entity, Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn } from 'typeorm'
|
||||||
import { IVariable } from "../../Interface";
|
import { IVariable } from '../../Interface'
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Variable implements IVariable{
|
export class Variable implements IVariable {
|
||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id: string
|
id: string
|
||||||
|
|
||||||
|
|
@ -13,10 +13,9 @@ export class Variable implements IVariable{
|
||||||
@Column({ nullable: true, type: 'text' })
|
@Column({ nullable: true, type: 'text' })
|
||||||
value: string
|
value: string
|
||||||
|
|
||||||
@Column({default: 'string', type: 'text'})
|
@Column({ default: 'string', type: 'text' })
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdDate: Date
|
createdDate: Date
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// material-ui
|
||||||
|
import { styled } from '@mui/material/styles'
|
||||||
|
|
||||||
|
// project imports
|
||||||
|
import MainCard from './MainCard'
|
||||||
|
|
||||||
|
const NodeCardWrapper = styled(MainCard)(({ theme }) => ({
|
||||||
|
background: theme.palette.card.main,
|
||||||
|
color: theme.darkTextPrimary,
|
||||||
|
border: 'solid 1px',
|
||||||
|
borderColor: theme.palette.primary[200] + 75,
|
||||||
|
width: '300px',
|
||||||
|
height: 'auto',
|
||||||
|
padding: '10px',
|
||||||
|
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 8%)',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: theme.palette.primary.main
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default NodeCardWrapper
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState, useEffect, useRef } from 'react'
|
import { useState, useEffect, useRef } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { FormControl, OutlinedInput, Popover } from '@mui/material'
|
import { FormControl, OutlinedInput, InputBase, Popover } from '@mui/material'
|
||||||
import SelectVariable from 'ui-component/json/SelectVariable'
|
import SelectVariable from 'ui-component/json/SelectVariable'
|
||||||
import { getAvailableNodesForVariable } from 'utils/genericHelper'
|
import { getAvailableNodesForVariable } from 'utils/genericHelper'
|
||||||
|
|
||||||
|
|
@ -50,29 +50,67 @@ export const Input = ({ inputParam, value, nodes, edges, nodeId, onChange, disab
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FormControl sx={{ mt: 1, width: '100%' }} size='small'>
|
{inputParam.name === 'note' ? (
|
||||||
<OutlinedInput
|
<FormControl sx={{ width: '100%', height: 'auto' }} size='small'>
|
||||||
id={inputParam.name}
|
<InputBase
|
||||||
size='small'
|
id={nodeId}
|
||||||
disabled={disabled}
|
size='small'
|
||||||
type={getInputType(inputParam.type)}
|
disabled={disabled}
|
||||||
placeholder={inputParam.placeholder}
|
type={getInputType(inputParam.type)}
|
||||||
multiline={!!inputParam.rows}
|
placeholder={inputParam.placeholder}
|
||||||
rows={inputParam.rows ?? 1}
|
multiline={!!inputParam.rows}
|
||||||
value={myValue}
|
minRows={inputParam.rows ?? 1}
|
||||||
name={inputParam.name}
|
value={myValue}
|
||||||
onChange={(e) => {
|
name={inputParam.name}
|
||||||
setMyValue(e.target.value)
|
onChange={(e) => {
|
||||||
onChange(e.target.value)
|
setMyValue(e.target.value)
|
||||||
}}
|
onChange(e.target.value)
|
||||||
inputProps={{
|
}}
|
||||||
step: inputParam.step ?? 1,
|
inputProps={{
|
||||||
style: {
|
step: inputParam.step ?? 1,
|
||||||
height: inputParam.rows ? '90px' : 'inherit'
|
style: {
|
||||||
}
|
border: 'none',
|
||||||
}}
|
background: 'none',
|
||||||
/>
|
color: '#212121'
|
||||||
</FormControl>
|
}
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
border: 'none',
|
||||||
|
background: 'none',
|
||||||
|
padding: '10px 14px',
|
||||||
|
textarea: {
|
||||||
|
'&::placeholder': {
|
||||||
|
color: '#616161'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
) : (
|
||||||
|
<FormControl sx={{ mt: 1, width: '100%' }} size='small'>
|
||||||
|
<OutlinedInput
|
||||||
|
id={inputParam.name}
|
||||||
|
size='small'
|
||||||
|
disabled={disabled}
|
||||||
|
type={getInputType(inputParam.type)}
|
||||||
|
placeholder={inputParam.placeholder}
|
||||||
|
multiline={!!inputParam.rows}
|
||||||
|
rows={inputParam.rows ?? 1}
|
||||||
|
value={myValue}
|
||||||
|
name={inputParam.name}
|
||||||
|
onChange={(e) => {
|
||||||
|
setMyValue(e.target.value)
|
||||||
|
onChange(e.target.value)
|
||||||
|
}}
|
||||||
|
inputProps={{
|
||||||
|
step: inputParam.step ?? 1,
|
||||||
|
style: {
|
||||||
|
height: inputParam.rows ? '90px' : 'inherit'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
<div ref={ref}></div>
|
<div ref={ref}></div>
|
||||||
{inputParam?.acceptVariable && (
|
{inputParam?.acceptVariable && (
|
||||||
<Popover
|
<Popover
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { styled } from '@mui/material/styles'
|
||||||
|
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'
|
||||||
|
|
||||||
|
const NodeTooltip = styled(({ className, ...props }) => <Tooltip {...props} classes={{ popper: className }} />)(({ theme }) => ({
|
||||||
|
[`& .${tooltipClasses.tooltip}`]: {
|
||||||
|
backgroundColor: theme.palette.nodeToolTip.background,
|
||||||
|
color: theme.palette.nodeToolTip.color,
|
||||||
|
boxShadow: theme.shadows[1]
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default NodeTooltip
|
||||||
|
|
@ -3,12 +3,13 @@ import { useContext, useState, useEffect } from 'react'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
// material-ui
|
// material-ui
|
||||||
import { styled, useTheme } from '@mui/material/styles'
|
import { useTheme } from '@mui/material/styles'
|
||||||
import { IconButton, Box, Typography, Divider, Button } from '@mui/material'
|
import { IconButton, Box, Typography, Divider, Button } from '@mui/material'
|
||||||
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'
|
import Tooltip from '@mui/material/Tooltip'
|
||||||
|
|
||||||
// project imports
|
// project imports
|
||||||
import MainCard from 'ui-component/cards/MainCard'
|
import NodeCardWrapper from '../../ui-component/cards/NodeCardWrapper'
|
||||||
|
import NodeTooltip from '../../ui-component/tooltip/NodeTooltip'
|
||||||
import NodeInputHandler from './NodeInputHandler'
|
import NodeInputHandler from './NodeInputHandler'
|
||||||
import NodeOutputHandler from './NodeOutputHandler'
|
import NodeOutputHandler from './NodeOutputHandler'
|
||||||
import AdditionalParamsDialog from 'ui-component/dialog/AdditionalParamsDialog'
|
import AdditionalParamsDialog from 'ui-component/dialog/AdditionalParamsDialog'
|
||||||
|
|
@ -19,28 +20,6 @@ import { baseURL } from 'store/constant'
|
||||||
import { IconTrash, IconCopy, IconInfoCircle, IconAlertTriangle } from '@tabler/icons'
|
import { IconTrash, IconCopy, IconInfoCircle, IconAlertTriangle } from '@tabler/icons'
|
||||||
import { flowContext } from 'store/context/ReactFlowContext'
|
import { flowContext } from 'store/context/ReactFlowContext'
|
||||||
|
|
||||||
const CardWrapper = styled(MainCard)(({ theme }) => ({
|
|
||||||
background: theme.palette.card.main,
|
|
||||||
color: theme.darkTextPrimary,
|
|
||||||
border: 'solid 1px',
|
|
||||||
borderColor: theme.palette.primary[200] + 75,
|
|
||||||
width: '300px',
|
|
||||||
height: 'auto',
|
|
||||||
padding: '10px',
|
|
||||||
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 8%)',
|
|
||||||
'&:hover': {
|
|
||||||
borderColor: theme.palette.primary.main
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
const LightTooltip = styled(({ className, ...props }) => <Tooltip {...props} classes={{ popper: className }} />)(({ theme }) => ({
|
|
||||||
[`& .${tooltipClasses.tooltip}`]: {
|
|
||||||
backgroundColor: theme.palette.nodeToolTip.background,
|
|
||||||
color: theme.palette.nodeToolTip.color,
|
|
||||||
boxShadow: theme.shadows[1]
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
// ===========================|| CANVAS NODE ||=========================== //
|
// ===========================|| CANVAS NODE ||=========================== //
|
||||||
|
|
||||||
const CanvasNode = ({ data }) => {
|
const CanvasNode = ({ data }) => {
|
||||||
|
|
@ -93,7 +72,7 @@ const CanvasNode = ({ data }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CardWrapper
|
<NodeCardWrapper
|
||||||
content={false}
|
content={false}
|
||||||
sx={{
|
sx={{
|
||||||
padding: 0,
|
padding: 0,
|
||||||
|
|
@ -101,7 +80,7 @@ const CanvasNode = ({ data }) => {
|
||||||
}}
|
}}
|
||||||
border={false}
|
border={false}
|
||||||
>
|
>
|
||||||
<LightTooltip
|
<NodeTooltip
|
||||||
open={!canvas.canvasDialogShow && open}
|
open={!canvas.canvasDialogShow && open}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onOpen={handleOpen}
|
onOpen={handleOpen}
|
||||||
|
|
@ -242,13 +221,12 @@ const CanvasNode = ({ data }) => {
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
{data.outputAnchors.map((outputAnchor, index) => (
|
{data.outputAnchors.map((outputAnchor, index) => (
|
||||||
<NodeOutputHandler key={index} outputAnchor={outputAnchor} data={data} />
|
<NodeOutputHandler key={index} outputAnchor={outputAnchor} data={data} />
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
</LightTooltip>
|
</NodeTooltip>
|
||||||
</CardWrapper>
|
</NodeCardWrapper>
|
||||||
<AdditionalParamsDialog
|
<AdditionalParamsDialog
|
||||||
show={showDialog}
|
show={showDialog}
|
||||||
dialogProps={dialogProps}
|
dialogProps={dialogProps}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { useContext, useState } from 'react'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
|
// material-ui
|
||||||
|
import { useTheme } from '@mui/material/styles'
|
||||||
|
|
||||||
|
// project imports
|
||||||
|
import NodeCardWrapper from '../../ui-component/cards/NodeCardWrapper'
|
||||||
|
import NodeTooltip from '../../ui-component/tooltip/NodeTooltip'
|
||||||
|
import { IconButton, Box } from '@mui/material'
|
||||||
|
import { IconCopy, IconTrash } from '@tabler/icons'
|
||||||
|
import { Input } from 'ui-component/input/Input'
|
||||||
|
|
||||||
|
// const
|
||||||
|
import { flowContext } from '../../store/context/ReactFlowContext'
|
||||||
|
|
||||||
|
const StickyNote = ({ data }) => {
|
||||||
|
const theme = useTheme()
|
||||||
|
const canvas = useSelector((state) => state.canvas)
|
||||||
|
const { deleteNode, duplicateNode } = useContext(flowContext)
|
||||||
|
const [inputParam] = data.inputParams
|
||||||
|
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOpen = () => {
|
||||||
|
setOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NodeCardWrapper
|
||||||
|
content={false}
|
||||||
|
sx={{
|
||||||
|
padding: 0,
|
||||||
|
borderColor: data.selected ? theme.palette.primary.main : theme.palette.text.secondary,
|
||||||
|
backgroundColor: data.selected ? '#FFDC00' : '#FFE770'
|
||||||
|
}}
|
||||||
|
border={false}
|
||||||
|
>
|
||||||
|
<NodeTooltip
|
||||||
|
open={!canvas.canvasDialogShow && open}
|
||||||
|
onClose={handleClose}
|
||||||
|
onOpen={handleOpen}
|
||||||
|
disableFocusListener={true}
|
||||||
|
title={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: 'transparent',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
title='Duplicate'
|
||||||
|
onClick={() => {
|
||||||
|
duplicateNode(data.id)
|
||||||
|
}}
|
||||||
|
sx={{ height: '35px', width: '35px', '&:hover': { color: theme?.palette.primary.main } }}
|
||||||
|
color={theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'}
|
||||||
|
>
|
||||||
|
<IconCopy />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
title='Delete'
|
||||||
|
onClick={() => {
|
||||||
|
deleteNode(data.id)
|
||||||
|
}}
|
||||||
|
sx={{ height: '35px', width: '35px', '&:hover': { color: 'red' } }}
|
||||||
|
color={theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'}
|
||||||
|
>
|
||||||
|
<IconTrash />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
placement='right-start'
|
||||||
|
>
|
||||||
|
<Box>
|
||||||
|
<Input
|
||||||
|
key={data.id}
|
||||||
|
inputParam={inputParam}
|
||||||
|
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)}
|
||||||
|
value={data.inputs[inputParam.name] ?? inputParam.default ?? ''}
|
||||||
|
nodes={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getNodes() : []}
|
||||||
|
edges={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getEdges() : []}
|
||||||
|
nodeId={data.id}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</NodeTooltip>
|
||||||
|
</NodeCardWrapper>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
StickyNote.propTypes = {
|
||||||
|
data: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StickyNote
|
||||||
|
|
@ -21,6 +21,7 @@ import { useTheme } from '@mui/material/styles'
|
||||||
// project imports
|
// project imports
|
||||||
import CanvasNode from './CanvasNode'
|
import CanvasNode from './CanvasNode'
|
||||||
import ButtonEdge from './ButtonEdge'
|
import ButtonEdge from './ButtonEdge'
|
||||||
|
import StickyNote from './StickyNote'
|
||||||
import CanvasHeader from './CanvasHeader'
|
import CanvasHeader from './CanvasHeader'
|
||||||
import AddNodes from './AddNodes'
|
import AddNodes from './AddNodes'
|
||||||
import ConfirmDialog from 'ui-component/dialog/ConfirmDialog'
|
import ConfirmDialog from 'ui-component/dialog/ConfirmDialog'
|
||||||
|
|
@ -46,7 +47,7 @@ import useNotifier from 'utils/useNotifier'
|
||||||
// const
|
// const
|
||||||
import { FLOWISE_CREDENTIAL_ID } from 'store/constant'
|
import { FLOWISE_CREDENTIAL_ID } from 'store/constant'
|
||||||
|
|
||||||
const nodeTypes = { customNode: CanvasNode }
|
const nodeTypes = { customNode: CanvasNode, stickyNote: StickyNote }
|
||||||
const edgeTypes = { buttonedge: ButtonEdge }
|
const edgeTypes = { buttonedge: ButtonEdge }
|
||||||
|
|
||||||
// ==============================|| CANVAS ||============================== //
|
// ==============================|| CANVAS ||============================== //
|
||||||
|
|
@ -276,7 +277,7 @@ const Canvas = () => {
|
||||||
const newNode = {
|
const newNode = {
|
||||||
id: newNodeId,
|
id: newNodeId,
|
||||||
position,
|
position,
|
||||||
type: 'customNode',
|
type: nodeData.type !== 'StickyNote' ? 'customNode' : 'stickyNote',
|
||||||
data: initNode(nodeData, newNodeId)
|
data: initNode(nodeData, newNodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ import { useTheme } from '@mui/material/styles'
|
||||||
|
|
||||||
// project imports
|
// project imports
|
||||||
import MarketplaceCanvasNode from './MarketplaceCanvasNode'
|
import MarketplaceCanvasNode from './MarketplaceCanvasNode'
|
||||||
|
|
||||||
import MarketplaceCanvasHeader from './MarketplaceCanvasHeader'
|
import MarketplaceCanvasHeader from './MarketplaceCanvasHeader'
|
||||||
|
import StickyNote from '../canvas/StickyNote'
|
||||||
|
|
||||||
const nodeTypes = { customNode: MarketplaceCanvasNode }
|
const nodeTypes = { customNode: MarketplaceCanvasNode, stickyNote: StickyNote }
|
||||||
const edgeTypes = { buttonedge: '' }
|
const edgeTypes = { buttonedge: '' }
|
||||||
|
|
||||||
// ==============================|| CANVAS ||============================== //
|
// ==============================|| CANVAS ||============================== //
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue