diff --git a/client/src/components/dynamic-groups/condition-builder.tsx b/client/src/components/dynamic-groups/condition-builder.tsx index 4396963..93b51c4 100644 --- a/client/src/components/dynamic-groups/condition-builder.tsx +++ b/client/src/components/dynamic-groups/condition-builder.tsx @@ -383,7 +383,99 @@ const ConditionBuilder: React.FC = ({ {...attributes} > {condition.isGroup ? ( - renderConditionGroup(condition, index, level) +
+
+
+ + + + Condition Group ({condition.logicalOperator}) + +
+ +
+ + + + + + + + + +
+
+ + {condition.id && expandedGroups.has(condition.id) && ( +
+ {condition.id ? ( + (() => { + const childConditions = getConditionsForParent(condition.id); + return childConditions.length === 0 ? ( +
+ No conditions in this group. Add one using the buttons above. +
+ ) : ( + childConditions.map((child, childIndex) => { + const originalIndex = conditions.findIndex(c => c === child); + return child.isGroup + ? + : ; + }) + ); + })() + ) : null} +
+ )} +
) : ( renderConditionContent(condition, index, level, listeners) )} @@ -539,9 +631,11 @@ const ConditionBuilder: React.FC = ({
{conditions.map((condition, index) => ( condition.parentId === null || condition.parentId === undefined ? ( - condition.isGroup ? - renderConditionGroup(condition, index) : - + ) : null ))}
diff --git a/server/storage.ts b/server/storage.ts index 42d0f12..3add990 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -45,6 +45,29 @@ export interface IStorage { getRole(id: number): Promise; getDefaultRole(): Promise; + // Dynamic Group Rules + listDynamicGroupRules(): Promise; + getDynamicGroupRule(id: number): Promise; + createDynamicGroupRule(rule: InsertDynamicGroupRule): Promise; + updateDynamicGroupRule(id: number, rule: Partial): Promise; + deleteDynamicGroupRule(id: number): Promise; + + // Dynamic Group Conditions + listConditionsForRule(ruleId: number): Promise; + createDynamicGroupCondition(condition: InsertDynamicGroupCondition): Promise; + updateDynamicGroupCondition(id: number, condition: Partial): Promise; + deleteDynamicGroupCondition(id: number): Promise; + + // Dynamic Group Rule Connections + linkRuleToConnections(ruleId: number, connectionIds: number[]): Promise; + getConnectionsForRule(ruleId: number): Promise; + + // Schedule Rules + getSchedulesForRule(ruleId: number): Promise; + createScheduleRule(schedule: InsertScheduleRule): Promise; + updateScheduleRule(id: number, schedule: Partial): Promise; + deleteScheduleRule(id: number): Promise; + // API Token management getApiToken(id: number): Promise; getApiTokenByToken(token: string): Promise; @@ -1215,6 +1238,132 @@ export class DatabaseStorage implements IStorage { return { data, metadata }; } + + // Dynamic Group Rules methods + async listDynamicGroupRules(): Promise { + return db.select().from(dynamicGroupRules).orderBy(dynamicGroupRules.name); + } + + async getDynamicGroupRule(id: number): Promise { + const result = await db.select().from(dynamicGroupRules).where(eq(dynamicGroupRules.id, id)); + return result.length > 0 ? result[0] : undefined; + } + + async createDynamicGroupRule(rule: InsertDynamicGroupRule): Promise { + const result = await db.insert(dynamicGroupRules).values({ + ...rule, + createdAt: new Date(), + updatedAt: new Date() + }).returning(); + return result[0]; + } + + async updateDynamicGroupRule(id: number, rule: Partial): Promise { + const result = await db.update(dynamicGroupRules) + .set({ + ...rule, + updatedAt: new Date() + }) + .where(eq(dynamicGroupRules.id, id)) + .returning(); + return result.length > 0 ? result[0] : undefined; + } + + async deleteDynamicGroupRule(id: number): Promise { + const result = await db.delete(dynamicGroupRules) + .where(eq(dynamicGroupRules.id, id)) + .returning({ id: dynamicGroupRules.id }); + return result.length > 0; + } + + // Dynamic Group Conditions methods + async listConditionsForRule(ruleId: number): Promise { + return db.select() + .from(dynamicGroupConditions) + .where(eq(dynamicGroupConditions.ruleId, ruleId)) + .orderBy(dynamicGroupConditions.position); + } + + async createDynamicGroupCondition(condition: InsertDynamicGroupCondition): Promise { + const result = await db.insert(dynamicGroupConditions).values(condition).returning(); + return result[0]; + } + + async updateDynamicGroupCondition(id: number, condition: Partial): Promise { + const result = await db.update(dynamicGroupConditions) + .set(condition) + .where(eq(dynamicGroupConditions.id, id)) + .returning(); + return result.length > 0 ? result[0] : undefined; + } + + async deleteDynamicGroupCondition(id: number): Promise { + const result = await db.delete(dynamicGroupConditions) + .where(eq(dynamicGroupConditions.id, id)) + .returning({ id: dynamicGroupConditions.id }); + return result.length > 0; + } + + // Dynamic Group Rule Connections methods + async linkRuleToConnections(ruleId: number, connectionIds: number[]): Promise { + // First delete existing connections + await db.delete(dynamicGroupRuleConnections) + .where(eq(dynamicGroupRuleConnections.ruleId, ruleId)); + + // Then insert new connections + if (connectionIds.length > 0) { + await db.insert(dynamicGroupRuleConnections) + .values(connectionIds.map(connectionId => ({ + ruleId, + connectionId + }))); + } + } + + async getConnectionsForRule(ruleId: number): Promise { + const connections = await db.select({ connectionId: dynamicGroupRuleConnections.connectionId }) + .from(dynamicGroupRuleConnections) + .where(eq(dynamicGroupRuleConnections.ruleId, ruleId)); + + return connections.map(c => c.connectionId); + } + + // Schedule Rules methods + async getSchedulesForRule(ruleId: number): Promise { + return db.select() + .from(scheduleRules) + .where(eq(scheduleRules.ruleId, ruleId)) + .orderBy(scheduleRules.id); + } + + async createScheduleRule(schedule: InsertScheduleRule): Promise { + const result = await db.insert(scheduleRules) + .values({ + ...schedule, + createdAt: new Date(), + updatedAt: new Date() + }) + .returning(); + return result[0]; + } + + async updateScheduleRule(id: number, schedule: Partial): Promise { + const result = await db.update(scheduleRules) + .set({ + ...schedule, + updatedAt: new Date() + }) + .where(eq(scheduleRules.id, id)) + .returning(); + return result.length > 0 ? result[0] : undefined; + } + + async deleteScheduleRule(id: number): Promise { + const result = await db.delete(scheduleRules) + .where(eq(scheduleRules.id, id)) + .returning({ id: scheduleRules.id }); + return result.length > 0; + } } export const storage = new DatabaseStorage();