iOS PWA push notification actions (yes/no buttons) not showing – any workaround?

I’m trying to implement push notifications for a PWA. Here’s the relevant code snippet using PHP with Minishlink/WebPush:

use MinishlinkWebPushWebPush;
use MinishlinkWebPushSubscription;
$webPush = new WebPush($auth);

        $payload = json_encode([
            'title' => 'Booking Reminder',
            'body' => 'Do you want to book now?',
            'icon' => 'at.png',
            'url' => '', // optional default fallback
            'actions' => [
                [
                    'action' => 'yes',
                    'title' => 'Yes',
                    'icon' => 'yes.png'
                ],
                [
                    'action' => 'no',
                    'title' => 'No',
                    'icon' => 'no.png'
                ]
            ]
        ]);
        $webPush->queueNotification($subscription, $payload);

And here is the relevant part of my serviceworker.js:

self.addEventListener('notificationclick', function (event) {
  event.notification.close();
  let targetUrl = '[target URL]';
  if (event.action === 'yes') {
    targetUrl = '[URL 1]';
  } else if (event.action === 'no') {
    targetUrl = '[URL 2]';
  } else {
    targetUrl = '[URL 3]';
  }
  event.waitUntil(
    clients.matchAll({ type: 'window', includeUncontrolled: true }).then(windowClients => {
      for (const client of windowClients) {
        if (client.url === targetUrl && 'focus' in client) {
          return client.focus();
        }
      }
      if (clients.openWindow) {
        return clients.openWindow(targetUrl);
      }
    })
  );
});

This setup works perfectly on Android — the “Yes” and “No” buttons appear and function correctly.

However, the buttons do not appear on iOS (tried – Safari+Chrome).

GPT Response –

You’re running into a known limitation on iOS: As of now, interactive notification actions (like your yes/no buttons) are not supported in iOS Safari Progressive Web Apps (PWAs).

Is there any known workaround or alternative to achieve similar functionality on iOS?
The problem is critical for my app since most of my users are on iOS, and the yes/no decision is central to the user experience.

Thanks in advance!

Make directory via SMB

I want to make a directory on a server, via SMB.
What is the simplest way to do this?

I use javascript in Mirth Connect Server 4.5.0. I’m not sure which SMB version – the settings in Mirth is minimum version 2.0.2, maximum version 3.1.1.

It seems that the methods for doing this has changed from what I can find in examples on StackOverflow and elsewhere.

For example NtlmPasswordAuthentication() in some examples has parameters:

Username,Password

in other places:

Domain,Username,Password 

and the version that seems to work for me (with Context == null):

Context,Domain,Username,Password.

The error I have now is “Java constructor for “jcifs.smb.SmbFile” with arguments “org.mozilla.javascript.ConsString,jcifs.smb.NtlmPasswordAuthentication” not found.”

Main part of my code so far:


var smbUsername = configurationMap.get('smb_user');
var smbPassword = configurationMap.get('smb_password');
var domain = configurationMap.get('domain');

var auth = new Packages.jcifs.smb.NtlmPasswordAuthentication(null,domain, smbUsername,smbPassword); //null, 
var url = "smb//:RGHDFSP01.regionh.top.local/DFS/Systemer/SectraRIS-PACS/Sectra_SRT/DICOM/"+SeriesUID

var sFile = new Packages.jcifs.smb.SmbFile(url, auth);        
if (!sFile.Exists())
    sFile.mkdir();

Using variable from one JavaScript code in a piece of jQuery code

I have an autofade button attached to each instance of my audio tracks:

<input type="button" id="autofadebtn<?php echo $track;?>"  value="Fade Out"

onclick="$(document).ready(function()

{
    $('#<?php echo $track;?>')[0].volume = .5;
    $('#<?php echo $track;?>').animate({volume: 0}, 30000); 
  });

  $('#<?php echo $track;?>').promise().done(function() { 
  $('#<?php echo $track;?>').trigger('pause');
});
    "
    >

I also have a volume slider:

var audio<?php echo $track;?> = document.getElementById("<?php echo $track;?>");
var slider<?php echo $track;?> = document.getElementById("slider<?php echo $track;?>");
var display<?php echo $track;?> = document.getElementById("display<?php echo $track;?>");


slider<?php echo $track;?>.addEventListener("input", sliderActions);

function sliderActions( )
{
  var newVolume = slider<?php echo $track;?>.value;

  display<?php echo $track;?>.innerText = newVolume; // range 0 to 100
  audio<?php echo $track;?>.volume = newVolume / 100; // range 0 to 1 
}

My issue is that I would like my autofade button to start at the volume the user moves the volume slider to. Currently the auto fade starts at .5. I can’t work out which variable to use from the volume slider. The autofade button is within the input tag whilst the volume slider script is at the bottom of the page.

I’ve tried replacing the volume = .5 in the autofade with the named variables from the volume slider but each time the autofade stops working.

Using chart.js with a background image plugin, can’t get entire image to show

I have successfully created a canvas background image plugin for a Chart.js chart, as shown here.

I’m using the plugin, instead of a CSS background, because I need the image to stay with the chart data points (‘scatter’ type chart).

However, I can’t make it show the entire image, no matter what settings I try in the plugin. It is cropping the image vertically. I’m using the same setup as shown at the link:

const custplugin = {
  id: 'custplugin',
  beforeDraw: (chart) => {
    if (image.complete) {
      const ctx = chart.ctx;
      const {top, left, width, height} = chart.chartArea;
      const x = left + width / 2 - image.width / 2;
      const y = top + height / 2 - image.height / 2;
      ctx.drawImage(image, x, y);
    } else {
      image.onload = () => chart.draw();
    }
  }
};

I tried setting CSS ‘overflow: visible’ for the ‘canvas’ element and the div holding that, but that has no effect. I’ve tried messing with the ‘const x’ and ‘const y’ settings in the plugin, but nothing seems to work.

How can I get the entire image to show?

Thanks for any help.

Sortablejs is slow on Chrome with large table (2000 records)

When my sortablejs has an table of 2000+ records it gets realy slow and the page gives me the option to wait or close tab.
But this table is used by clients(in need of an good UX) so this cant happen to them.

I have the following code example:

<!-- Latest Sortable -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/Sortable.min.js"></script>

<div id="left"></div>
<div id="right"></div> 
var left = document.getElementById("left");
var right = document.getElementById("right");

generateTable(2000, left)
generateTable(10, right)

function generateTable(nOfRows, wrap) {
  var newTable = document.createElement("table"),
      tBody = newTable.createTBody(),
      nOfColumns = 5,
      row = generateRow(nOfColumns);

  tBody.classList.add("sortable");
  
  for (var i = 0; i < nOfRows; i++) {
    tBody.appendChild(row.cloneNode(true));
  }

  (wrap.hasChildNodes() ? wrap.replaceChild : wrap.appendChild).call(wrap, newTable, wrap.children[0]);
}

function generateRow(n) {
  var row = document.createElement("tr"),
      text = document.createTextNode("cell");

  for (var i = 0; i < n; i++) {
    row.insertCell().appendChild(text.cloneNode(true));
  }

  return row.cloneNode(true);
}


Sortable.create(document.getElementsByClassName('sortable')[0], {
  items: "tr",
  group: '1',
  animation: 100
});

Sortable.create(document.getElementsByClassName('sortable')[1], {
  items: "tr",
  group: '1',
  animation: 100
});

code example

Unable to connect Backend on other network

I am making a group project in which one member doing Frontend and I am doing Backend . I what that using my IP he connect with Backend
When my laptop and his laptop both are in same network and I add his IP in cors then it works but when he is on different , he is unable to communicate with my Backend

My backend is in Node.js & Express.js

I am in ubuntu so I allow my port from firewall using

sudo ufw allow 8080

also use differant cors options like,

app.use(cors({
  origin: '*',
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization']
}))

and

app.use(cors())

and I listen on 0.0.0.0

const server = app.listen(PORT, '0.0.0.0', () => {
   console.log(`Server started on port ${PORT}`);
});

but still my friend is unable to access my Backend . I want to make it universal , means who enter my ip and port he can access like : 192.168.xx.xxx:8080/

Chartjs: Connect canvas background image and chart (type: ‘scatter’) so that data points remain in same spot on image?

I have successfully created a canvas background image plugin for a Chart.js chart, as shown here.

It is better at staying in place than a css background image, however, when the window is resized, the data points end up in different spots relative to the image. Is there any way to make the chart change size at the same rate as the image, so that the data points stay put relative to the image?

I’ve tried changing the ‘responsive’ and ‘maintainAspectRatio’ settings, but they don’t seem to make a difference in this regard.

My custom plugin is as shown at the link above:

const custplugin = {
  id: 'custplugin',
  beforeDraw: (chart) => {
    if (image.complete) {
      const ctx = chart.ctx;
      const {top, left, width, height} = chart.chartArea;
      const x = left + width / 2 - image.width / 2;
      const y = top + height / 2 - image.height / 2;
      ctx.drawImage(image, x, y);
    } else {
      image.onload = () => chart.draw();
    }
  }
};

Thanks for any help.

How to invoke durable function activity from within a callback function?

I’m trying to consume messages from kafka topic using Azure durable function and as the new messages arrive I want to invoke the activity function to process the messages. The problem here is that the callback function isn’t able to access the context and other local variables which are needed to invoke the activity function.

Please suggest if I’m dong it correctly and if there are any better/alternate approaches.

Here is my function code:

/* the orchestrator is invoked by a timer trigger */
/* using kafka javascript SDK (@confluentinc/kafka-javascript) to create a consumer */

const kafkaConsumerOrchestratorName = 'kafka_consumer_orchestrator';
const kafkaConsumerActivityName = 'kafka_consumer_activity';

df.app.orchestration(kafkaConsumerOrchestratorName, function* (context) {
    yield kafkaService.consumer.run({
        eachMessage: async ({ topic, partition, message }) => {
            /* context not accessible here */
            yield context.df.callActivity(kafkaConsumerActivityName, { topic, partition, message });
        }
    });
});

df.app.activity(kafkaConsumerActivityName, {
    handler: async (input, context) => {
        /* process messages */
        console.log(input);
    }
});

How to stop autoplay video with mutationObserver in YT

okay I am trying to stop autoplay youtube video after loading, using mutationobserver from JS.

The problem is the Youtube is a SPA(single page application). Due to which, if I stop the mutationobserver after pausing the first video video.pause(). I need to refresh page manually after switching to another video.
And if don’t stop after first excution i can’t play any video at all. Everytime I play a video mutation obserser notice & call function to execute video.pause().

Q. Can we use mutationObserver to check if ytb-watch-video-id has been changed. coonsidering if this change means page changed & call the function to pause autoplay?

<video tabindex="-1" class="video-stream html5-main-video" controlslist="nodownload" style="..." ytb-watch-video-id="S...s" ytb-miniplayer-video src="blob:https://www.youtube.com/...2b"></video>

How to contribute to a project where the repository only contains .patch files?

I’m trying to contribute to Zen Desktop (a browser based desktop environment, dev branch), but the repository only contains .patch files across all branches : no original .js/.css source files. For example:

src/browser/components/panelUI.css.patch  
src/browser/themes/shared/tabs.css.patch  

I do see .css and .js files but with .patch at the end and this is same everywhere.

I read the contribution and installation guidelines but I do not any explicit documentation on patch management.

How should I set up a development environment if the repo only provides patches? Are there any commands that I need to execute before I can start contributing?

Link: https://github.com/zen-browser/desktop

Grateful if any of you can help me!

ExpressJS Res.Download() Not Sending File to Download

I am trying to download the file from expressjs backend using Axios. The file is of size 1kB but on attempting to download it every time, I am getting 17 bytes file that does not open.

Here is my backend code:

const __dirname = path.resolve();

app.get("/download", function(req, res, next) {

        const dirPath = `${__dirname}/images/${req.query.dir}/output`;

        let files = fs.readdirSync(dirPath);

        res.download(`${dirPath}/${files[0]}`);

        res.status(200).send("Download complete");
});

And my frontend code is:

axios({
      url: `http://example.com/download?dir=${someDir}`,
      method: "GET",
      responseType: "blob"
    })
      .then(res => {
        //console.log(res.data);
        const href = URL.createObjectURL(res.data);
        //console.log(href);
        
        const link = document.createElement("a");
        link.href = href;
        link.setAttribute("download", output.jpeg);
        document.body.appendChild(link);
        link.click();

        document.body.removeChild(link);
        URL.revokeObjectURL(href);
      })
      .catch(er => console.log(er));

I am puzzled to find the root cause of this. Help on this appreciated

Why isn’t my react front end displaying anything?

I wanted to create a DisplayItems page which takes a GET method (in this case, dummy information from "http://localhost:8000/itemTest") and returns a table with the information with a radio button which allows you to pick which item you would like to bid on. This code used to work correctly but since adding a database to my front end, the code no longer works.

import React, { useState, useEffect } from "react";
import { useLocation, Link } from "react-router-dom";
import axios from "axios";

const DisplayItems = () => {
  const [items, setItems] = useState([]);
  const [filteredItems, setFilteredItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [selectedItemId, setSelectedItemId] = useState(null);

  const location = useLocation();
  const searchParams = new URLSearchParams(location.search);
  const searchQuery = searchParams.get("search") || "";

  useEffect(() => {
    axios
      .get("http://localhost:8000/itemTest")
      .then((response) => {
        console.log("API Response:", response.data);
        setItems(Array.isArray(response.data.item) ? response.data.item : []); // Ensure items is an array
        setLoading(false);
      })
      .catch((err) => {
        console.error("Error details:", err);
        setError(err.response?.data?.message || "Error fetching items");
        setLoading(false);
      });
  }, []);

  useEffect(() => {
    if (!searchQuery) {
      setFilteredItems(items);
    } else {
      const filtered = items.filter((item) =>
        item.name?.toLowerCase().includes(searchQuery.toLowerCase()) // Handle cases where name might be undefined
      );
      setFilteredItems(filtered);
    }
  }, [searchQuery, items]);

  const handleRadioChange = (id) => {
    setSelectedItemId(id);
  };

  if (loading) {
    return <p>Loading items...</p>;
  }

  if (error) {
    return <p>{error}</p>;
  }

  return (
    <div className="form-container">
      <h2>Display Items</h2>
      <div>
        {items.length > 0 ? (
          <table>
            <thead>
              <tr>
                <th>Select</th>
                <th>Name</th>
                <th>Description</th>
                <th>Price</th>
              </tr>
            </thead>
            <tbody>
              {filteredItems.map((item) => (
                <tr key={item.id}>
                  <td>
                    <input
                      type="radio"
                      name="bidSelection"
                      checked={selectedItemId === item.id}
                      onChange={() => handleRadioChange(item.id)}
                    />
                  </td>
                  <td>{item.name}</td>
                  <td>{item.itemdescription}</td>
                  <td>${item.price}</td>
                </tr>
              ))}
            </tbody>
          </table>
        ) : (
          <p>No items found.</p>
        )}
      </div>
      {selectedItemId && (
        <div>
          <Link to={`/forward/${selectedItemId}`}>
            <button>Bid</button>
          </Link>
        </div>
      )}
    </div>
  );
};

export default DisplayItems;

I have tried using "http://localhost:8000/itemTest" whose data is:

[{"id":"1","name":"bike","itemdescription":"This is a bicycle, used for transportation.","startingprice":"19.99","price":"19.99","highestbidderid":"","image_url":"http://example.com/sample-image.jpg"},{"id":"2","name":"paper","itemdescription":"a lovely piece of paper.","startingprice":"1.99","price":"1.99","highestbidderid":"","image_url":"http://example.com/sample-image.jpg"}]

I have checked my data initialization as well:

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class ItemCreate(BaseModel):
    itemdescription: str
    name: str
    price: float
    shippingprice: float
    endtime: datetime
    startingprice: float
    valid: bool
    action_type: str
    id: int

I have tried to debug this code for hours, but I cannot find why it was once working fine, and now it doesn’t.

this is not working for high to low using sort

useEffect(() => {
  //for duration
  if (
    filtering?.durationInMinutes &&
    selectedFilterItems.find((item) => item.type === 'durationInMinutes')
      ?.code !==
      `${filtering?.durationInMinutes?.from || '-'}${
        filtering?.durationInMinutes?.to
      }`
  ) {
    setSelectedFilterItems((prev) => {
      prev = prev.filter((items) => items.type !== 'durationInMinutes');
      return [
        ...prev,
        {
          displayItem: (
            <span className="flex items-center gap-2">
              {!!filtering?.durationInMinutes?.from && (
                <span className="flex items-center gap-2">
                  from{' '}
                  <strong>
                    {convertDuration(filtering?.durationInMinutes?.from)}
                  </strong>
                </span>
              )}{' '}
              {!!filtering?.durationInMinutes?.to && (
                <span className="flex items-center gap-2">
                  {!!filtering?.durationInMinutes?.from ? 'to ' : 'upto '}
                  <strong>
                    {convertDuration(filtering?.durationInMinutes?.to)}
                  </strong>
                </span>
              )}
            </span>
          ),
          type: 'durationInMinutes',
          code: `${filtering?.durationInMinutes?.from || '-'}${
            filtering?.durationInMinutes?.to
          }`,
        },
      ];
    });
  } else if (!filtering?.durationInMinutes) {
    setSelectedFilterItems(
      (prev) =>
        (prev = prev.filter((items) => items.type !== 'durationInMinutes'))
    );
  }

  if (
    (sortType.sort !== 'DEFAULT' &&
      selectedFilterItems.find((item) => item.type === 'sort')?.code !==
        sortType.sort) ||
    selectedFilterItems.find((item) => item.type === 'sort')?.code ===
      sortType.sort
  ) {
    setSelectedFilterItems((prev) => {
      prev = prev.filter((items) => items.type !== 'sort');
      return [
        ...prev,
        {
          displayItem: (
            <span className="flex items-center gap-2">
              Sort by <strong>{sortType.name}</strong>
            </span>
          ),
          type: 'sort',
          code: sortType.sort,
        },
      ];
    });
  } else if (sortType.sort === 'DEFAULT') {
    setSelectedFilterItems(
      (prev) => (prev = prev.filter((items) => items.type !== 'sort'))
    );
  }

i expected this to works both on low to high and high and low

Error on sst deploy Your sst.config.ts has top level imports – this is not allowed

Im upgrading from SST 3.2 to 3.11 but as soon as I use the deploy command, I get the following error: Your sst.config.ts has top level imports - this is not allowed. Move imports inside the function they are used and do a dynamic import: const mod = await import("./mod")

This is my old .config file:

import { settings } from 'path/to/settings';

const type = 'test';

export default $config(settings(type));

I have tried to change the config file like this:

const type = 'test';

export default $config(async () => {
  const { settings } = await import('path/to/settings');
  return settings(type);
});

But I get this error Unexpected error occurred. Please run with --print-logs or check .sst/log/sst.log if available. with an empty log folder.

I have tried to search for documentation on this but I have not been able to find anything. Has anyone experienced something similar when upgrading?