diff --git a/src/components/B4ACodeTree/B4ACodeTree.react.js b/src/components/B4ACodeTree/B4ACodeTree.react.js index d562bba98..a993977c8 100644 --- a/src/components/B4ACodeTree/B4ACodeTree.react.js +++ b/src/components/B4ACodeTree/B4ACodeTree.react.js @@ -166,6 +166,8 @@ export default class B4ACodeTree extends React.Component { } else if (selected.text === 'public') { source = publicFolderPlaceholder + } else { + source = 'Select a file to view' } } } @@ -269,7 +271,7 @@ export default class B4ACodeTree extends React.Component { else if (this.state.isFolderSelected === true) { content = this.state.source && this.state.source !== '' ? :
; } else if (this.state.selectedFile) { @@ -294,7 +296,7 @@ export default class B4ACodeTree extends React.Component { ; } else { content = ( - + ); } diff --git a/src/components/B4ACodeTree/B4ATreeActions.js b/src/components/B4ACodeTree/B4ATreeActions.js index e7b83aff4..1ffe649bc 100644 --- a/src/components/B4ACodeTree/B4ATreeActions.js +++ b/src/components/B4ACodeTree/B4ATreeActions.js @@ -248,11 +248,43 @@ const getConfig = (files) => { return { plugins: ['contextmenu', 'dnd', 'sort', 'types', 'unique', 'changed'], core: { - 'check_callback': true, + 'check_callback': async function (operation, node, node_parent) { + if (operation === 'create_node' && node.type === 'new-folder') { + const originalInputName = node.text; + const folderList = []; + node_parent.children.forEach(child => { + const childNode = $('#tree').jstree('get_node', child); + if ((childNode.type === 'new-folder' || childNode.type === 'folder') && childNode.text === node.text) { + folderList.push(childNode); + node.text = folderList.length ? `${originalInputName} (${folderList.length})` : `${originalInputName}`; + } + }); + } + if (operation === 'create_node' && node.type === 'new-file') { + const duplicate = node_parent.children.find(child => { + const childNode = $('#tree').jstree('get_node', child); + if ((childNode.type === 'new-file' || childNode.type === 'default') && childNode.text === node.text) {return true;} + return false; + }); + if (duplicate) { + overwriteFileModal.text = node.text + ' file already exists. Do you want to overwrite?' + // Show alert and wait for the user response + const alertResponse = await MySwal.fire(overwriteFileModal); + if (alertResponse.value) { + $('#tree').jstree('delete_node', duplicate); + const newNodeId = $('#tree').jstree('create_node', node_parent.id, node); + $('#tree').jstree('deselect_all'); + $('#tree').jstree('select_node', newNodeId); + } + } + } + return true; + }, 'data': files, 'theme': { 'name': 'default-dark', - } + }, + 'multiple': false, }, contextmenu: {items: customMenu}, types: { @@ -309,10 +341,20 @@ const selectFileOnTree = (nodeId) => { $('#tree').jstree().select_node(nodeId); // select specified node } -const sanitizeHTML = (str) => { - return str.replace(/[^\w. ]/gi, function (c) { - return '&#' + c.charCodeAt(0) + ';'; - }); +const sanitizeHTML = (filename) => { + const illegalRe = /[\/\?<>\\:\*\|"]/g; // Illegal characters for filenames + const controlRe = /[\x00-\x1f\x80-\x9f]/g; // Illegal control characters + const scriptTagRe = /.*?<\/script>|script/gi; // Script tags, case-insensitive and global match + + // Remove illegal and control characters + let cleanedFilename = filename.replace(illegalRe, '') .replace(controlRe, '').replace(scriptTagRe, ''); + + // Truncate to 200 characters if necessary + if (cleanedFilename.length > 200) { + cleanedFilename = cleanedFilename.substring(0, 200); + } + + return cleanedFilename; }; export default { diff --git a/src/components/PermissionsDialog/B4aPermissionsDialog.react.js b/src/components/PermissionsDialog/B4aPermissionsDialog.react.js index 526a92eb2..4e711f1d4 100644 --- a/src/components/PermissionsDialog/B4aPermissionsDialog.react.js +++ b/src/components/PermissionsDialog/B4aPermissionsDialog.react.js @@ -1085,7 +1085,8 @@ export default class B4aPermissionsDialog extends React.Component { ); } else if (pointer) { // get class info from schema - const { type, targetClass } = columns[key]; + const selectedCol = columns.find(col => col.name === key); + const { type, targetClass } = selectedCol; const pillText = type + (targetClass ? `<${targetClass}>` : ''); diff --git a/src/components/Sidebar/SidebarSection.react.js b/src/components/Sidebar/SidebarSection.react.js index cf8c7b03c..4b5ec3b94 100644 --- a/src/components/Sidebar/SidebarSection.react.js +++ b/src/components/Sidebar/SidebarSection.react.js @@ -9,10 +9,12 @@ import Icon from 'components/Icon/Icon.react'; import { Link } from 'react-router-dom'; import React from 'react'; import styles from 'components/Sidebar/B4aSidebar.scss'; +import { amplitudeLogEvent } from 'lib/amplitudeEvents'; const sendEvent = () => { // eslint-disable-next-line no-undef - back4AppNavigation && back4AppNavigation.atApiReferenceIntroEvent && back4AppNavigation.atApiReferenceIntroEvent() + // back4AppNavigation && back4AppNavigation.atApiReferenceIntroEvent && back4AppNavigation.atApiReferenceIntroEvent() + amplitudeLogEvent('at API Reference Introduction'); } const SidebarSection = ({ active, children, name, link, icon, style, primaryBackgroundColor, secondaryBackgroundColor, isCollapsed, onClick, badge }) => { diff --git a/src/components/Sidebar/SidebarSubItem.react.js b/src/components/Sidebar/SidebarSubItem.react.js index 8757eb7ea..8afef8960 100644 --- a/src/components/Sidebar/SidebarSubItem.react.js +++ b/src/components/Sidebar/SidebarSubItem.react.js @@ -9,11 +9,13 @@ import { Link } from "react-router-dom"; import React from "react"; import styles from "components/Sidebar/B4aSidebar.scss"; import B4aBadge from "components/B4aBadge/B4aBadge.react"; +import { amplitudeLogEvent } from 'lib/amplitudeEvents'; const sendEvent = () => { - back4AppNavigation && - back4AppNavigation.atApiReferenceIntroEvent && - back4AppNavigation.atApiReferenceIntroEvent(); + // back4AppNavigation && + // back4AppNavigation.atApiReferenceIntroEvent && + // back4AppNavigation.atApiReferenceIntroEvent(); + amplitudeLogEvent('at API Reference Introduction'); }; let SidebarSubItem = ({ active, name, action, link, children, badge }) => {