Fullcalendar eventClick is missing ‘end’ property value in ‘eventclick’ event details

I am not sure why but when I click on a event and look at the ‘eventclick’ data it is missing the end value.

Here is the data I am binding to the calendar (dropped this out just before I initialize the calendar)

binding data

as you can see the ‘end’ property value is provided prebind

and here is the eventclick values I am getting (JSON.stringify)

event data

as you can see the ‘end’ property is missing I was able to pass the same value as ‘end2’ but I would really would prefer to just use ‘end’

Can’t figure out the cause of unexpected behaviour of my async recursive animated graph flood-fill algorithm

I’ve recently been implementing an animated graph flood-fill algorithm, the main feature of which is the animated transition of an “impulse” between selected vertices of the graph. Let me briefly explain:

  1. Graph Structure: This is how the graph structure looks:
{
    "1": {
        "coordinates": [0.1, 0.4, -1],
        "connections": [3, 5]
    },
    "2": {
        "coordinates": [0.2, -0.4, 0.2],
        "connections": [1]
    },
    "3": {
        "coordinates": [1, -0.3, 0.9],
        "connections": [1, 2]
    },
    "4": {
        "coordinates": [-0.5, 0.4, 0.9],
        "connections": []
    },
    "5": {
        "coordinates": [0.0, 0.1, -0.2],
        "connections": [4, 2]
    }
}
  1. FloodFill Class: I use a FloodFill class with two async methods: animateImpulse and fill.
function startImpulseFromAttributes() {
    const graph = parseGraphDict();

    const floodFill = new FloodFill(graph, animationSpeed);
    floodFill.fill(startVertex, impulsePower, (impulse, vertex) => {
        post("Impulse", JSON.stringify(impulse), " active at vertex ", JSON.stringify(vertex));
    });
}

var activeObjects = []; // List to track created objects

function cleanupAllObjects() {
    activeObjects.forEach(obj => obj.freepeer());
    activeObjects = []; // Clear the list
}

class FloodFill {

    constructor(graph, animationSpeed) {
        this.graph = graph;
        this.animationSpeed = animationSpeed;
    }

    async animateImpulse(startCoord, endCoord, speed) {
        return new Promise((resolve) => {
            const gridshape = new JitterObject("jit.gl.gridshape", contextName);
            gridshape.shape = "cone";
            gridshape.color = [Math.random(), Math.random(), Math.random()];

            const animNode = new JitterObject("jit.anim.node");
            gridshape.anim = animNode.name;
            animNode.movemode = "local";
            animNode.scale = impulseScale;
            animNode.position = startCoord;
            animNode.lookat = endCoord;

            const animDrive = new JitterObject("jit.anim.drive");
            animDrive.targetname = animNode.name;
            animDrive.move(0, 0, speed);

            const goalVector = endCoord.map((v, i) => v - startCoord[i]);

            const checkPosition = new Task(() => {
                const pos = animNode.worldpos;
                const currentVector = pos.map((v, i) => v - startCoord[i]);

                if (veclength(currentVector) >= veclength(goalVector)) {
                    post("Animation completen");
                    gridshape.freepeer();
                    animNode.freepeer();
                    animDrive.freepeer(); 
                    checkPosition.cancel();
                    resolve();  
                    // post("Resolved promisen");
                }
            });

            checkPosition.interval = worldposQueryInterval;
            checkPosition.repeat();
        })
    }

    async fill(startVertexId, stepsLeft, actionCallback) {
        if (stepsLeft <= 0) {
            post("Stopped at vertex: ", startVertexId, ", no steps leftn");
            return;
        }

        const connections = this.graph[startVertexId]?.connections || [];
        post("Connections for vertex ", startVertexId, ": ", JSON.stringify(connections), "n");

        if (connections.length === 0) {
            post("Stopped at vertex: ", startVertexId, ", no connectionsn");
            return;
        }

        const powerPerConnection = Math.floor(stepsLeft / connections.length);
        post("Power per connection: ", powerPerConnection, "n");

        if (powerPerConnection <= 1) {
            post("Power per connection too low, stopping recursionn");
            return;
        }

        try {
            await Promise.all(connections.forEach(async (nextVertexId) => {
                post("Calling animateImpulse with start: ", JSON.stringify(this.graph[startVertexId]?.coordinates), " and end: ", JSON.stringify(this.graph[nextVertexId]?.coordinates), "n");

                try {
                    await this.animateImpulse(
                        this.graph[startVertexId]?.coordinates,
                        this.graph[nextVertexId]?.coordinates,
                        animationSpeed * scaleToAnimationSpeed(this.graph[startVertexId], this.graph[nextVertexId])
                    );
                } catch (e) {
                    post("Error in animateImpulse: ", e, "n");
                }
 
                await this.fill(nextVertexId, powerPerConnection - 1, actionCallback);
            }));
        } catch (e) { 
            post("Error resolving Promise in fill: ", e, "n");
        }
    }
}

The animateImpulse method is written for the Max/MSP Jitter API, which is why I’m using the Max/MSP API function post() instead of console.log. Essentially, it spawns a single 3D object and drives it from one coordinate to another, which takes some time. It can be replaced by a random timeout without changing its overall meaning. The important thing to note is that it returns a promise that resolves when the animation is complete (i.e., the point has reached its destination). It also uses something called Task, which checks the position of the object being animated at regular intervals.

The fill method is a recursive flood-fill algorithm. If you think of the directed graph as a tree, it traverses the graph with the ability to revisit nodes. I am avoiding cycles and iterations in this algorithm because I wanted the animation to be smooth, with no animations waiting for others to complete. This is also why I opted for recursion.


The Problem

During testing, I noticed that the algorithm behaves inconsistently between executions. The patterns of this unexpected behavior include:

  1. Skipped Animations: It sometimes skips animations for certain paths. This doesn’t happen randomly; it always skips specific paths. Logs show that for some paths, the promise resolves before the animation even starts.

  2. Unexpected Animations: It occasionally calls animateImpulse for vertices it is not supposed to animate.

These issues usually occur when one or many time-consuming animations are still in progress.


Is there something I might be overlooking in the design of the algorithm or its implementation that could cause these behaviors? Or is it a problem of MaxMsp JS API? Any suggestions or pointers would be greatly appreciated!


Let me know if you’d like further refinements! I’ll leave the files and a video of how the animation looks like.

https://drive.google.com/drive/folders/1ISaK6ISGsSeO-CKO12QlM-p-0J8CVM_8?usp=drive_link

How to use jQuery in Laravel blade files

first of all i know there are plenty of similar questions for this, but none of them solved my problem.

I have app.js:

import $ from 'jquery';

$(document).ready(function () {
    ...
});

window.$ = $;

and my index.blade.php file:

<html>
  <head>
    @vite(['resources/js/admin/app.js', 'resources/css/admin/app.css'])
  </head>
  <body>
    ...
    
    <script type="text/javascript">
        $(document).ready(function() {
             // Throws: $ is not defined
        });
    </script>
  </body>
</html>

It never can access jquery. I’ve tried everything. Other libraries work fine but jQuery just don’t.

Why in Safari do the values of window.screen.height and window.screen.availHeight differ between normal and private modes?

In Safari the values of window.screen.height and window.screen.availHeight differ between normal and private modes, but not between each other, in these conditions:

  • Only one tab is open,

  • The window is stretched across the entire display, and

  • The developer console is in a separate window

Externally, the browser control panel does not differ in size, and the dock is hidden.

Why do these values differ between normal and private modes, but not between each other?

Security issues with self signed certificates [closed]

Context:

I have a webapp running on localhost port 8080 (localhost:8080)

It has a backend express server that serves as a backend api offering many /api/* endpoints

All requests with other urls that hit the server redirect the user to the /Welcome page where my react frontend code is.

I use self signed certificates to mimic real https behaviour on localhost.

Problems:

  1. When i go to localhost:8080, the webapp has recently encountered a problem where my browser shows an error saying my local certificates are not secure. I have checked their expiry and that they are valid. The app still works from localhost:8080 although the error shown is annoying. I’d like to point out also this issue never happened to me earlier in my developments.

  2. When I go to localhost:3000 usually I am able to access the development server with hot reloading etc.. (it’s a vite server) But since today, I get a Provisional Headers Only error. (on any browsers) This makes the dev server totally unusable.

Can anybody give me hints how I can debug these issues, specifically the localhost:3000 issue as I need to get some developments going.

Thanks a lot.

initData or initDataUnsafe data is not transmitted in the Telegram mobile app

I have a website that I enable via telegram imni app in a bot Here is the code:

if (window.Telegram && window.Telegram.WebApp) {
            const user = Telegram.WebApp.initDataUnsafe.user;
            if (user) {
                const userId = user.id;
                alert("User ID: " + userId);
                loadUserData(userId);
            } else {
                alert("User data is not available.");
            }
        } else {
            alert("Telegram WebApp is not available.");
        }

        async function loadUserData(userId) {
            try {
                const response = await fetch(`/user?user_id=${userId}`);
                if (!response.ok) {
                    throw new Error('error');
                }

                const data = await response.json();
                document.getElementById("nickname").textContent = data.nickname;
                document.getElementById("avatar").src = data.avatar_url;
                document.getElementById("money").textContent = data.money;
            } catch (error) {
                console.error(error);
            }
        }

The problem is that telegram should pass the parameters initDataUnsafe and all the information on the user, as he came through telegram to the site In the web version of telegram everything works as it should and tg passes the data I need in initDataUnsafe, but in the mobile application of telegram initDataUnsafe is empty, that is, telegram does not pass anything, help to understand why it is so

Selecting last divider element that has not wrapped [duplicate]

To preface this, we can’t alter the HTML so the dividers have to be inserted using the provided HTML as shown in the HTML below. We can’t use ul and li tags either.

I did a thorough search on Stack Overflow and other sites and there seems to be no way to select the last element that has not wrapped. For our particular case, I have the following HTML structure, which is dynamically rendered from a Sightly (HTL) page in a new AEM component we’re building, so I can’t make any modifications to the HTML. We’re stuck using the following structure, but can modify CSS and JS. We can also add/remove classes to the HTML below.

<div class="container">
  <div class="multi-cta-group">
    <a class="btn btn-primary">
      Button number one
    </a>
    <div class="flex-divider hide-sm"></div>
    <a class="btn btn-primary">
      Button number two
    </a>
    <div class="flex-divider hide-sm"></div>
    <a class="btn btn-primary">
      CTA button number three
    </a>
    <div class="flex-divider hide-sm"></div>
    <a class="btn btn-primary">
      Button number four
    </a>
    <div class="flex-divider hide-sm"></div>
  </div>
</div>

When the window width is too narrow to display all buttons in the same row, the last button will wrap underneath to the next line. When the window width is reduced even more, then two buttons might wrap to the next row. When that happens, there’s a trailing divider on the first row that needs to be hidden. How can I target the last divider on the first row, or on both rows, so that it can be hidden?

Unlike another post on Stack Overflow, which shows examples using ul li tags and the ‘before’ pseudo-element, this scenario involves using tags styled as Bootstrap buttons (btn btn-primary), which adds to the complexity. Because this is unlike the ul li question, we can’t seem to do the following:

  1. Add dividers with the ‘before’ pseudo-element BETWEEN the buttons. They get inserted INTO the buttons.
  2. Target the last element on the row before wrapping. Every solution we tried places the dividers inside the buttons.

Content editors can author in one to four buttons. I’m using simple CSS to hide the last divider, so that’s not an issue, but if there were a way to hide the last divider on each row, that might be a better approach.

Here’s the CSS I have so far:

.container {
  justify-content: center;
  margin: 16px auto;
  padding: 16px 0;
}
.multi-cta-group {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: center;
}

.multi-cta-group a {
  color: #fff;
  justify-content: center;
}

.flex-divider {
  width: 1px;
  background-color: gray;
  height: auto;
}

.flex-divider:last-child {
  display: none;
}

.bg-gray-400 {
  background-color: #bdc2c7;
}

@media (max-width: 768px) {
  .multi-cta-group {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }

  .multi-cta-group .btn {
    justify-content: center;
    width: auto;
  }
}

There are some other discussions on other sites and it seems there’s no way to select the last element before wrapping.

Desktop (Last divider element is after the four. This is hidden by CSS and is no problem.)

One | Two | Three | Four 

Large Tablet (The viewport (window width) at which this wraps could vary depending on the length of button text and the number of buttons, so we can’t use media queries. In the example below, we need to hide the divider line after the ‘Three’.)

One | Two | Three |
Four

Small Tablet (Below the divider line after the two needs to be removed or hidden.)

One | Two 
Three | Four

Mobile (Mobile is not an issue. We’re simply hiding all divider divs with a class called hide-sm.)

One
Two
Three
Four

Upgrade Rails-/Webpacker-App with plain JS, VueJS and Stimulus to Importmaps

I want to migrate a Rails project away from Webpacker.
It uses different JS-parts: VueJS 2.6, StimulusJS, plain old Javascript with some JQuery.
Having used Importmaps in some projects i wonder if this would be a solution or if a packaging-toolchain like jsbundling-rails or vite.js needs to be added?

The app consists of different JS-codeparts:

    app/
    ├─ assets/
    │  ├─ javascripts/     # <-- some legacy-JS using JQuery
    ├─ javascripts/        # <-- VueJS-Application with some components
    ├─ shared/
    │  ├─ my_plugin/
    │  │  ├─ javascripts/  # <-- a Stimulus-controller

To my understanding, i need some bundling to use the VueJS-Part.
Currently it is beeing imported using the VueLoaderPlugin.
Is this necessary in the future or can i avoid it and use it only with Importmaps?

My understanding of the JS-build/packaging-toolchain is basic so i appreciate your advice.
What could be the most simple solution?

NOTE: The Stimulus-Part is not integrated with Webpacker yet, so it is not working in this app ATM 🙂

Search in a table with inputs on rows

i’m working on a new webapp that includes several tables with different information.
there tables where i only show information but there other table where i need that users can modify values. I always used to use a code that worked fine in simple tables, but tables with inputs it doesn’t work.

i always use this script code to search values in tables, it filters results and only shows rows that contains input value.

$(document).ready(function(){
    $("#inputsearch").on("keyup", function() {
        var value = $(this).val().toLowerCase();
        $("#bodytableresults tr").filter(function() {
        $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
        });
    });
});
<table>
    <thead>
        <tr>
            <th><input type="text" placeholder="Search...." id="inputsearch"></th>
        </tr>
    </thead>
    <tbody id="bodytableresults">
        <tr>
            <th>Mike<th>
        </tr>
        <tr>
            <th>Joan<th>
        </tr>
    </tbody>
</table>

it works fine in a simple table, but if i have inputs in cells, it doesn’t work.
Ex.

<table>
    <thead>
        <tr>
            <th><input type="text" placeholder="Search...." id="inputsearch"></th>
        </tr>
    </thead>
    <tbody id="bodytableresults">
    <tr>
        <th><input type="text" value="Mike"></th>
    </tr>
    <tr>
       <th><input type="text" value="Joan"></th>
    </tr>
    </tbody>
</table>

it’s possible to filter rows that contains inputs inside? i mean, search value inside different inputs on table

Why Node execute a file even file has no .js extension

We have always used file extension to provide details about the file. And in the scenario where we dont provide an extension we provide the details of the file with sheBang #!/usr/bin/env node which informs that it is executable file with node.

I forgot to add the shebang information and ran the file without extension and it worked perfectly fine.

// test file (no .js extension)
const app = require("app");
console.log(app)

similarly, i removed the app.js extension to test again

const express = require("express");
const app = express();

module.exports = app;

if(require.main === module) console.log("No Errors");

if you run the node test it works perfectly fine.

The question is Why?

If it works fine then why do we need to define extension explicitly for javascript?

How to achieve Transition effect and adjust div placement with css/javascript

Goal is to have a table with multiple sections (these will vary in size, for now just using 300px as a guide). Clicking to expand/collapse all is one button, then the option to click header to expand/collapse a single section. Ideally, I’m looking to have a transition effect to slide the content down. Most of the functionality current works but the final section doesn’t seem to match.

https://jsfiddle.net/z7pc41mb/1/

​html, body {
    margin:0px; 
    padding:0px;
}

.features-container {
    float: left;
    max-width: 500px;visi
    height: auto;
    
}

#box1 { visibility: hidden; height:0px; transition: height 1s; }
#box2 { visibility: hidden; height:0px; transition: height 1s; }
#box3 { visibility: hidden; height:0px; transition: height 1s; }
#box4 { visibility: hidden; height:0px; transition: height 1s; }
#boxhead { background-color: #224488; }
#box1head { background-color: #113366; }
#box2head { background-color: #113366; }
#box3head { background-color: #113366; }
#box4head { background-color: #113366; }

.sectionhead {
    position: relative;
    float: left; 
    color: #fff;
    width: 500px;
    height: 50px;
}

.sectioncontent {
    position: relative;
    float: left; 
    color: #fff;
    width: 500px;
    height: auto;
}

.subsection-row {
    position: relative;
    float:left;
    width: 500px;
}

.subsection-col1a {
    position: relative;
    float: left; 
    color #000;
    background-color: #666;
    width: 300px;
    height: 100px;
}
.subsection-col2a {
    position: relative;
    float: left; 
    color #000;
    background-color: #666; 
    width: 100px;
    height: 100px;
}
.subsection-col3a {
    position: relative;
    float: left; 
    color #000;
    background-color: #666;
    width: 100px;
    height: 100px;
}

.subsection-col1b {
    position: relative;
    float: left; 
    color #000;
    background-color: #888;
    width: 300px;
    height: 100px;
}
.subsection-col2b {
    position: relative;
    float: left; 
    color #000;
    background-color: #888; 
    width: 100px;
    height: 100px;
}
.subsection-col3b {
    position: relative;
    float: left; 
    color #000;
    background-color: #888;
    width: 100px;
    height: 100px;
}
    function ShowHideAll() {
      var box1 = document.getElementById('box1');
      var box2 = document.getElementById('box2');
      var box3 = document.getElementById('box3');
      var box4 = document.getElementById('box4');
      
      if (box1.style.height === "0px") {
        box1.style.visibility = "visible";
        box2.style.visibility = "visible";
        box3.style.visibility = "visible";
        box4.style.visibility = "visible";
        box1.style.height = "300px";
        box2.style.height = "300px";
        box3.style.height = "300px";
        box4.style.height = "300px";
        document.getElementById('box1head').style.backgroundColor = "#3366FF";
        document.getElementById('box2head').style.backgroundColor = "#3366FF";
        document.getElementById('box3head').style.backgroundColor = "#3366FF";
        document.getElementById('box4head').style.backgroundColor = "#3366FF";
      } else {
        box1.style.height = "0px";
        box2.style.height = "0px";
        box3.style.height = "0px";
        box4.style.height = "0px";
        document.getElementById('box1head').style.backgroundColor = "#113366";
        document.getElementById('box2head').style.backgroundColor = "#113366";
        document.getElementById('box3head').style.backgroundColor = "#113366";
        document.getElementById('box4head').style.backgroundColor = "#113366";
      }
    }
    
    
    function showHtmlDiv(toggable) {
      var htmlShow = document.getElementById(toggable);
      var HeadID = "head";
      var newHeadID = toggable + HeadID;
      var htmlShowHead = document.getElementById(newHeadID);
      if (htmlShow.style.height === "0px") {
        htmlShow.style.visibility = "visible";
        htmlShow.style.height = "300px";
        htmlShowHead.style.backgroundColor = "#3366FF";
      } else {
        htmlShow.style.height = "0px";
          htmlShowHead.style.backgroundColor = "#113366";
      }
    }
​<div class='features-container'>
    <div id='boxhead' class='sectionhead' onclick="ShowHideAll()">Show/Hide All</div>
    <div id='box1head' class='sectionhead' onclick="showHtmlDiv('box1')">Section Header #1</div>
        <div class='sectioncontent' id="box1">
    
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 1 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1b'>SECTION 1 COL 2</div>
                <div class='subsection-col2b'>COL 2</div>
                <div class='subsection-col3b'>COL 2</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 1 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>
            
        </div>
  <div id='box2head' class='sectionhead' onclick="showHtmlDiv('box2')">Section Header #2</div>
        <div class='sectioncontent' id="box2">
    
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 2 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1b'>SECTION 2 COL 2</div>
                <div class='subsection-col2b'>COL 2</div>
                <div class='subsection-col3b'>COL 2</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 2 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>
            
        </div>

    <div id='box3head' class='sectionhead' onclick="showHtmlDiv('box3')">Section Header #3</div>
        <div class='sectioncontent' id="box3">
    
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 3 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1b'>SECTION 3 COL 2</div>
                <div class='subsection-col2b'>COL 2</div>
                <div class='subsection-col3b'>COL 2</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 3 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>          
            
        </div>
        
        
    
    <div id='box4head' class='sectionhead' onclick="showHtmlDiv('box4')">Section Header #4</div>
        <div class='sectioncontent' id="box4">
    
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 4 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1b'>SECTION 4 COL 2</div>
                <div class='subsection-col2b'>COL 2</div>
                <div class='subsection-col3b'>COL 2</div>
            </div>
        
            <div class='subsection-row'>
                <div class='subsection-col1a'>SECTION 4 COL 1</div>
                <div class='subsection-col2a'>COL 2</div>
                <div class='subsection-col3a'>COL 3</div>
            </div>
            
        </div> 
        
        
        
<div>

Initially, it was built using display:block, to show/hide the div onClick, but a decision was made that we want the transition animation to slowly display the content. This led me to switch to visiblity and height, but it didn’t function for the last section, which would just display/hide rather than transition. I attempted to drop to 3 sections thinking maybe I made an error with the 4th sections settings but the issue persists.

My understanding is that the div is actually appearning/disappearing appropriately, but the children aren’t collapsing, which is why they appear visible but only showing the last as it’s essentially sitting on top.

Vertical stack bar displays zeroes / “invisible” values with Chart.js

I’m trying to make a vertical stack bar plot with Chart.js.
It works pretty well but for some labels (i.e., for one vertical part of the graph) I don’t necessarily have strictly positive values for all the dataset points. I don’t see the rectangle for those which is good, but if I hover at the wrong place, I see a 0 which bothers me.

Here is a MRE because my description was probably not very understandable:

var chart = new Chart(ctx, {
   type: 'bar',
   data: {
      labels: ['1', '2'],
      datasets: [{
         label: 'a',
         data: [1, 8],
         backgroundColor: '#22aa99'
      }, {
         label: 'b',
         data: [1, 2],
         backgroundColor: '#109618'
      }, {
         label: 'c',
         data: [0, 1],
         backgroundColor: '#dc3912'
      }, {
         label: 'd',
         data: [4, null],
         backgroundColor: '#3366cc'
      },
      {
         label: 'e',
         data: [4, null],
         backgroundColor: '#9661ca'
      }]
   },
   options: {
      responsive: false,
      legend: {
         position: 'right'
      },
      scales: {
         xAxes: [{
            stacked: true
         }],
         yAxes: [{
            stacked: true
         }]
      }
   }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx" width="700"></canvas>

I would like this not to be possible (hovering on d on the right part even though d is 0 (as well as e)):
enter image description here

Using data: [4, null] does not work either, since I have that now instead:
enter image description here

Display Image stored in a sharepoint Site, on a pdf that i want to export

Fetching Image from SharePoint URL for PDF Generation Results in 401 Error Despite Azure App Permissions

I am trying to fetch an image stored in SharePoint by its URL and embed it into a PDF that I generate using JavaScript. When I fetch the image in my browser (while logged into my Microsoft account), it works fine. However, when I attempt to export the PDF, the image does not display.

To resolve this, I tried using an Azure app for authentication. I granted the app Sites.Read.All and Files.Read.All permissions, but I am still getting a 401 Unauthorized error when trying to fetch the image.

Here’s what I’ve tried so far:

1. Fetching the image in the browser (works):

fetch('https://<sharepoint-site>/<image-url>')
  .then(response => response.blob())
  .then(blob => {
    // Process the image
  });

2. Using Azure app authentication (fails with 401):

const token = await getAccessToken(); // Function to get token using Azure AD
fetch('https://<sharepoint-site>/<image-url>', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
})
  .then(response => {
    if (!response.ok) throw new Error('Network response was not ok');
    return response.blob();
  })
  .then(blob => {
    // Process the image
  })
  .catch(error => console.error('Error fetching image:', error));

3. Azure App Permissions:

  • Sites.Read.All
  • Files.Read.All

Screenshot of API permissions for the Azure APP
Despite these permissions, I am still encountering a 401 Unauthorized error. Am I missing something in the authentication process or the permissions setup?

Additional Context:

  • I am using Microsoft Graph API for authentication.
  • The SharePoint site and image are accessible when I am logged in via the browser.
  • The PDF generation library I am using is html2pdf.

Any help or guidance on resolving this issue would be greatly appreciated!

ant design define help tag for form field errors

Application use ant.design. When we define Form.Item, we can define noStyle tag to remote style.

When we do that, it will remote the div tag which will display the error with class ant-form-item-additional.

Is there any way, we can define that manually? or is there any property which we can define to show error above the input field?