@lv-x-software-house/x_view 1.2.3-dev.6 → 1.2.3-dev.8

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.
Files changed (3) hide show
  1. package/dist/index.js +117 -14
  2. package/dist/index.mjs +117 -14
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -96,6 +96,17 @@ function defineAbilityFor(role) {
96
96
  cannot("manage", "AncestryBoard");
97
97
  cannot("update", "Node");
98
98
  break;
99
+ case "link_viewer":
100
+ can("read", "Node");
101
+ can("read", "Ancestry");
102
+ can("read", "Versioning");
103
+ cannot("read", "Scene");
104
+ cannot("read", "Connection");
105
+ cannot("read", "AncestryBoard");
106
+ cannot("read", "AncestryGroup");
107
+ cannot("dismiss", "Node");
108
+ cannot("manage", "all");
109
+ break;
99
110
  default:
100
111
  can("read", "Connection");
101
112
  can("dismiss", "Node");
@@ -9675,11 +9686,14 @@ function XViewScene({
9675
9686
  const { id, type, owner_id } = viewParams;
9676
9687
  try {
9677
9688
  const result = await check_user_permission(owner_id, type, id, session);
9689
+ const hasDirectLinkTarget = !!(focusNodeId || focusAncestryId);
9678
9690
  if (result.success && result.isValidMember) {
9679
9691
  setUserPermissionRole(result.permission);
9680
9692
  setPermissionStatus("granted");
9693
+ } else if (hasDirectLinkTarget) {
9694
+ setUserPermissionRole("link_viewer");
9695
+ setPermissionStatus("granted");
9681
9696
  } else {
9682
- console.warn("\u26D4 Acesso negado: Usu\xE1rio n\xE3o \xE9 membro deste card.");
9683
9697
  setPermissionStatus("denied");
9684
9698
  setIsLoading(false);
9685
9699
  }
@@ -10309,7 +10323,7 @@ function XViewScene({
10309
10323
  try {
10310
10324
  const typeStr = (viewParams == null ? void 0 : viewParams.type) || "";
10311
10325
  const sceneType = typeStr.toLowerCase().includes("database") ? "database" : "view";
10312
- const scenePromise = get_scene_view_data(configPath, ownerId2);
10326
+ const scenePromise = get_scene_view_data(configPath, ownerId2, typeStr, session, focusNodeId, focusAncestryId);
10313
10327
  const boardPromise = get_ancestry_board_action && session ? get_ancestry_board_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
10314
10328
  const [sceneResponse, boardResponse] = await Promise.all([scenePromise, boardPromise]);
10315
10329
  if ((sceneResponse == null ? void 0 : sceneResponse.success) && ((_a2 = sceneResponse.data) == null ? void 0 : _a2.scene) && ((_b2 = sceneResponse.data) == null ? void 0 : _b2.parent)) {
@@ -12723,7 +12737,7 @@ function XViewScene({
12723
12737
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
12724
12738
  }
12725
12739
  },
12726
- /* @__PURE__ */ import_react24.default.createElement(
12740
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react24.default.createElement(
12727
12741
  XViewSidebar,
12728
12742
  {
12729
12743
  dbNodes: searchableDbNodes,
@@ -13051,9 +13065,17 @@ async function save_view_data_logic(db_services, filename, data) {
13051
13065
  return { success: false, error: error.message };
13052
13066
  }
13053
13067
  }
13054
- async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13068
+ async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
13055
13069
  var _a, _b;
13056
13070
  try {
13071
+ if (!session || !session.user) {
13072
+ return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
13073
+ }
13074
+ const membershipCheck = await db_services.check_membership(owner_id, type, scene_config, session.user.id);
13075
+ const isFullMember = membershipCheck.success && membershipCheck.isValidMember;
13076
+ if (!isFullMember && !focusNodeId && !focusAncestryId) {
13077
+ return { success: false, error: "Acesso Negado: Voc\xEA n\xE3o possui permiss\xE3o para acessar este cen\xE1rio." };
13078
+ }
13057
13079
  const sceneResponse = await db_services.get_file(`x_view_scenes/${owner_id}/${scene_config}`);
13058
13080
  if (!sceneResponse || !sceneResponse.success) {
13059
13081
  console.error("Falha ao buscar dados da cena:", sceneResponse == null ? void 0 : sceneResponse.error);
@@ -13142,8 +13164,7 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13142
13164
  ancestryData.forEach((anc) => {
13143
13165
  const targetSourceId = anc._source_file_id || anc._imported_from_view_id;
13144
13166
  const targetOwnerId = anc._source_owner_id || anc._imported_from_view_owner_id;
13145
- if (targetSourceId && targetSourceId !== scene_config && // Não é o arquivo atual
13146
- targetOwnerId) {
13167
+ if (targetSourceId && targetSourceId !== scene_config && targetOwnerId) {
13147
13168
  const isAlreadyLoadedAsParent = parentDbObjects.some((db) => String(db.db_id) === String(targetSourceId));
13148
13169
  if (!isAlreadyLoadedAsParent) {
13149
13170
  const key = `${targetOwnerId}/${targetSourceId}`;
@@ -13174,7 +13195,6 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13174
13195
  });
13175
13196
  } else if (result.status === "fulfilled" && !((_b2 = result.value) == null ? void 0 : _b2.success)) {
13176
13197
  failedSources.add(result.value._meta_key);
13177
- } else if (result.status === "rejected") {
13178
13198
  }
13179
13199
  });
13180
13200
  ancestryData = ancestryData.filter((localAnc) => {
@@ -13243,7 +13263,6 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13243
13263
  ...ancestry,
13244
13264
  tree: cleanedTree,
13245
13265
  abstraction_tree: cleanedAbstraction
13246
- // Salva a árvore limpa
13247
13266
  };
13248
13267
  }).filter(Boolean);
13249
13268
  if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
@@ -13254,16 +13273,100 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13254
13273
  console.error("Falha ao salvar o arquivo de ancestralidade da cena atualizado:", saveError);
13255
13274
  }
13256
13275
  }
13276
+ if (!isFullMember) {
13277
+ const requiredNodeIds = /* @__PURE__ */ new Set();
13278
+ const requiredAncestryIds = /* @__PURE__ */ new Set();
13279
+ if (focusNodeId) requiredNodeIds.add(String(focusNodeId));
13280
+ if (focusAncestryId) requiredAncestryIds.add(String(focusAncestryId));
13281
+ const allNodesFromDb = Object.values(parentData).flatMap((db) => db.nodes || []);
13282
+ const extractDependenciesFromText = (text) => {
13283
+ if (!text) return;
13284
+ const mentionRegex = /\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g;
13285
+ const refRegex = /\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g;
13286
+ let match;
13287
+ while ((match = mentionRegex.exec(text)) !== null) {
13288
+ requiredNodeIds.add(match[1]);
13289
+ }
13290
+ while ((match = refRegex.exec(text)) !== null) {
13291
+ if (match[1] === "node") requiredNodeIds.add(match[2]);
13292
+ if (match[1] === "ancestry") requiredAncestryIds.add(match[2]);
13293
+ }
13294
+ };
13295
+ const extractTreeDependencies = (treeItem) => {
13296
+ var _a2;
13297
+ if (!treeItem) return;
13298
+ if (treeItem.node_id) requiredNodeIds.add(String(treeItem.node_id));
13299
+ if ((_a2 = treeItem.node) == null ? void 0 : _a2.id) requiredNodeIds.add(String(treeItem.node.id));
13300
+ if (treeItem.children) {
13301
+ treeItem.children.forEach(extractTreeDependencies);
13302
+ }
13303
+ if (treeItem.parallel_branches) {
13304
+ treeItem.parallel_branches.forEach((branch) => {
13305
+ if (branch.linked_ancestry_id) {
13306
+ requiredAncestryIds.add(String(branch.linked_ancestry_id));
13307
+ }
13308
+ if (branch.description) extractDependenciesFromText(branch.description);
13309
+ if (branch.description_sections) {
13310
+ branch.description_sections.forEach((s) => extractDependenciesFromText(s.content));
13311
+ }
13312
+ extractTreeDependencies(branch.tree);
13313
+ });
13314
+ }
13315
+ };
13316
+ let previousSize;
13317
+ do {
13318
+ previousSize = requiredNodeIds.size + requiredAncestryIds.size;
13319
+ requiredAncestryIds.forEach((ancId) => {
13320
+ const anc = ancestryData.find((a) => String(a.ancestry_id) === ancId);
13321
+ if (anc && !anc.is_private) {
13322
+ if (anc.description) extractDependenciesFromText(anc.description);
13323
+ if (anc.description_sections) {
13324
+ anc.description_sections.forEach((s) => extractDependenciesFromText(s.content));
13325
+ }
13326
+ extractTreeDependencies(anc.tree);
13327
+ extractTreeDependencies(anc.abstraction_tree);
13328
+ }
13329
+ });
13330
+ requiredNodeIds.forEach((nodeId) => {
13331
+ const node = allNodesFromDb.find((n) => String(n.id) === nodeId);
13332
+ if (node) {
13333
+ if (node.description) extractDependenciesFromText(node.description);
13334
+ if (node.description_sections) {
13335
+ node.description_sections.forEach((s) => extractDependenciesFromText(s.content));
13336
+ }
13337
+ }
13338
+ });
13339
+ } while (requiredNodeIds.size + requiredAncestryIds.size > previousSize);
13340
+ const restrictedSceneData = { ...validatedSceneData, nodes: [], links: [] };
13341
+ const restrictedParentData = {};
13342
+ const restrictedAncestryData = ancestryData.filter((a) => requiredAncestryIds.has(String(a.ancestry_id)) && !a.is_private);
13343
+ for (const [dbId, dbContent] of Object.entries(parentData)) {
13344
+ const filteredNodes = (dbContent.nodes || []).filter((n) => requiredNodeIds.has(String(n.id)));
13345
+ if (filteredNodes.length > 0) {
13346
+ restrictedParentData[dbId] = { ...dbContent, nodes: filteredNodes, links: [] };
13347
+ }
13348
+ }
13349
+ if (focusNodeId) {
13350
+ const mainNode = allNodesFromDb.find((n) => String(n.id) === String(focusNodeId));
13351
+ if (mainNode) {
13352
+ restrictedSceneData.nodes = [mainNode];
13353
+ }
13354
+ }
13355
+ return {
13356
+ success: true,
13357
+ data: {
13358
+ scene: restrictedSceneData,
13359
+ parent: restrictedParentData,
13360
+ ancestry: restrictedAncestryData
13361
+ }
13362
+ };
13363
+ }
13257
13364
  return {
13258
13365
  success: true,
13259
- data: {
13260
- scene: validatedSceneData,
13261
- parent: parentData,
13262
- ancestry: ancestryData
13263
- }
13366
+ data: { scene: validatedSceneData, parent: parentData, ancestry: ancestryData }
13264
13367
  };
13265
13368
  } catch (error) {
13266
- console.error("catch (error) em get_scene_view_data_logic:", error);
13369
+ console.error("Erro em get_scene_view_data_logic:", error);
13267
13370
  return { success: false, error: error.message };
13268
13371
  }
13269
13372
  }
package/dist/index.mjs CHANGED
@@ -52,6 +52,17 @@ function defineAbilityFor(role) {
52
52
  cannot("manage", "AncestryBoard");
53
53
  cannot("update", "Node");
54
54
  break;
55
+ case "link_viewer":
56
+ can("read", "Node");
57
+ can("read", "Ancestry");
58
+ can("read", "Versioning");
59
+ cannot("read", "Scene");
60
+ cannot("read", "Connection");
61
+ cannot("read", "AncestryBoard");
62
+ cannot("read", "AncestryGroup");
63
+ cannot("dismiss", "Node");
64
+ cannot("manage", "all");
65
+ break;
55
66
  default:
56
67
  can("read", "Connection");
57
68
  can("dismiss", "Node");
@@ -9675,11 +9686,14 @@ function XViewScene({
9675
9686
  const { id, type, owner_id } = viewParams;
9676
9687
  try {
9677
9688
  const result = await check_user_permission(owner_id, type, id, session);
9689
+ const hasDirectLinkTarget = !!(focusNodeId || focusAncestryId);
9678
9690
  if (result.success && result.isValidMember) {
9679
9691
  setUserPermissionRole(result.permission);
9680
9692
  setPermissionStatus("granted");
9693
+ } else if (hasDirectLinkTarget) {
9694
+ setUserPermissionRole("link_viewer");
9695
+ setPermissionStatus("granted");
9681
9696
  } else {
9682
- console.warn("\u26D4 Acesso negado: Usu\xE1rio n\xE3o \xE9 membro deste card.");
9683
9697
  setPermissionStatus("denied");
9684
9698
  setIsLoading(false);
9685
9699
  }
@@ -10309,7 +10323,7 @@ function XViewScene({
10309
10323
  try {
10310
10324
  const typeStr = (viewParams == null ? void 0 : viewParams.type) || "";
10311
10325
  const sceneType = typeStr.toLowerCase().includes("database") ? "database" : "view";
10312
- const scenePromise = get_scene_view_data(configPath, ownerId2);
10326
+ const scenePromise = get_scene_view_data(configPath, ownerId2, typeStr, session, focusNodeId, focusAncestryId);
10313
10327
  const boardPromise = get_ancestry_board_action && session ? get_ancestry_board_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
10314
10328
  const [sceneResponse, boardResponse] = await Promise.all([scenePromise, boardPromise]);
10315
10329
  if ((sceneResponse == null ? void 0 : sceneResponse.success) && ((_a2 = sceneResponse.data) == null ? void 0 : _a2.scene) && ((_b2 = sceneResponse.data) == null ? void 0 : _b2.parent)) {
@@ -12723,7 +12737,7 @@ function XViewScene({
12723
12737
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
12724
12738
  }
12725
12739
  },
12726
- /* @__PURE__ */ React23.createElement(
12740
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ React23.createElement(
12727
12741
  XViewSidebar,
12728
12742
  {
12729
12743
  dbNodes: searchableDbNodes,
@@ -13051,9 +13065,17 @@ async function save_view_data_logic(db_services, filename, data) {
13051
13065
  return { success: false, error: error.message };
13052
13066
  }
13053
13067
  }
13054
- async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13068
+ async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
13055
13069
  var _a, _b;
13056
13070
  try {
13071
+ if (!session || !session.user) {
13072
+ return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
13073
+ }
13074
+ const membershipCheck = await db_services.check_membership(owner_id, type, scene_config, session.user.id);
13075
+ const isFullMember = membershipCheck.success && membershipCheck.isValidMember;
13076
+ if (!isFullMember && !focusNodeId && !focusAncestryId) {
13077
+ return { success: false, error: "Acesso Negado: Voc\xEA n\xE3o possui permiss\xE3o para acessar este cen\xE1rio." };
13078
+ }
13057
13079
  const sceneResponse = await db_services.get_file(`x_view_scenes/${owner_id}/${scene_config}`);
13058
13080
  if (!sceneResponse || !sceneResponse.success) {
13059
13081
  console.error("Falha ao buscar dados da cena:", sceneResponse == null ? void 0 : sceneResponse.error);
@@ -13142,8 +13164,7 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13142
13164
  ancestryData.forEach((anc) => {
13143
13165
  const targetSourceId = anc._source_file_id || anc._imported_from_view_id;
13144
13166
  const targetOwnerId = anc._source_owner_id || anc._imported_from_view_owner_id;
13145
- if (targetSourceId && targetSourceId !== scene_config && // Não é o arquivo atual
13146
- targetOwnerId) {
13167
+ if (targetSourceId && targetSourceId !== scene_config && targetOwnerId) {
13147
13168
  const isAlreadyLoadedAsParent = parentDbObjects.some((db) => String(db.db_id) === String(targetSourceId));
13148
13169
  if (!isAlreadyLoadedAsParent) {
13149
13170
  const key = `${targetOwnerId}/${targetSourceId}`;
@@ -13174,7 +13195,6 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13174
13195
  });
13175
13196
  } else if (result.status === "fulfilled" && !((_b2 = result.value) == null ? void 0 : _b2.success)) {
13176
13197
  failedSources.add(result.value._meta_key);
13177
- } else if (result.status === "rejected") {
13178
13198
  }
13179
13199
  });
13180
13200
  ancestryData = ancestryData.filter((localAnc) => {
@@ -13243,7 +13263,6 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13243
13263
  ...ancestry,
13244
13264
  tree: cleanedTree,
13245
13265
  abstraction_tree: cleanedAbstraction
13246
- // Salva a árvore limpa
13247
13266
  };
13248
13267
  }).filter(Boolean);
13249
13268
  if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
@@ -13254,16 +13273,100 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
13254
13273
  console.error("Falha ao salvar o arquivo de ancestralidade da cena atualizado:", saveError);
13255
13274
  }
13256
13275
  }
13276
+ if (!isFullMember) {
13277
+ const requiredNodeIds = /* @__PURE__ */ new Set();
13278
+ const requiredAncestryIds = /* @__PURE__ */ new Set();
13279
+ if (focusNodeId) requiredNodeIds.add(String(focusNodeId));
13280
+ if (focusAncestryId) requiredAncestryIds.add(String(focusAncestryId));
13281
+ const allNodesFromDb = Object.values(parentData).flatMap((db) => db.nodes || []);
13282
+ const extractDependenciesFromText = (text) => {
13283
+ if (!text) return;
13284
+ const mentionRegex = /\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g;
13285
+ const refRegex = /\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g;
13286
+ let match;
13287
+ while ((match = mentionRegex.exec(text)) !== null) {
13288
+ requiredNodeIds.add(match[1]);
13289
+ }
13290
+ while ((match = refRegex.exec(text)) !== null) {
13291
+ if (match[1] === "node") requiredNodeIds.add(match[2]);
13292
+ if (match[1] === "ancestry") requiredAncestryIds.add(match[2]);
13293
+ }
13294
+ };
13295
+ const extractTreeDependencies = (treeItem) => {
13296
+ var _a2;
13297
+ if (!treeItem) return;
13298
+ if (treeItem.node_id) requiredNodeIds.add(String(treeItem.node_id));
13299
+ if ((_a2 = treeItem.node) == null ? void 0 : _a2.id) requiredNodeIds.add(String(treeItem.node.id));
13300
+ if (treeItem.children) {
13301
+ treeItem.children.forEach(extractTreeDependencies);
13302
+ }
13303
+ if (treeItem.parallel_branches) {
13304
+ treeItem.parallel_branches.forEach((branch) => {
13305
+ if (branch.linked_ancestry_id) {
13306
+ requiredAncestryIds.add(String(branch.linked_ancestry_id));
13307
+ }
13308
+ if (branch.description) extractDependenciesFromText(branch.description);
13309
+ if (branch.description_sections) {
13310
+ branch.description_sections.forEach((s) => extractDependenciesFromText(s.content));
13311
+ }
13312
+ extractTreeDependencies(branch.tree);
13313
+ });
13314
+ }
13315
+ };
13316
+ let previousSize;
13317
+ do {
13318
+ previousSize = requiredNodeIds.size + requiredAncestryIds.size;
13319
+ requiredAncestryIds.forEach((ancId) => {
13320
+ const anc = ancestryData.find((a) => String(a.ancestry_id) === ancId);
13321
+ if (anc && !anc.is_private) {
13322
+ if (anc.description) extractDependenciesFromText(anc.description);
13323
+ if (anc.description_sections) {
13324
+ anc.description_sections.forEach((s) => extractDependenciesFromText(s.content));
13325
+ }
13326
+ extractTreeDependencies(anc.tree);
13327
+ extractTreeDependencies(anc.abstraction_tree);
13328
+ }
13329
+ });
13330
+ requiredNodeIds.forEach((nodeId) => {
13331
+ const node = allNodesFromDb.find((n) => String(n.id) === nodeId);
13332
+ if (node) {
13333
+ if (node.description) extractDependenciesFromText(node.description);
13334
+ if (node.description_sections) {
13335
+ node.description_sections.forEach((s) => extractDependenciesFromText(s.content));
13336
+ }
13337
+ }
13338
+ });
13339
+ } while (requiredNodeIds.size + requiredAncestryIds.size > previousSize);
13340
+ const restrictedSceneData = { ...validatedSceneData, nodes: [], links: [] };
13341
+ const restrictedParentData = {};
13342
+ const restrictedAncestryData = ancestryData.filter((a) => requiredAncestryIds.has(String(a.ancestry_id)) && !a.is_private);
13343
+ for (const [dbId, dbContent] of Object.entries(parentData)) {
13344
+ const filteredNodes = (dbContent.nodes || []).filter((n) => requiredNodeIds.has(String(n.id)));
13345
+ if (filteredNodes.length > 0) {
13346
+ restrictedParentData[dbId] = { ...dbContent, nodes: filteredNodes, links: [] };
13347
+ }
13348
+ }
13349
+ if (focusNodeId) {
13350
+ const mainNode = allNodesFromDb.find((n) => String(n.id) === String(focusNodeId));
13351
+ if (mainNode) {
13352
+ restrictedSceneData.nodes = [mainNode];
13353
+ }
13354
+ }
13355
+ return {
13356
+ success: true,
13357
+ data: {
13358
+ scene: restrictedSceneData,
13359
+ parent: restrictedParentData,
13360
+ ancestry: restrictedAncestryData
13361
+ }
13362
+ };
13363
+ }
13257
13364
  return {
13258
13365
  success: true,
13259
- data: {
13260
- scene: validatedSceneData,
13261
- parent: parentData,
13262
- ancestry: ancestryData
13263
- }
13366
+ data: { scene: validatedSceneData, parent: parentData, ancestry: ancestryData }
13264
13367
  };
13265
13368
  } catch (error) {
13266
- console.error("catch (error) em get_scene_view_data_logic:", error);
13369
+ console.error("Erro em get_scene_view_data_logic:", error);
13267
13370
  return { success: false, error: error.message };
13268
13371
  }
13269
13372
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.3-dev.6",
3
+ "version": "1.2.3-dev.8",
4
4
  "description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
5
5
  "author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
6
6
  "license": "UNLICENSED",