@adatechnology/conversations-ui 0.1.0-rc.29 → 0.1.0-rc.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flows/index.d.ts +104 -8
- package/dist/flows/index.js +188 -157
- package/package.json +1 -1
- package/src/flows/FlowsWorkspace.tsx +94 -312
- package/src/flows/flowCanvasModel.test.ts +293 -0
- package/src/flows/flowCanvasModel.ts +342 -0
- package/src/flows/index.ts +21 -0
package/dist/flows/index.d.ts
CHANGED
|
@@ -329,13 +329,109 @@ interface FlowWhatsAppPreviewProps {
|
|
|
329
329
|
}
|
|
330
330
|
declare function FlowWhatsAppPreview({ body, options, labels, }: FlowWhatsAppPreviewProps): react.JSX.Element;
|
|
331
331
|
|
|
332
|
-
/**
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Derivações puras do canvas do editor: posições, arestas, contagem de conversas vivas e o nó que
|
|
334
|
+
* nasce de cada item da paleta.
|
|
335
|
+
*
|
|
336
|
+
* Viviam dentro do componente, e é ali que estava o risco. Uma aresta com destino errado não pinta
|
|
337
|
+
* errado — ela leva a conversa do cliente para o lugar errado, e o sintoma aparece longe de quem
|
|
338
|
+
* editou. Um card que o layout joga para fora da área visível se lê como "apaguei sem querer".
|
|
339
|
+
*
|
|
340
|
+
* A topologia sai daqui em forma neutra (`FlowEdgeSpec`) e o estilo fica no componente: o teste cobra
|
|
341
|
+
* o que importa e roda sem navegador nem `@xyflow/react`. Cor de traço ninguém quebra sem ver.
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
type FlowNodePosition = {
|
|
345
|
+
readonly x: number;
|
|
346
|
+
readonly y: number;
|
|
347
|
+
};
|
|
348
|
+
/** Onde cada conversa viva está parada agora. */
|
|
349
|
+
type FlowLivePosition = {
|
|
350
|
+
readonly currentState: string;
|
|
351
|
+
readonly flow: string | null;
|
|
352
|
+
readonly nodeId: string | null;
|
|
353
|
+
readonly menuNodeId: string | null;
|
|
354
|
+
};
|
|
355
|
+
/**
|
|
356
|
+
* Pseudo-nó que representa um fluxo alvo ainda não mesclado no canvas.
|
|
357
|
+
*
|
|
358
|
+
* Um portal por (nó de origem, fluxo alvo): duas opções do mesmo nó indo para o mesmo fluxo
|
|
359
|
+
* compartilham o portal, senão o card ficaria cercado de caixas idênticas.
|
|
360
|
+
*/
|
|
361
|
+
declare function portalNodeId(sourceNodeId: string, target: string): string;
|
|
362
|
+
declare function chainFrameNodeId(actionNodeId: string): string;
|
|
363
|
+
declare const GROUP_HEADER_NODE_ID = "__group_header__";
|
|
364
|
+
/**
|
|
365
|
+
* Quantas conversas estão paradas em cada nó de um fluxo.
|
|
366
|
+
*
|
|
367
|
+
* A raiz é caso à parte: o servidor guarda o passo do menu em `menuNodeId`, num campo próprio, e uma
|
|
368
|
+
* conversa no menu não carrega `flow`. Ler `nodeId` ali daria contagem zero na tela mais visitada do
|
|
369
|
+
* editor.
|
|
370
|
+
*/
|
|
371
|
+
declare function countLiveByNode(params: {
|
|
372
|
+
readonly flowKey: string;
|
|
373
|
+
readonly rootFlowKey: string;
|
|
374
|
+
readonly positions: readonly FlowLivePosition[] | undefined;
|
|
375
|
+
}): Record<string, number>;
|
|
376
|
+
/**
|
|
377
|
+
* Um layout só para TODOS os nós de TODOS os fluxos abertos juntos.
|
|
378
|
+
*
|
|
379
|
+
* Posicionar cada fluxo à parte e deslocar não resolve: nada impede dois fluxos de ocuparem o mesmo
|
|
380
|
+
* espaço, e a altura real de cada card é ignorada. Aqui o ranqueamento por BFS roda sobre o grafo
|
|
381
|
+
* mesclado inteiro, com os saltos `flow:<key>` já resolvidos para o nó inicial do alvo.
|
|
382
|
+
*/
|
|
383
|
+
declare function computeMergedLayout(params: {
|
|
384
|
+
readonly openKeys: readonly string[];
|
|
385
|
+
readonly graphs: Readonly<Record<string, FlowGraphData>>;
|
|
386
|
+
readonly primaryFlowKey: string;
|
|
387
|
+
}): Map<string, FlowNodePosition>;
|
|
388
|
+
/** Papel visual da aresta. O componente traduz em traço, cor e seta; o modelo só decide qual é. */
|
|
389
|
+
type FlowEdgeKind = 'linear' | 'branch' | 'fallback';
|
|
390
|
+
type FlowEdgeSpec = {
|
|
391
|
+
readonly id: string;
|
|
392
|
+
readonly source: string;
|
|
393
|
+
readonly target: string;
|
|
394
|
+
readonly sourceHandle?: string;
|
|
395
|
+
readonly kind: FlowEdgeKind;
|
|
396
|
+
/** Salto entre fluxos — tracejado, esteja o alvo mesclado ou num portal. */
|
|
397
|
+
readonly crossFlow: boolean;
|
|
398
|
+
readonly live: boolean;
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Arestas de todos os fluxos abertos.
|
|
402
|
+
*
|
|
403
|
+
* A regra que não é óbvia: um salto `flow:<key>` vira ligação real até o nó inicial do alvo quando
|
|
404
|
+
* esse fluxo já está no canvas, e só cai no portal quando não está. Sem isso, abrir dois fluxos
|
|
405
|
+
* ligados mostrava uma caixa de portal entre dois cards que já estavam ali do lado.
|
|
406
|
+
*/
|
|
407
|
+
declare function buildFlowEdges(params: {
|
|
408
|
+
readonly openKeys: readonly string[];
|
|
409
|
+
readonly graphs: Readonly<Record<string, FlowGraphData>>;
|
|
410
|
+
readonly rootFlowKey: string;
|
|
411
|
+
readonly livePositions?: readonly FlowLivePosition[] | undefined;
|
|
412
|
+
}): FlowEdgeSpec[];
|
|
413
|
+
/** Nós de um fluxo que ninguém aponta — o card ganha contorno tracejado para cobrar a ligação. */
|
|
414
|
+
declare function detachedNodeIds(graph: FlowGraphData): Set<string>;
|
|
415
|
+
/** Retângulo que envolve uma cadeia de coleta, em coordenadas do canvas. */
|
|
416
|
+
declare function chainFrameBounds(params: {
|
|
417
|
+
readonly nodeIds: readonly string[];
|
|
418
|
+
readonly graph: FlowGraphData;
|
|
419
|
+
readonly positionOf: (nodeId: string) => FlowNodePosition;
|
|
420
|
+
readonly padding: number;
|
|
421
|
+
}): {
|
|
422
|
+
x: number;
|
|
423
|
+
y: number;
|
|
424
|
+
width: number;
|
|
425
|
+
height: number;
|
|
426
|
+
};
|
|
427
|
+
/**
|
|
428
|
+
* O nó que nasce de cada item da paleta.
|
|
429
|
+
*
|
|
430
|
+
* `contextKey` igual ao id porque é o que o motor usa para guardar a resposta: deixá-lo vazio faria a
|
|
431
|
+
* pergunta ser feita e a resposta descartada, sem erro em lugar nenhum.
|
|
432
|
+
*/
|
|
433
|
+
declare function newNodeFromSpec(spec: NewNodeSpec, existingIds: ReadonlySet<string>): FlowNodeData;
|
|
434
|
+
|
|
339
435
|
interface CreateFlowInput {
|
|
340
436
|
key: string;
|
|
341
437
|
label: string;
|
|
@@ -454,4 +550,4 @@ declare function applyConnection(node: FlowNodeData, resolved: ResolvedConnectio
|
|
|
454
550
|
*/
|
|
455
551
|
declare function isGraphDirty(working: FlowGraphData | undefined, published: FlowGraphData | undefined): boolean;
|
|
456
552
|
|
|
457
|
-
export { BUILT_IN_ACTION_KINDS, CONDITION_OPERATORS, CROSS_FLOW_PREFIX, type CollectionChain, type ConnectionRequest, type CreateFlowInput, DEFAULT_FLOW_EDITOR_LABELS, type FlowEditorLabels, FlowGroupFrame, type FlowGroupFrameData, FlowGroupHeader, type FlowGroupHeaderData, type FlowLivePosition, FlowMapCanvas, type FlowMapCanvasProps, FlowMapNode, type FlowMapNodeData, FlowNodeCard, type FlowNodeCardData, FlowNodePanel, type FlowNodePanelProps, FlowPalette, type FlowPaletteActionOption, type FlowPaletteProps, FlowPortalNode, type FlowPortalNodeData, type FlowValidationLabels, FlowWhatsAppPreview, type FlowWhatsAppPreviewProps, FlowsWorkspace, type FlowsWorkspaceApi, type FlowsWorkspaceProps, type GraphIssue, NODE_CARD_WIDTH, type NewNodeSpec, type ResolvedConnection, WHATSAPP_LIMITS, applyConnection, computeAutoLayout, computeFlowMapLayout, crossFlowKey, crossFlowTargetsOf, estimateNodeHeight, findCollectionChains, flowGroupFrameNodeTypes, flowGroupHeaderNodeTypes, flowMapNodeTypes, flowNodeTypes, flowPortalNodeTypes, isCrossFlowTarget, isGraphDirty, mergeFlowEditorLabels, mergedFlowKeysFrom, namespaceNodeId, nodeLabel, parseNamespacedId, removeNodeAndCleanRefs, rendersAsButtons, resolveConnection, slugifyNodeId, targetsOf, validateGraph };
|
|
553
|
+
export { BUILT_IN_ACTION_KINDS, CONDITION_OPERATORS, CROSS_FLOW_PREFIX, type CollectionChain, type ConnectionRequest, type CreateFlowInput, DEFAULT_FLOW_EDITOR_LABELS, type FlowEdgeKind, type FlowEdgeSpec, type FlowEditorLabels, FlowGroupFrame, type FlowGroupFrameData, FlowGroupHeader, type FlowGroupHeaderData, type FlowLivePosition, FlowMapCanvas, type FlowMapCanvasProps, FlowMapNode, type FlowMapNodeData, FlowNodeCard, type FlowNodeCardData, FlowNodePanel, type FlowNodePanelProps, type FlowNodePosition, FlowPalette, type FlowPaletteActionOption, type FlowPaletteProps, FlowPortalNode, type FlowPortalNodeData, type FlowValidationLabels, FlowWhatsAppPreview, type FlowWhatsAppPreviewProps, FlowsWorkspace, type FlowsWorkspaceApi, type FlowsWorkspaceProps, GROUP_HEADER_NODE_ID, type GraphIssue, NODE_CARD_WIDTH, type NewNodeSpec, type ResolvedConnection, WHATSAPP_LIMITS, applyConnection, buildFlowEdges, chainFrameBounds, chainFrameNodeId, computeAutoLayout, computeFlowMapLayout, computeMergedLayout, countLiveByNode, crossFlowKey, crossFlowTargetsOf, detachedNodeIds, estimateNodeHeight, findCollectionChains, flowGroupFrameNodeTypes, flowGroupHeaderNodeTypes, flowMapNodeTypes, flowNodeTypes, flowPortalNodeTypes, isCrossFlowTarget, isGraphDirty, mergeFlowEditorLabels, mergedFlowKeysFrom, namespaceNodeId, newNodeFromSpec, nodeLabel, parseNamespacedId, portalNodeId, removeNodeAndCleanRefs, rendersAsButtons, resolveConnection, slugifyNodeId, targetsOf, validateGraph };
|