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

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