Need help choosing the right stack for a static log parser application

Calling all the front-end experts to help me with the below problem:-

Context of the problem:-

I am currently working on building a log parser for the set of logs in txt format. This log parser is an HTML page that will read the existing .txt file and segregate each log based on multiple patterns on different columns like log level, timestamp etc using a regular expression and display it to the user in a table format. A similar screenshot is shown below:-
Example of the application I am going to build

Detailed functionality of the problem :-

  1. The webpage should load the .txt log file which is present in the location.

  2. Then the parsing of the log text file should happen through regular expression, where we group the text according to multiple formats like test cases, devices used, log level etc.

  3. Then display these logs in the respective column.

  4. We will have a filter option also, which user can use to remove or add the filters according to various combinations of the groups.

The core functionality for which I need help is:- how to build an effective parser of the text from the log files, Is normal regex enough or should I use any library?

Since I am displaying the logs in the table format as shown above, should I create this table from scratch or is there any library available that I can customize and use it?

Research I have done:-

I am a backend dev for a device driver testing at my company and it’s been more than 2 years since I did anything related to web development. So I am not familiar with the new frameworks and web development as a whole. But here are the things I did research on for building this application:-

  1. Our team already did somewhat similar to this using basic vanilla javascript. The log parsing using regex was working seamlessly for low-memory files, but when the log text file size starts getting bigger, we faced huge latency even for initial parsing. This made the solution unusable along with some design deficits.

  2. During my intern days, where I worked in frontend, I did all the static applications using Webpack which could bring the total code size and provides modification even if I use multiple libraries.

I am planning to use the Webpack solution for now, but if there are any better suggestions, I am ready to learn and explore that path. So please suggest if you find any better alternative?

The function replace(/s+/g,’ ‘).trim() and trim() is not good working for input value

I tried to use replace(/s+/g,' ').trim() as well as just .trim() but it’s not working.

I want to remove any spaces typed in input1 from input2 and input3. Please help.

var input1 = document.getElementById('myInput1');
var input2 = document.getElementById('myInput2');
var input3 = document.getElementById('myInput3');

  input1.addEventListener('change', function() {
    input2.value = input1.value + "@gmail.com".replace(/s+/g,' ').trim();
    input3.value = input1.value + "@gmail.com".trim();
  });
<input type="text" id="myInput1" />
<input type="text" id="myInput2" />
<input type="text" id="myInput3" />

Fetching dynamic data when user loads page

I was wondering one thing, since I am not using React or any other JS framework, only vanilla JS, I noticed that it takes a second to retrieve an image from Firebase Storage. Do you know any workaround for this so that the UX wont be effected? I am kinda thinking that this will have an impact of the overall speed and performance of the app… And I really dont want to convert this entire project to React or any other framework. If its not easy to integrate. Since the project is massive by now and will take months to convert probably.

How to correctly create npm package with multiple entrypoints

I’m writing my own project on VUE version 3 (+TS). I moved some utility classes to a separate NPM library. My library is assembled into several JS files (one for each class) + all exports from these files are re-exported to index.js:

import StorageService from './lib/storageService';
import TransportService from './lib/transportService';
import TokenService from './lib/tokenService';
import AuthService from './lib/authService';

const myServices = {
  StorageService,
  TransportService,
  TokenService,
  AuthService,
};

export { myServices as default, StorageService, TransportService, TokenService, AuthService };

The library’s package.json file is as follows:

// ..... Выше - стандартные поля
  "type": "module",
  "files": [
    "src",
    "dist/*",
    "index.d.ts",
    "auth-service.d.ts",
    "token-service.d.ts",
    "storage-service.d.ts",
    "transport-service.d.ts"
  ],
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "type": "./dist/index.d.js"
    },
    "./authService": {
      "import": "./dist/auth-service.js",
      "type": "./dist/auth-service.d.js"
    },
    "./tokenService": {
      "import": "./dist/token-service.js",
      "type": "./dist/token-service.d.js"
    },
    "./storageService": {
      "import": "./dist/storage-service.js",
      "type": "./dist/storage-service.d.js"
    },
    "./transportService": {
      "import": "./dist/transport-service.js",
      "type": "./dist/transport-service.d.js"
    }
  },
  "main": "./dist/index.js",
  "module": "./dist/index.js"

I’m installing my NPM package. If I import classes from index.js – everything works as it should. But if I want to import a specific class from the corresponding JS file from my lib, I get an error in WebStorm: Vue: Cannot find module my-services/transportService or its corresponding type declarations.

import { TransportService } from 'my-services';
// First version: This works

import TransportService from 'my-services/transportService';
// Second version: In this case, I get an error in WebStorm: Vue: Cannot find module my-services/transportService or its corresponding type declarations.

In this case, the application build passes, and everything works in both: the first and second versions! But in the second option, WebStorm highlights the import and does not understand the types that come from the imported module (which negates the typescript typing).

What am I doing wrong? And what is the correct way to assemble/design a library with several entrypoints? (I’m new to this, and I still need to make a separate library of components, and there I also really want to decompose groups of components that are common in meaning into separate entrypoints).

I found a description of a similar problem on the Internet, and they suggest setting the Vue Service parameter in the Vue Language Server (Volar) in the Typescript/VUE Webstorm settings. I did that, but it didn’t help me. 🙁

Image Authenticaion

I have a NestJS application that servers images which requires authentication. For my authentication I’m using JWT however when I want to display the image in an img tag I cannot attach the Authorization header to the GET request. I’ve read some articles about how to authenticate files, some recommended Signed Url but did not really show how exactly it should be implemented.

I use NestJS for the backend API and MINIO for my datastore.

How to simulate a HTML button press on other tab while being in another tab without switching tabs

I want to make a tampermonkey script that presses a button with “next” id (button id=”next”) on youtubePlaylistRandomizer website when I press a specific key combination. I want it to work even if I am on another tab.I don’t want to switch tabs, simulate the press and return to my tab back again.

I tried making a script while getting help from Google Gemini. I could do it but it only worked when I was on that tab.
I tried to adding a thing to local storage with one script whenever i pressed my key combination(Alt + N). Then tried to read local storage every second and do the click on button thing when I had the thing in the local storage. But it still didn’t work except only if I were on that tab.

React app is crashing when I try to render rc-tree and and a MUI TextField which displays all the selected values

This is the component which I wrote:

const CheckableTree = () => {
  const [checkedKeys, setCheckedKeys] = useState([]);
  const [checkedLeafKeys, setCheckedLeafKeys] = useState([]);

  const onCheck = useCallback((checkedKeys, info) => {
    const checkedLeafNodeKeys = info.checkedNodes
      .filter((node) => !node.children)
      .map((node) => node.key);
    setCheckedLeafKeys(checkedLeafNodeKeys);
    setCheckedKeys(checkedKeys);
  }, []);

  return (
    <FormControl>
      <Tree
        checkable
        selectable={false}
        onCheck={onCheck}
        checkedKeys={checkedKeys}
        defaultExpandAll
        autoExpandAll
        defaultExpandParent
        multiple
        showIcon={false}
        treeData={treeData}
        switcherIcon={null}
      />
    <TextField
      id="outlined-basic"
      label="Checked Leaf Nodes"
      variant="outlined"
      InputProps={{
        startAdornment: checkedLeafKeys.map((key) => (
          <Chip key={key} label={key} style={{ margin: "0 5px" }} />
        )),
      }}
    />
    </FormControl>
  );
};

I want the TextField to be displayed with MUI Chips but the app is crashing. I tried using useMemo but had no luck with that too.

I am fairly new to React. Any help is appreciated. Thanks!

Puppeteer – XLSX: Missing data in CSV from Array

I have run into an unusual issue related to CSV generation from an array of data i create through web-scraping using Puppeteer.

Through console logs in my code i can see that all the data is correctly obtained after the scrape. Thereafter, i create a CSV file mapped in a particular way with the data collected.

For some reason, not all the data is being written in the CSV file when i do a comparison with my array.

What could be the issue – code below (i have posted the part of the scrape and the code reflecting the generation of the CSV file. Can post anything relevant/required upon request

Thanks in advance

for(const prodPage of prodLinks){
    if(prodPage){
      await page.goto(prodPage).then(async() => {
        //console.log('n' + 'Scraping ' + prodPage + 'n')
        //try {
          const extractProdInfo = await page.evaluate((furnitureRange, rangeLink, prodPage) => {
      
            const handle = document.querySelector('.barcode').textContent.toString()
             const title = document.querySelector('[data-ui-id="page-title-wrapper"]').textContent
      
             const colour = document.getElementById('attr-other').querySelector('tr:first-child').querySelector('td:last-child').textContent
      
            const desc = document.getElementById('js-product-description').textContent;
      
            const dimensionsArray = [];
            const dimensionsTable = document.getElementById('attr-dimensions');
            const dimensionRows = dimensionsTable.querySelectorAll('tr');
      
            dimensionRows.forEach(row => {
                const dimensionLabel = row.querySelector('td:first-child').textContent.trim();
                const dimensionValue = row.querySelector('td:last-child').textContent.trim();
                const concatenatedDimension = `${dimensionLabel}: ${dimensionValue}`;
                dimensionsArray.push(concatenatedDimension);
            });
      
            let detailsArray = [];
            const otherDetailsTable = document.getElementById('attr-other');
            const detailRows = otherDetailsTable.querySelectorAll('tr');
            
            detailRows.forEach(row => {
                const detailLabel = row.querySelector('td:first-child').textContent.trim();
                const detailValue = row.querySelector('td:last-child').textContent.trim();
                const concatenatedDetail = `${detailLabel}: ${detailValue}`;
                detailsArray.push(concatenatedDetail);
            });
            
            // Remove the RRP detail from the array
            detailsArray = detailsArray.filter(detail => !detail.startsWith('RRP'));
      
            const body  = desc + "<br><br>" + "nn<b>Dimensions:</b>n" + dimensionsArray.join("<br>") + "<br><br>" + "nn<b>Highlights:</b>n" + detailsArray.join('<br>')
      
            //CHANGE ACCORDING TO SCRAPE TYPE
             const type = 'Tables'
             const categoryNo = '2158'
            // // ------------------------------
      
            const tagsArray = []
            for (const range of furnitureRange) {
              if (rangeLink.includes(range)) {
                let capitalizedTag;
                if (range.includes('-')) {
                  // Remove hyphens and capitalize both words
                  capitalizedTag = range.split('-')
                    .map(word => word.charAt(0).toUpperCase() + word.slice(1))
                    .join(' ');
                } else {
                  // Capitalize first letter only
                  capitalizedTag = range.charAt(0).toUpperCase() + range.slice(1);
                }
                tagsArray.push(capitalizedTag);
              }
            }
            tagsArray.push(type, colour)
      
            const imgElements = document.querySelectorAll('.fotorama__img');
            const imageURLs = [];
            imgElements.forEach(img => {
              const src = img.getAttribute('src');
              // Filter out thumbnail URLs
              if (!src.includes('thumbnail') && !src.includes('cache/c')) {
                imageURLs.push(src);
              }
            });
      
            let priceElement = document.getElementById('js-original-price');
            let priceText;
        
            if (priceElement) {
                priceText = priceElement.textContent.trim().replace('£', '');
            } else {
                priceElement = document.querySelector('.pack-price');
                if (priceElement) {
                    priceText = priceElement.textContent.trim().replace('£', '');
                }
            }
             
            priceText = Math.ceil(priceText * 1.45).toFixed(2).toString()
      
            return {
                handle: handle,
                title: title + ' - ' + colour,
                body: body,
                vendor: 'gallery-direct',
                collection: type,
                productCategory: categoryNo,
                type: type,
                tags: tagsArray.join(','),
                imageSrc: imageURLs,
                imagePosition: '1',
                variantPrice: priceText,
                variantSKU: handle,
                prodURL: prodPage
            };
          }, furnitureRange, rangeLink, prodPage)
          //console.log(allProductData)

          allProductData.push(extractProdInfo)
      })
    }  
  }

//console.log(allProductData)

//Create Failed Products Data Log
function createFailedLog(outputName, errors) {
  const filePath = 'failed-scraping-products.txt';

  // Format the date
  const dateFormatted = new Date().toISOString().split('T')[0];

  // Create the batch heading
  const batchHeading = outputName + ' Log - ' + dateFormatted + 'n';

  // Convert the errors array to a string
  const errorString = errors.join('n');

  // Combine the batch heading and errors
  const dataToWrite = batchHeading + errorString + 'n' + 'n';

  // Check if the file exists
  if (fs.existsSync(filePath)) {
    // If the file exists, append the new errors with batch heading
    fs.appendFileSync(filePath, dataToWrite);
  } else {
    // If the file doesn't exist, create a new file and write the errors with batch heading
    fs.writeFileSync(filePath, dataToWrite);
  }
}
console.log('n' + 'Failed Scrapes: ' + failedProdData.length)
console.log('allProductData: ' + allProductData.length)
if(failedProdData.length > 0){
  console.log('Writing Failed Scraping Products log ... ')
  createFailedLog(outputName,failedProdData)
}

/// Function to create CSV data from object data
const createCSVData = (data, headers, defaults) => {
  const csvData = [];
  
  // Push headers as the first row
  csvData.push(headers);
  
  data.forEach(item => {
      const { imageSrc, ...rest } = item;
      imageSrc.forEach((imgSrc, index) => {
          const newRow = {
              'Handle': item.handle, // Copy handle only for the first image
              'Title': index === 0 ? item.title : '', // Copy title only for the first image
              'Body (HTML)': index === 0 ? item.body : '', // Copy body only for the first image
              'Vendor': index === 0 ? item.vendor : '', // Copy vendor only for the first image
              'Collection': index === 0 ? item.collection : '', // Copy collection only for the first image
              'Product Category': index === 0 ? item.productCategory : '', // Copy product category only for the first image
              'Type': index === 0 ? item.type : '', // Copy type only for the first image
              'Tags': index === 0 ? item.tags : '', // Copy tags only for the first image
              'Published': index === 0 ? defaults['Published'] : '',
              'Option1 Name': defaults['Option1 Name'],
              'Option1 Value': defaults['Option1 Value'],
              'Option2 Name': defaults['Option2 Name'],
              'Option2 Value': defaults['Option2 Value'],
              'Option3 Name': defaults['Option3 Name'],
              'Option3 Value': defaults['Option3 Value'],
              'Variant SKU': item.variantSKU,
              'Variant Grams': index === 0 ? defaults['Variant Grams'] : '',
              'Variant Inventory Qty': index === 0 ? defaults['Variant Inventory Qty'] : '',
              'Variant Inventory Policy': index === 0 ? defaults['Variant Inventory Policy'] : '',
              'Variant Fulfillment Service': index === 0 ? defaults['Variant Fulfillment Service'] : '',
              'Variant Price': index === 0 ? item.variantPrice : '', // Copy variant price only for the first image
              'Variant Compare At Price': index === 0 ? defaults['Variant Compare At Price'] : '',
              'Variant Requires Shipping': index === 0 ? defaults['Variant Requires Shipping'] : '',
              'Variant Taxable': index === 0 ? defaults['Variant Taxable'] : '',
              'Image Src': imgSrc,
              'Image Position': index + 1, // Increment Image Position
              'Gift Card': index === 0 ? defaults['Gift Card'] : '',
              'Variant Weight Unit': index === 0 ? defaults['Variant Weight Unit'] : '',
              'Status': index === 0 ? defaults['Status'] : ''
          };
          csvData.push(Object.values(newRow));
      });
  });
  return csvData;
};

// Create CSV data
const csvData = createCSVData(allProductData, headersArray, defaultValues);

// Convert data to worksheet
const ws = XLSX.utils.aoa_to_sheet(csvData);

console.log('All product data collected. Now generating CSV file. This may take several minutes...')

// Create workbook and add worksheet
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'ScraperWebsite');

//Format CSV generated sheet
const dateFormatted = new Date().toISOString().split('T')[0];
const filename = outputName+`_${dateFormatted}.csv`;
// Write workbook to file
XLSX.writeFile(wb, filename);
  console.log( 'CSV generated')


    // Read the generated CSV file
  const csvFilePath = filename; // Assuming filename contains the path to the generated CSV file
  const readCSV = fs.readFileSync(csvFilePath, 'utf8').split('n');

  // Extract handles from the CSV data
  const csvHandles = readCSV.slice(1) // Exclude the header row
    .map(row => row.split(',')[0]); // Assuming 'Handle' is the first column

  // Find handles in allProductData that are not in the CSV file
  const missingHandles = allProductData.filter(item => !csvHandles.includes(item.handle));

  // Extract prodURLs for missing handles
  const missingUrls = missingHandles.map(item => item.prodURL);

  // Log the missing URLs
  console.log('Missing URLs in CSV:');
  console.log(missingUrls);

Can someone explain how to use tmdb api to find watch providers?

I am currently working on a project where i use tmdb api, but now when i need to get watch provider for movies i only get empty array in my console.

 const Testa = () =>{
    fetch("https://api.themoviedb.org/3/movie/106646/watch/providers?&api_key=")
    .then((res) => res.json())
    .then((data1) => {
       setIsWatching(data1);
       console.log(isWatching)
     })
    }

I have tried to read docs and copy code but i still get empty array in console

extends AudioWorkletProcessor class and using an existing audioNode inside the class

I would like to create a new AudioNode by extending using the AudioWorkletProcessor class but I would like to use an existing audioNode (let’s say a GainNode) inside the class, for instance inside the process function. the problem is that I don’t know how to access to the AudioContext inside the the Class or the GainNode.process function, is there a proper way to do so ?

I know how to create and connect audionodes the regular way, that’s not my purpose here. I would like to create a new audioNode build from existing audionodes that could be used as one audionode entity.

TIA

Text identified via aria-describedby not “read” by screen reader

I am adding accessibility to my web application. I have two required fields in a form that I wish to associate with two separate error messages, defined as spans. I am using aria-invalid to flag the fields when they are not present, and aria-describedby to identify the error message elements. The screen reader software (JAWS) is not reading the text of the associated error message elements when the input field gets focus.

<form id="kiosksform" action="loc/save" method="post">
  <h1 class="title mt-2" id="registration-title">Create Kiosk</h1>
  <div class="bg-3 text-left">
    <table id="table" class="text-left table table-hover ml-0 table_edit mt-5">
      <thead>
        <tr>
          <th class="text-center" scope="col"><u data-toggle="tooltip" title="Item"</u></th>
          <th class="text-center" scope="col"><u data-toggle="tooltip" title="Enter the value">Value</u></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td class="kiosk-table-data">KIOSK Code</td>
          <td class="kiosk_table_data">
            <input type="text" name="kiosk_code" id="kiosk_code_id" value="" data-toggle="tooltip"
                   title="Enter kiosk code" class="pt1 p1-2" required 
                   aria-describedby="kiosk_code_validation" aria-invalid="false" 
                   onkeyup="validateFields()">
          </td>
        </tr>
        <tr>
          <td class="kiosk-table-data">KIOSK Name</td>
          <td class="kiosk_table_data">
            <input type="text" name="kiosk_name" id="kiosk_name_id" value="" data-toggle="tooltip"
                   title="Enter kiosk name" class="pt1 p1-2" required 
                   aria-describedby="kiosk_name_validation" aria-invalid="false" 
                   onkeyup="validateFields()">
          </td>
        </tr>
      </tbody>
    </table>

    <div class="button-holder mt-3">
      <button type="submit" onclick="return validateForm()" id="regButton" 
              class="btn btn-primary btn-width" data-toggle="tooltip" 
              title="Click to save your changes">Save</button>
      <a href="/loc" id="regButtonCancel" class="btn btn-width text-decoration-none"
         data-toggle="tooltip" title="Click to cancel transaction">Cancel</a>
    </div>

    <div class="container mt-3">
      <span id="kiosk_code_validation" class="text-danger text-center m1"> </span>
      <span id="kiosk_name_validation" class="text-danger text-center m1"> </span>
    </div>
  </div>
</form>

<script>
  function validateFields() {
    let formValidated      = false
    let kioskCodeValidated = false
    let kioskNameValidated = false

    let kioskCode = document.getElementById('kiosk_code_id');
    let kioskName = document.getElementById('kiosk_name_id');
    let kioskCodeValidation = document.getElementById('kiosk_code_validation');
    let kioskNameValidation = document.getElementById('kiosk_name_validation');

    document.getElementById("regButton").disabled = true

    if (kioskCode.value.length < 2) {
      kioskCodeValidation.innerHTML = "Kiosk Code must be at least two characters in length"
      kioskCodeValidation.style.display="block"
      kioskCode.setAttribute("aria-invalid", "true")
    } else {
      kioskCodeValidated = true
      kioskCodeValidation.style.display="none"
      kioskCodeValidation.innerHtml = ""
      kioskCode.setAttribute("aria-invalid", "false")
    }

    if (kioskName.value.length < 2) {
      kioskNameValidation.innerHTML = "Please enter a full Kiosk Name or location"
      kioskNameValidation.style.display="block"
      kioskName.setAttribute("aria-invalid", "true")
    } else {
      kioskNameValidated = true
      kioskNameValidation.style.display="none"
      kioskNameValidation.innerHtml = ""
      kioskName.setAttribute("aria-invalid", "false")
    }

    if (kioskCodeValidated && kioskNameValidated) {
        formValidated = true
        document.getElementById("regButton").disabled = false;
    }
  }

  validateFields();

Am I missing something to get JAWS to announce the error text when the field gets focus?

How to Dynamically Update HTML Table Content with JavaScript without jQuery?

I’m building a web application where I need to dynamically update the content of an HTML table based on user input, without using jQuery or any other libraries. I’ve managed to add rows to the table, but I’m struggling with updating existing rows. Here’s the HTML structure of my table:

<table id="data-table">
  <tr>
    <th>Name</th>
    <th>Age</th>
  </tr>
  <!-- Rows will be added here dynamically -->
</table>

And the JavaScript code I’ve used to add rows:

function addRow(name, age) {
  const table = document.getElementById("data-table");
  const row = table.insertRow(-1);
  const cell1 = row.insertCell(0);
  const cell2 = row.insertCell(1);
  cell1.innerHTML = name;
  cell2.innerHTML = age;
}

This works for adding new rows, but I’m unsure how to update an existing row’s cells with new data. Is there an efficient way to search for a row by one of the cell values (e.g., Name) and update it directly in plain JavaScript?