+
+ {triggerObjectType}
+
+ {/* {conditions.map(({ condition, logicalOperator }, index) => { */}
+ {conditions.map(({ condition, logicalOperator }, index) => {
+ const isFirstCondition = index === 0;
+ const isLastCondition = index === conditions.length - 1;
+
+ return (
+
+ {/* Row 1 */}
+
+
+ {/* Row 2 */}
+
+
+
+
+
+
+
+ );
+ })}
+
+ );
+}
+
+function getNestedConditions(triggerCondition: AstNode) {
+ switch (triggerCondition.name) {
+ case 'And': {
+ const andOperands = triggerCondition.children ?? [];
+ return andOperands.map(
+ (operator, index) =>
+ ({
+ logicalOperator: index === 0 ? 'where' : 'and',
+ condition: operator,
+ } as const)
+ );
+ }
+ case 'Or': {
+ const orOperands = triggerCondition.children ?? [];
+ return orOperands.map(
+ (operator, index) =>
+ ({
+ logicalOperator: index === 0 ? 'where' : 'or',
+ condition: operator,
+ } as const)
+ );
+ }
+ default:
+ return [
+ {
+ logicalOperator: 'where',
+ condition: triggerCondition,
+ } as const,
+ ];
+ }
+}
diff --git a/packages/app-builder/src/models/ast-node.ts b/packages/app-builder/src/models/ast-node.ts
index 0d03dd394..b673a3d58 100644
--- a/packages/app-builder/src/models/ast-node.ts
+++ b/packages/app-builder/src/models/ast-node.ts
@@ -1,14 +1,6 @@
-import { type NodeDto, type ScenarioIterationRule } from '@marble-api';
-import { assertNever } from '@typescript-utils';
+import { type NodeDto } from '@marble-api';
import * as R from 'remeda';
-import {
- isConstantOperator,
- isDbFieldOperator,
- isMathOperator,
- isPayloadFieldOperator,
-} from './operators';
-
export interface AstNode {
name: string | null;
constant: ConstantType | null;
@@ -39,77 +31,6 @@ export function NewAstNode({
};
}
-export function adaptFormulaDto(
- formula: ScenarioIterationRule['formula']
-): AstNode {
- if (isConstantOperator(formula)) {
- return NewAstNode({
- name: formula.type,
- constant: formula.staticData.value,
- });
- }
- if (isDbFieldOperator(formula)) {
- return NewAstNode({
- name: formula.type,
- namedChildren: {
- triggerTableName: {
- name: 'STRING_CONSTANT',
- constant: formula.staticData.triggerTableName,
- children: [],
- namedChildren: {},
- },
- path: {
- name: 'STRING_LIST_CONSTANT',
- constant: formula.staticData.path,
- children: [],
- namedChildren: {},
- },
- fieldName: {
- name: 'STRING_CONSTANT',
- constant: formula.staticData.fieldName,
- children: [],
- namedChildren: {},
- },
- },
- });
- }
- if (isPayloadFieldOperator(formula)) {
- return NewAstNode({
- name: formula.type,
- namedChildren: {
- fieldName: {
- name: 'STRING_CONSTANT',
- constant: formula.staticData.fieldName,
- children: [],
- namedChildren: {},
- },
- },
- });
- }
- if (isMathOperator(formula) || formula.type === 'NOT') {
- return NewAstNode({
- name: formula.type,
- children: formula.children.map(adaptFormulaDto),
- });
- }
- if (formula.type === 'ROUND_FLOAT') {
- return NewAstNode({
- name: formula.type,
- children: formula.children.map(adaptFormulaDto),
- namedChildren: {
- level: {
- name: 'FLOAT_CONSTANT',
- constant: formula.staticData.level,
- children: [],
- namedChildren: {},
- },
- },
- });
- }
-
- assertNever('unknwon Operator:', formula);
-}
-
export function adaptNodeDto(nodeDto: NodeDto): AstNode {
return NewAstNode({
name: nodeDto.name,
diff --git a/packages/app-builder/src/models/ast-view-model.ts b/packages/app-builder/src/models/ast-view-model.ts
index 62e33081b..62deebb78 100644
--- a/packages/app-builder/src/models/ast-view-model.ts
+++ b/packages/app-builder/src/models/ast-view-model.ts
@@ -8,43 +8,34 @@ import {
import {
type EditorIdentifier,
type EditorIdentifiersByType,
+ getIdentifiersFromAstNode,
} from './identifier';
export interface AstViewModel {
label: string;
+ tooltip: string;
astNode: AstNode;
}
export function adaptAstNodeToViewModel(astNode: AstNode): AstViewModel {
return {
label: getAstNodeDisplayName(astNode),
+ tooltip: '',
astNode,
};
}
-// This implementation might be problematic in the future, we might need to standartise each node with something like a hash function
export function adaptAstNodeToViewModelFromIdentifier(
astNode: AstNode,
identifiers: EditorIdentifiersByType
): AstViewModel {
- const astString = JSON.stringify(astNode);
- for (const identifier of identifiers.databaseAccessors) {
- if (astString === JSON.stringify(identifier.node)) {
- return adaptEditorIdentifierToViewModel(identifier);
- }
- }
- for (const identifier of identifiers.customListAccessors) {
- if (astString === JSON.stringify(identifier.node)) {
- return adaptEditorIdentifierToViewModel(identifier);
- }
- }
- for (const identifier of identifiers.payloadAccessors) {
- if (astString === JSON.stringify(identifier.node)) {
- return adaptEditorIdentifierToViewModel(identifier);
- }
+ const identifier = getIdentifiersFromAstNode(astNode, identifiers);
+ if (identifier) {
+ return adaptEditorIdentifierToViewModel(identifier);
}
return {
label: getAstNodeDisplayName(astNode),
+ tooltip: '',
astNode,
};
}
@@ -54,6 +45,7 @@ export function adaptEditorIdentifierToViewModel(
): AstViewModel {
return {
label: identifier.name,
+ tooltip: identifier.description,
astNode: identifier.node,
};
}
diff --git a/packages/app-builder/src/models/identifier.ts b/packages/app-builder/src/models/identifier.ts
index af37bda27..410fe709b 100644
--- a/packages/app-builder/src/models/identifier.ts
+++ b/packages/app-builder/src/models/identifier.ts
@@ -34,3 +34,27 @@ export function adaptIdentifierDto(identifier: Identifier): EditorIdentifier {
node: adaptNodeDto(identifier.node),
});
}
+
+// This implementation might be problematic in the future, we might need to standartise each node with something like a hash function
+export function getIdentifiersFromAstNode(
+ node: AstNode,
+ identifiers: EditorIdentifiersByType
+) {
+ const astString = JSON.stringify(node);
+ for (const identifier of identifiers.databaseAccessors) {
+ if (astString === JSON.stringify(identifier.node)) {
+ return identifier;
+ }
+ }
+ for (const identifier of identifiers.customListAccessors) {
+ if (astString === JSON.stringify(identifier.node)) {
+ return identifier;
+ }
+ }
+ for (const identifier of identifiers.payloadAccessors) {
+ if (astString === JSON.stringify(identifier.node)) {
+ return identifier;
+ }
+ }
+ return null;
+}
diff --git a/packages/app-builder/src/models/operators.ts b/packages/app-builder/src/models/operators.ts
index f1e9ff8a0..b85f567c7 100644
--- a/packages/app-builder/src/models/operators.ts
+++ b/packages/app-builder/src/models/operators.ts
@@ -1,30 +1,8 @@
+import { type AstNode } from './ast-node';
import {
- type AndOperator,
- type BoolConstantOperator,
- type DbFieldBoolOperator,
- type DbFieldFloatOperator,
- type DbFieldStringOperator,
- type DivideFloatOperator,
- type EqualBoolOperator,
- type EqualFloatOperator,
- type EqualStringOperator,
- type FloatConstantOperator,
- type GreaterFloatOperator,
- type GreaterOrEqualFloatOperator,
- type LesserFloatOperator,
- type LesserOrEqualFloatOperator,
- type Operator,
- type OrOperator,
- type PayloadFieldBoolOperator,
- type PayloadFieldFloatOperator,
- type PayloadFieldStringOperator,
- type ProductFloatOperator,
- type StringConstantOperator,
- type StringIsInListOperator,
- type StringListConstantOperator,
- type SubstractFloatOperator,
- type SumFloatOperator,
-} from '@marble-api';
+ type EditorIdentifiersByType,
+ getIdentifiersFromAstNode,
+} from './identifier';
/**
* This file is heavilly based on the actual Operator DTOs from the API.
@@ -33,104 +11,40 @@ import {
* It may be removed once the API is updated to the new AST model
*/
-export type DbFieldOperator =
- | DbFieldBoolOperator
- | DbFieldFloatOperator
- | DbFieldStringOperator;
-
-export function isDbFieldOperator(
- operator: Operator
-): operator is DbFieldOperator {
- switch (operator.type) {
- case 'DB_FIELD_BOOL':
- case 'DB_FIELD_FLOAT':
- case 'DB_FIELD_STRING':
- return true;
- default:
- return false;
+export function isConstantNode(node: AstNode) {
+ if (node.name === null) {
+ return true;
}
+ return false;
}
-export type PayloadFieldOperator =
- | PayloadFieldBoolOperator
- | PayloadFieldStringOperator
- | PayloadFieldFloatOperator;
-
-export function isPayloadFieldOperator(
- operator: Operator
-): operator is PayloadFieldOperator {
- switch (operator.type) {
- case 'PAYLOAD_FIELD_BOOL':
- case 'PAYLOAD_FIELD_FLOAT':
- case 'PAYLOAD_FIELD_STRING':
+export function isMathAst(node: AstNode) {
+ switch (node.name) {
+ case 'And':
+ case 'Or':
+ case '=':
+ case '+':
+ case '/':
+ case '-':
+ case '*':
+ case 'IsInList':
+ case '>':
+ case '<':
return true;
default:
return false;
}
}
-export type DataFieldOperator = DbFieldOperator | PayloadFieldOperator;
-
-export function isDataFieldOperator(
- operator: Operator
-): operator is DataFieldOperator {
- return isDbFieldOperator(operator) || isPayloadFieldOperator(operator);
-}
-
-export type ConstantOperator =
- | BoolConstantOperator
- | FloatConstantOperator
- | StringConstantOperator
- | StringListConstantOperator;
-
-export function isConstantOperator(
- operator: Operator
-): operator is ConstantOperator {
- switch (operator.type) {
- case 'BOOL_CONSTANT':
- case 'FLOAT_CONSTANT':
- case 'STRING_CONSTANT':
- case 'STRING_LIST_CONSTANT':
- return true;
- default:
- return false;
- }
+export function isPayload(node: AstNode) {
+ if (node.name === 'Payload') return true;
+ return false;
}
-export type MathOperator =
- | AndOperator
- | OrOperator
- | EqualBoolOperator
- | EqualFloatOperator
- | EqualStringOperator
- | SumFloatOperator
- | DivideFloatOperator
- | SubstractFloatOperator
- | ProductFloatOperator
- | GreaterFloatOperator
- | GreaterOrEqualFloatOperator
- | LesserFloatOperator
- | LesserOrEqualFloatOperator
- | StringIsInListOperator;
-
-export function isMathOperator(operator: Operator): operator is MathOperator {
- switch (operator.type) {
- case 'AND':
- case 'OR':
- case 'EQUAL_BOOL':
- case 'EQUAL_FLOAT':
- case 'EQUAL_STRING':
- case 'SUM_FLOAT':
- case 'DIVIDE_FLOAT':
- case 'SUBTRACT_FLOAT':
- case 'PRODUCT_FLOAT':
- case 'STRING_IS_IN_LIST':
- case 'GREATER_FLOAT':
- case 'GREATER_OR_EQUAL_FLOAT':
- case 'LESSER_FLOAT':
- case 'LESSER_OR_EQUAL_FLOAT':
- return true;
- default:
- return false;
- }
+export function isIdentifier(
+ node: AstNode,
+ identifiers: EditorIdentifiersByType
+) {
+ if (getIdentifiersFromAstNode(node, identifiers)) return true;
+ return false;
}
diff --git a/packages/app-builder/src/repositories/ScenarioRepository.ts b/packages/app-builder/src/repositories/ScenarioRepository.ts
index 66612ac11..6bebd088e 100644
--- a/packages/app-builder/src/repositories/ScenarioRepository.ts
+++ b/packages/app-builder/src/repositories/ScenarioRepository.ts
@@ -34,14 +34,13 @@ export function wrapInOrAndGroups(astNode?: AstNode): AstNode {
export function getScenarioRepository() {
return (marbleApiClient: MarbleApi) => ({
getScenarioIterationRule: async ({ ruleId }: { ruleId: string }) => {
- const { formula_ast_expression, ...rule } =
- await marbleApiClient.getScenarioIterationRule(ruleId);
+ const rule = await marbleApiClient.getScenarioIterationRule(ruleId);
- if (!formula_ast_expression) {
+ if (!rule.formula_ast_expression) {
return { ...rule, astNode: wrapInOrAndGroups() };
}
- const astNode = adaptNodeDto(formula_ast_expression);
+ const astNode = adaptNodeDto(rule.formula_ast_expression);
const orAndGroupAstNode = isOrAndGroup(astNode)
? astNode
diff --git a/packages/app-builder/src/routes/__builder/scenarios/$scenarioId/i/$iterationId/edit/trigger.tsx b/packages/app-builder/src/routes/__builder/scenarios/$scenarioId/i/$iterationId/edit/trigger.tsx
index 73f61bbc4..4c5c798b4 100644
--- a/packages/app-builder/src/routes/__builder/scenarios/$scenarioId/i/$iterationId/edit/trigger.tsx
+++ b/packages/app-builder/src/routes/__builder/scenarios/$scenarioId/i/$iterationId/edit/trigger.tsx
@@ -1,15 +1,9 @@
import { Callout, Paper } from '@app-builder/components';
-import { Formula } from '@app-builder/components/Scenario/Formula';
-import { LogicalOperatorLabel } from '@app-builder/components/Scenario/LogicalOperator';
-import { ScenarioBox } from '@app-builder/components/Scenario/ScenarioBox';
-import { type Operator } from '@marble-api';
-import clsx from 'clsx';
+import { TriggerCondition } from '@app-builder/components/Scenario/Trigger/Trigger';
import { type Namespace } from 'i18next';
-import { Fragment } from 'react';
import { toast } from 'react-hot-toast';
import { Trans, useTranslation } from 'react-i18next';
-import { useCurrentScenario } from '../../../../$scenarioId';
import { useCurrentScenarioIteration } from '../../$iterationId';
export const handle = {
@@ -19,12 +13,7 @@ export const handle = {
export default function Trigger() {
const { t } = useTranslation(handle.i18n);
- const {
- scenarioId,
- body: { triggerCondition },
- } = useCurrentScenarioIteration();
-
- const { triggerObjectType } = useCurrentScenario();
+ const { scenarioId } = useCurrentScenarioIteration();
return (