Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automations/ast impl #1522

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
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
4 changes: 2 additions & 2 deletions src/cloud/components/Automations/EventInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react'
import { JsonTypeDef } from '../../lib/automations/events'
import { BoostType } from '../../lib/automations'

interface EventSelectProps {
name: string
typeDef: JsonTypeDef
typeDef: BoostType
}

const EventInfo = ({ typeDef }: EventSelectProps) => {
Expand Down
24 changes: 15 additions & 9 deletions src/cloud/components/Automations/FilterBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import FormSelect, {
import FormRow from '../../../design/components/molecules/Form/templates/FormRow'
import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem'
import { SerializedPipe } from '../../interfaces/db/automations'
import { JsonTypeDef } from '../../lib/automations/events'
import { BoostType } from '../../lib/automations'
import { flattenType } from '../../lib/automations/types'
import { flattenObj } from '../../lib/utils/object'

interface FilterBuilderProps {
typeDef: JsonTypeDef
typeDef: BoostType
filter: SerializedPipe['filter']
onChange: (filter: SerializedPipe['filter']) => void
}
Expand All @@ -27,15 +28,20 @@ const FilterBuilder = ({ typeDef, filter, onChange }: FilterBuilderProps) => {
string | number | boolean | undefined
>()

const flattenedTypeKeys = useMemo(
() =>
Object.entries(flattenObj(typeDef as any)).map(([key, val]) => ({
const flattenedTypeKeys = useMemo(() => {
const supportedPrimitives = new Set(['number', 'string', 'boolean'])
return Array.from(flattenType(typeDef))
.filter(
([, type]) =>
type.type === 'primitive' && supportedPrimitives.has(type.def)
)
.map(([path, type]) => [path.join('.'), type] as const)
.map(([key, val]) => ({
label: key,
value: key,
type: val,
})),
[typeDef]
)
type: val.def,
}))
}, [typeDef])

const flattenedFilter = useMemo(() => flattenObj(filter), [filter])

Expand Down
49 changes: 31 additions & 18 deletions src/cloud/components/Automations/PipeBuilder.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mdiPlus } from '@mdi/js'
import React, { useMemo } from 'react'
import React, { useCallback, useMemo } from 'react'
import Button from '../../../design/components/atoms/Button'
import Form from '../../../design/components/molecules/Form'
import FormInput from '../../../design/components/molecules/Form/atoms/FormInput'
Expand All @@ -8,19 +8,19 @@ import FormRow from '../../../design/components/molecules/Form/templates/FormRow
import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem'
import styled from '../../../design/lib/styled'
import { SerializedPipe } from '../../interfaces/db/automations'
import { OpNode, StructNode } from '../../lib/automations/ast'
import supportedEvents from '../../lib/automations/events'
import CreateDocActionConfigurator from './actions/CreateDocActionConfigurator'
import UpdateDocActionConfigurator from './actions/UpdateDocActionConfigurator'
import EventInfo from './EventInfo'
import FilterBuilder from './FilterBuilder'

const SUPPORTED_EVENT_NAMES = Object.keys(supportedEvents).map((key) => {
return { label: key, value: key }
})

const SUPPORTED_ACTION_OPTIONS = [
{ value: 'boost.doc.create', label: 'boost.doc.create' },
{ value: 'boost.doc.update', label: 'boost.doc.update' },
{ value: 'boost.docs.create', label: 'boost.docs.create' },
{ value: 'boost.docs.update', label: 'boost.docs.update' },
]

interface PipeBuilderProps {
Expand All @@ -34,11 +34,23 @@ const PipeBuilder = ({ pipe, onChange }: PipeBuilderProps) => {
}, [pipe.event])

const action = useMemo(() => {
if (pipe.configuration.type !== 'operation') {
return SUPPORTED_ACTION_OPTIONS[0]
}

const identifier = pipe.configuration.identifier
return (
SUPPORTED_ACTION_OPTIONS.find(({ value }) => value === pipe.action) ||
SUPPORTED_ACTION_OPTIONS.find(({ value }) => value === identifier) ||
SUPPORTED_ACTION_OPTIONS[0]
)
}, [pipe.action])
}, [pipe.configuration])

const updateConfig = useCallback(
(input: SerializedPipe['configuration']['input']) => {
onChange({ ...pipe, configuration: { ...pipe.configuration, input } })
},
[pipe, onChange]
)

return (
<Container>
Expand All @@ -63,11 +75,7 @@ const PipeBuilder = ({ pipe, onChange }: PipeBuilderProps) => {
</FormRowItem>
</FormRow>
<FormRow>
{currentEvent != null ? (
<EventInfo name={pipe.event} typeDef={currentEvent} />
) : (
<div>Select Event</div>
)}
<div>Select Event</div>
</FormRow>
</div>

Expand Down Expand Up @@ -96,22 +104,27 @@ const PipeBuilder = ({ pipe, onChange }: PipeBuilderProps) => {
<FormSelect
options={SUPPORTED_ACTION_OPTIONS}
value={action}
onChange={({ value }) => onChange({ ...pipe, action: value })}
onChange={({ value }) =>
onChange({
...pipe,
configuration: OpNode(value, StructNode({})),
})
}
/>
</FormRowItem>
</FormRow>
<FormRow>
{action.value === 'boost.doc.create' && (
{action.value === 'boost.docs.create' && (
<CreateDocActionConfigurator
configuration={pipe.configuration}
onChange={(configuration) => onChange({ ...pipe, configuration })}
configuration={pipe.configuration.input}
onChange={updateConfig}
eventType={currentEvent}
/>
)}
{action.value === 'boost.doc.update' && (
{action.value === 'boost.docs.update' && (
<UpdateDocActionConfigurator
configuration={pipe.configuration}
onChange={(configuration) => onChange({ ...pipe, configuration })}
configuration={pipe.configuration.input}
onChange={updateConfig}
eventType={currentEvent}
/>
)}
Expand Down
16 changes: 8 additions & 8 deletions src/cloud/components/Automations/WorkflowBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,17 @@ const Container = styled.div`
}
`

const defaultPipe = {
const defaultPipe: SerializedPipe = {
name: 'New Pipeline',
event: 'github.issues.opened',
action: 'boost.doc.create',
configuration: {
title: '$event.issue.title',
content: '$event.issue.body',
props: {
IssueID: {
type: 'number',
data: '$event.issue.id',
type: 'operation',
identifier: 'boost.docs.create',
input: {
type: 'constructor',
info: {
type: 'struct',
refs: {},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,78 +1,108 @@
import React, { useMemo, useState } from 'react'
import React, { useMemo } from 'react'
import FormSelect from '../../../../design/components/molecules/Form/atoms/FormSelect'
import FormRowItem from '../../../../design/components/molecules/Form/templates/FormRowItem'
import { pickBy } from 'ramda'
import { BoostAST, BoostPrimitives, BoostType } from '../../../lib/automations'
import { LiteralNode, RefNode } from '../../../lib/automations/ast'
import { StdPrimitives } from '../../../lib/automations/types'

const CONFIG_TYPES = [
{ label: 'Event', value: 'event' },
{ label: 'Custom', value: 'custom' },
]

interface ActionConfigurationInputProps {
onChange: (value: any) => void
value: any
onChange: (value: BoostAST | undefined) => void
value: BoostAST
customInput: (
onChange: ActionConfigurationInputProps['onChange'],
value: any
value: Extract<BoostAST, { type: 'literal' }> | null
) => React.ReactNode
eventDataOptions: Record<string, string>
type?: string
eventDataOptions: Record<string, BoostType>
type: BoostPrimitives | StdPrimitives
defaultValue: any
}
const ActionConfigurationInput = ({
value,
eventDataOptions,
onChange,
customInput,
type: dataType,
defaultValue,
}: ActionConfigurationInputProps) => {
const [type, setType] = useState(() => {
if (typeof value === 'string') {
if (value.startsWith('$event')) {
const type = useMemo(() => {
if (value == null) {
return CONFIG_TYPES[1]
}

if (value.type === 'reference') {
if (value.identifier.startsWith('$event')) {
return CONFIG_TYPES[0]
}
if (value.startsWith('$env')) {
if (value.identifier.startsWith('$env')) {
return CONFIG_TYPES[1]
}
}
return CONFIG_TYPES[1]
})
}, [value])

const options = useMemo(() => {
return Object.keys(
pickBy((val) => dataType == null || val === dataType, eventDataOptions)
pickBy(
(val) => val.type === 'primitive' && val.def === dataType,
eventDataOptions
)
).map((key) => ({ label: key, value: key }))
}, [eventDataOptions, dataType])

const normalized = useMemo(() => {
if (typeof value === 'string') {
if (value.startsWith('$event')) {
return value.substr('$event.'.length)
if (value == null) {
return ''
}

if (value.type === 'reference') {
if (value.identifier.startsWith('$event')) {
return value.identifier.substr('$event.'.length)
}

if (value.startsWith('$env')) {
return value.substr('$env.'.length)
if (value.identifier.startsWith('$env')) {
return value.identifier.substr('$env.'.length)
}
}

return typeof value === 'string' || typeof value === 'number'
? value.toString()
: ''
return value.type === 'literal' ? value.value?.toString() || '' : ''
}, [value])

return (
<>
<FormRowItem>
<FormSelect options={CONFIG_TYPES} value={type} onChange={setType} />
<FormSelect
options={CONFIG_TYPES}
value={type}
onChange={(val) => {
if (val.value === 'event') {
onChange(RefNode('$event.'))
} else {
onChange(LiteralNode(dataType, defaultValue))
}
}}
/>
</FormRowItem>
<FormRowItem>
{type.value === 'event' && (
<FormSelect
value={{ label: normalized, value: normalized }}
options={options}
onChange={({ value }) => onChange(`$event.${value}`)}
onChange={({ value }) => onChange(RefNode(`$event.${value}`))}
/>
)}
{type.value === 'custom' && customInput(onChange, value)}
{type.value === 'custom' &&
customInput(
onChange,
value == null || value.type !== 'literal'
? LiteralNode(dataType, defaultValue)
: value
)}
</FormRowItem>
</>
)
Expand Down
Loading