@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.js CHANGED
@@ -15789,7 +15789,11 @@ function XViewScene({
15789
15789
  };
15790
15790
  const tweenToTarget = (0, import_react33.useCallback)(
15791
15791
  (target, zoomFactor = 1, forcedDirection = null) => {
15792
- const { camera: sceneCamera, controls: sceneControls, tweenGroup } = stateRef.current;
15792
+ const {
15793
+ camera: sceneCamera,
15794
+ controls: sceneControls,
15795
+ tweenGroup
15796
+ } = stateRef.current;
15793
15797
  if (!sceneCamera || !sceneControls || !tweenGroup) return;
15794
15798
  const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
15795
15799
  const controlsTween = new import_tween2.Tween(sceneControls.target).to(targetPos, 1500).easing(import_tween2.Easing.Cubic.Out);
@@ -16346,341 +16350,372 @@ function XViewScene({
16346
16350
  },
16347
16351
  []
16348
16352
  );
16349
- const handleActivateReshapeLens = (0, import_react33.useCallback)(({ type, columns, centerNodeId }) => {
16350
- const { nodeObjects, tweenGroup, camera, controls } = stateRef.current;
16351
- if (!nodeObjects || !tweenGroup || !camera || !controls) return;
16352
- const activeNodeIds = Object.keys(nodeObjects);
16353
- if (activeNodeIds.length === 0) return;
16354
- let sumX = 0;
16355
- let sumY = 0;
16356
- let nodeCount = 0;
16357
- activeNodeIds.forEach((id) => {
16358
- const mesh = nodeObjects[id];
16359
- if (mesh && mesh.material) {
16360
- const opacityTween = new import_tween2.Tween(mesh.material).to({ opacity: 1 }, 1200).easing(import_tween2.Easing.Cubic.Out);
16361
- tweenGroup.add(opacityTween);
16362
- opacityTween.start();
16363
- }
16364
- if (mesh && mesh.userData && mesh.userData.labelObject) {
16365
- mesh.userData.labelObject.visible = true;
16366
- }
16367
- });
16368
- if (type === "Column") {
16369
- const colSpacing = 80;
16370
- const rowSpacing = 80;
16371
- const numCols = columns || 4;
16372
- activeNodeIds.forEach((id, index) => {
16373
- const mesh = nodeObjects[id];
16374
- const col = index % numCols;
16375
- const row = Math.floor(index / numCols);
16376
- const targetX = (col - (numCols - 1) / 2) * colSpacing;
16377
- const targetY = -(row * rowSpacing) + 50;
16378
- const posTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16379
- tweenGroup.add(posTween);
16380
- posTween.start();
16381
- if (mesh.userData.labelObject) {
16382
- const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16383
- const lblTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16384
- tweenGroup.add(lblTween);
16385
- lblTween.start();
16386
- }
16387
- sumX += targetX;
16388
- sumY += targetY;
16389
- nodeCount++;
16390
- });
16391
- } else if (type === "Circle") {
16392
- const total = activeNodeIds.length;
16393
- const radius = Math.max(80, total * 8);
16394
- activeNodeIds.forEach((id, index) => {
16353
+ const handleActivateReshapeLens = (0, import_react33.useCallback)(
16354
+ ({ type, columns, centerNodeId }) => {
16355
+ const { nodeObjects, tweenGroup, camera, controls } = stateRef.current;
16356
+ if (!nodeObjects || !tweenGroup || !camera || !controls) return;
16357
+ const activeNodeIds = Object.keys(nodeObjects);
16358
+ if (activeNodeIds.length === 0) return;
16359
+ let sumX = 0;
16360
+ let sumY = 0;
16361
+ let nodeCount = 0;
16362
+ activeNodeIds.forEach((id) => {
16395
16363
  const mesh = nodeObjects[id];
16396
- const angle = index / total * Math.PI * 2;
16397
- const targetX = Math.cos(angle) * radius;
16398
- const targetY = Math.sin(angle) * radius;
16399
- const posTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16400
- tweenGroup.add(posTween);
16401
- posTween.start();
16402
- if (mesh.userData.labelObject) {
16403
- const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16404
- const lblTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16405
- tweenGroup.add(lblTween);
16406
- lblTween.start();
16407
- }
16408
- sumX += targetX;
16409
- sumY += targetY;
16410
- nodeCount++;
16411
- });
16412
- } else if (type === "Star") {
16413
- const centerMesh = centerNodeId ? nodeObjects[String(centerNodeId)] : null;
16414
- const orbitingNodeIds = activeNodeIds.filter((id) => id !== String(centerNodeId));
16415
- const totalOrbiting = orbitingNodeIds.length;
16416
- const radius = Math.max(80, totalOrbiting * 10);
16417
- if (centerMesh) {
16418
- const posTween = new import_tween2.Tween(centerMesh.position).to({ x: 0, y: 0, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16419
- tweenGroup.add(posTween);
16420
- posTween.start();
16421
- if (centerMesh.userData.labelObject) {
16422
- const labelTarget = new THREE3.Vector3(0, 0, 0).add(centerMesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16423
- const lblTween = new import_tween2.Tween(centerMesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16424
- tweenGroup.add(lblTween);
16425
- lblTween.start();
16364
+ if (mesh && mesh.material) {
16365
+ const opacityTween = new import_tween2.Tween(mesh.material).to({ opacity: 1 }, 1200).easing(import_tween2.Easing.Cubic.Out);
16366
+ tweenGroup.add(opacityTween);
16367
+ opacityTween.start();
16368
+ }
16369
+ if (mesh && mesh.userData && mesh.userData.labelObject) {
16370
+ mesh.userData.labelObject.visible = true;
16426
16371
  }
16427
- sumX += 0;
16428
- sumY += 0;
16429
- nodeCount++;
16430
- }
16431
- orbitingNodeIds.forEach((id, index) => {
16432
- const mesh = nodeObjects[id];
16433
- const angle = totalOrbiting > 0 ? index / totalOrbiting * Math.PI * 2 : 0;
16434
- const targetX = Math.cos(angle) * radius;
16435
- const targetY = Math.sin(angle) * radius;
16436
- const posTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16437
- tweenGroup.add(posTween);
16438
- posTween.start();
16439
- if (mesh.userData.labelObject) {
16440
- const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16441
- const lblTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16442
- tweenGroup.add(lblTween);
16443
- lblTween.start();
16444
- }
16445
- sumX += targetX;
16446
- sumY += targetY;
16447
- nodeCount++;
16448
16372
  });
16449
- }
16450
- if (nodeCount > 0) {
16451
- const centerX = sumX / nodeCount;
16452
- const centerY = sumY / nodeCount;
16453
- const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16454
- const targetTween = new import_tween2.Tween(controls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16455
- tweenGroup.add(targetTween);
16456
- targetTween.start();
16457
- let zoomZ = 140;
16458
16373
  if (type === "Column") {
16459
- const numRows = Math.ceil(nodeCount / (columns || 4));
16460
- zoomZ = Math.max(140, numRows * 50);
16461
- } else if (type === "Circle" || type === "Star") {
16462
- const radius = Math.max(80, nodeCount * 8);
16463
- zoomZ = radius * 2.5;
16464
- }
16465
- const camTween = new import_tween2.Tween(camera.position).to({ x: targetFocus.x, y: targetFocus.y, z: zoomZ }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16466
- tweenGroup.add(camTween);
16467
- camTween.start();
16468
- }
16469
- }, []);
16470
- const handleActivateQuestLens = (0, import_react33.useCallback)(({ assigneeId, status: status2, milestoneId }) => {
16471
- var _a2;
16472
- const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
16473
- if (!nodeObjects || !tweenGroup || !graphGroup) return;
16474
- const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
16475
- const filteredQuests = allQuests.filter((q) => {
16476
- const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
16477
- const matchStatus = !status2 ? q.status !== "Done" : String(q.status) === String(status2);
16478
- const matchMilestone = !milestoneId || q.milestone_ids && q.milestone_ids.includes(milestoneId);
16479
- return matchAssignee && matchStatus && matchMilestone;
16480
- });
16481
- if (filteredQuests.length === 0) {
16482
- console.warn("Nenhuma quest encontrada para os filtros selecionados.");
16483
- return;
16484
- }
16485
- const questsByStatus = {
16486
- Backlog: [],
16487
- "In Progress": [],
16488
- Review: [],
16489
- Done: []
16490
- };
16491
- filteredQuests.forEach((q) => {
16492
- if (questsByStatus[q.status]) {
16493
- questsByStatus[q.status].push(q);
16374
+ const colSpacing = 80;
16375
+ const rowSpacing = 80;
16376
+ const numCols = columns || 4;
16377
+ activeNodeIds.forEach((id, index) => {
16378
+ const mesh = nodeObjects[id];
16379
+ const col = index % numCols;
16380
+ const row = Math.floor(index / numCols);
16381
+ const targetX = (col - (numCols - 1) / 2) * colSpacing;
16382
+ const targetY = -(row * rowSpacing) + 50;
16383
+ const posTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16384
+ tweenGroup.add(posTween);
16385
+ posTween.start();
16386
+ if (mesh.userData.labelObject) {
16387
+ const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(
16388
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16389
+ );
16390
+ const lblTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16391
+ tweenGroup.add(lblTween);
16392
+ lblTween.start();
16393
+ }
16394
+ sumX += targetX;
16395
+ sumY += targetY;
16396
+ nodeCount++;
16397
+ });
16398
+ } else if (type === "Circle") {
16399
+ const total = activeNodeIds.length;
16400
+ const radius = Math.max(80, total * 8);
16401
+ activeNodeIds.forEach((id, index) => {
16402
+ const mesh = nodeObjects[id];
16403
+ const angle = index / total * Math.PI * 2;
16404
+ const targetX = Math.cos(angle) * radius;
16405
+ const targetY = Math.sin(angle) * radius;
16406
+ const posTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16407
+ tweenGroup.add(posTween);
16408
+ posTween.start();
16409
+ if (mesh.userData.labelObject) {
16410
+ const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(
16411
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16412
+ );
16413
+ const lblTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16414
+ tweenGroup.add(lblTween);
16415
+ lblTween.start();
16416
+ }
16417
+ sumX += targetX;
16418
+ sumY += targetY;
16419
+ nodeCount++;
16420
+ });
16421
+ } else if (type === "Star") {
16422
+ const centerMesh = centerNodeId ? nodeObjects[String(centerNodeId)] : null;
16423
+ const orbitingNodeIds = activeNodeIds.filter(
16424
+ (id) => id !== String(centerNodeId)
16425
+ );
16426
+ const totalOrbiting = orbitingNodeIds.length;
16427
+ const radius = Math.max(80, totalOrbiting * 10);
16428
+ if (centerMesh) {
16429
+ const posTween = new import_tween2.Tween(centerMesh.position).to({ x: 0, y: 0, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16430
+ tweenGroup.add(posTween);
16431
+ posTween.start();
16432
+ if (centerMesh.userData.labelObject) {
16433
+ const labelTarget = new THREE3.Vector3(0, 0, 0).add(
16434
+ centerMesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16435
+ );
16436
+ const lblTween = new import_tween2.Tween(centerMesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16437
+ tweenGroup.add(lblTween);
16438
+ lblTween.start();
16439
+ }
16440
+ sumX += 0;
16441
+ sumY += 0;
16442
+ nodeCount++;
16443
+ }
16444
+ orbitingNodeIds.forEach((id, index) => {
16445
+ const mesh = nodeObjects[id];
16446
+ const angle = totalOrbiting > 0 ? index / totalOrbiting * Math.PI * 2 : 0;
16447
+ const targetX = Math.cos(angle) * radius;
16448
+ const targetY = Math.sin(angle) * radius;
16449
+ const posTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16450
+ tweenGroup.add(posTween);
16451
+ posTween.start();
16452
+ if (mesh.userData.labelObject) {
16453
+ const labelTarget = new THREE3.Vector3(targetX, targetY, 0).add(
16454
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16455
+ );
16456
+ const lblTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTarget, 1500).easing(import_tween2.Easing.Cubic.InOut);
16457
+ tweenGroup.add(lblTween);
16458
+ lblTween.start();
16459
+ }
16460
+ sumX += targetX;
16461
+ sumY += targetY;
16462
+ nodeCount++;
16463
+ });
16494
16464
  }
16495
- });
16496
- const questTimeInfos = /* @__PURE__ */ new Map();
16497
- const allActiveTimePoints = /* @__PURE__ */ new Set();
16498
- filteredQuests.forEach((q) => {
16499
- const info = parseDateProp(q.Date);
16500
- questTimeInfos.set(String(q.id), info);
16501
- if (!info.isUndated) {
16502
- allActiveTimePoints.add(info.startDate.getTime());
16503
- if (info.endDate && info.type === "interval") {
16504
- allActiveTimePoints.add(info.endDate.getTime());
16505
- }
16465
+ if (nodeCount > 0) {
16466
+ const centerX = sumX / nodeCount;
16467
+ const centerY = sumY / nodeCount;
16468
+ const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16469
+ const targetTween = new import_tween2.Tween(controls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16470
+ tweenGroup.add(targetTween);
16471
+ targetTween.start();
16472
+ let zoomZ = 140;
16473
+ if (type === "Column") {
16474
+ const numRows = Math.ceil(nodeCount / (columns || 4));
16475
+ zoomZ = Math.max(140, numRows * 50);
16476
+ } else if (type === "Circle" || type === "Star") {
16477
+ const radius = Math.max(80, nodeCount * 8);
16478
+ zoomZ = radius * 2.5;
16479
+ }
16480
+ const camTween = new import_tween2.Tween(camera.position).to({ x: targetFocus.x, y: targetFocus.y, z: zoomZ }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16481
+ tweenGroup.add(camTween);
16482
+ camTween.start();
16506
16483
  }
16507
- });
16508
- const sortedTimePoints = Array.from(allActiveTimePoints).sort((a, b) => a - b);
16509
- const timeToYMap = /* @__PURE__ */ new Map();
16510
- sortedTimePoints.forEach((ms, idx) => {
16511
- timeToYMap.set(ms, idx * TIMELINE_LAYER_SPACING_Y);
16512
- });
16513
- const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
16514
- let sumX = 0;
16515
- let sumY = 0;
16516
- let questCount = 0;
16517
- const positionGroups = /* @__PURE__ */ new Map();
16518
- const NODE_X_GAP = 22;
16519
- QUEST_STATUS_ORDER.forEach((statusName) => {
16520
- const questsInCol = questsByStatus[statusName];
16521
- questsInCol.forEach((q, rowIndex) => {
16522
- const timeInfo = questTimeInfos.get(String(q.id)) || { isUndated: true };
16523
- let nodeY;
16524
- if (!timeInfo.isUndated) {
16525
- nodeY = timeToYMap.get(timeInfo.startDate.getTime());
16526
- } else {
16527
- const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16528
- nodeY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16529
- }
16530
- const posKey = `${statusName}_${nodeY}`;
16531
- if (!positionGroups.has(posKey)) positionGroups.set(posKey, []);
16532
- positionGroups.get(posKey).push(String(q.id));
16484
+ },
16485
+ []
16486
+ );
16487
+ const handleActivateQuestLens = (0, import_react33.useCallback)(
16488
+ ({ assigneeId, status: status2, milestoneId }) => {
16489
+ var _a2;
16490
+ const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
16491
+ if (!nodeObjects || !tweenGroup || !graphGroup) return;
16492
+ const allQuests = ((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || [];
16493
+ const filteredQuests = allQuests.filter((q) => {
16494
+ const matchAssignee = !assigneeId || String(q.assignee_id) === String(assigneeId);
16495
+ const matchStatus = !status2 ? q.status !== "Done" : String(q.status) === String(status2);
16496
+ const matchMilestone = !milestoneId || q.milestone_ids && q.milestone_ids.includes(milestoneId);
16497
+ return matchAssignee && matchStatus && matchMilestone;
16533
16498
  });
16534
- });
16535
- Object.values(nodeObjects).forEach((mesh) => {
16536
- const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
16537
- if (oldLabel) {
16538
- mesh.remove(oldLabel);
16539
- if (oldLabel.material) oldLabel.material.dispose();
16540
- }
16541
- if (mesh.userData.timelineIntervalBar) {
16542
- if (graphGroup) graphGroup.remove(mesh.userData.timelineIntervalBar);
16543
- mesh.userData.timelineIntervalBar = null;
16544
- }
16545
- if (mesh.userData.timelineEndLabel) {
16546
- if (graphGroup) graphGroup.remove(mesh.userData.timelineEndLabel);
16547
- mesh.userData.timelineEndLabel = null;
16548
- }
16549
- });
16550
- const nonFilteredNodeIds = Object.keys(nodeObjects).filter((id) => !filteredQuests.some((q) => String(q.id) === String(id)));
16551
- const COMMON_START_X = startX - 100;
16552
- const COMMON_COL_SPACING = 30;
16553
- const COMMON_ROW_SPACING = 35;
16554
- const MAX_COMMON_ROWS = 15;
16555
- nonFilteredNodeIds.forEach((id, idx) => {
16556
- const mesh = nodeObjects[id];
16557
- if (!mesh) return;
16558
- const col = Math.floor(idx / MAX_COMMON_ROWS);
16559
- const row = idx % MAX_COMMON_ROWS;
16560
- const targetX = COMMON_START_X - col * COMMON_COL_SPACING;
16561
- const targetY = -(row * COMMON_ROW_SPACING) + 50;
16562
- const targetZ = 0;
16563
- if (mesh.material) {
16564
- const opacityTween = new import_tween2.Tween(mesh.material).to({ opacity: 1 }, 1200).easing(import_tween2.Easing.Cubic.Out);
16565
- tweenGroup.add(opacityTween);
16566
- opacityTween.start();
16567
- }
16568
- if (mesh.userData.labelObject) {
16569
- mesh.userData.labelObject.visible = true;
16570
- const labelTargetPos = new THREE3.Vector3(targetX, targetY, targetZ).add(
16571
- mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16572
- );
16573
- const labelTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(import_tween2.Easing.Cubic.InOut);
16574
- tweenGroup.add(labelTween);
16575
- labelTween.start();
16499
+ if (filteredQuests.length === 0) {
16500
+ console.warn("Nenhuma quest encontrada para os filtros selecionados.");
16501
+ return;
16576
16502
  }
16577
- const sideTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: targetZ }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16578
- tweenGroup.add(sideTween);
16579
- sideTween.start();
16580
- });
16581
- filteredQuests.forEach((q) => {
16582
- const mesh = nodeObjects[String(q.id)];
16583
- if (mesh) {
16584
- if (mesh.material) {
16585
- const fadeInTween = new import_tween2.Tween(mesh.material).to({ opacity: 1 }, 1200).easing(import_tween2.Easing.Cubic.Out);
16586
- tweenGroup.add(fadeInTween);
16587
- fadeInTween.start();
16503
+ const questsByStatus = {
16504
+ Backlog: [],
16505
+ "In Progress": [],
16506
+ Review: [],
16507
+ Done: []
16508
+ };
16509
+ filteredQuests.forEach((q) => {
16510
+ if (questsByStatus[q.status]) {
16511
+ questsByStatus[q.status].push(q);
16588
16512
  }
16589
- if (mesh.userData.labelObject) {
16590
- mesh.userData.labelObject.visible = true;
16513
+ });
16514
+ const questTimeInfos = /* @__PURE__ */ new Map();
16515
+ const allActiveTimePoints = /* @__PURE__ */ new Set();
16516
+ filteredQuests.forEach((q) => {
16517
+ const info = parseDateProp(q.Date);
16518
+ questTimeInfos.set(String(q.id), info);
16519
+ if (!info.isUndated) {
16520
+ allActiveTimePoints.add(info.startDate.getTime());
16521
+ if (info.endDate && info.type === "interval") {
16522
+ allActiveTimePoints.add(info.endDate.getTime());
16523
+ }
16591
16524
  }
16592
- }
16593
- });
16594
- QUEST_STATUS_ORDER.forEach((statusName, colIndex) => {
16595
- if (status2 && status2 !== statusName) return;
16596
- const questsInCol = questsByStatus[statusName];
16597
- const colX = startX + colIndex * QUEST_LENS_COLUMN_SPACING;
16598
- questsInCol.forEach((q, rowIndex) => {
16599
- const nodeId = String(q.id);
16600
- let mesh = nodeObjects[nodeId];
16601
- const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
16602
- let targetY;
16603
- if (!timeInfo.isUndated) {
16604
- targetY = timeToYMap.get(timeInfo.startDate.getTime());
16605
- } else {
16606
- const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16607
- targetY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16608
- }
16609
- const posKey = `${statusName}_${targetY}`;
16610
- const group = positionGroups.get(posKey) || [nodeId];
16611
- const indexInGroup = group.indexOf(nodeId);
16612
- const xOffset = (indexInGroup - (group.length - 1) / 2) * NODE_X_GAP;
16613
- const finalX = colX + xOffset;
16614
- if (!mesh) {
16615
- mesh = addOrUpdateNodeMesh(q, new THREE3.Vector3(finalX, 150, 0), true);
16616
- }
16617
- const lensTween = new import_tween2.Tween(mesh.position).to({ x: finalX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16618
- tweenGroup.add(lensTween);
16619
- lensTween.start();
16620
- sumX += finalX;
16621
- sumY += targetY;
16622
- questCount++;
16623
- if (!timeInfo.isUndated && timeInfo.label && !mesh.getObjectByName("questDateLabel")) {
16624
- const dateSprite = createTextSprite(timeInfo.label, 36);
16625
- dateSprite.name = "questDateLabel";
16626
- dateSprite.position.set(0, -5.5, 0);
16627
- mesh.add(dateSprite);
16628
- }
16629
- if (timeInfo.type === "interval" && timeToYMap.has(timeInfo.endDate.getTime())) {
16630
- const endY = timeToYMap.get(timeInfo.endDate.getTime());
16631
- if (Math.abs(endY - targetY) > 0.1) {
16632
- const barHeight = Math.abs(endY - targetY);
16633
- const barGeometry = new THREE3.CylinderGeometry(
16634
- TIMELINE_INTERVAL_BAR_RADIUS,
16635
- TIMELINE_INTERVAL_BAR_RADIUS,
16636
- 1,
16637
- 16
16638
- );
16639
- const barMaterial = new THREE3.MeshStandardMaterial({
16640
- color: TIMELINE_GOLD_COLOR,
16641
- emissive: 12092939,
16642
- emissiveIntensity: 0.4,
16643
- transparent: true,
16644
- opacity: TIMELINE_INTERVAL_BAR_OPACITY,
16645
- roughness: 0.3,
16646
- metalness: 0.8
16647
- });
16648
- const intervalBar = new THREE3.Mesh(barGeometry, barMaterial);
16649
- intervalBar.userData.associatedNodeId = mesh.userData.id;
16650
- intervalBar.position.set(finalX, (targetY + endY) / 2, -0.5);
16651
- intervalBar.scale.y = barHeight;
16652
- graphGroup.add(intervalBar);
16653
- mesh.userData.timelineIntervalBar = intervalBar;
16654
- const endLabel = createTextSprite(timeInfo.label.split(" - ")[1] || "", 30);
16655
- endLabel.name = "timelineEndLabel";
16656
- endLabel.position.set(finalX, endY + 4, 0);
16657
- graphGroup.add(endLabel);
16658
- mesh.userData.timelineEndLabel = endLabel;
16525
+ });
16526
+ const sortedTimePoints = Array.from(allActiveTimePoints).sort(
16527
+ (a, b) => a - b
16528
+ );
16529
+ const timeToYMap = /* @__PURE__ */ new Map();
16530
+ sortedTimePoints.forEach((ms, idx) => {
16531
+ timeToYMap.set(ms, idx * TIMELINE_LAYER_SPACING_Y);
16532
+ });
16533
+ const startX = -((QUEST_STATUS_ORDER.length - 1) * QUEST_LENS_COLUMN_SPACING) / 2;
16534
+ let sumX = 0;
16535
+ let sumY = 0;
16536
+ let questCount = 0;
16537
+ const positionGroups = /* @__PURE__ */ new Map();
16538
+ const NODE_X_GAP = 22;
16539
+ QUEST_STATUS_ORDER.forEach((statusName) => {
16540
+ const questsInCol = questsByStatus[statusName];
16541
+ questsInCol.forEach((q, rowIndex) => {
16542
+ const timeInfo = questTimeInfos.get(String(q.id)) || {
16543
+ isUndated: true
16544
+ };
16545
+ let nodeY;
16546
+ if (!timeInfo.isUndated) {
16547
+ nodeY = timeToYMap.get(timeInfo.startDate.getTime());
16548
+ } else {
16549
+ const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16550
+ nodeY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16659
16551
  }
16552
+ const posKey = `${statusName}_${nodeY}`;
16553
+ if (!positionGroups.has(posKey)) positionGroups.set(posKey, []);
16554
+ positionGroups.get(posKey).push(String(q.id));
16555
+ });
16556
+ });
16557
+ Object.values(nodeObjects).forEach((mesh) => {
16558
+ const oldLabel = mesh.getObjectByName("questDateLabel") || mesh.getObjectByName("timelineLabel");
16559
+ if (oldLabel) {
16560
+ mesh.remove(oldLabel);
16561
+ if (oldLabel.material) oldLabel.material.dispose();
16562
+ }
16563
+ if (mesh.userData.timelineIntervalBar) {
16564
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineIntervalBar);
16565
+ mesh.userData.timelineIntervalBar = null;
16566
+ }
16567
+ if (mesh.userData.timelineEndLabel) {
16568
+ if (graphGroup) graphGroup.remove(mesh.userData.timelineEndLabel);
16569
+ mesh.userData.timelineEndLabel = null;
16570
+ }
16571
+ });
16572
+ const nonFilteredNodeIds = Object.keys(nodeObjects).filter(
16573
+ (id) => !filteredQuests.some((q) => String(q.id) === String(id))
16574
+ );
16575
+ const COMMON_START_X = startX - 100;
16576
+ const COMMON_COL_SPACING = 30;
16577
+ const COMMON_ROW_SPACING = 35;
16578
+ const MAX_COMMON_ROWS = 15;
16579
+ nonFilteredNodeIds.forEach((id, idx) => {
16580
+ const mesh = nodeObjects[id];
16581
+ if (!mesh) return;
16582
+ const col = Math.floor(idx / MAX_COMMON_ROWS);
16583
+ const row = idx % MAX_COMMON_ROWS;
16584
+ const targetX = COMMON_START_X - col * COMMON_COL_SPACING;
16585
+ const targetY = -(row * COMMON_ROW_SPACING) + 50;
16586
+ const targetZ = 0;
16587
+ if (mesh.material) {
16588
+ const opacityTween = new import_tween2.Tween(mesh.material).to({ opacity: 1 }, 1200).easing(import_tween2.Easing.Cubic.Out);
16589
+ tweenGroup.add(opacityTween);
16590
+ opacityTween.start();
16660
16591
  }
16661
16592
  if (mesh.userData.labelObject) {
16662
- const labelTargetPos = new THREE3.Vector3(finalX, targetY, 0).add(
16663
- mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16664
- );
16593
+ mesh.userData.labelObject.visible = true;
16594
+ const labelTargetPos = new THREE3.Vector3(
16595
+ targetX,
16596
+ targetY,
16597
+ targetZ
16598
+ ).add(mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0));
16665
16599
  const labelTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(import_tween2.Easing.Cubic.InOut);
16666
16600
  tweenGroup.add(labelTween);
16667
16601
  labelTween.start();
16668
16602
  }
16603
+ const sideTween = new import_tween2.Tween(mesh.position).to({ x: targetX, y: targetY, z: targetZ }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16604
+ tweenGroup.add(sideTween);
16605
+ sideTween.start();
16669
16606
  });
16670
- });
16671
- if (questCount > 0) {
16672
- const { camera: sceneCamera, controls: sceneControls } = stateRef.current;
16673
- const centerX = sumX / questCount;
16674
- const centerY = sumY / questCount;
16675
- const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16676
- const targetTween = new import_tween2.Tween(sceneControls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16677
- tweenGroup.add(targetTween);
16678
- targetTween.start();
16679
- const camTween = new import_tween2.Tween(sceneCamera.position).to({ x: targetFocus.x, y: targetFocus.y, z: 140 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16680
- tweenGroup.add(camTween);
16681
- camTween.start();
16682
- }
16683
- }, [addOrUpdateNodeMesh]);
16607
+ filteredQuests.forEach((q) => {
16608
+ const mesh = nodeObjects[String(q.id)];
16609
+ if (mesh) {
16610
+ if (mesh.material) {
16611
+ const fadeInTween = new import_tween2.Tween(mesh.material).to({ opacity: 1 }, 1200).easing(import_tween2.Easing.Cubic.Out);
16612
+ tweenGroup.add(fadeInTween);
16613
+ fadeInTween.start();
16614
+ }
16615
+ if (mesh.userData.labelObject) {
16616
+ mesh.userData.labelObject.visible = true;
16617
+ }
16618
+ }
16619
+ });
16620
+ QUEST_STATUS_ORDER.forEach((statusName, colIndex) => {
16621
+ if (status2 && status2 !== statusName) return;
16622
+ const questsInCol = questsByStatus[statusName];
16623
+ const colX = startX + colIndex * QUEST_LENS_COLUMN_SPACING;
16624
+ questsInCol.forEach((q, rowIndex) => {
16625
+ const nodeId = String(q.id);
16626
+ let mesh = nodeObjects[nodeId];
16627
+ const timeInfo = questTimeInfos.get(nodeId) || { isUndated: true };
16628
+ let targetY;
16629
+ if (!timeInfo.isUndated) {
16630
+ targetY = timeToYMap.get(timeInfo.startDate.getTime());
16631
+ } else {
16632
+ const undatedOffset = sortedTimePoints.length > 0 ? sortedTimePoints.length * 5 : 0;
16633
+ targetY = -40 - rowIndex * QUEST_LENS_ROW_SPACING - undatedOffset;
16634
+ }
16635
+ const posKey = `${statusName}_${targetY}`;
16636
+ const group = positionGroups.get(posKey) || [nodeId];
16637
+ const indexInGroup = group.indexOf(nodeId);
16638
+ const xOffset = (indexInGroup - (group.length - 1) / 2) * NODE_X_GAP;
16639
+ const finalX = colX + xOffset;
16640
+ if (!mesh) {
16641
+ mesh = addOrUpdateNodeMesh(
16642
+ q,
16643
+ new THREE3.Vector3(finalX, 150, 0),
16644
+ true
16645
+ );
16646
+ }
16647
+ const lensTween = new import_tween2.Tween(mesh.position).to({ x: finalX, y: targetY, z: 0 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16648
+ tweenGroup.add(lensTween);
16649
+ lensTween.start();
16650
+ sumX += finalX;
16651
+ sumY += targetY;
16652
+ questCount++;
16653
+ if (!timeInfo.isUndated && timeInfo.label && !mesh.getObjectByName("questDateLabel")) {
16654
+ const dateSprite = createTextSprite(timeInfo.label, 36);
16655
+ dateSprite.name = "questDateLabel";
16656
+ dateSprite.position.set(0, -5.5, 0);
16657
+ mesh.add(dateSprite);
16658
+ }
16659
+ if (timeInfo.type === "interval" && timeToYMap.has(timeInfo.endDate.getTime())) {
16660
+ const endY = timeToYMap.get(timeInfo.endDate.getTime());
16661
+ if (Math.abs(endY - targetY) > 0.1) {
16662
+ const barHeight = Math.abs(endY - targetY);
16663
+ const barGeometry = new THREE3.CylinderGeometry(
16664
+ TIMELINE_INTERVAL_BAR_RADIUS,
16665
+ TIMELINE_INTERVAL_BAR_RADIUS,
16666
+ 1,
16667
+ 16
16668
+ );
16669
+ const barMaterial = new THREE3.MeshStandardMaterial({
16670
+ color: TIMELINE_GOLD_COLOR,
16671
+ emissive: 12092939,
16672
+ emissiveIntensity: 0.4,
16673
+ transparent: true,
16674
+ opacity: TIMELINE_INTERVAL_BAR_OPACITY,
16675
+ roughness: 0.3,
16676
+ metalness: 0.8
16677
+ });
16678
+ const intervalBar = new THREE3.Mesh(barGeometry, barMaterial);
16679
+ intervalBar.userData.associatedNodeId = mesh.userData.id;
16680
+ intervalBar.position.set(finalX, (targetY + endY) / 2, -0.5);
16681
+ intervalBar.scale.y = barHeight;
16682
+ graphGroup.add(intervalBar);
16683
+ mesh.userData.timelineIntervalBar = intervalBar;
16684
+ const endLabel = createTextSprite(
16685
+ timeInfo.label.split(" - ")[1] || "",
16686
+ 30
16687
+ );
16688
+ endLabel.name = "timelineEndLabel";
16689
+ endLabel.position.set(finalX, endY + 4, 0);
16690
+ graphGroup.add(endLabel);
16691
+ mesh.userData.timelineEndLabel = endLabel;
16692
+ }
16693
+ }
16694
+ if (mesh.userData.labelObject) {
16695
+ const labelTargetPos = new THREE3.Vector3(finalX, targetY, 0).add(
16696
+ mesh.userData.labelOffset || new THREE3.Vector3(0, 3.8, 0)
16697
+ );
16698
+ const labelTween = new import_tween2.Tween(mesh.userData.labelObject.position).to(labelTargetPos, 1500).easing(import_tween2.Easing.Cubic.InOut);
16699
+ tweenGroup.add(labelTween);
16700
+ labelTween.start();
16701
+ }
16702
+ });
16703
+ });
16704
+ if (questCount > 0) {
16705
+ const { camera: sceneCamera, controls: sceneControls } = stateRef.current;
16706
+ const centerX = sumX / questCount;
16707
+ const centerY = sumY / questCount;
16708
+ const targetFocus = new THREE3.Vector3(centerX, centerY, 0);
16709
+ const targetTween = new import_tween2.Tween(sceneControls.target).to({ x: targetFocus.x, y: targetFocus.y, z: targetFocus.z }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16710
+ tweenGroup.add(targetTween);
16711
+ targetTween.start();
16712
+ const camTween = new import_tween2.Tween(sceneCamera.position).to({ x: targetFocus.x, y: targetFocus.y, z: 140 }, 1500).easing(import_tween2.Easing.Cubic.InOut);
16713
+ tweenGroup.add(camTween);
16714
+ camTween.start();
16715
+ }
16716
+ },
16717
+ [addOrUpdateNodeMesh]
16718
+ );
16684
16719
  (0, import_react33.useEffect)(() => {
16685
16720
  if (!isInitialized || !sceneDataRef.current) return;
16686
16721
  const currentMount = mountRef.current;
@@ -17065,7 +17100,9 @@ function XViewScene({
17065
17100
  const clickedNodeId = String(clickedNode.userData.id);
17066
17101
  const parentId = String(currentSelectedParent);
17067
17102
  if (clickedNodeId === parentId) {
17068
- alert("Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo.");
17103
+ alert(
17104
+ "Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo."
17105
+ );
17069
17106
  return;
17070
17107
  }
17071
17108
  const parentInfo = stateRef.current.nodeIdToParentFileMap.get(clickedNodeId);
@@ -17414,7 +17451,11 @@ function XViewScene({
17414
17451
  ancestryData: ancestryDataRef.current
17415
17452
  });
17416
17453
  (_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
17417
- const { keysPressed, controls: sceneControls, camera: sceneCamera } = stateRef.current;
17454
+ const {
17455
+ keysPressed,
17456
+ controls: sceneControls,
17457
+ camera: sceneCamera
17458
+ } = stateRef.current;
17418
17459
  if (sceneControls && keysPressed) {
17419
17460
  const panSpeed = 1.5;
17420
17461
  const rotateSpeed = 0.02;
@@ -17438,10 +17479,18 @@ function XViewScene({
17438
17479
  offset.multiplyScalar(factor);
17439
17480
  sceneCamera.position.copy(sceneControls.target).add(offset);
17440
17481
  } else if (!isCtrl && !isShift && (dirX !== 0 || dirY !== 0)) {
17441
- const distance = sceneCamera.position.distanceTo(sceneControls.target);
17482
+ const distance = sceneCamera.position.distanceTo(
17483
+ sceneControls.target
17484
+ );
17442
17485
  const currentPanSpeed = panSpeed * (distance / 100);
17443
- const vecX = new THREE3.Vector3().setFromMatrixColumn(sceneCamera.matrix, 0);
17444
- const vecY = new THREE3.Vector3().setFromMatrixColumn(sceneCamera.matrix, 1);
17486
+ const vecX = new THREE3.Vector3().setFromMatrixColumn(
17487
+ sceneCamera.matrix,
17488
+ 0
17489
+ );
17490
+ const vecY = new THREE3.Vector3().setFromMatrixColumn(
17491
+ sceneCamera.matrix,
17492
+ 1
17493
+ );
17445
17494
  vecX.multiplyScalar(dirX * currentPanSpeed);
17446
17495
  vecY.multiplyScalar(dirY * currentPanSpeed);
17447
17496
  sceneCamera.position.add(vecX).add(vecY);
@@ -17838,115 +17887,143 @@ function XViewScene({
17838
17887
  const handleStartVersioning = (nodeData) => {
17839
17888
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
17840
17889
  };
17841
- const handleStartQuestQuick = (0, import_react33.useCallback)((questNode) => {
17842
- var _a2, _b2, _c2;
17843
- if (!questNode || !actionHandlerContext) return;
17844
- const allParentNodes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
17845
- const blockCheck = isQuestBlocked(questNode, allParentNodes);
17846
- if (blockCheck.isBlocked) {
17847
- alert(`Esta quest n\xE3o pode ser iniciada pois possui depend\xEAncias pendentes: ${blockCheck.pendingDependencies.map((d) => d.raw_title || d.name).join(", ")}`);
17848
- return;
17849
- }
17850
- const {
17851
- labelObject,
17852
- labelOffset,
17853
- aura,
17854
- borderRing,
17855
- timelineIntervalBar,
17856
- timelineEndLabel,
17857
- ...cleanQuestNode
17858
- } = questNode;
17859
- const newTimeline = [...cleanQuestNode.timeline || [], createTimelineEntry(
17860
- ((_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id) || "unknown",
17861
- `Status "In Progress" - Respons\xE1vel: ${((_b2 = session == null ? void 0 : session.user) == null ? void 0 : _b2.name) || "usu\xE1rio"}`,
17862
- "status_changed"
17863
- )];
17864
- const updatedNode = {
17865
- ...cleanQuestNode,
17866
- status: "In Progress",
17867
- color: "#eab308",
17868
- assignee_id: (_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.id,
17869
- timeline: newTimeline
17870
- };
17871
- if (userActionHandlers.handleSaveNodeDetails) {
17872
- userActionHandlers.handleSaveNodeDetails(actionHandlerContext, updatedNode, true);
17873
- }
17874
- setDetailsNode(updatedNode);
17875
- }, [session, actionHandlerContext]);
17876
- const handleFinishQuestQuick = (0, import_react33.useCallback)((questNode) => {
17877
- var _a2, _b2, _c2, _d2;
17878
- if (!questNode || !actionHandlerContext) return;
17879
- const {
17880
- labelObject,
17881
- labelOffset,
17882
- aura,
17883
- borderRing,
17884
- timelineIntervalBar,
17885
- timelineEndLabel,
17886
- ...cleanQuestNode
17887
- } = questNode;
17888
- let nextAssigneeId = cleanQuestNode.assignee_id;
17889
- let nextStatus = "Done";
17890
- let newTimeline = [...cleanQuestNode.timeline || []];
17891
- const reviewStack = [...cleanQuestNode.reviewStack || []];
17892
- const currentReviewerIdx = reviewStack.findIndex((r) => r.status !== "completed");
17893
- let nextIdxToAssign = 0;
17894
- if (currentReviewerIdx !== -1 && reviewStack[currentReviewerIdx].userId === cleanQuestNode.assignee_id) {
17895
- reviewStack[currentReviewerIdx].status = "completed";
17896
- nextIdxToAssign = currentReviewerIdx + 1;
17897
- } else {
17898
- nextIdxToAssign = currentReviewerIdx !== -1 ? currentReviewerIdx : reviewStack.length;
17899
- }
17900
- if (nextIdxToAssign < reviewStack.length) {
17901
- const remainingMandatory = reviewStack.slice(nextIdxToAssign).some((r) => r.mandatory);
17902
- const hasAnyMandatory = reviewStack.some((r) => r.mandatory);
17903
- if (!hasAnyMandatory || remainingMandatory) {
17904
- const nextReviewer = reviewStack[nextIdxToAssign];
17905
- nextAssigneeId = nextReviewer.userId;
17906
- nextStatus = "Review";
17890
+ const handleStartQuestQuick = (0, import_react33.useCallback)(
17891
+ (questNode) => {
17892
+ var _a2, _b2, _c2;
17893
+ if (!questNode || !actionHandlerContext) return;
17894
+ const allParentNodes = Object.values(parentDataRef.current).flatMap(
17895
+ (fileData) => fileData.nodes || []
17896
+ );
17897
+ const blockCheck = isQuestBlocked(questNode, allParentNodes);
17898
+ if (blockCheck.isBlocked) {
17899
+ alert(
17900
+ `Esta quest n\xE3o pode ser iniciada pois possui depend\xEAncias pendentes: ${blockCheck.pendingDependencies.map((d) => d.raw_title || d.name).join(", ")}`
17901
+ );
17902
+ return;
17903
+ }
17904
+ const {
17905
+ labelObject,
17906
+ labelOffset,
17907
+ aura,
17908
+ borderRing,
17909
+ timelineIntervalBar,
17910
+ timelineEndLabel,
17911
+ ...cleanQuestNode
17912
+ } = questNode;
17913
+ const newTimeline = [
17914
+ ...cleanQuestNode.timeline || [],
17915
+ createTimelineEntry(
17916
+ ((_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id) || "unknown",
17917
+ `Status "In Progress" - Respons\xE1vel: ${((_b2 = session == null ? void 0 : session.user) == null ? void 0 : _b2.name) || "usu\xE1rio"}`,
17918
+ "status_changed"
17919
+ )
17920
+ ];
17921
+ const updatedNode = {
17922
+ ...cleanQuestNode,
17923
+ status: "In Progress",
17924
+ color: "#eab308",
17925
+ assignee_id: (_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.id,
17926
+ timeline: newTimeline
17927
+ };
17928
+ if (userActionHandlers.handleSaveNodeDetails) {
17929
+ userActionHandlers.handleSaveNodeDetails(
17930
+ actionHandlerContext,
17931
+ updatedNode,
17932
+ true
17933
+ );
17934
+ }
17935
+ setDetailsNode(updatedNode);
17936
+ },
17937
+ [session, actionHandlerContext]
17938
+ );
17939
+ const handleFinishQuestQuick = (0, import_react33.useCallback)(
17940
+ (questNode) => {
17941
+ var _a2, _b2, _c2, _d2;
17942
+ if (!questNode || !actionHandlerContext) return;
17943
+ const {
17944
+ labelObject,
17945
+ labelOffset,
17946
+ aura,
17947
+ borderRing,
17948
+ timelineIntervalBar,
17949
+ timelineEndLabel,
17950
+ ...cleanQuestNode
17951
+ } = questNode;
17952
+ let nextAssigneeId = cleanQuestNode.assignee_id;
17953
+ let nextStatus = "Done";
17954
+ let newTimeline = [...cleanQuestNode.timeline || []];
17955
+ const reviewStack = [...cleanQuestNode.reviewStack || []];
17956
+ const currentReviewerIdx = reviewStack.findIndex(
17957
+ (r) => r.status !== "completed"
17958
+ );
17959
+ let nextIdxToAssign = 0;
17960
+ if (currentReviewerIdx !== -1 && reviewStack[currentReviewerIdx].userId === cleanQuestNode.assignee_id) {
17961
+ reviewStack[currentReviewerIdx].status = "completed";
17962
+ nextIdxToAssign = currentReviewerIdx + 1;
17907
17963
  } else {
17908
- nextStatus = "Done";
17909
- for (let i = nextIdxToAssign; i < reviewStack.length; i++) {
17910
- reviewStack[i].status = "skipped";
17964
+ nextIdxToAssign = currentReviewerIdx !== -1 ? currentReviewerIdx : reviewStack.length;
17965
+ }
17966
+ if (nextIdxToAssign < reviewStack.length) {
17967
+ const remainingMandatory = reviewStack.slice(nextIdxToAssign).some((r) => r.mandatory);
17968
+ const hasAnyMandatory = reviewStack.some((r) => r.mandatory);
17969
+ if (!hasAnyMandatory || remainingMandatory) {
17970
+ const nextReviewer = reviewStack[nextIdxToAssign];
17971
+ nextAssigneeId = nextReviewer.userId;
17972
+ nextStatus = "Review";
17973
+ } else {
17974
+ nextStatus = "Done";
17975
+ for (let i = nextIdxToAssign; i < reviewStack.length; i++) {
17976
+ reviewStack[i].status = "skipped";
17977
+ }
17911
17978
  }
17979
+ } else {
17980
+ nextStatus = "Done";
17912
17981
  }
17913
- } else {
17914
- nextStatus = "Done";
17915
- }
17916
- if (nextStatus === "Review") {
17917
- const nextReviewerName = ((_a2 = viewMembers.find((m) => m.id === nextAssigneeId)) == null ? void 0 : _a2.name) || "revisor";
17918
- newTimeline.push(createTimelineEntry(
17919
- "system",
17920
- `Status "Review" - Respons\xE1vel: ${nextReviewerName}`,
17921
- "status_changed",
17922
- { metadata: { to_assignee_id: nextAssigneeId } }
17923
- ));
17924
- } else if (nextStatus === "Done") {
17925
- const finisherName = ((_b2 = viewMembers.find((m) => {
17926
- var _a3;
17927
- return m.id === (((_a3 = session == null ? void 0 : session.user) == null ? void 0 : _a3.id) || cleanQuestNode.assignee_id);
17928
- })) == null ? void 0 : _b2.name) || ((_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.name) || "respons\xE1vel";
17929
- newTimeline.push(createTimelineEntry(
17930
- ((_d2 = session == null ? void 0 : session.user) == null ? void 0 : _d2.id) || cleanQuestNode.assignee_id,
17931
- `Status "Done" - Finalizado por ${finisherName}`,
17932
- "status_changed"
17933
- ));
17934
- }
17935
- const updatedNode = {
17936
- ...cleanQuestNode,
17937
- status: nextStatus,
17938
- color: nextStatus === "Done" ? "#22c55e" : "#a855f7",
17939
- assignee_id: nextAssigneeId,
17940
- reviewStack,
17941
- timeline: newTimeline
17942
- };
17943
- if (userActionHandlers.handleSaveNodeDetails) {
17944
- userActionHandlers.handleSaveNodeDetails(actionHandlerContext, updatedNode);
17945
- }
17946
- if (detailsNode && String(detailsNode.id) === String(cleanQuestNode.id)) {
17947
- setDetailsNode(null);
17948
- }
17949
- }, [session, actionHandlerContext, viewMembers, detailsNode]);
17982
+ if (nextStatus === "Review") {
17983
+ const nextReviewerName = ((_a2 = viewMembers.find((m) => m.id === nextAssigneeId)) == null ? void 0 : _a2.name) || "revisor";
17984
+ newTimeline.push(
17985
+ createTimelineEntry(
17986
+ "system",
17987
+ `Status "Review" - Respons\xE1vel: ${nextReviewerName}`,
17988
+ "status_changed",
17989
+ { metadata: { to_assignee_id: nextAssigneeId } }
17990
+ )
17991
+ );
17992
+ } else if (nextStatus === "Done") {
17993
+ const finisherName = ((_b2 = viewMembers.find(
17994
+ (m) => {
17995
+ var _a3;
17996
+ return m.id === (((_a3 = session == null ? void 0 : session.user) == null ? void 0 : _a3.id) || cleanQuestNode.assignee_id);
17997
+ }
17998
+ )) == null ? void 0 : _b2.name) || ((_c2 = session == null ? void 0 : session.user) == null ? void 0 : _c2.name) || "respons\xE1vel";
17999
+ newTimeline.push(
18000
+ createTimelineEntry(
18001
+ ((_d2 = session == null ? void 0 : session.user) == null ? void 0 : _d2.id) || cleanQuestNode.assignee_id,
18002
+ `Status "Done" - Finalizado por ${finisherName}`,
18003
+ "status_changed"
18004
+ )
18005
+ );
18006
+ }
18007
+ const updatedNode = {
18008
+ ...cleanQuestNode,
18009
+ status: nextStatus,
18010
+ color: nextStatus === "Done" ? "#22c55e" : "#a855f7",
18011
+ assignee_id: nextAssigneeId,
18012
+ reviewStack,
18013
+ timeline: newTimeline
18014
+ };
18015
+ if (userActionHandlers.handleSaveNodeDetails) {
18016
+ userActionHandlers.handleSaveNodeDetails(
18017
+ actionHandlerContext,
18018
+ updatedNode
18019
+ );
18020
+ }
18021
+ if (detailsNode && String(detailsNode.id) === String(cleanQuestNode.id)) {
18022
+ setDetailsNode(null);
18023
+ }
18024
+ },
18025
+ [session, actionHandlerContext, viewMembers, detailsNode]
18026
+ );
17950
18027
  const handleCancelQuest = (0, import_react33.useCallback)(() => {
17951
18028
  const { graphGroup, ghostElements } = stateRef.current;
17952
18029
  if (ghostElements.node && graphGroup) {
@@ -17997,48 +18074,56 @@ function XViewScene({
17997
18074
  if (questNodeId && sceneConfigId) {
17998
18075
  const sceneData = sceneDataRef.current;
17999
18076
  if (sceneData && sceneData.quest_nodes) {
18000
- const questIndex = sceneData.quest_nodes.findIndex((q) => String(q.id) === String(questNodeId));
18077
+ const questIndex = sceneData.quest_nodes.findIndex(
18078
+ (q) => String(q.id) === String(questNodeId)
18079
+ );
18001
18080
  if (questIndex !== -1) {
18002
18081
  sceneData.quest_nodes[questIndex].quest_tree = formattedTree;
18003
18082
  sceneData.quest_nodes[questIndex].quest_abstraction_tree = formattedAbstractionTree;
18004
18083
  if (parentDataRef.current[sceneConfigId]) {
18005
- const parentIndex = parentDataRef.current[sceneConfigId].nodes.findIndex(
18006
- (q) => String(q.id) === String(questNodeId)
18007
- );
18084
+ const parentIndex = parentDataRef.current[sceneConfigId].nodes.findIndex((q) => String(q.id) === String(questNodeId));
18008
18085
  if (parentIndex !== -1) {
18009
18086
  parentDataRef.current[sceneConfigId].nodes[parentIndex].quest_tree = formattedTree;
18010
18087
  parentDataRef.current[sceneConfigId].nodes[parentIndex].quest_abstraction_tree = formattedAbstractionTree;
18011
18088
  }
18012
18089
  }
18013
- if (save_view_data && sceneSaveUrl) {
18014
- const sceneFileData = {
18015
- ...sceneData,
18016
- nodes: sceneData.nodes || [],
18017
- links: sceneData.links || [],
18018
- quest_nodes: sceneData.quest_nodes,
18019
- quest_links: sceneData.quest_links || [],
18020
- quest_counter: sceneData.quest_counter || 1,
18021
- milestones: sceneData.milestones || []
18022
- };
18023
- await save_view_data(sceneSaveUrl, sceneFileData);
18024
- }
18025
- const updatedNodeData = sceneData.quest_nodes[questIndex];
18026
- const nodeMesh = (_a2 = stateRef.current.nodeObjects) == null ? void 0 : _a2[String(questNodeId)];
18027
- if (nodeMesh) {
18028
- nodeMesh.userData = {
18029
- ...nodeMesh.userData,
18030
- ...updatedNodeData
18031
- };
18032
- }
18033
- if (detailsNode && String(detailsNode.id) === String(questNodeId)) {
18034
- setDetailsNode((prev) => ({
18035
- ...prev,
18036
- quest_tree: formattedTree,
18037
- quest_abstraction_tree: formattedAbstractionTree
18038
- }));
18039
- }
18040
- setSceneVersion((v) => v + 1);
18090
+ const sceneFileData = {
18091
+ ...sceneData,
18092
+ nodes: sceneData.nodes || [],
18093
+ links: sceneData.links || [],
18094
+ quest_counter: sceneData.quest_counter || 1
18095
+ };
18096
+ delete sceneFileData.quest_nodes;
18097
+ delete sceneFileData.quest_links;
18098
+ delete sceneFileData.milestones;
18099
+ const questFileData = {
18100
+ nodes: sceneData.quest_nodes || [],
18101
+ links: sceneData.quest_links || [],
18102
+ milestones: sceneData.milestones || []
18103
+ };
18104
+ await save_view_data(sceneSaveUrl, sceneFileData);
18105
+ const questSaveUrl = sceneSaveUrl.replace(
18106
+ "x_view_scenes",
18107
+ "x_view_quests"
18108
+ );
18109
+ await save_view_data(questSaveUrl, questFileData);
18110
+ }
18111
+ const updatedNodeData = sceneData.quest_nodes[questIndex];
18112
+ const nodeMesh = (_a2 = stateRef.current.nodeObjects) == null ? void 0 : _a2[String(questNodeId)];
18113
+ if (nodeMesh) {
18114
+ nodeMesh.userData = {
18115
+ ...nodeMesh.userData,
18116
+ ...updatedNodeData
18117
+ };
18041
18118
  }
18119
+ if (detailsNode && String(detailsNode.id) === String(questNodeId)) {
18120
+ setDetailsNode((prev) => ({
18121
+ ...prev,
18122
+ quest_tree: formattedTree,
18123
+ quest_abstraction_tree: formattedAbstractionTree
18124
+ }));
18125
+ }
18126
+ setSceneVersion((v) => v + 1);
18042
18127
  }
18043
18128
  }
18044
18129
  };
@@ -18100,21 +18185,33 @@ function XViewScene({
18100
18185
  graphDataRef2.current[sceneConfigId2].nodes.push(newNode);
18101
18186
  const sceneFileData = {
18102
18187
  ...sceneDataRef2.current,
18103
- quest_nodes: graphDataRef2.current[sceneConfigId2].nodes,
18104
- quest_links: graphDataRef2.current[sceneConfigId2].links,
18105
18188
  quest_counter: currentCounter + 1
18106
18189
  };
18190
+ delete sceneFileData.quest_nodes;
18191
+ delete sceneFileData.quest_links;
18192
+ delete sceneFileData.milestones;
18193
+ const questFileData = {
18194
+ nodes: graphDataRef2.current[sceneConfigId2].nodes,
18195
+ links: graphDataRef2.current[sceneConfigId2].links,
18196
+ milestones: sceneDataRef2.current.milestones || []
18197
+ };
18107
18198
  try {
18108
18199
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
18200
+ const questSaveUrl = sceneSaveUrl2.replace("x_view_scenes", "x_view_quests");
18201
+ await actions.save_view_data(questSaveUrl, questFileData);
18109
18202
  sceneDataRef2.current.quest_counter = currentCounter + 1;
18110
18203
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
18111
18204
  parentFileId: sceneConfigId2,
18112
18205
  ownerId: ownerId2,
18113
18206
  datasetName: "Quests Internas (View)"
18114
18207
  });
18115
- sceneDataRef2.current.quest_nodes = [...graphDataRef2.current[sceneConfigId2].nodes];
18208
+ sceneDataRef2.current.quest_nodes = [
18209
+ ...graphDataRef2.current[sceneConfigId2].nodes
18210
+ ];
18116
18211
  if (parentDataRef.current[sceneConfigId2]) {
18117
- parentDataRef.current[sceneConfigId2].nodes = [...graphDataRef2.current[sceneConfigId2].nodes];
18212
+ parentDataRef.current[sceneConfigId2].nodes = [
18213
+ ...graphDataRef2.current[sceneConfigId2].nodes
18214
+ ];
18118
18215
  }
18119
18216
  const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
18120
18217
  const { graphGroup, ghostElements } = stateRef2.current;
@@ -18179,11 +18276,22 @@ function XViewScene({
18179
18276
  specificParentData.links.push(newLink);
18180
18277
  const viewFilePayload = {
18181
18278
  ...sceneDataRef2.current,
18182
- quest_nodes: specificParentData.nodes,
18183
- quest_links: specificParentData.links,
18184
18279
  quest_counter: sceneDataRef2.current.quest_counter || 1
18185
18280
  };
18281
+ delete viewFilePayload.quest_nodes;
18282
+ delete viewFilePayload.quest_links;
18283
+ delete viewFilePayload.milestones;
18284
+ const questFilePayload = {
18285
+ nodes: specificParentData.nodes,
18286
+ links: specificParentData.links,
18287
+ milestones: sceneDataRef2.current.milestones || []
18288
+ };
18186
18289
  await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
18290
+ const questSaveUrl = sceneSaveUrl2.replace(
18291
+ "x_view_scenes",
18292
+ "x_view_quests"
18293
+ );
18294
+ await context.actions.save_view_data(questSaveUrl, questFilePayload);
18187
18295
  } else {
18188
18296
  const specificParentData = JSON.parse(
18189
18297
  JSON.stringify(graphDataRef2.current[parentFileIdToSave])
@@ -18216,9 +18324,7 @@ function XViewScene({
18216
18324
  if (line.material) line.material.dispose();
18217
18325
  });
18218
18326
  renderedAncestries.splice(renderIndex, 1);
18219
- stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18220
- (a) => a.lines
18221
- );
18327
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
18222
18328
  }
18223
18329
  }, []);
18224
18330
  const handleRenderAncestry = (0, import_react33.useCallback)(
@@ -18791,9 +18897,7 @@ function XViewScene({
18791
18897
  });
18792
18898
  };
18793
18899
  renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
18794
- stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18795
- (a) => a.lines
18796
- );
18900
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
18797
18901
  tweenToTarget(rootTargetPos, 0.7);
18798
18902
  },
18799
18903
  [
@@ -18928,10 +19032,7 @@ function XViewScene({
18928
19032
  };
18929
19033
  const descriptionText = targetAncestryInfo.description || "";
18930
19034
  const savedSections = targetAncestryInfo.description_sections || [];
18931
- const sections = parseDescriptionSections(
18932
- descriptionText,
18933
- savedSections
18934
- );
19035
+ const sections = parseDescriptionSections(descriptionText, savedSections);
18935
19036
  let focusTargetId = null;
18936
19037
  if (popped && popped.nodeId) {
18937
19038
  const mentionTag = `[[MENTION:node:${popped.nodeId}]]`;
@@ -19544,16 +19645,26 @@ function XViewScene({
19544
19645
  const result = await save_view_data(finalSaveUrl, masterAncestryList);
19545
19646
  if (result.success && isExternalSave && isEditMode && currentAncestryId && ancestry_save_url && get_ancestry_file) {
19546
19647
  try {
19547
- const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
19648
+ const viewDbResponse = await get_ancestry_file(
19649
+ sceneConfigId,
19650
+ ownerId
19651
+ );
19548
19652
  if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
19549
- const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(currentAncestryId));
19653
+ const hasInViewDb = viewDbResponse.data.some(
19654
+ (anc) => String(anc.ancestry_id) === String(currentAncestryId)
19655
+ );
19550
19656
  if (hasInViewDb) {
19551
- const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(currentAncestryId));
19657
+ const updatedViewDb = viewDbResponse.data.filter(
19658
+ (anc) => String(anc.ancestry_id) !== String(currentAncestryId)
19659
+ );
19552
19660
  await save_view_data(ancestry_save_url, updatedViewDb);
19553
19661
  }
19554
19662
  }
19555
19663
  } catch (fallbackErr) {
19556
- console.error("Falha ao limpar c\xF3pia residual na edi\xE7\xE3o:", fallbackErr);
19664
+ console.error(
19665
+ "Falha ao limpar c\xF3pia residual na edi\xE7\xE3o:",
19666
+ fallbackErr
19667
+ );
19557
19668
  }
19558
19669
  }
19559
19670
  if (result.success) {
@@ -19664,7 +19775,10 @@ function XViewScene({
19664
19775
  try {
19665
19776
  let updatedAncestriesForFile;
19666
19777
  if (get_ancestry_file && isExternalSave) {
19667
- const remoteResponse = await get_ancestry_file(sourceFileId, sourceOwnerId);
19778
+ const remoteResponse = await get_ancestry_file(
19779
+ sourceFileId,
19780
+ sourceOwnerId
19781
+ );
19668
19782
  if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
19669
19783
  updatedAncestriesForFile = remoteResponse.data.filter(
19670
19784
  (anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete)
@@ -19679,11 +19793,16 @@ function XViewScene({
19679
19793
  (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
19680
19794
  );
19681
19795
  }
19682
- const result = await save_view_data(finalSaveUrl, updatedAncestriesForFile);
19796
+ const result = await save_view_data(
19797
+ finalSaveUrl,
19798
+ updatedAncestriesForFile
19799
+ );
19683
19800
  if (result.success) {
19684
19801
  success = true;
19685
19802
  } else {
19686
- throw new Error(result.error || "Ocorreu um erro desconhecido ao excluir.");
19803
+ throw new Error(
19804
+ result.error || "Ocorreu um erro desconhecido ao excluir."
19805
+ );
19687
19806
  }
19688
19807
  } catch (error) {
19689
19808
  deletionError = error;
@@ -19692,15 +19811,25 @@ function XViewScene({
19692
19811
  try {
19693
19812
  const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
19694
19813
  if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
19695
- const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(ancestryIdToDelete));
19814
+ const hasInViewDb = viewDbResponse.data.some(
19815
+ (anc) => String(anc.ancestry_id) === String(ancestryIdToDelete)
19816
+ );
19696
19817
  if (hasInViewDb) {
19697
- const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete));
19698
- const fallbackResult = await save_view_data(ancestry_save_url, updatedViewDb);
19818
+ const updatedViewDb = viewDbResponse.data.filter(
19819
+ (anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete)
19820
+ );
19821
+ const fallbackResult = await save_view_data(
19822
+ ancestry_save_url,
19823
+ updatedViewDb
19824
+ );
19699
19825
  if (fallbackResult.success) success = true;
19700
19826
  }
19701
19827
  }
19702
19828
  } catch (fallbackErr) {
19703
- console.error("Falha ao limpar c\xF3pia residual da View DB:", fallbackErr);
19829
+ console.error(
19830
+ "Falha ao limpar c\xF3pia residual da View DB:",
19831
+ fallbackErr
19832
+ );
19704
19833
  }
19705
19834
  }
19706
19835
  if (!success && deletionError) {
@@ -19878,23 +20007,28 @@ function XViewScene({
19878
20007
  ...sceneDataRef.current,
19879
20008
  nodes: sceneDataRef.current.nodes || [],
19880
20009
  links: sceneDataRef.current.links || [],
19881
- quest_nodes: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || sceneDataRef.current.quest_nodes || [],
19882
- quest_links: ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || sceneDataRef.current.quest_links || [],
19883
- quest_counter: sceneDataRef.current.quest_counter || 1,
20010
+ quest_counter: sceneDataRef.current.quest_counter || 1
20011
+ };
20012
+ delete sceneFileData.quest_nodes;
20013
+ delete sceneFileData.quest_links;
20014
+ delete sceneFileData.milestones;
20015
+ const questFileData = {
20016
+ nodes: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || sceneDataRef.current.quest_nodes || [],
20017
+ links: ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || sceneDataRef.current.quest_links || [],
19884
20018
  milestones: newMilestones
19885
20019
  };
19886
20020
  try {
19887
20021
  await save_view_data(sceneSaveUrl, sceneFileData);
20022
+ const questSaveUrl = sceneSaveUrl.replace(
20023
+ "x_view_scenes",
20024
+ "x_view_quests"
20025
+ );
20026
+ await save_view_data(questSaveUrl, questFileData);
19888
20027
  } catch (error) {
19889
20028
  console.error("Erro ao salvar milestones:", error);
19890
20029
  }
19891
20030
  },
19892
- [
19893
- sceneConfigId,
19894
- sceneSaveUrl,
19895
- save_view_data,
19896
- viewParams == null ? void 0 : viewParams.type
19897
- ]
20031
+ [sceneConfigId, sceneSaveUrl, save_view_data, viewParams == null ? void 0 : viewParams.type]
19898
20032
  );
19899
20033
  const handleSaveCurrentView = (0, import_react33.useCallback)(async () => {
19900
20034
  var _a2, _b2, _c2;
@@ -19928,13 +20062,25 @@ function XViewScene({
19928
20062
  ...sceneDataRef.current,
19929
20063
  nodes: currentNodes,
19930
20064
  links: currentLinks,
19931
- quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
19932
- quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || [],
19933
- quest_counter: sceneDataRef.current.quest_counter || 1,
20065
+ quest_counter: sceneDataRef.current.quest_counter || 1
20066
+ };
20067
+ delete sceneFileData.quest_nodes;
20068
+ delete sceneFileData.quest_links;
20069
+ delete sceneFileData.milestones;
20070
+ const questFileData = {
20071
+ nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
20072
+ links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || [],
19934
20073
  milestones: sceneDataRef.current.milestones || []
19935
20074
  };
19936
20075
  try {
19937
20076
  await save_view_data(sceneSaveUrl, sceneFileData);
20077
+ if (isView) {
20078
+ const questSaveUrl = sceneSaveUrl.replace(
20079
+ "x_view_scenes",
20080
+ "x_view_quests"
20081
+ );
20082
+ await save_view_data(questSaveUrl, questFileData);
20083
+ }
19938
20084
  } catch (error) {
19939
20085
  console.error("Erro na chamada de save_view_data:", error);
19940
20086
  }
@@ -20051,7 +20197,12 @@ function XViewScene({
20051
20197
  if (isUiClear) {
20052
20198
  const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
20053
20199
  if (!isView) return;
20054
- const { graphGroup, glowTexture, controls: sceneControls, nodeObjects } = stateRef.current;
20200
+ const {
20201
+ graphGroup,
20202
+ glowTexture,
20203
+ controls: sceneControls,
20204
+ nodeObjects
20205
+ } = stateRef.current;
20055
20206
  if (graphGroup) {
20056
20207
  let ghostPosition = sceneControls.target.clone();
20057
20208
  const existingNodes = Object.values(nodeObjects);
@@ -20107,7 +20258,12 @@ function XViewScene({
20107
20258
  setQuestMode({ isActive: true });
20108
20259
  }
20109
20260
  }
20110
- const isArrowKey = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key);
20261
+ const isArrowKey = [
20262
+ "ArrowUp",
20263
+ "ArrowDown",
20264
+ "ArrowLeft",
20265
+ "ArrowRight"
20266
+ ].includes(event.key);
20111
20267
  if (isArrowKey) {
20112
20268
  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;
20113
20269
  if (isUiClear) {
@@ -20153,7 +20309,12 @@ function XViewScene({
20153
20309
  if (isLoading || status === "loading" || permissionStatus === "loading") {
20154
20310
  return /* @__PURE__ */ import_react33.default.createElement(LoadingScreen, null);
20155
20311
  }
20156
- const overlayHiddenStyle = questTreeMode.isActive ? { opacity: 0, pointerEvents: "none", transform: "translateX(30px)", transition: "all 300ms ease-in-out" } : {};
20312
+ const overlayHiddenStyle = questTreeMode.isActive ? {
20313
+ opacity: 0,
20314
+ pointerEvents: "none",
20315
+ transform: "translateX(30px)",
20316
+ transition: "all 300ms ease-in-out"
20317
+ } : {};
20157
20318
  if (permissionStatus === "denied") {
20158
20319
  return /* @__PURE__ */ import_react33.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react33.default.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ import_react33.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react33.default.createElement(
20159
20320
  "svg",
@@ -20618,18 +20779,12 @@ function XViewScene({
20618
20779
  data: multiContextMenu,
20619
20780
  userRole: userPermissionRole,
20620
20781
  onClose: () => setMultiContextMenu((prev) => ({ ...prev, visible: false })),
20621
- onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(
20622
- actionHandlerContext,
20623
- ids
20624
- ),
20782
+ onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(actionHandlerContext, ids),
20625
20783
  onDismissOtherNodes: (ids) => userActionHandlers.handleDismissOtherMultipleNodes(
20626
20784
  actionHandlerContext,
20627
20785
  ids
20628
20786
  ),
20629
- onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(
20630
- actionHandlerContext,
20631
- ids
20632
- )
20787
+ onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
20633
20788
  }
20634
20789
  ),
20635
20790
  /* @__PURE__ */ import_react33.default.createElement(
@@ -20782,7 +20937,7 @@ async function save_view_data_logic(db_services, filename, data) {
20782
20937
  }
20783
20938
  }
20784
20939
  async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
20785
- var _a, _b;
20940
+ var _a, _b, _c;
20786
20941
  try {
20787
20942
  if (!session || !session.user) {
20788
20943
  return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
@@ -20805,28 +20960,44 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
20805
20960
  parentDbObjects.push({ db_id: scene_config, owner_id });
20806
20961
  }
20807
20962
  }
20963
+ const isView = type && type.toLowerCase() === "view";
20808
20964
  const parentResponsesPromises = parentDbObjects.map(
20809
20965
  (db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
20810
20966
  );
20967
+ if (isView) {
20968
+ parentResponsesPromises.push(
20969
+ db_services.get_file(`x_view_quests/${owner_id}/${scene_config}`)
20970
+ );
20971
+ }
20811
20972
  const parentResponsesResults = await Promise.allSettled(parentResponsesPromises);
20812
20973
  const parentData = {};
20974
+ let questDataObj = null;
20813
20975
  for (let i = 0; i < parentResponsesResults.length; i++) {
20814
20976
  const result = parentResponsesResults[i];
20977
+ if (isView && i === parentResponsesResults.length - 1) {
20978
+ if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
20979
+ questDataObj = result.value.data;
20980
+ }
20981
+ continue;
20982
+ }
20815
20983
  const db_info = parentDbObjects[i];
20816
- if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
20984
+ if (result.status === "fulfilled" && ((_b = result.value) == null ? void 0 : _b.success)) {
20817
20985
  parentData[db_info.db_id] = result.value.data;
20818
20986
  } else {
20819
20987
  console.warn(
20820
20988
  `Arquivo pai n\xE3o carregado: ${db_info.db_id}. Pode ter sido deletado.`,
20821
- result.status === "rejected" ? result.reason : (_b = result.value) == null ? void 0 : _b.error
20989
+ result.status === "rejected" ? result.reason : (_c = result.value) == null ? void 0 : _c.error
20822
20990
  );
20823
20991
  }
20824
20992
  }
20825
- if (type && type.toLowerCase() === "view") {
20993
+ const currentQuestNodes = (questDataObj == null ? void 0 : questDataObj.nodes) || sceneData.quest_nodes || [];
20994
+ const currentQuestLinks = (questDataObj == null ? void 0 : questDataObj.links) || sceneData.quest_links || [];
20995
+ const currentMilestones = (questDataObj == null ? void 0 : questDataObj.milestones) || sceneData.milestones || [];
20996
+ if (isView) {
20826
20997
  parentData[scene_config] = {
20827
20998
  dataset_name: "Quests Internas (View)",
20828
- nodes: sceneData.quest_nodes || [],
20829
- links: sceneData.quest_links || []
20999
+ nodes: currentQuestNodes,
21000
+ links: currentQuestLinks
20830
21001
  };
20831
21002
  }
20832
21003
  const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
@@ -20858,7 +21029,12 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
20858
21029
  const validatedSceneData = {
20859
21030
  ...sceneData,
20860
21031
  nodes: validatedNodes,
20861
- links: validatedLinks
21032
+ links: validatedLinks,
21033
+ // Re-injetando no validated para que o restante do sistema (e.g. XViewScene local state)
21034
+ // continue acessando as quests sem perceber a separação física
21035
+ quest_nodes: currentQuestNodes,
21036
+ quest_links: currentQuestLinks,
21037
+ milestones: currentMilestones
20862
21038
  };
20863
21039
  const ancestryFilePaths = [];
20864
21040
  ancestryFilePaths.push({