@lv-x-software-house/x_view 1.2.6 → 1.2.7-dev.1

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/index.mjs CHANGED
@@ -15852,7 +15852,11 @@ function XViewScene({
15852
15852
  };
15853
15853
  const tweenToTarget = useCallback7(
15854
15854
  (target, zoomFactor = 1, forcedDirection = null) => {
15855
- const { camera: sceneCamera, controls: sceneControls, tweenGroup } = stateRef.current;
15855
+ const {
15856
+ camera: sceneCamera,
15857
+ controls: sceneControls,
15858
+ tweenGroup
15859
+ } = stateRef.current;
15856
15860
  if (!sceneCamera || !sceneControls || !tweenGroup) return;
15857
15861
  const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
15858
15862
  const controlsTween = new Tween2(sceneControls.target).to(targetPos, 1500).easing(Easing2.Cubic.Out);
@@ -16409,341 +16413,372 @@ function XViewScene({
16409
16413
  },
16410
16414
  []
16411
16415
  );
16412
- const handleActivateReshapeLens = useCallback7(({ type, columns, centerNodeId }) => {
16413
- const { nodeObjects, tweenGroup, camera, controls } = stateRef.current;
16414
- if (!nodeObjects || !tweenGroup || !camera || !controls) return;
16415
- const activeNodeIds = Object.keys(nodeObjects);
16416
- if (activeNodeIds.length === 0) return;
16417
- let sumX = 0;
16418
- let sumY = 0;
16419
- let nodeCount = 0;
16420
- activeNodeIds.forEach((id) => {
16421
- const mesh = nodeObjects[id];
16422
- if (mesh && mesh.material) {
16423
- const opacityTween = new Tween2(mesh.material).to({ opacity: 1 }, 1200).easing(Easing2.Cubic.Out);
16424
- tweenGroup.add(opacityTween);
16425
- opacityTween.start();
16426
- }
16427
- if (mesh && mesh.userData && mesh.userData.labelObject) {
16428
- mesh.userData.labelObject.visible = true;
16429
- }
16430
- });
16431
- if (type === "Column") {
16432
- const colSpacing = 80;
16433
- const rowSpacing = 80;
16434
- const numCols = columns || 4;
16435
- activeNodeIds.forEach((id, index) => {
16436
- const mesh = nodeObjects[id];
16437
- const col = index % numCols;
16438
- const row = Math.floor(index / numCols);
16439
- const targetX = (col - (numCols - 1) / 2) * colSpacing;
16440
- const targetY = -(row * rowSpacing) + 50;
16441
- const posTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16442
- tweenGroup.add(posTween);
16443
- posTween.start();
16444
- if (mesh.userData.labelObject) {
16445
- const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16446
- const lblTween = new Tween2(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16447
- tweenGroup.add(lblTween);
16448
- lblTween.start();
16449
- }
16450
- sumX += targetX;
16451
- sumY += targetY;
16452
- nodeCount++;
16453
- });
16454
- } else if (type === "Circle") {
16455
- const total = activeNodeIds.length;
16456
- const radius = Math.max(80, total * 8);
16457
- activeNodeIds.forEach((id, index) => {
16416
+ const handleActivateReshapeLens = useCallback7(
16417
+ ({ type, columns, centerNodeId }) => {
16418
+ const { nodeObjects, tweenGroup, camera, controls } = stateRef.current;
16419
+ if (!nodeObjects || !tweenGroup || !camera || !controls) return;
16420
+ const activeNodeIds = Object.keys(nodeObjects);
16421
+ if (activeNodeIds.length === 0) return;
16422
+ let sumX = 0;
16423
+ let sumY = 0;
16424
+ let nodeCount = 0;
16425
+ activeNodeIds.forEach((id) => {
16458
16426
  const mesh = nodeObjects[id];
16459
- const angle = index / total * Math.PI * 2;
16460
- const targetX = Math.cos(angle) * radius;
16461
- const targetY = Math.sin(angle) * radius;
16462
- const posTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16463
- tweenGroup.add(posTween);
16464
- posTween.start();
16465
- if (mesh.userData.labelObject) {
16466
- const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16467
- const lblTween = new Tween2(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16468
- tweenGroup.add(lblTween);
16469
- lblTween.start();
16470
- }
16471
- sumX += targetX;
16472
- sumY += targetY;
16473
- nodeCount++;
16474
- });
16475
- } else if (type === "Star") {
16476
- const centerMesh = centerNodeId ? nodeObjects[String(centerNodeId)] : null;
16477
- const orbitingNodeIds = activeNodeIds.filter((id) => id !== String(centerNodeId));
16478
- const totalOrbiting = orbitingNodeIds.length;
16479
- const radius = Math.max(80, totalOrbiting * 10);
16480
- if (centerMesh) {
16481
- const posTween = new Tween2(centerMesh.position).to({ x: 0, y: 0, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16482
- tweenGroup.add(posTween);
16483
- posTween.start();
16484
- if (centerMesh.userData.labelObject) {
16485
- const labelTarget = new THREE3.Vector3(0, 0, 0).add(centerMesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16486
- const lblTween = new Tween2(centerMesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16487
- tweenGroup.add(lblTween);
16488
- lblTween.start();
16427
+ if (mesh && mesh.material) {
16428
+ const opacityTween = new Tween2(mesh.material).to({ opacity: 1 }, 1200).easing(Easing2.Cubic.Out);
16429
+ tweenGroup.add(opacityTween);
16430
+ opacityTween.start();
16431
+ }
16432
+ if (mesh && mesh.userData && mesh.userData.labelObject) {
16433
+ mesh.userData.labelObject.visible = true;
16489
16434
  }
16490
- sumX += 0;
16491
- sumY += 0;
16492
- nodeCount++;
16493
- }
16494
- orbitingNodeIds.forEach((id, index) => {
16495
- const mesh = nodeObjects[id];
16496
- const angle = totalOrbiting > 0 ? index / totalOrbiting * Math.PI * 2 : 0;
16497
- const targetX = Math.cos(angle) * radius;
16498
- const targetY = Math.sin(angle) * radius;
16499
- const posTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16500
- tweenGroup.add(posTween);
16501
- posTween.start();
16502
- if (mesh.userData.labelObject) {
16503
- const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16504
- const lblTween = new Tween2(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16505
- tweenGroup.add(lblTween);
16506
- lblTween.start();
16507
- }
16508
- sumX += targetX;
16509
- sumY += targetY;
16510
- nodeCount++;
16511
16435
  });
16512
- }
16513
- if (nodeCount > 0) {
16514
- const centerX = sumX / nodeCount;
16515
- const centerY = sumY / nodeCount;
16516
- const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16517
- const targetTween = new Tween2(controls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(Easing2.Cubic.InOut);
16518
- tweenGroup.add(targetTween);
16519
- targetTween.start();
16520
- let zoomZ = 140;
16521
16436
  if (type === "Column") {
16522
- const numRows = Math.ceil(nodeCount / (columns || 4));
16523
- zoomZ = Math.max(140, numRows * 50);
16524
- } else if (type === "Circle" || type === "Star") {
16525
- const radius = Math.max(80, nodeCount * 8);
16526
- zoomZ = radius * 2.5;
16527
- }
16528
- const camTween = new Tween2(camera.position).to({ x: targetFocus.x, y: targetFocus.y, z: zoomZ }, 1500).easing(Easing2.Cubic.InOut);
16529
- tweenGroup.add(camTween);
16530
- camTween.start();
16531
- }
16532
- }, []);
16533
- const handleActivateQuestLens = useCallback7(({ assigneeId, status: status2, milestoneId }) => {
16534
- var _a2;
16535
- const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
16536
- if (!nodeObjects || !tweenGroup || !graphGroup) return;
16537
- const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
16538
- const filteredQuests = allQuests.filter((q) => {
16539
- const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
16540
- const matchStatus = !status2 ? q.status !== "Done" : String(q.status) === String(status2);
16541
- const matchMilestone = !milestoneId || q.milestone_ids && q.milestone_ids.includes(milestoneId);
16542
- return matchAssignee && matchStatus && matchMilestone;
16543
- });
16544
- if (filteredQuests.length === 0) {
16545
- console.warn("Nenhuma quest encontrada para os filtros selecionados.");
16546
- return;
16547
- }
16548
- const questsByStatus = {
16549
- Backlog: [],
16550
- "In Progress": [],
16551
- Review: [],
16552
- Done: []
16553
- };
16554
- filteredQuests.forEach((q) => {
16555
- if (questsByStatus[q.status]) {
16556
- questsByStatus[q.status].push(q);
16437
+ const colSpacing = 80;
16438
+ const rowSpacing = 80;
16439
+ const numCols = columns || 4;
16440
+ activeNodeIds.forEach((id, index) => {
16441
+ const mesh = nodeObjects[id];
16442
+ const col = index % numCols;
16443
+ const row = Math.floor(index / numCols);
16444
+ const targetX = (col - (numCols - 1) / 2) * colSpacing;
16445
+ const targetY = -(row * rowSpacing) + 50;
16446
+ const posTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16447
+ tweenGroup.add(posTween);
16448
+ posTween.start();
16449
+ if (mesh.userData.labelObject) {
16450
+ const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(
16451
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16452
+ );
16453
+ const lblTween = new Tween2(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16454
+ tweenGroup.add(lblTween);
16455
+ lblTween.start();
16456
+ }
16457
+ sumX += targetX;
16458
+ sumY += targetY;
16459
+ nodeCount++;
16460
+ });
16461
+ } else if (type === "Circle") {
16462
+ const total = activeNodeIds.length;
16463
+ const radius = Math.max(80, total * 8);
16464
+ activeNodeIds.forEach((id, index) => {
16465
+ const mesh = nodeObjects[id];
16466
+ const angle = index / total * Math.PI * 2;
16467
+ const targetX = Math.cos(angle) * radius;
16468
+ const targetY = Math.sin(angle) * radius;
16469
+ const posTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16470
+ tweenGroup.add(posTween);
16471
+ posTween.start();
16472
+ if (mesh.userData.labelObject) {
16473
+ const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(
16474
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16475
+ );
16476
+ const lblTween = new Tween2(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16477
+ tweenGroup.add(lblTween);
16478
+ lblTween.start();
16479
+ }
16480
+ sumX += targetX;
16481
+ sumY += targetY;
16482
+ nodeCount++;
16483
+ });
16484
+ } else if (type === "Star") {
16485
+ const centerMesh = centerNodeId ? nodeObjects[String(centerNodeId)] : null;
16486
+ const orbitingNodeIds = activeNodeIds.filter(
16487
+ (id) => id !== String(centerNodeId)
16488
+ );
16489
+ const totalOrbiting = orbitingNodeIds.length;
16490
+ const radius = Math.max(80, totalOrbiting * 10);
16491
+ if (centerMesh) {
16492
+ const posTween = new Tween2(centerMesh.position).to({ x: 0, y: 0, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16493
+ tweenGroup.add(posTween);
16494
+ posTween.start();
16495
+ if (centerMesh.userData.labelObject) {
16496
+ const labelTarget = new THREE3.Vector3(0, 0, 0).add(
16497
+ centerMesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16498
+ );
16499
+ const lblTween = new Tween2(centerMesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16500
+ tweenGroup.add(lblTween);
16501
+ lblTween.start();
16502
+ }
16503
+ sumX += 0;
16504
+ sumY += 0;
16505
+ nodeCount++;
16506
+ }
16507
+ orbitingNodeIds.forEach((id, index) => {
16508
+ const mesh = nodeObjects[id];
16509
+ const angle = totalOrbiting > 0 ? index / totalOrbiting * Math.PI * 2 : 0;
16510
+ const targetX = Math.cos(angle) * radius;
16511
+ const targetY = Math.sin(angle) * radius;
16512
+ const posTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16513
+ tweenGroup.add(posTween);
16514
+ posTween.start();
16515
+ if (mesh.userData.labelObject) {
16516
+ const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(
16517
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16518
+ );
16519
+ const lblTween = new Tween2(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(Easing2.Cubic.InOut);
16520
+ tweenGroup.add(lblTween);
16521
+ lblTween.start();
16522
+ }
16523
+ sumX += targetX;
16524
+ sumY += targetY;
16525
+ nodeCount++;
16526
+ });
16557
16527
  }
16558
- });
16559
- const questTimeInfos = /* @__PURE__ */ new Map();
16560
- const allActiveTimePoints = /* @__PURE__ */ new Set();
16561
- filteredQuests.forEach((q) => {
16562
- const info = parseDateProp(q.Date);
16563
- questTimeInfos.set(String(q.id), info);
16564
- if (!info.isUndated) {
16565
- allActiveTimePoints.add(info.startDate.getTime());
16566
- if (info.endDate && info.type === "interval") {
16567
- allActiveTimePoints.add(info.endDate.getTime());
16568
- }
16528
+ if (nodeCount > 0) {
16529
+ const centerX = sumX / nodeCount;
16530
+ const centerY = sumY / nodeCount;
16531
+ const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16532
+ const targetTween = new Tween2(controls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(Easing2.Cubic.InOut);
16533
+ tweenGroup.add(targetTween);
16534
+ targetTween.start();
16535
+ let zoomZ = 140;
16536
+ if (type === "Column") {
16537
+ const numRows = Math.ceil(nodeCount / (columns || 4));
16538
+ zoomZ = Math.max(140, numRows * 50);
16539
+ } else if (type === "Circle" || type === "Star") {
16540
+ const radius = Math.max(80, nodeCount * 8);
16541
+ zoomZ = radius * 2.5;
16542
+ }
16543
+ const camTween = new Tween2(camera.position).to({ x: targetFocus.x, y: targetFocus.y, z: zoomZ }, 1500).easing(Easing2.Cubic.InOut);
16544
+ tweenGroup.add(camTween);
16545
+ camTween.start();
16569
16546
  }
16570
- });
16571
- const sortedTimePoints = Array.from(allActiveTimePoints).sort((a, b) => a - b);
16572
- const timeToYMap = /* @__PURE__ */ new Map();
16573
- sortedTimePoints.forEach((ms, idx) => {
16574
- timeToYMap.set(ms, idx * TIMELINE_LAYER_SPACING_Y);
16575
- });
16576
- const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
16577
- let sumX = 0;
16578
- let sumY = 0;
16579
- let questCount = 0;
16580
- const positionGroups = /* @__PURE__ */ new Map();
16581
- const NODE_X_GAP = 22;
16582
- QUEST_STATUS_ORDER.forEach((statusName) => {
16583
- const questsInCol = questsByStatus[statusName];
16584
- questsInCol.forEach((q, rowIndex) => {
16585
- const timeInfo = questTimeInfos.get(String(q.id)) || { isUndated: true };
16586
- let nodeY;
16587
- if (!timeInfo.isUndated) {
16588
- nodeY = timeToYMap.get(timeInfo.startDate.getTime());
16589
- } else {
16590
- const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16591
- nodeY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16592
- }
16593
- const posKey = `${statusName}_${nodeY}`;
16594
- if (!positionGroups.has(posKey)) positionGroups.set(posKey, []);
16595
- positionGroups.get(posKey).push(String(q.id));
16547
+ },
16548
+ []
16549
+ );
16550
+ const handleActivateQuestLens = useCallback7(
16551
+ ({ assigneeId, status: status2, milestoneId }) => {
16552
+ var _a2;
16553
+ const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
16554
+ if (!nodeObjects || !tweenGroup || !graphGroup) return;
16555
+ const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
16556
+ const filteredQuests = allQuests.filter((q) => {
16557
+ const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
16558
+ const matchStatus = !status2 ? q.status !== "Done" : String(q.status) === String(status2);
16559
+ const matchMilestone = !milestoneId || q.milestone_ids && q.milestone_ids.includes(milestoneId);
16560
+ return matchAssignee && matchStatus && matchMilestone;
16596
16561
  });
16597
- });
16598
- Object.values(nodeObjects).forEach((mesh) => {
16599
- const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
16600
- if (oldLabel) {
16601
- mesh.remove(oldLabel);
16602
- if (oldLabel.material) oldLabel.material.dispose();
16603
- }
16604
- if (mesh.userData.timelineIntervalBar) {
16605
- if (graphGroup) graphGroup.remove(mesh.userData.timelineIntervalBar);
16606
- mesh.userData.timelineIntervalBar = null;
16607
- }
16608
- if (mesh.userData.timelineEndLabel) {
16609
- if (graphGroup) graphGroup.remove(mesh.userData.timelineEndLabel);
16610
- mesh.userData.timelineEndLabel = null;
16611
- }
16612
- });
16613
- const nonFilteredNodeIds = Object.keys(nodeObjects).filter((id) => !filteredQuests.some((q) => String(q.id) === String(id)));
16614
- const COMMON_START_X = startX - 100;
16615
- const COMMON_COL_SPACING = 30;
16616
- const COMMON_ROW_SPACING = 35;
16617
- const MAX_COMMON_ROWS = 15;
16618
- nonFilteredNodeIds.forEach((id, idx) => {
16619
- const mesh = nodeObjects[id];
16620
- if (!mesh) return;
16621
- const col = Math.floor(idx / MAX_COMMON_ROWS);
16622
- const row = idx % MAX_COMMON_ROWS;
16623
- const targetX = COMMON_START_X - col * COMMON_COL_SPACING;
16624
- const targetY = -(row * COMMON_ROW_SPACING) + 50;
16625
- const targetZ = 0;
16626
- if (mesh.material) {
16627
- const opacityTween = new Tween2(mesh.material).to({ opacity: 1 }, 1200).easing(Easing2.Cubic.Out);
16628
- tweenGroup.add(opacityTween);
16629
- opacityTween.start();
16630
- }
16631
- if (mesh.userData.labelObject) {
16632
- mesh.userData.labelObject.visible = true;
16633
- const labelTargetPos = new THREE3.Vector3(targetX, targetY, targetZ).add(
16634
- mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16635
- );
16636
- const labelTween = new Tween2(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(Easing2.Cubic.InOut);
16637
- tweenGroup.add(labelTween);
16638
- labelTween.start();
16562
+ if (filteredQuests.length === 0) {
16563
+ console.warn("Nenhuma quest encontrada para os filtros selecionados.");
16564
+ return;
16639
16565
  }
16640
- const sideTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: targetZ }, 1500).easing(Easing2.Cubic.InOut);
16641
- tweenGroup.add(sideTween);
16642
- sideTween.start();
16643
- });
16644
- filteredQuests.forEach((q) => {
16645
- const mesh = nodeObjects[String(q.id)];
16646
- if (mesh) {
16647
- if (mesh.material) {
16648
- const fadeInTween = new Tween2(mesh.material).to({ opacity: 1 }, 1200).easing(Easing2.Cubic.Out);
16649
- tweenGroup.add(fadeInTween);
16650
- fadeInTween.start();
16566
+ const questsByStatus = {
16567
+ Backlog: [],
16568
+ "In Progress": [],
16569
+ Review: [],
16570
+ Done: []
16571
+ };
16572
+ filteredQuests.forEach((q) => {
16573
+ if (questsByStatus[q.status]) {
16574
+ questsByStatus[q.status].push(q);
16651
16575
  }
16652
- if (mesh.userData.labelObject) {
16653
- mesh.userData.labelObject.visible = true;
16576
+ });
16577
+ const questTimeInfos = /* @__PURE__ */ new Map();
16578
+ const allActiveTimePoints = /* @__PURE__ */ new Set();
16579
+ filteredQuests.forEach((q) => {
16580
+ const info = parseDateProp(q.Date);
16581
+ questTimeInfos.set(String(q.id), info);
16582
+ if (!info.isUndated) {
16583
+ allActiveTimePoints.add(info.startDate.getTime());
16584
+ if (info.endDate && info.type === "interval") {
16585
+ allActiveTimePoints.add(info.endDate.getTime());
16586
+ }
16654
16587
  }
16655
- }
16656
- });
16657
- QUEST_STATUS_ORDER.forEach((statusName, colIndex) => {
16658
- if (status2 && status2 !== statusName) return;
16659
- const questsInCol = questsByStatus[statusName];
16660
- const colX = startX + colIndex * QUEST_LENS_COLUMN_SPACING;
16661
- questsInCol.forEach((q, rowIndex) => {
16662
- const nodeId = String(q.id);
16663
- let mesh = nodeObjects[nodeId];
16664
- const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
16665
- let targetY;
16666
- if (!timeInfo.isUndated) {
16667
- targetY = timeToYMap.get(timeInfo.startDate.getTime());
16668
- } else {
16669
- const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16670
- targetY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16671
- }
16672
- const posKey = `${statusName}_${targetY}`;
16673
- const group = positionGroups.get(posKey) || [nodeId];
16674
- const indexInGroup = group.indexOf(nodeId);
16675
- const xOffset = (indexInGroup - (group.length - 1) / 2) * NODE_X_GAP;
16676
- const finalX = colX + xOffset;
16677
- if (!mesh) {
16678
- mesh = addOrUpdateNodeMesh(q, new THREE3.Vector3(finalX, 150, 0), true);
16679
- }
16680
- const lensTween = new Tween2(mesh.position).to({ x: finalX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16681
- tweenGroup.add(lensTween);
16682
- lensTween.start();
16683
- sumX += finalX;
16684
- sumY += targetY;
16685
- questCount++;
16686
- if (!timeInfo.isUndated && timeInfo.label && !mesh.getObjectByName("questDateLabel")) {
16687
- const dateSprite = createTextSprite(timeInfo.label, 36);
16688
- dateSprite.name = "questDateLabel";
16689
- dateSprite.position.set(0, -5.5, 0);
16690
- mesh.add(dateSprite);
16691
- }
16692
- if (timeInfo.type === "interval" && timeToYMap.has(timeInfo.endDate.getTime())) {
16693
- const endY = timeToYMap.get(timeInfo.endDate.getTime());
16694
- if (Math.abs(endY - targetY) > 0.1) {
16695
- const barHeight = Math.abs(endY - targetY);
16696
- const barGeometry = new THREE3.CylinderGeometry(
16697
- TIMELINE_INTERVAL_BAR_RADIUS,
16698
- TIMELINE_INTERVAL_BAR_RADIUS,
16699
- 1,
16700
- 16
16701
- );
16702
- const barMaterial = new THREE3.MeshStandardMaterial({
16703
- color: TIMELINE_GOLD_COLOR,
16704
- emissive: 12092939,
16705
- emissiveIntensity: 0.4,
16706
- transparent: true,
16707
- opacity: TIMELINE_INTERVAL_BAR_OPACITY,
16708
- roughness: 0.3,
16709
- metalness: 0.8
16710
- });
16711
- const intervalBar = new THREE3.Mesh(barGeometry, barMaterial);
16712
- intervalBar.userData.associatedNodeId = mesh.userData.id;
16713
- intervalBar.position.set(finalX, (targetY + endY) / 2, -0.5);
16714
- intervalBar.scale.y = barHeight;
16715
- graphGroup.add(intervalBar);
16716
- mesh.userData.timelineIntervalBar = intervalBar;
16717
- const endLabel = createTextSprite(timeInfo.label.split(" - ")[1] || "", 30);
16718
- endLabel.name = "timelineEndLabel";
16719
- endLabel.position.set(finalX, endY + 4, 0);
16720
- graphGroup.add(endLabel);
16721
- mesh.userData.timelineEndLabel = endLabel;
16588
+ });
16589
+ const sortedTimePoints = Array.from(allActiveTimePoints).sort(
16590
+ (a, b) => a - b
16591
+ );
16592
+ const timeToYMap = /* @__PURE__ */ new Map();
16593
+ sortedTimePoints.forEach((ms, idx) => {
16594
+ timeToYMap.set(ms, idx * TIMELINE_LAYER_SPACING_Y);
16595
+ });
16596
+ const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
16597
+ let sumX = 0;
16598
+ let sumY = 0;
16599
+ let questCount = 0;
16600
+ const positionGroups = /* @__PURE__ */ new Map();
16601
+ const NODE_X_GAP = 22;
16602
+ QUEST_STATUS_ORDER.forEach((statusName) => {
16603
+ const questsInCol = questsByStatus[statusName];
16604
+ questsInCol.forEach((q, rowIndex) => {
16605
+ const timeInfo = questTimeInfos.get(String(q.id)) || {
16606
+ isUndated: true
16607
+ };
16608
+ let nodeY;
16609
+ if (!timeInfo.isUndated) {
16610
+ nodeY = timeToYMap.get(timeInfo.startDate.getTime());
16611
+ } else {
16612
+ const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16613
+ nodeY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16722
16614
  }
16615
+ const posKey = `${statusName}_${nodeY}`;
16616
+ if (!positionGroups.has(posKey)) positionGroups.set(posKey, []);
16617
+ positionGroups.get(posKey).push(String(q.id));
16618
+ });
16619
+ });
16620
+ Object.values(nodeObjects).forEach((mesh) => {
16621
+ const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
16622
+ if (oldLabel) {
16623
+ mesh.remove(oldLabel);
16624
+ if (oldLabel.material) oldLabel.material.dispose();
16625
+ }
16626
+ if (mesh.userData.timelineIntervalBar) {
16627
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineIntervalBar);
16628
+ mesh.userData.timelineIntervalBar = null;
16629
+ }
16630
+ if (mesh.userData.timelineEndLabel) {
16631
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineEndLabel);
16632
+ mesh.userData.timelineEndLabel = null;
16633
+ }
16634
+ });
16635
+ const nonFilteredNodeIds = Object.keys(nodeObjects).filter(
16636
+ (id) => !filteredQuests.some((q) => String(q.id) === String(id))
16637
+ );
16638
+ const COMMON_START_X = startX - 100;
16639
+ const COMMON_COL_SPACING = 30;
16640
+ const COMMON_ROW_SPACING = 35;
16641
+ const MAX_COMMON_ROWS = 15;
16642
+ nonFilteredNodeIds.forEach((id, idx) => {
16643
+ const mesh = nodeObjects[id];
16644
+ if (!mesh) return;
16645
+ const col = Math.floor(idx / MAX_COMMON_ROWS);
16646
+ const row = idx % MAX_COMMON_ROWS;
16647
+ const targetX = COMMON_START_X - col * COMMON_COL_SPACING;
16648
+ const targetY = -(row * COMMON_ROW_SPACING) + 50;
16649
+ const targetZ = 0;
16650
+ if (mesh.material) {
16651
+ const opacityTween = new Tween2(mesh.material).to({ opacity: 1 }, 1200).easing(Easing2.Cubic.Out);
16652
+ tweenGroup.add(opacityTween);
16653
+ opacityTween.start();
16723
16654
  }
16724
16655
  if (mesh.userData.labelObject) {
16725
- const labelTargetPos = new THREE3.Vector3(finalX, targetY, 0).add(
16726
- mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16727
- );
16656
+ mesh.userData.labelObject.visible = true;
16657
+ const labelTargetPos = new THREE3.Vector3(
16658
+ targetX,
16659
+ targetY,
16660
+ targetZ
16661
+ ).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16728
16662
  const labelTween = new Tween2(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(Easing2.Cubic.InOut);
16729
16663
  tweenGroup.add(labelTween);
16730
16664
  labelTween.start();
16731
16665
  }
16666
+ const sideTween = new Tween2(mesh.position).to({ x: targetX, y: targetY, z: targetZ }, 1500).easing(Easing2.Cubic.InOut);
16667
+ tweenGroup.add(sideTween);
16668
+ sideTween.start();
16732
16669
  });
16733
- });
16734
- if (questCount > 0) {
16735
- const { camera: sceneCamera, controls: sceneControls } = stateRef.current;
16736
- const centerX = sumX / questCount;
16737
- const centerY = sumY / questCount;
16738
- const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16739
- const targetTween = new Tween2(sceneControls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(Easing2.Cubic.InOut);
16740
- tweenGroup.add(targetTween);
16741
- targetTween.start();
16742
- const camTween = new Tween2(sceneCamera.position).to({ x: targetFocus.x, y: targetFocus.y, z: 140 }, 1500).easing(Easing2.Cubic.InOut);
16743
- tweenGroup.add(camTween);
16744
- camTween.start();
16745
- }
16746
- }, [addOrUpdateNodeMesh]);
16670
+ filteredQuests.forEach((q) => {
16671
+ const mesh = nodeObjects[String(q.id)];
16672
+ if (mesh) {
16673
+ if (mesh.material) {
16674
+ const fadeInTween = new Tween2(mesh.material).to({ opacity: 1 }, 1200).easing(Easing2.Cubic.Out);
16675
+ tweenGroup.add(fadeInTween);
16676
+ fadeInTween.start();
16677
+ }
16678
+ if (mesh.userData.labelObject) {
16679
+ mesh.userData.labelObject.visible = true;
16680
+ }
16681
+ }
16682
+ });
16683
+ QUEST_STATUS_ORDER.forEach((statusName, colIndex) => {
16684
+ if (status2 && status2 !== statusName) return;
16685
+ const questsInCol = questsByStatus[statusName];
16686
+ const colX = startX + colIndex * QUEST_LENS_COLUMN_SPACING;
16687
+ questsInCol.forEach((q, rowIndex) => {
16688
+ const nodeId = String(q.id);
16689
+ let mesh = nodeObjects[nodeId];
16690
+ const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
16691
+ let targetY;
16692
+ if (!timeInfo.isUndated) {
16693
+ targetY = timeToYMap.get(timeInfo.startDate.getTime());
16694
+ } else {
16695
+ const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16696
+ targetY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16697
+ }
16698
+ const posKey = `${statusName}_${targetY}`;
16699
+ const group = positionGroups.get(posKey) || [nodeId];
16700
+ const indexInGroup = group.indexOf(nodeId);
16701
+ const xOffset = (indexInGroup - (group.length - 1) / 2) * NODE_X_GAP;
16702
+ const finalX = colX + xOffset;
16703
+ if (!mesh) {
16704
+ mesh = addOrUpdateNodeMesh(
16705
+ q,
16706
+ new THREE3.Vector3(finalX, 150, 0),
16707
+ true
16708
+ );
16709
+ }
16710
+ const lensTween = new Tween2(mesh.position).to({ x: finalX, y: targetY, z: 0 }, 1500).easing(Easing2.Cubic.InOut);
16711
+ tweenGroup.add(lensTween);
16712
+ lensTween.start();
16713
+ sumX += finalX;
16714
+ sumY += targetY;
16715
+ questCount++;
16716
+ if (!timeInfo.isUndated && timeInfo.label && !mesh.getObjectByName("questDateLabel")) {
16717
+ const dateSprite = createTextSprite(timeInfo.label, 36);
16718
+ dateSprite.name = "questDateLabel";
16719
+ dateSprite.position.set(0, -5.5, 0);
16720
+ mesh.add(dateSprite);
16721
+ }
16722
+ if (timeInfo.type === "interval" && timeToYMap.has(timeInfo.endDate.getTime())) {
16723
+ const endY = timeToYMap.get(timeInfo.endDate.getTime());
16724
+ if (Math.abs(endY - targetY) > 0.1) {
16725
+ const barHeight = Math.abs(endY - targetY);
16726
+ const barGeometry = new THREE3.CylinderGeometry(
16727
+ TIMELINE_INTERVAL_BAR_RADIUS,
16728
+ TIMELINE_INTERVAL_BAR_RADIUS,
16729
+ 1,
16730
+ 16
16731
+ );
16732
+ const barMaterial = new THREE3.MeshStandardMaterial({
16733
+ color: TIMELINE_GOLD_COLOR,
16734
+ emissive: 12092939,
16735
+ emissiveIntensity: 0.4,
16736
+ transparent: true,
16737
+ opacity: TIMELINE_INTERVAL_BAR_OPACITY,
16738
+ roughness: 0.3,
16739
+ metalness: 0.8
16740
+ });
16741
+ const intervalBar = new THREE3.Mesh(barGeometry, barMaterial);
16742
+ intervalBar.userData.associatedNodeId = mesh.userData.id;
16743
+ intervalBar.position.set(finalX, (targetY + endY) / 2, -0.5);
16744
+ intervalBar.scale.y = barHeight;
16745
+ graphGroup.add(intervalBar);
16746
+ mesh.userData.timelineIntervalBar = intervalBar;
16747
+ const endLabel = createTextSprite(
16748
+ timeInfo.label.split(" - ")[1] || "",
16749
+ 30
16750
+ );
16751
+ endLabel.name = "timelineEndLabel";
16752
+ endLabel.position.set(finalX, endY + 4, 0);
16753
+ graphGroup.add(endLabel);
16754
+ mesh.userData.timelineEndLabel = endLabel;
16755
+ }
16756
+ }
16757
+ if (mesh.userData.labelObject) {
16758
+ const labelTargetPos = new THREE3.Vector3(finalX, targetY, 0).add(
16759
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16760
+ );
16761
+ const labelTween = new Tween2(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(Easing2.Cubic.InOut);
16762
+ tweenGroup.add(labelTween);
16763
+ labelTween.start();
16764
+ }
16765
+ });
16766
+ });
16767
+ if (questCount > 0) {
16768
+ const { camera: sceneCamera, controls: sceneControls } = stateRef.current;
16769
+ const centerX = sumX / questCount;
16770
+ const centerY = sumY / questCount;
16771
+ const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16772
+ const targetTween = new Tween2(sceneControls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(Easing2.Cubic.InOut);
16773
+ tweenGroup.add(targetTween);
16774
+ targetTween.start();
16775
+ const camTween = new Tween2(sceneCamera.position).to({ x: targetFocus.x, y: targetFocus.y, z: 140 }, 1500).easing(Easing2.Cubic.InOut);
16776
+ tweenGroup.add(camTween);
16777
+ camTween.start();
16778
+ }
16779
+ },
16780
+ [addOrUpdateNodeMesh]
16781
+ );
16747
16782
  useEffect25(() => {
16748
16783
  if (!isInitialized || !sceneDataRef.current) return;
16749
16784
  const currentMount = mountRef.current;
@@ -17128,7 +17163,9 @@ function XViewScene({
17128
17163
  const clickedNodeId = String(clickedNode.userData.id);
17129
17164
  const parentId = String(currentSelectedParent);
17130
17165
  if (clickedNodeId === parentId) {
17131
- alert("Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo.");
17166
+ alert(
17167
+ "Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo."
17168
+ );
17132
17169
  return;
17133
17170
  }
17134
17171
  const parentInfo = stateRef.current.nodeIdToParentFileMap.get(clickedNodeId);
@@ -17477,7 +17514,11 @@ function XViewScene({
17477
17514
  ancestryData: ancestryDataRef.current
17478
17515
  });
17479
17516
  (_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
17480
- const { keysPressed, controls: sceneControls, camera: sceneCamera } = stateRef.current;
17517
+ const {
17518
+ keysPressed,
17519
+ controls: sceneControls,
17520
+ camera: sceneCamera
17521
+ } = stateRef.current;
17481
17522
  if (sceneControls && keysPressed) {
17482
17523
  const panSpeed = 1.5;
17483
17524
  const rotateSpeed = 0.02;
@@ -17501,10 +17542,18 @@ function XViewScene({
17501
17542
  offset.multiplyScalar(factor);
17502
17543
  sceneCamera.position.copy(sceneControls.target).add(offset);
17503
17544
  } else if (!isCtrl && !isShift && (dirX !== 0 || dirY !== 0)) {
17504
- const distance = sceneCamera.position.distanceTo(sceneControls.target);
17545
+ const distance = sceneCamera.position.distanceTo(
17546
+ sceneControls.target
17547
+ );
17505
17548
  const currentPanSpeed = panSpeed * (distance / 100);
17506
- const vecX = new THREE3.Vector3().setFromMatrixColumn(sceneCamera.matrix, 0);
17507
- const vecY = new THREE3.Vector3().setFromMatrixColumn(sceneCamera.matrix, 1);
17549
+ const vecX = new THREE3.Vector3().setFromMatrixColumn(
17550
+ sceneCamera.matrix,
17551
+ 0
17552
+ );
17553
+ const vecY = new THREE3.Vector3().setFromMatrixColumn(
17554
+ sceneCamera.matrix,
17555
+ 1
17556
+ );
17508
17557
  vecX.multiplyScalar(dirX * currentPanSpeed);
17509
17558
  vecY.multiplyScalar(dirY * currentPanSpeed);
17510
17559
  sceneCamera.position.add(vecX).add(vecY);
@@ -17901,115 +17950,143 @@ function XViewScene({
17901
17950
  const handleStartVersioning = (nodeData) => {
17902
17951
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
17903
17952
  };
17904
- const handleStartQuestQuick = useCallback7((questNode) => {
17905
- var _a2, _b2, _c2;
17906
- if (!questNode || !actionHandlerContext) return;
17907
- const allParentNodes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
17908
- const blockCheck = isQuestBlocked(questNode, allParentNodes);
17909
- if (blockCheck.isBlocked) {
17910
- alert(`Esta quest n\xE3o pode ser iniciada pois possui depend\xEAncias pendentes: ${blockCheck.pendingDependencies.map((d) => d.raw_title || d.name).join(", ")}`);
17911
- return;
17912
- }
17913
- const {
17914
- labelObject,
17915
- labelOffset,
17916
- aura,
17917
- borderRing,
17918
- timelineIntervalBar,
17919
- timelineEndLabel,
17920
- ...cleanQuestNode
17921
- } = questNode;
17922
- const newTimeline = [...cleanQuestNode.timeline || [], createTimelineEntry(
17923
- ((_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id) || "unknown",
17924
- `Status "In Progress" - Respons\xE1vel: ${((_b2 = session == null ? void 0 : session.user) == null ? void 0 : _b2.name) || "usu\xE1rio"}`,
17925
- "status_changed"
17926
- )];
17927
- const updatedNode = {
17928
- ...cleanQuestNode,
17929
- status: "In Progress",
17930
- color: "#eab308",
17931
- assignee_id: (_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.id,
17932
- timeline: newTimeline
17933
- };
17934
- if (userActionHandlers.handleSaveNodeDetails) {
17935
- userActionHandlers.handleSaveNodeDetails(actionHandlerContext, updatedNode, true);
17936
- }
17937
- setDetailsNode(updatedNode);
17938
- }, [session, actionHandlerContext]);
17939
- const handleFinishQuestQuick = useCallback7((questNode) => {
17940
- var _a2, _b2, _c2, _d2;
17941
- if (!questNode || !actionHandlerContext) return;
17942
- const {
17943
- labelObject,
17944
- labelOffset,
17945
- aura,
17946
- borderRing,
17947
- timelineIntervalBar,
17948
- timelineEndLabel,
17949
- ...cleanQuestNode
17950
- } = questNode;
17951
- let nextAssigneeId = cleanQuestNode.assignee_id;
17952
- let nextStatus = "Done";
17953
- let newTimeline = [...cleanQuestNode.timeline || []];
17954
- const reviewStack = [...cleanQuestNode.reviewStack || []];
17955
- const currentReviewerIdx = reviewStack.findIndex((r) => r.status !== "completed");
17956
- let nextIdxToAssign = 0;
17957
- if (currentReviewerIdx !== -1 && reviewStack[currentReviewerIdx].userId === cleanQuestNode.assignee_id) {
17958
- reviewStack[currentReviewerIdx].status = "completed";
17959
- nextIdxToAssign = currentReviewerIdx + 1;
17960
- } else {
17961
- nextIdxToAssign = currentReviewerIdx !== -1 ? currentReviewerIdx : reviewStack.length;
17962
- }
17963
- if (nextIdxToAssign < reviewStack.length) {
17964
- const remainingMandatory = reviewStack.slice(nextIdxToAssign).some((r) => r.mandatory);
17965
- const hasAnyMandatory = reviewStack.some((r) => r.mandatory);
17966
- if (!hasAnyMandatory || remainingMandatory) {
17967
- const nextReviewer = reviewStack[nextIdxToAssign];
17968
- nextAssigneeId = nextReviewer.userId;
17969
- nextStatus = "Review";
17953
+ const handleStartQuestQuick = useCallback7(
17954
+ (questNode) => {
17955
+ var _a2, _b2, _c2;
17956
+ if (!questNode || !actionHandlerContext) return;
17957
+ const allParentNodes = Object.values(parentDataRef.current).flatMap(
17958
+ (fileData) => fileData.nodes || []
17959
+ );
17960
+ const blockCheck = isQuestBlocked(questNode, allParentNodes);
17961
+ if (blockCheck.isBlocked) {
17962
+ alert(
17963
+ `Esta quest n\xE3o pode ser iniciada pois possui depend\xEAncias pendentes: ${blockCheck.pendingDependencies.map((d) => d.raw_title || d.name).join(", ")}`
17964
+ );
17965
+ return;
17966
+ }
17967
+ const {
17968
+ labelObject,
17969
+ labelOffset,
17970
+ aura,
17971
+ borderRing,
17972
+ timelineIntervalBar,
17973
+ timelineEndLabel,
17974
+ ...cleanQuestNode
17975
+ } = questNode;
17976
+ const newTimeline = [
17977
+ ...cleanQuestNode.timeline || [],
17978
+ createTimelineEntry(
17979
+ ((_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id) || "unknown",
17980
+ `Status "In Progress" - Respons\xE1vel: ${((_b2 = session == null ? void 0 : session.user) == null ? void 0 : _b2.name) || "usu\xE1rio"}`,
17981
+ "status_changed"
17982
+ )
17983
+ ];
17984
+ const updatedNode = {
17985
+ ...cleanQuestNode,
17986
+ status: "In Progress",
17987
+ color: "#eab308",
17988
+ assignee_id: (_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.id,
17989
+ timeline: newTimeline
17990
+ };
17991
+ if (userActionHandlers.handleSaveNodeDetails) {
17992
+ userActionHandlers.handleSaveNodeDetails(
17993
+ actionHandlerContext,
17994
+ updatedNode,
17995
+ true
17996
+ );
17997
+ }
17998
+ setDetailsNode(updatedNode);
17999
+ },
18000
+ [session, actionHandlerContext]
18001
+ );
18002
+ const handleFinishQuestQuick = useCallback7(
18003
+ (questNode) => {
18004
+ var _a2, _b2, _c2, _d2;
18005
+ if (!questNode || !actionHandlerContext) return;
18006
+ const {
18007
+ labelObject,
18008
+ labelOffset,
18009
+ aura,
18010
+ borderRing,
18011
+ timelineIntervalBar,
18012
+ timelineEndLabel,
18013
+ ...cleanQuestNode
18014
+ } = questNode;
18015
+ let nextAssigneeId = cleanQuestNode.assignee_id;
18016
+ let nextStatus = "Done";
18017
+ let newTimeline = [...cleanQuestNode.timeline || []];
18018
+ const reviewStack = [...cleanQuestNode.reviewStack || []];
18019
+ const currentReviewerIdx = reviewStack.findIndex(
18020
+ (r) => r.status !== "completed"
18021
+ );
18022
+ let nextIdxToAssign = 0;
18023
+ if (currentReviewerIdx !== -1 && reviewStack[currentReviewerIdx].userId === cleanQuestNode.assignee_id) {
18024
+ reviewStack[currentReviewerIdx].status = "completed";
18025
+ nextIdxToAssign = currentReviewerIdx + 1;
17970
18026
  } else {
17971
- nextStatus = "Done";
17972
- for (let i = nextIdxToAssign; i < reviewStack.length; i++) {
17973
- reviewStack[i].status = "skipped";
18027
+ nextIdxToAssign = currentReviewerIdx !== -1 ? currentReviewerIdx : reviewStack.length;
18028
+ }
18029
+ if (nextIdxToAssign < reviewStack.length) {
18030
+ const remainingMandatory = reviewStack.slice(nextIdxToAssign).some((r) => r.mandatory);
18031
+ const hasAnyMandatory = reviewStack.some((r) => r.mandatory);
18032
+ if (!hasAnyMandatory || remainingMandatory) {
18033
+ const nextReviewer = reviewStack[nextIdxToAssign];
18034
+ nextAssigneeId = nextReviewer.userId;
18035
+ nextStatus = "Review";
18036
+ } else {
18037
+ nextStatus = "Done";
18038
+ for (let i = nextIdxToAssign; i < reviewStack.length; i++) {
18039
+ reviewStack[i].status = "skipped";
18040
+ }
17974
18041
  }
18042
+ } else {
18043
+ nextStatus = "Done";
17975
18044
  }
17976
- } else {
17977
- nextStatus = "Done";
17978
- }
17979
- if (nextStatus === "Review") {
17980
- const nextReviewerName = ((_a2 = viewMembers.find((m) => m.id === nextAssigneeId)) == null ? void 0 : _a2.name) || "revisor";
17981
- newTimeline.push(createTimelineEntry(
17982
- "system",
17983
- `Status "Review" - Respons\xE1vel: ${nextReviewerName}`,
17984
- "status_changed",
17985
- { metadata: { to_assignee_id: nextAssigneeId } }
17986
- ));
17987
- } else if (nextStatus === "Done") {
17988
- const finisherName = ((_b2 = viewMembers.find((m) => {
17989
- var _a3;
17990
- return m.id === (((_a3 = session == null ? void 0 : session.user) == null ? void 0 : _a3.id) || cleanQuestNode.assignee_id);
17991
- })) == null ? void 0 : _b2.name) || ((_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.name) || "respons\xE1vel";
17992
- newTimeline.push(createTimelineEntry(
17993
- ((_d2 = session == null ? void 0 : session.user) == null ? void 0 : _d2.id) || cleanQuestNode.assignee_id,
17994
- `Status "Done" - Finalizado por ${finisherName}`,
17995
- "status_changed"
17996
- ));
17997
- }
17998
- const updatedNode = {
17999
- ...cleanQuestNode,
18000
- status: nextStatus,
18001
- color: nextStatus === "Done" ? "#22c55e" : "#a855f7",
18002
- assignee_id: nextAssigneeId,
18003
- reviewStack,
18004
- timeline: newTimeline
18005
- };
18006
- if (userActionHandlers.handleSaveNodeDetails) {
18007
- userActionHandlers.handleSaveNodeDetails(actionHandlerContext, updatedNode);
18008
- }
18009
- if (detailsNode && String(detailsNode.id) === String(cleanQuestNode.id)) {
18010
- setDetailsNode(null);
18011
- }
18012
- }, [session, actionHandlerContext, viewMembers, detailsNode]);
18045
+ if (nextStatus === "Review") {
18046
+ const nextReviewerName = ((_a2 = viewMembers.find((m) => m.id === nextAssigneeId)) == null ? void 0 : _a2.name) || "revisor";
18047
+ newTimeline.push(
18048
+ createTimelineEntry(
18049
+ "system",
18050
+ `Status "Review" - Respons\xE1vel: ${nextReviewerName}`,
18051
+ "status_changed",
18052
+ { metadata: { to_assignee_id: nextAssigneeId } }
18053
+ )
18054
+ );
18055
+ } else if (nextStatus === "Done") {
18056
+ const finisherName = ((_b2 = viewMembers.find(
18057
+ (m) => {
18058
+ var _a3;
18059
+ return m.id === (((_a3 = session == null ? void 0 : session.user) == null ? void 0 : _a3.id) || cleanQuestNode.assignee_id);
18060
+ }
18061
+ )) == null ? void 0 : _b2.name) || ((_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.name) || "respons\xE1vel";
18062
+ newTimeline.push(
18063
+ createTimelineEntry(
18064
+ ((_d2 = session == null ? void 0 : session.user) == null ? void 0 : _d2.id) || cleanQuestNode.assignee_id,
18065
+ `Status "Done" - Finalizado por ${finisherName}`,
18066
+ "status_changed"
18067
+ )
18068
+ );
18069
+ }
18070
+ const updatedNode = {
18071
+ ...cleanQuestNode,
18072
+ status: nextStatus,
18073
+ color: nextStatus === "Done" ? "#22c55e" : "#a855f7",
18074
+ assignee_id: nextAssigneeId,
18075
+ reviewStack,
18076
+ timeline: newTimeline
18077
+ };
18078
+ if (userActionHandlers.handleSaveNodeDetails) {
18079
+ userActionHandlers.handleSaveNodeDetails(
18080
+ actionHandlerContext,
18081
+ updatedNode
18082
+ );
18083
+ }
18084
+ if (detailsNode && String(detailsNode.id) === String(cleanQuestNode.id)) {
18085
+ setDetailsNode(null);
18086
+ }
18087
+ },
18088
+ [session, actionHandlerContext, viewMembers, detailsNode]
18089
+ );
18013
18090
  const handleCancelQuest = useCallback7(() => {
18014
18091
  const { graphGroup, ghostElements } = stateRef.current;
18015
18092
  if (ghostElements.node && graphGroup) {
@@ -18060,48 +18137,56 @@ function XViewScene({
18060
18137
  if (questNodeId && sceneConfigId) {
18061
18138
  const sceneData = sceneDataRef.current;
18062
18139
  if (sceneData && sceneData.quest_nodes) {
18063
- const questIndex = sceneData.quest_nodes.findIndex((q) => String(q.id) === String(questNodeId));
18140
+ const questIndex = sceneData.quest_nodes.findIndex(
18141
+ (q) => String(q.id) === String(questNodeId)
18142
+ );
18064
18143
  if (questIndex !== -1) {
18065
18144
  sceneData.quest_nodes[questIndex].quest_tree = formattedTree;
18066
18145
  sceneData.quest_nodes[questIndex].quest_abstraction_tree = formattedAbstractionTree;
18067
18146
  if (parentDataRef.current[sceneConfigId]) {
18068
- const parentIndex = parentDataRef.current[sceneConfigId].nodes.findIndex(
18069
- (q) => String(q.id) === String(questNodeId)
18070
- );
18147
+ const parentIndex = parentDataRef.current[sceneConfigId].nodes.findIndex((q) => String(q.id) === String(questNodeId));
18071
18148
  if (parentIndex !== -1) {
18072
18149
  parentDataRef.current[sceneConfigId].nodes[parentIndex].quest_tree = formattedTree;
18073
18150
  parentDataRef.current[sceneConfigId].nodes[parentIndex].quest_abstraction_tree = formattedAbstractionTree;
18074
18151
  }
18075
18152
  }
18076
- if (save_view_data && sceneSaveUrl) {
18077
- const sceneFileData = {
18078
- ...sceneData,
18079
- nodes: sceneData.nodes || [],
18080
- links: sceneData.links || [],
18081
- quest_nodes: sceneData.quest_nodes,
18082
- quest_links: sceneData.quest_links || [],
18083
- quest_counter: sceneData.quest_counter || 1,
18084
- milestones: sceneData.milestones || []
18085
- };
18086
- await save_view_data(sceneSaveUrl, sceneFileData);
18087
- }
18088
- const updatedNodeData = sceneData.quest_nodes[questIndex];
18089
- const nodeMesh = (_a2 = stateRef.current.nodeObjects) == null ? void 0 : _a2[String(questNodeId)];
18090
- if (nodeMesh) {
18091
- nodeMesh.userData = {
18092
- ...nodeMesh.userData,
18093
- ...updatedNodeData
18094
- };
18095
- }
18096
- if (detailsNode && String(detailsNode.id) === String(questNodeId)) {
18097
- setDetailsNode((prev) => ({
18098
- ...prev,
18099
- quest_tree: formattedTree,
18100
- quest_abstraction_tree: formattedAbstractionTree
18101
- }));
18102
- }
18103
- setSceneVersion((v) => v + 1);
18153
+ const sceneFileData = {
18154
+ ...sceneData,
18155
+ nodes: sceneData.nodes || [],
18156
+ links: sceneData.links || [],
18157
+ quest_counter: sceneData.quest_counter || 1
18158
+ };
18159
+ delete sceneFileData.quest_nodes;
18160
+ delete sceneFileData.quest_links;
18161
+ delete sceneFileData.milestones;
18162
+ const questFileData = {
18163
+ nodes: sceneData.quest_nodes || [],
18164
+ links: sceneData.quest_links || [],
18165
+ milestones: sceneData.milestones || []
18166
+ };
18167
+ await save_view_data(sceneSaveUrl, sceneFileData);
18168
+ const questSaveUrl = sceneSaveUrl.replace(
18169
+ "x_view_scenes",
18170
+ "x_view_quests"
18171
+ );
18172
+ await save_view_data(questSaveUrl, questFileData);
18173
+ }
18174
+ const updatedNodeData = sceneData.quest_nodes[questIndex];
18175
+ const nodeMesh = (_a2 = stateRef.current.nodeObjects) == null ? void 0 : _a2[String(questNodeId)];
18176
+ if (nodeMesh) {
18177
+ nodeMesh.userData = {
18178
+ ...nodeMesh.userData,
18179
+ ...updatedNodeData
18180
+ };
18104
18181
  }
18182
+ if (detailsNode && String(detailsNode.id) === String(questNodeId)) {
18183
+ setDetailsNode((prev) => ({
18184
+ ...prev,
18185
+ quest_tree: formattedTree,
18186
+ quest_abstraction_tree: formattedAbstractionTree
18187
+ }));
18188
+ }
18189
+ setSceneVersion((v) => v + 1);
18105
18190
  }
18106
18191
  }
18107
18192
  };
@@ -18163,21 +18248,33 @@ function XViewScene({
18163
18248
  graphDataRef2.current[sceneConfigId2].nodes.push(newNode);
18164
18249
  const sceneFileData = {
18165
18250
  ...sceneDataRef2.current,
18166
- quest_nodes: graphDataRef2.current[sceneConfigId2].nodes,
18167
- quest_links: graphDataRef2.current[sceneConfigId2].links,
18168
18251
  quest_counter: currentCounter + 1
18169
18252
  };
18253
+ delete sceneFileData.quest_nodes;
18254
+ delete sceneFileData.quest_links;
18255
+ delete sceneFileData.milestones;
18256
+ const questFileData = {
18257
+ nodes: graphDataRef2.current[sceneConfigId2].nodes,
18258
+ links: graphDataRef2.current[sceneConfigId2].links,
18259
+ milestones: sceneDataRef2.current.milestones || []
18260
+ };
18170
18261
  try {
18171
18262
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
18263
+ const questSaveUrl = sceneSaveUrl2.replace("x_view_scenes", "x_view_quests");
18264
+ await actions.save_view_data(questSaveUrl, questFileData);
18172
18265
  sceneDataRef2.current.quest_counter = currentCounter + 1;
18173
18266
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
18174
18267
  parentFileId: sceneConfigId2,
18175
18268
  ownerId: ownerId2,
18176
18269
  datasetName: "Quests Internas (View)"
18177
18270
  });
18178
- sceneDataRef2.current.quest_nodes = [...graphDataRef2.current[sceneConfigId2].nodes];
18271
+ sceneDataRef2.current.quest_nodes = [
18272
+ ...graphDataRef2.current[sceneConfigId2].nodes
18273
+ ];
18179
18274
  if (parentDataRef.current[sceneConfigId2]) {
18180
- parentDataRef.current[sceneConfigId2].nodes = [...graphDataRef2.current[sceneConfigId2].nodes];
18275
+ parentDataRef.current[sceneConfigId2].nodes = [
18276
+ ...graphDataRef2.current[sceneConfigId2].nodes
18277
+ ];
18181
18278
  }
18182
18279
  const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
18183
18280
  const { graphGroup, ghostElements } = stateRef2.current;
@@ -18242,11 +18339,22 @@ function XViewScene({
18242
18339
  specificParentData.links.push(newLink);
18243
18340
  const viewFilePayload = {
18244
18341
  ...sceneDataRef2.current,
18245
- quest_nodes: specificParentData.nodes,
18246
- quest_links: specificParentData.links,
18247
18342
  quest_counter: sceneDataRef2.current.quest_counter || 1
18248
18343
  };
18344
+ delete viewFilePayload.quest_nodes;
18345
+ delete viewFilePayload.quest_links;
18346
+ delete viewFilePayload.milestones;
18347
+ const questFilePayload = {
18348
+ nodes: specificParentData.nodes,
18349
+ links: specificParentData.links,
18350
+ milestones: sceneDataRef2.current.milestones || []
18351
+ };
18249
18352
  await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
18353
+ const questSaveUrl = sceneSaveUrl2.replace(
18354
+ "x_view_scenes",
18355
+ "x_view_quests"
18356
+ );
18357
+ await context.actions.save_view_data(questSaveUrl, questFilePayload);
18250
18358
  } else {
18251
18359
  const specificParentData = JSON.parse(
18252
18360
  JSON.stringify(graphDataRef2.current[parentFileIdToSave])
@@ -18279,9 +18387,7 @@ function XViewScene({
18279
18387
  if (line.material) line.material.dispose();
18280
18388
  });
18281
18389
  renderedAncestries.splice(renderIndex, 1);
18282
- stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18283
- (a) => a.lines
18284
- );
18390
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
18285
18391
  }
18286
18392
  }, []);
18287
18393
  const handleRenderAncestry = useCallback7(
@@ -18854,9 +18960,7 @@ function XViewScene({
18854
18960
  });
18855
18961
  };
18856
18962
  renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
18857
- stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18858
- (a) => a.lines
18859
- );
18963
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
18860
18964
  tweenToTarget(rootTargetPos, 0.7);
18861
18965
  },
18862
18966
  [
@@ -18991,10 +19095,7 @@ function XViewScene({
18991
19095
  };
18992
19096
  const descriptionText = targetAncestryInfo.description || "";
18993
19097
  const savedSections = targetAncestryInfo.description_sections || [];
18994
- const sections = parseDescriptionSections(
18995
- descriptionText,
18996
- savedSections
18997
- );
19098
+ const sections = parseDescriptionSections(descriptionText, savedSections);
18998
19099
  let focusTargetId = null;
18999
19100
  if (popped && popped.nodeId) {
19000
19101
  const mentionTag = `[[MENTION:node:${popped.nodeId}]]`;
@@ -19607,16 +19708,26 @@ function XViewScene({
19607
19708
  const result = await save_view_data(finalSaveUrl, masterAncestryList);
19608
19709
  if (result.success && isExternalSave && isEditMode && currentAncestryId && ancestry_save_url && get_ancestry_file) {
19609
19710
  try {
19610
- const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
19711
+ const viewDbResponse = await get_ancestry_file(
19712
+ sceneConfigId,
19713
+ ownerId
19714
+ );
19611
19715
  if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
19612
- const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(currentAncestryId));
19716
+ const hasInViewDb = viewDbResponse.data.some(
19717
+ (anc) => String(anc.ancestry_id) === String(currentAncestryId)
19718
+ );
19613
19719
  if (hasInViewDb) {
19614
- const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(currentAncestryId));
19720
+ const updatedViewDb = viewDbResponse.data.filter(
19721
+ (anc) => String(anc.ancestry_id) !== String(currentAncestryId)
19722
+ );
19615
19723
  await save_view_data(ancestry_save_url, updatedViewDb);
19616
19724
  }
19617
19725
  }
19618
19726
  } catch (fallbackErr) {
19619
- console.error("Falha ao limpar c\xF3pia residual na edi\xE7\xE3o:", fallbackErr);
19727
+ console.error(
19728
+ "Falha ao limpar c\xF3pia residual na edi\xE7\xE3o:",
19729
+ fallbackErr
19730
+ );
19620
19731
  }
19621
19732
  }
19622
19733
  if (result.success) {
@@ -19727,7 +19838,10 @@ function XViewScene({
19727
19838
  try {
19728
19839
  let updatedAncestriesForFile;
19729
19840
  if (get_ancestry_file && isExternalSave) {
19730
- const remoteResponse = await get_ancestry_file(sourceFileId, sourceOwnerId);
19841
+ const remoteResponse = await get_ancestry_file(
19842
+ sourceFileId,
19843
+ sourceOwnerId
19844
+ );
19731
19845
  if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
19732
19846
  updatedAncestriesForFile = remoteResponse.data.filter(
19733
19847
  (anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete)
@@ -19742,11 +19856,16 @@ function XViewScene({
19742
19856
  (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
19743
19857
  );
19744
19858
  }
19745
- const result = await save_view_data(finalSaveUrl, updatedAncestriesForFile);
19859
+ const result = await save_view_data(
19860
+ finalSaveUrl,
19861
+ updatedAncestriesForFile
19862
+ );
19746
19863
  if (result.success) {
19747
19864
  success = true;
19748
19865
  } else {
19749
- throw new Error(result.error || "Ocorreu um erro desconhecido ao excluir.");
19866
+ throw new Error(
19867
+ result.error || "Ocorreu um erro desconhecido ao excluir."
19868
+ );
19750
19869
  }
19751
19870
  } catch (error) {
19752
19871
  deletionError = error;
@@ -19755,15 +19874,25 @@ function XViewScene({
19755
19874
  try {
19756
19875
  const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
19757
19876
  if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
19758
- const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(ancestryIdToDelete));
19877
+ const hasInViewDb = viewDbResponse.data.some(
19878
+ (anc) => String(anc.ancestry_id) === String(ancestryIdToDelete)
19879
+ );
19759
19880
  if (hasInViewDb) {
19760
- const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete));
19761
- const fallbackResult = await save_view_data(ancestry_save_url, updatedViewDb);
19881
+ const updatedViewDb = viewDbResponse.data.filter(
19882
+ (anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete)
19883
+ );
19884
+ const fallbackResult = await save_view_data(
19885
+ ancestry_save_url,
19886
+ updatedViewDb
19887
+ );
19762
19888
  if (fallbackResult.success) success = true;
19763
19889
  }
19764
19890
  }
19765
19891
  } catch (fallbackErr) {
19766
- console.error("Falha ao limpar c\xF3pia residual da View DB:", fallbackErr);
19892
+ console.error(
19893
+ "Falha ao limpar c\xF3pia residual da View DB:",
19894
+ fallbackErr
19895
+ );
19767
19896
  }
19768
19897
  }
19769
19898
  if (!success && deletionError) {
@@ -19941,23 +20070,28 @@ function XViewScene({
19941
20070
  ...sceneDataRef.current,
19942
20071
  nodes: sceneDataRef.current.nodes || [],
19943
20072
  links: sceneDataRef.current.links || [],
19944
- quest_nodes: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || sceneDataRef.current.quest_nodes || [],
19945
- quest_links: ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || sceneDataRef.current.quest_links || [],
19946
- quest_counter: sceneDataRef.current.quest_counter || 1,
20073
+ quest_counter: sceneDataRef.current.quest_counter || 1
20074
+ };
20075
+ delete sceneFileData.quest_nodes;
20076
+ delete sceneFileData.quest_links;
20077
+ delete sceneFileData.milestones;
20078
+ const questFileData = {
20079
+ nodes: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || sceneDataRef.current.quest_nodes || [],
20080
+ links: ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || sceneDataRef.current.quest_links || [],
19947
20081
  milestones: newMilestones
19948
20082
  };
19949
20083
  try {
19950
20084
  await save_view_data(sceneSaveUrl, sceneFileData);
20085
+ const questSaveUrl = sceneSaveUrl.replace(
20086
+ "x_view_scenes",
20087
+ "x_view_quests"
20088
+ );
20089
+ await save_view_data(questSaveUrl, questFileData);
19951
20090
  } catch (error) {
19952
20091
  console.error("Erro ao salvar milestones:", error);
19953
20092
  }
19954
20093
  },
19955
- [
19956
- sceneConfigId,
19957
- sceneSaveUrl,
19958
- save_view_data,
19959
- viewParams == null ? void 0 : viewParams.type
19960
- ]
20094
+ [sceneConfigId, sceneSaveUrl, save_view_data, viewParams == null ? void 0 : viewParams.type]
19961
20095
  );
19962
20096
  const handleSaveCurrentView = useCallback7(async () => {
19963
20097
  var _a2, _b2, _c2;
@@ -19991,13 +20125,25 @@ function XViewScene({
19991
20125
  ...sceneDataRef.current,
19992
20126
  nodes: currentNodes,
19993
20127
  links: currentLinks,
19994
- quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
19995
- quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || [],
19996
- quest_counter: sceneDataRef.current.quest_counter || 1,
20128
+ quest_counter: sceneDataRef.current.quest_counter || 1
20129
+ };
20130
+ delete sceneFileData.quest_nodes;
20131
+ delete sceneFileData.quest_links;
20132
+ delete sceneFileData.milestones;
20133
+ const questFileData = {
20134
+ nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
20135
+ links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || [],
19997
20136
  milestones: sceneDataRef.current.milestones || []
19998
20137
  };
19999
20138
  try {
20000
20139
  await save_view_data(sceneSaveUrl, sceneFileData);
20140
+ if (isView) {
20141
+ const questSaveUrl = sceneSaveUrl.replace(
20142
+ "x_view_scenes",
20143
+ "x_view_quests"
20144
+ );
20145
+ await save_view_data(questSaveUrl, questFileData);
20146
+ }
20001
20147
  } catch (error) {
20002
20148
  console.error("Erro na chamada de save_view_data:", error);
20003
20149
  }
@@ -20114,7 +20260,12 @@ function XViewScene({
20114
20260
  if (isUiClear) {
20115
20261
  const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
20116
20262
  if (!isView) return;
20117
- const { graphGroup, glowTexture, controls: sceneControls, nodeObjects } = stateRef.current;
20263
+ const {
20264
+ graphGroup,
20265
+ glowTexture,
20266
+ controls: sceneControls,
20267
+ nodeObjects
20268
+ } = stateRef.current;
20118
20269
  if (graphGroup) {
20119
20270
  let ghostPosition = sceneControls.target.clone();
20120
20271
  const existingNodes = Object.values(nodeObjects);
@@ -20170,7 +20321,12 @@ function XViewScene({
20170
20321
  setQuestMode({ isActive: true });
20171
20322
  }
20172
20323
  }
20173
- const isArrowKey = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key);
20324
+ const isArrowKey = [
20325
+ "ArrowUp",
20326
+ "ArrowDown",
20327
+ "ArrowLeft",
20328
+ "ArrowRight"
20329
+ ].includes(event.key);
20174
20330
  if (isArrowKey) {
20175
20331
  const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_d2 = context.versionMode) == null ? void 0 : _d2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isBoardsOpen && !isSidebarOpen && !isMilestoneManagerOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
20176
20332
  if (isUiClear) {
@@ -20216,7 +20372,12 @@ function XViewScene({
20216
20372
  if (isLoading || status === "loading" || permissionStatus === "loading") {
20217
20373
  return /* @__PURE__ */ React32.createElement(LoadingScreen, null);
20218
20374
  }
20219
- const overlayHiddenStyle = questTreeMode.isActive ? { opacity: 0, pointerEvents: "none", transform: "translateX(30px)", transition: "all 300ms ease-in-out" } : {};
20375
+ const overlayHiddenStyle = questTreeMode.isActive ? {
20376
+ opacity: 0,
20377
+ pointerEvents: "none",
20378
+ transform: "translateX(30px)",
20379
+ transition: "all 300ms ease-in-out"
20380
+ } : {};
20220
20381
  if (permissionStatus === "denied") {
20221
20382
  return /* @__PURE__ */ React32.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React32.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React32.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React32.createElement(
20222
20383
  "svg",
@@ -20681,18 +20842,12 @@ function XViewScene({
20681
20842
  data: multiContextMenu,
20682
20843
  userRole: userPermissionRole,
20683
20844
  onClose: () => setMultiContextMenu((prev) => ({ ...prev, visible: false })),
20684
- onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(
20685
- actionHandlerContext,
20686
- ids
20687
- ),
20845
+ onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(actionHandlerContext, ids),
20688
20846
  onDismissOtherNodes: (ids) => userActionHandlers.handleDismissOtherMultipleNodes(
20689
20847
  actionHandlerContext,
20690
20848
  ids
20691
20849
  ),
20692
- onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(
20693
- actionHandlerContext,
20694
- ids
20695
- )
20850
+ onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
20696
20851
  }
20697
20852
  ),
20698
20853
  /* @__PURE__ */ React32.createElement(
@@ -20845,7 +21000,7 @@ async function save_view_data_logic(db_services, filename, data) {
20845
21000
  }
20846
21001
  }
20847
21002
  async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
20848
- var _a, _b;
21003
+ var _a, _b, _c;
20849
21004
  try {
20850
21005
  if (!session || !session.user) {
20851
21006
  return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
@@ -20868,28 +21023,44 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
20868
21023
  parentDbObjects.push({ db_id: scene_config, owner_id });
20869
21024
  }
20870
21025
  }
21026
+ const isView = type && type.toLowerCase() === "view";
20871
21027
  const parentResponsesPromises = parentDbObjects.map(
20872
21028
  (db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
20873
21029
  );
21030
+ if (isView) {
21031
+ parentResponsesPromises.push(
21032
+ db_services.get_file(`x_view_quests/${owner_id}/${scene_config}`)
21033
+ );
21034
+ }
20874
21035
  const parentResponsesResults = await Promise.allSettled(parentResponsesPromises);
20875
21036
  const parentData = {};
21037
+ let questDataObj = null;
20876
21038
  for (let i = 0; i < parentResponsesResults.length; i++) {
20877
21039
  const result = parentResponsesResults[i];
21040
+ if (isView && i === parentResponsesResults.length - 1) {
21041
+ if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
21042
+ questDataObj = result.value.data;
21043
+ }
21044
+ continue;
21045
+ }
20878
21046
  const db_info = parentDbObjects[i];
20879
- if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
21047
+ if (result.status === "fulfilled" && ((_b = result.value) == null ? void 0 : _b.success)) {
20880
21048
  parentData[db_info.db_id] = result.value.data;
20881
21049
  } else {
20882
21050
  console.warn(
20883
21051
  `Arquivo pai n\xE3o carregado: ${db_info.db_id}. Pode ter sido deletado.`,
20884
- result.status === "rejected" ? result.reason : (_b = result.value) == null ? void 0 : _b.error
21052
+ result.status === "rejected" ? result.reason : (_c = result.value) == null ? void 0 : _c.error
20885
21053
  );
20886
21054
  }
20887
21055
  }
20888
- if (type && type.toLowerCase() === "view") {
21056
+ const currentQuestNodes = (questDataObj == null ? void 0 : questDataObj.nodes) || sceneData.quest_nodes || [];
21057
+ const currentQuestLinks = (questDataObj == null ? void 0 : questDataObj.links) || sceneData.quest_links || [];
21058
+ const currentMilestones = (questDataObj == null ? void 0 : questDataObj.milestones) || sceneData.milestones || [];
21059
+ if (isView) {
20889
21060
  parentData[scene_config] = {
20890
21061
  dataset_name: "Quests Internas (View)",
20891
- nodes: sceneData.quest_nodes || [],
20892
- links: sceneData.quest_links || []
21062
+ nodes: currentQuestNodes,
21063
+ links: currentQuestLinks
20893
21064
  };
20894
21065
  }
20895
21066
  const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
@@ -20921,7 +21092,12 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
20921
21092
  const validatedSceneData = {
20922
21093
  ...sceneData,
20923
21094
  nodes: validatedNodes,
20924
- links: validatedLinks
21095
+ links: validatedLinks,
21096
+ // Re-injetando no validated para que o restante do sistema (e.g. XViewScene local state)
21097
+ // continue acessando as quests sem perceber a separação física
21098
+ quest_nodes: currentQuestNodes,
21099
+ quest_links: currentQuestLinks,
21100
+ milestones: currentMilestones
20925
21101
  };
20926
21102
  const ancestryFilePaths = [];
20927
21103
  ancestryFilePaths.push({