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