How can I return a Filter Formula reference range?

I’m trying to return a range I’ve gotten results with via cell formula with the app script equivalent so I can in turn overwrite the array with different values.

This is the formula I’m using which returns the correct range:

=FILTER( FILTER($10:$500, Beginning_Date <= Date_Range, End_Date >= Date_Range, Jobs_Range=Job), Employee_Name = Names_Range)

What this does is create an array by searching the rows of Date and Job ranges where conditions are True to return a range of columns, before being filtered a 2nd time on Names in a column to return the correct row.

How can I implement something that will return the resulting array in Apps Script?

function onOpen() {
    var ui = SpreadsheetApp.getUi();
    var menu = ui.createMenu('Replace Projected Hours')
    menu.addItem("Replace Hours","ReplaceProjectedHours").addToUi();
}

function ReplaceProjectedHours() {
  const ss = SpreadsheetApp.getActive();
  const sn = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Projected Hours');
  const sheetrange = sn.getRange("$1:$500").getValues();

  const dateRangeBeginning = ss.getRangeByName("Date_Range_Beginning").getValue();
  var dateRangeBeginningNumber = dateRangeBeginning.getTime()/1000/86400 + 25569;
  
  const dateRangeEnd = ss.getRangeByName("Date_Range_End").getValue();
  var dateRangeEndingNumber = dateRangeEnd.getTime()/1000/86400 + 25569;

  const daterange = ss.getRangeByName("Date_Support_Range").getValues();
  //Logger.log(Array.isArray(daterange));
  var dateCriteria = SpreadsheetApp.newFilterCriteria().whenNumberBetween(dateRangeBeginningNumber,dateRangeEndingNumber);
  var dateFilter = daterange.filter(function(d){return d[1]==dateCriteria});
  Logger.log(dateFilter);
  Logger.log(Array.isArray(dateFilter));

  var employeeName = ss.getRangeByName("Employee_Name").getValues();
  var employeeNameRange = ss.getRangeByName("Employee_Names_Range").getValues();
  //var employeeCriteria = employeeNameRange.getValues(employeeName);
  var employeeFilter = employeeNameRange.filter(function(e){return e[1]==employeeName})
  Logger.log(employeeFilter);
  Logger.log(Array.isArray(employeeFilter));

  const job = ss.getRangeByName("Job").getValue();
  const jobNameRange = ss.getRangeByName("Job_Names_Range").getValues();
  //var jobCriteria = SpreadsheetApp.newFilterCriteria().jobNameRange.getRange().getValues(job);
  var jobFilter = jobNameRange.filter(function(j){return j[1]==job});

  const projectedHoursPerWeek = ss.getRangeByName("Projected_Hours_per_Week").getValues();

  var filteredRowResults = sheetrange.filter(function(r){return r[1]==dateFilter && r[2]==jobFilter &&r[3]==employeeFilter});
  Logger.log(filteredRowResults);
   Logger.log(Array.isArray(filteredRowResults));

  //var filteredColumnResults = filteredRowResults.filter(function(c){return c[1]==employeeFilter});
  
  //var newSheet = ss.insertSheet();
  //newSheet.getRange(2,1,filteredRowResults.length).setValues(filteredRowResults);

  //filteredColumnResults.setValue(projectedHoursPerWeek);
 
  

}

Currently I’m not seeing any results from each individual filter function. They’re returning arrays but no values, and frankly I’m not sure if the filter function is the right tool for the formula equivalent in script.

There is also currently a problem with my dates comparison since I need to change the values from the dateRange into numbers correctly but I think that’s out of scope for this question.

Conflict between RequiredFieldValidator and Client Side CustomValidator

3rd time’s a charm. Let me apologize for not knowing proper StackOverflow etiquette in my previous two question attempts.

I am trying to validate a page. By design, it is allowable for the user to move to the next page of the application when there are invalid fields. Invalid fields need to be completed before a final submit on a subsequent page, but not to just move to the next page.

In addition to the validators, there is a UserControl that displays a validation summary. I am aware of the ValidationSummary control, but I need something different. My UserControl always shows all the items in it. If they are valid, they get a check mark, if not, no check mark.

Most of the validators on my page are plain RequiredFieldValidators. I validate the Textboxes with CustomValidators, using the ClientValidationFunction property.

I think my problem is that when I choose an item from a dropdown, and that server side validation fires, it incorrectly overwrites the client side validation that has already happened on the Textboxes.

How can I correct this behavior? I’ve already tried EnableClientScript=False on the dropdown.

The JavaScript and controls in question are as follows:

function Page_ClientValidate_NoBlock(strGroup)
{
    Page_ClientValidate(strGroup);
    Page_BlockSubmit = false;
}

function Validate_txtSample_CS(sender, args)
{
    args.IsValid = ValidateTextboxContent("<%=txtSample.ClientID%>", "<%=SFRvs.Line11_GreenCheck_ClientID%>");
}

function ValidateTextboxContent(strTextboxID, strGreenCheckID)
{
    var strValue = document.getElementById(strTextboxID).value;
    var booValid = (strValue != null && strValue != "");
    var strStyle;
    if (booValid == true)
        strStyle = 'visible';
    else
        strStyle = 'hidden';

    document.getElementById(strGreenCheckID).style.visibility = strStyle;
    return booValid;
}

<telerik:RadComboBox ID="cbDispo" runat="server" AutoPostBack="true" 
    EmptyMessage="? select"
    EnableVirtualScrolling="true" RenderMode="Lightweight" Width="180"
    OnSelectedIndexChanged="cbDispo_SelectedIndexChanged" >
</telerik:RadComboBox>
<asp:RequiredFieldValidator ID="valDispo" runat="server" 
    ControlToValidate="cbDispo" ValidationGroup="vgPage04" 
    Display="Static" CssClass="cssRF_splat"
    Text="*" ErrorMessage="Employee Disposition" >
</asp:RequiredFieldValidator>

<telerik:RadTextBox ID="txtSample" runat="server" AutoPostBack="false"
    RenderMode="Lightweight" style="max-width:none;" Resize="None" Width="330px"
    OnBlur="Page_ClientValidate_NoBlock('vgPage04');" >
</telerik:RadTextBox>
<asp:CustomValidator ID="valSample" runat="server" 
    ControlToValidate="txtSample"
    ClientValidationFunction="Validate_txtSample_CS" 
    ValidationGroup="vgPage04" ValidateEmptyText="True" 
    Display="Static" CssClass="cssRF_splat" 
    Text="*" ErrorMessage="Part of Body">
</asp:CustomValidator>

In Page_Load, both IsPostBack and !IsPostBack Page_Load call

Page.Validate();

Thanks!

Why does my brush algorithm draw jagged strokes?

Recently I’ve been working on a drawing web app using React.js and Pixi.js. I’ve encountered a problem with simulating drawing with a “brush” where, if I use a Graphic object and add lines to it for every mouse movement, the lines accumulate and make the app run slow at some point.
So I settled for an approach where instead of drawing every line and keeping it in memory, every line I draw, I clear immediately and the result of the line draw is recorded in a texture of a Sprite element which is then used to add that texture to the texture of a Container. I mimicked this approach from Pixi.js’s official website: Render Texture Advanced.
The code that handles the drawing:

bg // Graphic for input detection
.rect(0, 0, app.width, app.height)
.fill('white')
.on('pointermove', e => {
    const mouse = mousePos(e, app);
    stroke
    .clear()
    .moveTo(last.x, last.y)
    .lineTo(mouse.x, mouse.y)
    .stroke({
        color: 'red',
        width: 4,
        cap: 'round'
     });
const strokeTexture = app.renderer.generateTexture(stroke);
brush.texture = strokeTexture;

brush.position.set(last.x, last.y);

const temp = rt1;
rt1 = rt2;
rt2 = temp;

canvas.texture = rt1;

app.renderer.render({
    container: app.stage,
    target: rt2,
    clear: false
});

last = mouse;

The result of this is a brush stroke that is jagged and the stroke has an irregular path

The stroke has an irregular path

I’m not sure what’s causing this.

I’ve tinkered a bit by either removing the .moveTo or brush.position.set parts of the code or changing their arguments up, but nothing seems to work.

Recording System Audio in MacOS Using Electron JS without relying on BlackHole

I am working on an application with electron js which requires system audio to be recorded. I actually want the microphone+system audio just like a screen recorder(I just need audio).
I have researched a lot and found there are limitations in macOS that doesn’t allow capturing system audio. We have to use something like BlackHole.
I don’t want users to install BlackHole or similar to use my app on their system.
There is an app https://www.granola.ai/ which records system audio without BlackHole and yes they are also using electron js.

What I have tried:
Here is my current code which uses ffmpeg to record and save audio.

ipcMain.on('start-recording', () => {
  // save in the current folder
  const outputPath = path.join(app.getAppPath(), `meeting-${Date.now()}.mp3`);
  console.log(`Recording to: ${outputPath}`);

  // Check device indexes from ffmpeg -f avfoundation -list_devices true -i ""
  ffmpegProcess = spawn('ffmpeg', [
    '-f',
    'avfoundation',
    '-i',
    '1:0', // 1:0 = mic + system audio, tweak as needed
    '-acodec',
    'libavdevice',
    '-q:a',
    '4',
    outputPath,
  ]);

  ffmpegProcess.stderr.on('data', (data: any) => {
    console.log(`[ffmpeg] ${data}`);
  });

  ffmpegProcess.on('close', (code: any) => {
    console.log(`ffmpeg exited with code ${code}`);
    mainWindow?.webContents.send('recording-complete', outputPath);
  });
});

ipcMain.on('stop-recording', () => {
  console.log('stop-recording--2', ffmpegProcess);
  if (ffmpegProcess) {
    console.log('stop-recording');
    ffmpegProcess.stdin.write('q'); // Graceful stop
    ffmpegProcess.stdin.end();
    ffmpegProcess = null;
  }
});

Deleting data points in qDrant DB

I am trying to delete all the data points that are associated with a particular email Id, but I am encountering the following error.

source code:

app.get('/cleanUpResources', async (req, res) => {
    const _id = req.query.email;
    const embeddings = new VertexAIEmbeddings({
        model: "text-embedding-004",
    });

    const vectorStore = await QdrantVectorStore.fromExistingCollection(embeddings, {
        url: <url>,
        apiKey: <api-key>,
        collectionName: 'pdf-docs',
    });

    // Delete all points with payload field 'id' equal to req.body.email
    await vectorStore.delete({
        filter: {
            must: [
                {
                    key: "id",
                    match: { value: JSON.stringify(_id) },
                },
            ],
        },
    });

    return res.json({ message: `Deleted all points with id: ${id}` });
})

Error:

Error: Bad Request
    at Object.fun [as deletePoints] (file:///C:/Users/abhis/OneDrive/Desktop/PROJECTS/PDF-RAG/server/node_modules/@qdrant/openapi-typescript-fetch/dist/esm/fetcher.js:169:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async QdrantClient.delete (file:///C:/Users/abhis/OneDrive/Desktop/PROJECTS/PDF-RAG/server/node_modules/@qdrant/js-client-rest/dist/esm/qdrant-client.js:628:26)
    at async QdrantVectorStore.delete (file:///C:/Users/abhis/OneDrive/Desktop/PROJECTS/PDF-RAG/server/node_modules/@langchain/qdrant/dist/vectorstores.js:140:13)
    at async file:///C:/Users/abhis/OneDrive/Desktop/PROJECTS/PDF-RAG/server/app.js:73:5

qDrant DB Collection structure:

metadata: {
"source":"uploads1753380027445-401326695-CT20244465298_Appl…"
"pdf":{}
"loc":{}
"id":"<email_address>"
}

I have also gone through the documentation but not able to debug this.
https://v03.api.js.langchain.com/classes/_langchain_qdrant.QdrantVectorStore.html#delete

https://qdrant.tech/documentation/concepts/points/#delete-points

How to show custom alert on before unload event in react

I want to show dialog box with custom message on unload. the behavior is inconsistent.

  // Handle browser tab close or refresh
  useEffect(() => {
    const handleBeforeUnload = (e) => {
      e.preventDefault();
      e.returnValue = '';
    };
    window.addEventListener('beforeunload', handleBeforeUnload);
    return () => window.removeEventListener('beforeunload', handleBeforeUnload);
  }, []);

Datatable ajax reload with new data

So I already have my main table set up upon initial load in a javascript file as such:

let table = new DataTable('#UsersTable', {
    ajax: 'user_data',
    rowId: 'id',
    columns: [
        { data: 'id', className: 'dt-left' },
        { data: 'email' },
        { data: 'first_name' },
        { data: 'last_name' },
        { data: 'group' },
        { data: 'parent-group' },
        { data: 'role' },
        { data: 'create_date', className: 'dt-left' },
        { data: 'active' },
        { data: 'deleted' }
    ],
    layout: {
      topStart: 'buttons'
    },  
    buttons: [
      { extend: 'copy', text: '<i class="bi bi-clipboard-plus"></i> Copy', className: 'btn-primary btn-sm' },
      { extend: 'csv', text: '<i class="bi bi-filetype-csv"></i> CSV', className: 'btn-primary btn-sm' },
      { extend: 'excel', text: '<i class="bi bi-file-earmark-excel"></i> Excel', className: 'btn-primary btn-sm' },
      { extend: 'pdf', text: '<i class="bi bi-file-earmark-pdf"></i> PDF', className: 'btn-primary btn-sm' },
      { extend: 'print', text: '<i class="bi bi-printer"></i> Print', className: 'btn-primary btn-sm' }
    ],
    select: true,
    responsive: true,
    processing: true,  
    initComplete: function () {
      // Remove btn-secondary if still present
      document.querySelectorAll('.btn').forEach(btn => {
        btn.classList.remove('btn-secondary');
      });
    }
  });

but then when I’m in my user admin portal I have a filter function where the user should be able to filter down the data to a smaller data set. I want it to reload the table with the new data but the $(‘#UsersTable’).DataTable().ajax.reload(); of course just reloads the function from above. Here’s what I have that gets the correct filtered data:

 $('#filterform').submit(function() {
      event.preventDefault();
      
      var role_id = $('#role_id_ff').val();
      var is_active = $('#is_active_ff').val();
      var is_deleted = $('#is_deleted_ff').val();
      var license_type = $('#license_type_ff').val();
      var receive_news = $('#receive_news_ff').val();
      var receive_marketing = $('#receive_marketing_ff').val();
      var parent_id = $('#parent_id_ff').val();
      var group_id = $('#group_id_ff').val();

      $.ajax({
        url: "<?php echo base_url('/admin/users/get_list'); ?>", 
        type: "POST", 
        data: { // Data to be sent to the server as a plain object
          role_id: role_id,
          is_active: is_active,
          is_locked: 0,
          is_deleted: is_deleted,
          license_type: license_type,
          receive_news: receive_news,
          receive_marketing : receive_marketing,
          parent_id: parent_id,
          group_id: group_id
        },
        dataType: "json", // Expected data type from the server response (e.g., "json", "html", "text")
        success: function(response) {
          // Callback function executed on successful request
          console.log("Success:", response);
          
          //here I want to reload the table but with the new filtered data
          $('#UsersTable').DataTable().ajax.reload();
        },
        error: function(jqXHR, textStatus, errorThrown) {
          // Callback function executed on request error
          console.error("Error:", textStatus, errorThrown);
        }
      });
});

Kind of stuck here. I thought of just doing a new datatable call with the new data but it says I “can’t reinitialize”

Why does my input bar jump down and then return to its position after clicking the send button?

I’m building a chat interface using HTML, CSS, and JavaScript. Every time I send a message using the “Send” button, the input bar (where the user types messages) momentarily jumps down and then returns to its original position.

This only happens when I run the page using python3 -m http.server and open it on a mobile browser (like Chrome on Android). It seems like a layout reflow issue triggered by DOM updates or the virtual keyboard.

I have:

  • Used event.preventDefault() to stop default form behavior
  • Ensured the input stays focused after sending
  • Added padding to prevent overlap with the keyboard
  • Used position: fixed for the .chat-input-area

But the issue still persists.

to Reproduce

  1. Start a local server using python3 -m http.server
  2. Open the page on a mobile browser
  3. Type a message and click the Send button
  4. The input bar jumps down and comes back to its original position
const chatMessages = document.getElementById('chatMessages');
const chatInput = document.getElementById('chatMessageInput');
const sendBtn = document.getElementById('sendMessageBtn');

sendBtn.addEventListener('click', () => {
  const message = chatInput.value.trim();

  if (!message) return;

  const msgDiv = document.createElement('div');
  msgDiv.className = 'message';
  msgDiv.textContent = message;
  chatMessages.appendChild(msgDiv);
  chatInput.value = '';
  chatInput.focus();
  chatMessages.scrollTop = chatMessages.scrollHeight;
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body,
html {
  height: 100%;
  font-family: sans-serif;
}

.chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background: #111;
  color: white;
}

.chat-messages {
  flex-grow: 1;
  overflow-y: auto;
  padding: 16px;
}

.message {
  margin: 8px 0;
}


.chat-input-area {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  padding: 12px;
  background: #222;
}

.chat-input-area input {
  flex: 1;
  padding: 10px;
  font-size: 1rem;
}

.chat-input-area button {
  padding: 10px 16px;
  margin-left: 8px;
  background: #8B5CF6;
  color: white;
  border: none;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>

<body>
  <div class="chat-container">
    <div class="chat-messages" id="chatMessages">
      <div class="message">Hello!</div>
    </div>
    <div class="chat-input-area">
      <input type="text" id="chatMessageInput" placeholder="Type a message..." />
      <button id="sendMessageBtn">Send</button>
    </div>
  </div>
</body>

</html>

Alter image after loading using html canvas

I want to draw a border around an image after it is loaded using new Image()

This works, I see the border, but modifying image.src inside the onload function calls onload again in an infinite loop. But how can I alter the image otherwise?

<!DOCTYPE html>
<html>
<body>
    <script>
        let image = new Image();
        image.onload = function () {
            console.log("onload");
            let canvas = document.createElement('canvas');
            let ctx = canvas.getContext('2d');
            ctx.drawImage(image, 0, 0);
            ctx.strokeStyle = 'red';
            ctx.lineWidth = 5;
            ctx.strokeRect(0, 0, image.width, image.height);
            image.src = canvas.toDataURL();
        };
        image.src = "https://placehold.co/600x400";
        document.body.appendChild(image);
    </script>
</body>
</html>

React Table with useRowSelect throws “Maximum update depth exceeded” when adding selection column

I had a functional table component, I tried to apply the checkbox to it using useRowSelect, but I always get the “Maximum update depth exceeded error”. I don’t know what to do.

import React, { useEffect, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { usePagination, useRowSelect, useSortBy, useTable } from "react-table";

import Icon from "@mui/material/Icon";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableContainer from "@mui/material/TableContainer";
import TableRow from "@mui/material/TableRow";

import pxToRem from "assets/theme/functions/pxToRem";
import classNames from "classnames";
import MDBox from "components/MDBox";
import MDPagination from "components/MDPagination";
import MDDataTableBodyCell from "components/MDTable/MDDataTableBodyCell";
import MDDataTableHeadCell from "components/MDTable/MDDataTableHeadCell";
import MDTypography from "components/MDTypography";
import { useMaterialUIController } from "context";
import useAppData from "context/AppContext";
import PropTypes from "prop-types";
import "regenerator-runtime/runtime.js";

export default function Table7({
    tableColumn,
    searchResult,
    searchAction,
    sizePerPage,
    paginationStyle,
    isSorted,
    noEndBorder,
    pageKeyMap,
    isPaginationServer,
    initialPageSize,
    buttonInRow,
    hideHeader,
    hideTotalEntries,
    fullwidth,
    rowClasses
}) {

    const { t } = useTranslation();
    const [controller] = useMaterialUIController();
    const { gridSpace, rowGap, columnGap } = controller;
    const { getSearchHistory } = useAppData();
    const columnsData = useMemo(() => tableColumn, [tableColumn]);
    const searchResultData = isPaginationServer
        ? searchResult
        : {
            currentPage: 1,
            pageSize: sizePerPage,
            total: searchResult.length,
            list: searchResult
        }

    const initialState = useMemo(() => {
        const searchHistory = getSearchHistory(pageKeyMap);
        return {
            pageSize: searchHistory.pageSize ?? initialPageSize,
            pageIndex: searchHistory.page ? searchHistory.page - 1 : 0,

        }
    }, [initialPageSize]);

    const IndeterminateCheckbox = React.forwardRef(
        ({ indeterminate, ...rest }, ref) => {
            const defaultRef = React.useRef()
            const resolvedRef = ref || defaultRef

            React.useEffect(() => {
                resolvedRef.current.indeterminate = indeterminate
            }, [resolvedRef, indeterminate])

            return (
                <>
                    <input type="checkbox" ref={resolvedRef} {...rest} />
                </>
            )
        }
    )

    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        prepareRow,
        rows,
        page,
        pageOptions,
        canPreviousPage,
        canNextPage,
        gotoPage,
        previousPage,
        nextPage,
        pageCount,
        setPageSize,
        state: { pageSize, pageIndex, sortBy, selectedRowIds }
    } = useTable({
        columns: columnsData,
        data: searchResultData.list ?? [],
        manualSortBy: isPaginationServer,
        manualPagination: isPaginationServer,
        pageCount: Math.ceil(searchResultData.total / searchResultData.pageSize),
        initialState: initialState,
    },
        useSortBy,
        usePagination,
        useRowSelect,
        hooks => {
            hooks.visibleColumns.push(columns => [
                // Let's make a column for selection
                {
                    id: 'selection',
                    // The header can use the table's getToggleAllRowsSelectedProps method
                    // to render a checkbox
                    Header: ({ getToggleAllPageRowsSelectedProps }) => (
                        <div>
                            <IndeterminateCheckbox {...getToggleAllPageRowsSelectedProps()} />
                        </div>
                    ),
                    // The cell can use the individual row's getToggleRowSelectedProps method
                    // to the render a checkbox
                    Cell: ({ row }) => (
                        <div>
                            <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
                        </div>
                    ),
                },
                ...columns,
            ])
        }
    )

    const searchHistory = getSearchHistory(pageKeyMap);
    useEffect(() => {
        if (isPaginationServer) {
            if (pageIndex !== searchHistory.page - 1) {
                gotoPage(0);
            }
        }
    }, [searchHistory]);


    useEffect(() => {
        if (isPaginationServer) {
            searchHistory.page = (pageIndex + 1);
            searchHistory.pageSize = pageSize;
            searchHistory.sortField = sortBy.length > 0 ? sortBy[0].id : null;
            searchHistory.sortOrder = sortBy.length > 0 ? sortBy[0].desc ? 'desc' : 'asc' : null;
            searchAction(searchHistory)
        }
    }, [pageIndex, sortBy, pageSize])


    const paginationComponent = useMemo(() => {
        let pagination = [];
        let lado = 2;

        // tamanho padrão
        let startPage = pageIndex - lado;
        let maxPage = pageIndex + lado;

        // controle para enconstar nas pontas
        if (startPage < 0) {
            maxPage += -1 * startPage;
        } else if (maxPage > pageCount - 1) {
            startPage -= maxPage - pageCount + 1;
        }

        // limpeza de paginas extras
        if (startPage < 0) {
            startPage = 0;
        }
        if (maxPage > pageCount - 1) {
            maxPage = pageCount - 1;
        }

        pagination.push(<MDPagination disabled={pageIndex == startPage} key={"first"} item onClick={() => gotoPage(0)}>
            <Icon sx={{ fontWeight: "bold" }}>first_page</Icon>
        </MDPagination>);
        pagination.push(<MDPagination disabled={pageIndex == startPage} key={"prev"} item onClick={() => previousPage()}>
            <Icon sx={{ fontWeight: "bold" }}>chevron_left</Icon>
        </MDPagination>);

        for (let currentPage = startPage; currentPage <= maxPage; currentPage++) {
            pagination.push(<MDPagination
                color={"primary"}
                item
                key={currentPage}
                onClick={() => gotoPage(currentPage)}
                active={currentPage == pageIndex}
            >
                {currentPage + 1}
            </MDPagination>);
        }

        pagination.push(<MDPagination disabled={pageIndex == pageCount - 1} key={"next"} item onClick={() => nextPage()}>
            <Icon sx={{ fontWeight: "bold" }}>chevron_right</Icon>
        </MDPagination>);
        pagination.push(<MDPagination disabled={pageIndex == pageCount - 1} key={"last"} item onClick={() => gotoPage(pageCount - 1)}>
            <Icon sx={{ fontWeight: "bold" }}>last_page</Icon>
        </MDPagination>);

        return pagination;
    }, [pageIndex, pageCount]);

    // A function that sets the sorted value for the table
    const setSortedValue = (column) => {
        let sortedValue;
        if (column.Header == null || (typeof column.Header != 'string')) {
            sortedValue = false;
        } else if (isSorted && column.isSorted) {
            sortedValue = column.isSortedDesc ? "desc" : "asce";
        } else {
            sortedValue = "none";
        }
        return sortedValue;
    };

    // Setting the entries starting point
    let entriesStart = searchResultData.total < 1 ? 0 : pageIndex * pageSize + 1;
    let entriesEnd = ((pageIndex === pageOptions.length - 1) || (searchResultData?.total < pageSize)) ? searchResultData?.total : pageSize * (pageIndex + 1);

    return (<>
        {/* <MDBox mt={2}> */}
        <TableContainer component={MDBox} mt={rowGap}
            sx={[{
                boxShadow: "none",
                borderRadius: 0,
                position: "relative",
            },
            fullwidth && {
                width: `calc(100% + ${pxToRem(48)})`,
                left: `${pxToRem(-24)}`,
            }
            ]}
        >
            <Table {...getTableProps()}>
                {!!!hideHeader && <MDBox component="thead">
                    {headerGroups.map((headerGroup, key) => (
                        <TableRow key={key} {...headerGroup.getHeaderGroupProps()}>
                            {headerGroup.headers.map((column, key) => (
                                <MDDataTableHeadCell
                                    key={key}
                                    {...column.getHeaderProps(isSorted && column.getSortByToggleProps({ title: undefined }))}
                                    width={column.width ? column.width : "auto"}
                                    align={column.align ? column.align : "left"}
                                    sorted={setSortedValue(column)}
                                >

                                    {column.Header != null && column.render("Header")}
                                </MDDataTableHeadCell>
                            ))}
                        </TableRow>
                    ))}
                </MDBox>}
                <TableBody {...getTableBodyProps()}>
                    {page.length === 0 ?
                        <MDDataTableBodyCell>
                            Nenhum Registro Encontrado
                        </MDDataTableBodyCell>
                        :
                        page.map((item, index) => {
                            prepareRow(item)
                            return (
                                <TableRow key={index} {...item.getRowProps({
                                    className: classNames(
                                        // { "striped": index % 2 === 0 },
                                        { "hasRowSelection": buttonInRow },
                                        rowClasses ? rowClasses(item.original, index) : null,
                                    ),
                                    style: { "borderBottom": "2px dashed #F0FBFC" }
                                })
                                }>
                                    {item.cells.map((cell) => (
                                        <MDDataTableBodyCell
                                            funcButtonInRow={buttonInRow ? () => buttonInRow(cell.row.original) : buttonInRow}
                                            key={index}
                                            noBorder={noEndBorder && rows.length - 1 === index}
                                            align={cell.column.align ? cell.column.align : "left"}
                                            {...cell.getCellProps()}
                                        >
                                            {cell.render("Cell")}
                                        </MDDataTableBodyCell>
                                    )
                                    )}
                                </TableRow>
                            );
                        })
                    }
                </TableBody>
            </Table>
        </TableContainer>
        {(!hideTotalEntries || pageCount > 1) && <MDBox
            display="flex"
            flexDirection={{ xs: "column", sm: "row" }}
            justifyContent="space-between"
            alignItems={{ xs: "flex-start", sm: "center" }}
            mt={rowGap}
        >
            {!hideTotalEntries && (
                <MDBox mb={{ xs: 3, sm: 0 }}>
                    <MDTypography
                        variant="button"
                        color="secondary"
                        fontWeight="regular"
                    >
                        {t('general.table.pagination', [entriesStart, entriesEnd, searchResultData.total])}
                    </MDTypography>
                </MDBox>
            )}

            {pageCount > 1 && (
                <MDPagination
                    variant={paginationStyle.variant ? paginationStyle.variant : 'gradient'}
                    color={paginationStyle.color ? paginationStyle.color : 'dark'}
                >
                    {paginationComponent}
                </MDPagination>
            )}
        </MDBox>}
        {/* </MDBox> */}
    </>);
}

Table7.defaultProps = {
    initialPageSize: 10,
    sizePerPage: { defaultValue: 10, sizes: [1, 5, 10, 15, 20, 25] },
    paginationStyle: { variant: "gradient", color: "dark" },
    isSorted: true,
    noEndBorder: false,
    searchResult: PropTypes.any.isRequired,
    columns: PropTypes.array.isRequired,
    isPaginationServer: false,
    pageKeyMap: null,
    buttonInRow: null,
    hideHeader: false,
    hideTotalEntries: false,
    fullwidth: true,
    rowClasses: null
};

Table7.propTypes = {
    initialPageSize: PropTypes.number,
    sizePerPage: PropTypes.oneOfType([
        PropTypes.shape({
            defaultValue: PropTypes.number,
            sizes: PropTypes.arrayOf(PropTypes.number),
        }),
    ]),
    paginationStyle: PropTypes.shape({
        variant: PropTypes.oneOf(["contained", "gradient"]),
        color: PropTypes.oneOf([
            "primary",
            "secondary",
            "info",
            "success",
            "warning",
            "error",
            "dark",
            "light",
        ]),
    }),
    isSorted: PropTypes.bool,
    noEndBorder: PropTypes.bool,
    isPaginationServer: PropTypes.bool,
    pageKeyMap: PropTypes.string,
    buttonInRow: PropTypes.func,
    hideHeader: PropTypes.bool,
    hideTotalEntries: PropTypes.bool,
    fullwidth: PropTypes.bool,
    rowClasses: PropTypes.string,
};

All you need to trigger the error is to uncomment the commented part. I took the checkbox implementation directly from the documentation

https://react-table-v7-docs.netlify.app/docs/examples/row-selection-and-pagination

what you tried -> useRowSelect to obtain a selection with checkbox

what you expected to happen -> to be able to select my records with the checkbox in the table

what actually resulted.-> Unhandled Runtime Error
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

How to interact with renderer from new button?

If I add new controls to the player (chordsOff, transpose, metronome) what to put in the “onclick” to access the abcjs-audio or the renderer?

Even something like simple play / stop didn’t work.
I have tried the same function as on the other buttons on the default player:

<button onclick="(function(t) { u(e.options.playPromiseHandler || e.options.playHandler, t, s, e.options.afterResume, !!e.options.playPromiseHandler) })();">Test U</button>

Error: u is not defined

Or:

<button onclick="abcjs.midi.startPlaying(document.getElementById('abcjs-midi-687e010d06e5e'));">Test play</button>

Error abcjs is not defined

Blocking SCORM Course Progress on LMS Communication Loss (SAP successfactor)

we’re working on a SCORM course developed in Articulate Storyline, and we’re trying to implement a specific client requirement — but we’re stuck.

**The requirement:
If the communication between the course and the LMS is interrupted, the course should:

  • block any further progress, and
  • display the following message:**

“Warning! Communication with the platform has been interrupted.
Please close the course and reopen it after checking your network connection.”

Any help would be truly appreciated!

Thanks so much in advance,
ALeksey

**What we’ve tried:
**Normally, we manage this kind of behavior directly through LMS settings, but in this case, the client insists that the logic must be handled within the SCORM itself.

We’ve tried everything we could think of to detect communication loss and trigger this behavior from within Storyline — but nothing has worked so far. At this point, we honestly don’t know what else to try.

Has anyone faced a similar situation?
Is there any workaround or JS-based solution that could help us detect LMS connection issues and respond accordingly from within the SCORM?

react-helmet-async page titles only update after reload, not on navigation

I have a React 19 app bootstrapped with Vite and using React Router v6. I want to set the browser tab title per page using react-helmet-async.
The updates only after I reload the page, but not when I navigate via router links.

A. main.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { HelmetProvider } from 'react-helmet-async';
import './index.css';
import { UserProvider } from './context/UserContext';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <HelmetProvider>
      <UserProvider>
        <App />
      </UserProvider>
    </HelmetProvider>
  </React.StrictMode>
)

B. App Routing (App.jsx)

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Login from './pages/Login';
import Index from './pages/Index';
import PasswordReset from './pages/PasswordReset';
import PrivateRoute from './components/PrivateRoute';
// ... all your imports

export default function App() {
  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path="/password-reset" element={<PasswordReset />} />
        {/* ...all your other routes, exactly as you pasted above... */}
        <Route path="/unauthorized" element={<div>❌ You are not authorized to view this page.</div>} />
      </Routes>
    </Router>
  );
}

C: Page example

import { useEffect, useState } from 'react';
import Layout from '../../components/Layout';
import LoadingIndicator from '../../components/shared/LoadingIndicator';
import ErrorMessage from '../../components/shared/ErrorMessage';
import axios from 'axios';
import { Helmet } from 'react-helmet-async'; // ← add this

export default function MapSearchLog() {
  const [logContent, setLogContent] = useState('');
  const [logDate, setLogDate] = useState('');
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    axios
      .get('/api/dashboards/mapsearchlog', {
        withCredentials: true, // Use cookies/session for auth
      })
      .then((res) => {
        setLogDate(res.data.date || '');
        const rawContent = res.data.content || '';
        const plainText = rawContent
          .replace(/<brs*/?>/gi, 'n')
          .replace(/r/g, '');
        setLogContent(plainText);
        setError(null);
      })
      .catch((err) => {
        console.error(err);
        setError('Failed to load log file');
      })
      .finally(() => setLoading(false));
  }, []);

  return (
    <Layout>
      <Helmet>
        <title>Map Search Log</title>
      </Helmet>
      <div className="p-6 max-w-5xl mx-auto">
        <h1 className="text-2xl font-bold text-[#008C9E] mb-4">
          Map Search Log File
        </h1>
        <p className="mb-4 text-sm text-gray-500">
          Date:{' '}
          {logDate || new Date().toISOString().split('T')[0].replace(/-/g, '')}
        </p>

        {loading && <LoadingIndicator />}
        {error && <ErrorMessage message={error} />}

        {!loading && !error && (
          <>
            <button
              className="mb-3 px-4 py-2 bg-cyan-600 text-white rounded hover:bg-cyan-700 text-sm"
              onClick={() => {
                const blob = new Blob([logContent], { type: 'text/plain' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `mapsearch_log_${logDate || ''}.txt`;
                a.click();
                URL.revokeObjectURL(url);
              }}
            >
              Download Log
            </button>
            <pre className="p-4 bg-white rounded-lg border shadow text-sm whitespace-pre-wrap">
              {logContent}
            </pre>
          </>
        )}
      </div>
    </Layout>
  );
}

Above is some example of the code I used

react-helmet-async page titles only update after reload, not on navigation (Vite + React 19 + React Router 6)

I have a React 19 app bootstrapped with Vite and using React Router v6. I want to set the browser tab title per page using react-helmet-async.
The updates only after I reload the page, but not when I navigate via router links.

A. main.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { HelmetProvider } from 'react-helmet-async';
import './index.css';
import { UserProvider } from './context/UserContext';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <HelmetProvider>
      <UserProvider>
        <App />
      </UserProvider>
    </HelmetProvider>
  </React.StrictMode>
)

B. App Routing (App.jsx)

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Login from './pages/Login';
import Index from './pages/Index';
import PasswordReset from './pages/PasswordReset';
import PrivateRoute from './components/PrivateRoute';
// ... all your imports

export default function App() {
  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path="/password-reset" element={<PasswordReset />} />
        {/* ...all your other routes, exactly as you pasted above... */}
        <Route path="/unauthorized" element={<div>❌ You are not authorized to view this page.</div>} />
      </Routes>
    </Router>
  );
}

C: Page example

import { useEffect, useState } from 'react';
import Layout from '../../components/Layout';
import LoadingIndicator from '../../components/shared/LoadingIndicator';
import ErrorMessage from '../../components/shared/ErrorMessage';
import axios from 'axios';
import { Helmet } from 'react-helmet-async'; // ← add this

export default function MapSearchLog() {
  const [logContent, setLogContent] = useState('');
  const [logDate, setLogDate] = useState('');
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    axios
      .get('/api/dashboards/mapsearchlog', {
        withCredentials: true, // Use cookies/session for auth
      })
      .then((res) => {
        setLogDate(res.data.date || '');
        const rawContent = res.data.content || '';
        const plainText = rawContent
          .replace(/<brs*/?>/gi, 'n')
          .replace(/r/g, '');
        setLogContent(plainText);
        setError(null);
      })
      .catch((err) => {
        console.error(err);
        setError('Failed to load log file');
      })
      .finally(() => setLoading(false));
  }, []);

  return (
    <Layout>
      <Helmet>
        <title>Map Search Log</title>
      </Helmet>
      <div className="p-6 max-w-5xl mx-auto">
        <h1 className="text-2xl font-bold text-[#008C9E] mb-4">
          Map Search Log File
        </h1>
        <p className="mb-4 text-sm text-gray-500">
          Date:{' '}
          {logDate || new Date().toISOString().split('T')[0].replace(/-/g, '')}
        </p>

        {loading && <LoadingIndicator />}
        {error && <ErrorMessage message={error} />}

        {!loading && !error && (
          <>
            <button
              className="mb-3 px-4 py-2 bg-cyan-600 text-white rounded hover:bg-cyan-700 text-sm"
              onClick={() => {
                const blob = new Blob([logContent], { type: 'text/plain' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `mapsearch_log_${logDate || ''}.txt`;
                a.click();
                URL.revokeObjectURL(url);
              }}
            >
              Download Log
            </button>
            <pre className="p-4 bg-white rounded-lg border shadow text-sm whitespace-pre-wrap">
              {logContent}
            </pre>
          </>
        )}
      </div>
    </Layout>
  );
}

Above is some example of the code I used

Why does JavaScript map() return undefined without return in arrow function? [duplicate]

I’m trying to use JavaScript’s map function to extract names from an array of objects. I expected it to return an array of names like [“Alice”, “Bob”, “Charlie”], but it returned [undefined, undefined, undefined] when I forgot to include the return statement in my arrow function. I want to understand why this happens and when return is required.

Here’s the working code:

const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 22 }
];

const names = users.map((user) => {
  return user.name;
});

console.log(names); // ["Alice", "Bob", "Charlie"]

And here’s what I accidentally did:

const names = users.map((user) => {
  user.name;
});

console.log(names); // [undefined, undefined, undefined]

Why does the second version return undefined? I thought arrow functions returned values automatically. How does using curly braces in arrow functions affect return behavior?

[undefined, undefined, undefined]