How to Retrieve Logs from %temp%OfficeAddins.log.txt and Display Them in an Excale Add-in Side Panel

I have developed an Office JavaScript Excel add-in that provides live product pricing using custom streaming functions. The office add-in javascript-only function is designed to log errors in a file located at %temp%OfficeAddins.log.txt on the user’s machine.

To enhance troubleshooting for customer issues, I want to:

  1. Programmatically access the %temp%OfficeAddins.log.txt file
  2. Read the file contents
  3. Display the logs dynamically in the side panel of the add-in, allowing users to view error details

Questions:

  • Is there a way to programmatically access the %temp% directory and read the OfficeAddins.log.txt file from within the add-in side panel?
  • If direct file access is not possible, what alternative solutions could be used to fetch and display the logs from that file in the side panel?
  • Can the Office.js API facilitate secure access to that file?

Additional Information

  • The add-in is built using HTML, CSS and JavaScript, and it operates within the Office.js framework

Why does the iterator close after a break in a for…of loop?

I have a generator that yields 1000 items. I noticed that when I use a for...of loop to partially consume the generator and then break out of the loop, the iterator seems to close. As a result, my subsequent for...of loop doesn’t resume where the first one left off.

Here’s the code:

function* test() {
  const array = Array.from({ length: 1000 }, (_, index) => index);

  for (let item of array) {
    yield item;
  }
}

const iterator = test();
console.log('Before first loop', iterator);

let j = 0;
for (const i of iterator) {
  console.log('A', i);

  if (j++ === 3) {
    break; // Break after consuming 4 items
  }
}

console.log('Before second loop', iterator);

j = 0;
for (const i of iterator) {
  console.log('B', i);

  if (j++ === 3) {
    break;
  }
}

and here is the log:

Before first loop test {<suspended>}
A 0
A 1
A 2
A 3
Before second loop test {<closed>}

I expected the second loop to pick up where the first one left off, but it doesn’t. From my understanding, for...of works with iterators and should resume the iteration unless explicitly reset.

  • Why does breaking out of the first for...of loop close the iterator?
  • How exactly does for...of interact with the generator’s lifecycle?
  • Is there a way to prevent this closure without switching to next()?

I understand I could manually call next() on the generator, but I’m specifically asking about how for...of works in this context.

Turning a horizontal scroll image gallery for desktop (using vertical scroll gesture) into a vertical scroll gallery (using vertical scroll gesture))

I am trying to figure out how I can make this code turn a gallery that scrolls horizontally on desktop to a vertical scrolling gallery on mobile breakpoint sizes. I currently have it working properly for the horizontal scroll on desktop using the vertical scroll gesture, but I can’t figure out how to have the code switch to have the gallery scroll vertically on mobile breakpoints. I tried an “if else” statement (isMobile) that should check to see if the width of the screen is a certain size and then the gallery should scroll vertically but it does not work. Code setup below.

<script>
  import { gsap } from "gsap";

  let target = 0;
  let current = 0;
  let ease = 0.075;
  const isMobile = window.innerWidth <= 768;
  const sliderWrapper = document.querySelector(".slider-wrapper");
  let maxScroll = sliderWrapper?.offsetWidth - window.innerWidth;

  function lerp(start:number, end:number, factor:number) {
    return start + (end - start) * factor;
  }

  function update() {
    current = lerp(current, target, ease);

    gsap.set(".slider-wrapper", {
      x: -current,
    });

    requestAnimationFrame(update);
  }

  window.addEventListener("resize", () => {
    maxScroll = sliderWrapper?.offsetWidth - window.innerWidth;
  });

  if (!isMobile) {
    window.addEventListener("wheel", (e) => {
      target += e.deltaY;
      e.preventDefault();

      target = Math.max(0, target);
      target = Math.min(maxScroll, target);
    });
  } else {
    window.addEventListener("wheel", (e) => {
      target += e.deltaY;
        gsap.set(".slider-wrapper", {
        Y: -current,
      });
    });
  }

  update();
</script>

onPointerOver and onPointerOut detect all child elements

The problem is that I have onPointerOver and onPointerOut triggered on each child element, but I need it to be on a common group, because then the component is re-rendered too often.

There is a group here, and now when I move the mouse cursor, the component is redrawn many times, I want my state to change only 1 time when I move the mouse cursor and move it away.

This is changing, but the fact is that my head consists of many InstancedMesh, and it turns out that this state changes for each square that my head consists of.

How do I make this work only for the entire group, that is, so that when I hover the cursor, it only reacts to the entire group, and not to individual squares?

    <group
      position={position}
      onPointerOver={(e) => {
        e.stopPropagation();  
        handlePointerOver(e); 
      }}
      onPointerOut={(e) => {
        e.stopPropagation();
        handlePointerOut(e);
      }}
    >
      <Head scale={scale} isVisibleGrid={isVisibleGrid} position={scaledPosition(0, 24, 0)} />

    </group>
  const handlePointerOver = (e: ThreeEvent<PointerEvent>) => {
    setIsVisibleGrid(true);
    e.stopPropagation();
  };

  const handlePointerOut = (e: ThreeEvent<PointerEvent>) => {
    setIsVisibleGrid(false);
    e.stopPropagation();
  };

mapBox autofill sessionToken usage?

I have searched through the documents, but found nothing specific to the address autofill property sessionToken. Does anyone have reference information that includes the behavior, lifecycle and related functions for the property?

I have a prototype using the property along with accessToken, but not sure if it is actually correctly operating as designed.

function initAutocomplete() {
            const autofill = document.querySelector('mapbox-address-autofill');
            //const minimap = document.querySelector('mapbox-address-minimap');
            autofill.accessToken = ACCESS_TOKEN;
            autofill.sessionToken = 'testsession-token'
            //minimap.accessToken = ACCESS_TOKEN;
            autofill.addEventListener('retrieve', (event) => {
                const featureCollection = event.detail;
                if (!featureCollection || !featureCollection.features.length) {
                    minimap.feature = null;
                    return;
                }
                mapboxfeature = featureCollection.features[0];
                //minimap.feature = feature;
                fillInAddress();
            });
            
        }

What are the benefits of Next.js Server Actions, and why should I use them instead of client-side API calls?

I am working on a Nextjs web application. I am using server actions for fetching data and submitting forms using rest apis in java spring boot. It works great. However, I have a few doubts in my mind and I noticed a couple of drawbacks as well.

For server action, they do not show up in network tab. So, for manual QA it is not possible to see what is being sent to server and what is being returned.

How much of a difference will it make if I ditch server actions and stick with client api calls?

I would appreciate a detailed answer to help me understand this.

How do I change file pathing after installation?

I am taking a course on react and after installing the dependancies, one of the first tasks is to run npm start. However I think i’m running into a pathing issue, but am unaware of how to fix it.

daynenhinckley@Daynens-MacBook-Pro ~ % npm start
npm error code ENOENT
npm error syscall open
npm error path /Users/daynenhinckley/package.json
npm error errno -2
npm error enoent Could not read package.json: Error: ENOENT: no such file or directory, open '/Users/daynenhinckley/package.json'
npm error enoent This is related to npm not being able to find a file.
npm error enoent
npm error A complete log of this run can be found in: /Users/daynenhinckley/.npm/_logs/2025-01-04T01_03_23_571Z-debug-0.log

this is the log of what I get when I run the code. I’m still learning how to set up pathing but I’m not sure how to reconfigure pathing to go where I want after it’s set up. Any help is appreciated.

error: FirebaseError: Firebase: No Firebase App ‘[DEFAULT]’ has been created – call initializeApp() first (app/no-app)

I am building a web app using firebase local emulation. I have firebase authentication working but I’m getting errors that don’t make sense when trying to query my database.

Here is the relevant testing code:

import { initializeApp, getApps } from 'firebase/app';
import { getAuth, connectAuthEmulator, signInWithEmailAndPassword, signOut } from 'firebase/auth';
import { executeQuery, getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect';
import { getStudentByemail, connectorConfig } from '@firebasegen/default-connector';

let fbApp = null;
let dConnect = null;
let fbInitialized = false;

async function fetchFbConfig() {
  try {
    const response = await fetch('http://localhost:5001/<project-name>/us-central1/getApiKey');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const fbConfig = await response.json();
    return fbConfig;
  } catch (error) {
    console.error('Error fetching Firebase config:', error);
  }
}

// Initialize Firebase with the fetched config
fetchFbConfig()
  .then(fbConfig => {
    if (!fbConfig) throw new Error('Failed to fetch Firebase config');

    // Initialize Firebase only if it hasn't been initialized already
    if (!getApps().length) {
      fbApp = initializeApp(fbConfig);
      const auth = getAuth(fbApp);

      connectAuthEmulator(auth, "http://127.0.0.1:9099");

          console.log('Initializing DataConnect...');
          dConnect = getDataConnect(connectorConfig);

          if (!dConnect) throw new Error('dataConnect not initialized');

          connectDataConnectEmulator(dConnect, 'localhost', 9399);
          dConnect.setInitialized();
          fbInitialized = true;

          window.GetStudentByemail = async function(_email) {
            if (!fbInitialized || !dConnect) {
              throw new Error('Firebase/DataConnect not initialized');
            }
            console.log('GetStudentByemail function activated with ', _email);
            try {
              const query = getStudentByemail({ email: _email });
              console.log('Query:', query);
              const qryRef = await executeQuery(dConnect, query);
              
              return new Promise((resolve, reject) => {
                qryRef.onSnapshot(
                  snapshot => resolve(snapshot.data()),
                  error => reject(error)
                );
              });
            } catch (error) {
              console.error('GetStudentByemail error:', error);
              throw error;
            }
          };
          
          window.signInUser = function(email, password, callback) {
            if (!fbInitialized) {
              console.error('Firebase not initialized');
              callback(false);
              return;
            }

            signInWithEmailAndPassword(auth, email, password)
              .then((userCredential) => {
                if (userCredential.user.emailVerified) {
                  console.log('User signed in:', userCredential.user);
                  callback(true);
                } else {
                  console.error('Email not verified.');
                  signOut(auth);
                  callback(false);
                }
              })
              .catch((error) => {
                console.error('Error signing in:', error.code, error.message);
                callback(false);
              });
          };

          window.signInUser("<email>", "<password>", async function(isLoggedIn) {
            if (isLoggedIn) {
              try {
                  console.log('fetchStudentData function activated with ', "<email>");
                  const studentData = await window.GetStudentByemail("<email>");
                  console.log('Fetched student data:', studentData);
                } catch (error) {
                  console.error('Error fetching student data:', error);
                }
            } else {
              console.log('User not logged in.');
            }
          });
    }
  })
  .catch((error) => {
    console.error('Error initializing Firebase:', error);
  });

The console log is:

Initializing DataConnect... index.js:35:18
User signed in: Object <> index.js:76:26
fetchStudentData function activated with  <email> index.js:93:26
GetStudentByemail function activated with  <email> index.js:48:20
GetStudentByemail error: FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - call initializeApp() first (app/no-app).

The error is being thrown on the line

const query = getStudentByemail({ email: _email });

in the function GetStudentByemail. The query getStudentByemail give the correct response when called from within the data connection execution terminal in VSCode and is present and correct in the SDK.

Obviously the firebase app is created because the user is signed in and dataConnect is also correctly initialised, so the only thing that makes sense is if the execution of the promise preceeds the initialisation of the firebase app. I’ve read about promises being executed from a different queue (microtasks) that maybe causing this error, but I’m lost and clutching at straws and even if this is the case I have no idea how to solve.

Please excuse any incorrect terminology, I’m not a programmer so I’m very much out of my depth here.

Any help would be greatly appreciated.

useState rerenders bindings increment when key added to object but not removed

I’m running a bunch of generated checkboxes through useState as a generic object, eg:

const [stuff, setStuff] = useState(() => {
  // do stuff to get saved stuff.
  // assume very basic format of { uuid: boolean, uuid: boolean, ... }
  return theStuff
}

The stuff is then fed to the UI by child components that uses the stuff, eg:

{stuff.map((thing, i) => (
  <Fragment key={i}>
    <input
      type="checkbox"
      id={thing}
      name={thing}
      checked={stuff[thing] || false}
      onChange={() => handleChanges(thing)}
    />
  </Fragment>
)};

Now when one of the few hundred checkboxes is created and one/many get checked I just throw the state object mentioned in the first snippet. This works great, updates the state on the screen re-renders and also updates the values and re-renders on other sibling components so I can display like counts of selected etc.

export const handleChanges = (thing) => {
  setStuff((prevStuff) => ({
    ...prevStuff,
    [thing]: !prevStuff[thing]
  }));
}

The Problem
It may be in handleChanges I assume my learning curve on React lifecycle handling is hurting me because:

  • It will update the used values in sibling components when I ADD to the object, but not when I REMOVE from the object.
  • If I handle the change by way of a delete stuff.uuid then it WILL update the values used on the sibling components both ways…but it does not update the checked state of the checkbox.

Hope this isn’t too verbose, but I can’t seem to find how to have setState update both when adding and removing from the object on the sibling components. This while keeping the state object a nice clean object of only the uuid’s selected.

Save and/or Apply Background Image on click

This question is not how to add Background Images, it is how to have it save the setting once the option has been selected, so after the page is refreshed or page is changed it remembers the choice.

I have made it so my background changes on click, however it does not save the theme and actually apply change after leaving the page or refreshing.


1.Is there anyway to apply it to the original code? if so I would really like help on how to do so.

if not

2.What changes would I need to make to have the NEW JS work with what I have now?

Extra Challenge:

(I only want it to affect the profile page and settings page and not the full website)

I Would really appreciate the help I don’t mean to sound terrible.


Down below are links to the Codepens.

1.This is my original code I used to be able to change background:https://codepen.io/Elixble/pen/RwzZaWB

2.This is the code I’ve tried to implement but have gotten confused/lost on how to get it to work with what I have:https://codepen.io/Elixble/pen/KwPyyVY

I will also show the code below.

1.Working code but DOES NOT save

(HTML)

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<body id="Background">
  <div id="SettingsBox">
    <div>

      <div class="Embers" data-class="Embers-Theme-Card-Gradient" onclick="myFunction(this)">
        <h1>Embers</h1>

        <div class="mouse-position-tracker">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>
      </div>

      <div class="Darkmode-Theme-Card" data-class="Darkmode-Theme-Card-Gradient" onclick="myFunction(this)">
        <h1>Darkmode</h1>

        <div class="mouse-position-tracker">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>
      </div>
    </div>
  </div>
</body>

JS


function myFunction(obj) {
  $('body#Background').removeClass().addClass($(obj).data('class'));
}

CSS


body {
  width: 100%;
  height: 100vh;
  background-repeat: no-repeat;
  background-size: cover;
  background-image: url("https://i.postimg.cc/q78KTSXn/Dark-Mode-Background.png");
  position: absolute;
  margin: auto;
}

.Embers-Theme-Card-Gradient{
  background-image: url("https://i.postimg.cc/RFdn3tYZ/Embers-Background.png");
  position:relative;
}

.Darkmode-Theme-Card-Gradient{
("https://i.postimg.cc/q78KTSXn/Dark-Mode-Background.png");
  position:relative;
}

.Coffee-Theme-Card-Gradient{
("https://i.postimg.cc/Njxp1Q0J/Coffee.png");
  position:relative;
}

.Embers {
  --perspective: 1400px;
  --rotateX: 0;
  --rotateY: 0;
  --angle: 6.5deg;
  position: absolute;
  display: grid;
  place-content: center;
  text-align: center;
  box-shadow: rgba(0, 0, 0, 0.25) -20px 20px 20px 0px;
  padding: 2rem;
  aspect-ratio: 1 / 2;
  background-image: url("https://i.postimg.cc/wBDMSNcj/Embers.png");
  background-size: cover;
  transform: perspective(var(--perspective)) rotateX(var(--rotateX)) rotateY(var(--rotateY));
  transition: transform 350ms ease;
  width: 180px;
  height: 75px;
  border-radius: 20px;
  left: 29%;
  bottom: 80%;
}

.Embers> :where(h1,
p) {
  background: rgba(221, 221, 221, 0.432);
  margin: 0;
  padding: 0.5rem;
}

.mouse-position-tracker {
  position: absolute;
  inset: 0;
}

.mouse-position-tracker>div {
  position: absolute;
  width: calc(100% / 3);
  height: calc(100% / 3);
  z-index: 2;
}

.Embers:has(.mouse-position-tracker>div:nth-child(1):hover) {
  --rotateX: var(--angle);
  --rotateY: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(2):hover) {
  --rotateX: var(--angle);
}

.Embers:has(.mouse-position-tracker>div:nth-child(3):hover) {
  --rotateX: var(--angle);
  --rotateY: var(--angle);
}

.Embers:has(.mouse-position-tracker>div:nth-child(4):hover) {
  --rotateY: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(6):hover) {
  --rotateY: var(--angle);
}

.Embers:has(.mouse-position-tracker>div:nth-child(7):hover) {
  --rotateX: calc(var(--angle) * -1);
  --rotateY: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(8):hover) {
  --rotateX: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(9):hover) {
  --rotateX: calc(var(--angle) * -1);
  --rotateY: var(--angle);
}


/* 1st, 4th, 7th */

.mouse-position-tracker>div:nth-of-type(3n - 2) {
  left: 0;
}


/* 2nd, 5th, 8th */

.mouse-position-tracker>div:nth-of-type(3n - 1) {
  left: calc(100% / 3);
}


/* 3rd, 6th, 9th */

.mouse-position-tracker>div:nth-of-type(3n) {
  right: 0;
}


/* 1-3 */

.mouse-position-tracker>div:nth-child(n+1):nth-child(-n+3) {
  top: 0;
}


/* 4-6 */

.mouse-position-tracker>div:nth-child(n+4):nth-child(-n+6) {
  top: calc(100% / 3);
}


/* 7-9 */

.mouse-position-tracker>div:nth-child(n+7):nth-child(-n+9) {
  bottom: 0;
}


/* general styling */

 :root {
  --shadow: 0px 1px 2.2px rgba(0, 0, 0, 0.02), 0px 2.5px 5.3px rgba(0, 0, 0, 0.028), 0px 4.6px 10px rgba(0, 0, 0, 0.035), 0px 8.3px 17.9px rgba(0, 0, 0, 0.042), 0px 15.5px 33.4px rgba(0, 0, 0, 0.05), 0px 37px 80px rgba(0, 0, 0, 0.07);
}

.Embers {
  cursor: pointer;
}

.Darkmode-Theme-Card {
  --perspective: 1400px;
  --rotateX: 0;
  --rotateY: 0;
  --angle: 5deg;
  position: absolute;
  display: grid;
  place-content: center;
  text-align: center;
  box-shadow: rgba(0, 0, 0, 0.25) -20px 20px 20px 0px;
  padding: 2rem;
  aspect-ratio: 1 / 2;
  background-image: url("https://i.postimg.cc/Px4xqk7G/DarkMode.png");
  background-size: cover;
  transform: perspective(var(--perspective)) rotateX(var(--rotateX)) rotateY(var(--rotateY));
  transition: transform 350ms ease;
  width: 180px;
  height: 75px;
  border-radius: 20px;
  left: 10%;
  bottom: 80%;
}

.Darkmode-Theme-Card > :where(h1, p) {
    background: rgba(221, 221, 221, 0.432);
    margin: 0;
    padding: 0.5rem;
  }
  
  .mouse-position-tracker {
    position: absolute;
    inset: 0;
  }
  
  .mouse-position-tracker > div {
    position: absolute;
    width: calc(100% / 3);
    height: calc(100% / 3);
    z-index: 2;
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(1):hover) {
    --rotateX: var(--angle);
    --rotateY: calc(var(--angle) * -1);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(2):hover) {
    --rotateX: var(--angle);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(3):hover) {
    --rotateX: var(--angle);
    --rotateY: var(--angle);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(4):hover) {
    --rotateY: calc(var(--angle) * -1);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(6):hover) {
    --rotateY: var(--angle);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(7):hover) {
    --rotateX: calc(var(--angle) * -1);
    --rotateY: calc(var(--angle) * -1);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(8):hover) {
    --rotateX: calc(var(--angle) * -1);
  }
  
 .Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(9):hover) {
    --rotateX: calc(var(--angle) * -1);
    --rotateY: var(--angle);
  }
  
  /* 1st, 4th, 7th */
  .mouse-position-tracker > div:nth-of-type(3n - 2) {
    left: 0;
  }
  /* 2nd, 5th, 8th */
  .mouse-position-tracker > div:nth-of-type(3n - 1) {
    left: calc(100% / 3);
  }
  /* 3rd, 6th, 9th */
  .mouse-position-tracker > div:nth-of-type(3n) {
    right: 0;
  }
  
  /* 1-3 */
  .mouse-position-tracker > div:nth-child(n + 1):nth-child(-n + 3) {
    top: 0;
  }
  
  /* 4-6 */
  .mouse-position-tracker > div:nth-child(n + 4):nth-child(-n + 6) {
    top: calc(100% / 3);
  }
  
  /* 7-9 */
  .mouse-position-tracker > div:nth-child(n + 7):nth-child(-n + 9) {
    bottom: 0;
  }
  
  /* general styling */
  :root {
    --shadow: 0px 1px 2.2px rgba(0, 0, 0, 0.02),
      0px 2.5px 5.3px rgba(0, 0, 0, 0.028), 0px 4.6px 10px rgba(0, 0, 0, 0.035),
      0px 8.3px 17.9px rgba(0, 0, 0, 0.042), 0px 15.5px 33.4px rgba(0, 0, 0, 0.05),
      0px 37px 80px rgba(0, 0, 0, 0.07);
  }

  .Darkmode-Theme-Card
  {
    cursor:pointer;
  }

#SettingsBox
{
  position:relative;
  height:850px;
  width:1400px;
  background-color:rgba(0, 0, 0, 0.25);
  border-radius:20px;
  box-shadow: -5px 5px 15px #111a;
  margin:auto;
  top:10%;
}

2.NOT Working (Same HTML and CSS)
(HTML)

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<body id="Background">
  <div id="SettingsBox">
    <div>

      <div class="Embers" data-class="Embers-Theme-Card-Gradient" onclick="myFunction(this)">
        <h1>Embers</h1>

        <div class="mouse-position-tracker">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>
      </div>

      <div class="Darkmode-Theme-Card" data-class="Darkmode-Theme-Card-Gradient" onclick="myFunction(this)">
        <h1>Darkmode</h1>

        <div class="mouse-position-tracker">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>
      </div>
    </div>
  </div>
</body>

JS


let Embers = localStorage.getItem( 'Embers' )
const themeSwitch = document-getElementById ('Background')

const enableEmbers = () =› {
document.body.classList.add ('Embers')
localStorage setItem( 'Embers', 'active')
}

const disableEmbers = () => {
document. body. classList. remove( 'Embers')
localStorage setItem( 'Embers', null)
}

themeSwitch. addEventListener ("click", () => {
Embers !== "active" ? enableDarkmode() : disableDarkmode()
({

CSS


body {
  width: 100%;
  height: 100vh;
  background-repeat: no-repeat;
  background-size: cover;
  background-image: url("https://i.postimg.cc/q78KTSXn/Dark-Mode-Background.png");
  position: absolute;
  margin: auto;
}

.Embers-Theme-Card-Gradient{
  background-image: url("https://i.postimg.cc/RFdn3tYZ/Embers-Background.png");
  position:relative;
}

.Darkmode-Theme-Card-Gradient{
("https://i.postimg.cc/q78KTSXn/Dark-Mode-Background.png");
  position:relative;
}

.Coffee-Theme-Card-Gradient{
("https://i.postimg.cc/Njxp1Q0J/Coffee.png");
  position:relative;
}

.Embers {
  --perspective: 1400px;
  --rotateX: 0;
  --rotateY: 0;
  --angle: 6.5deg;
  position: absolute;
  display: grid;
  place-content: center;
  text-align: center;
  box-shadow: rgba(0, 0, 0, 0.25) -20px 20px 20px 0px;
  padding: 2rem;
  aspect-ratio: 1 / 2;
  background-image: url("https://i.postimg.cc/wBDMSNcj/Embers.png");
  background-size: cover;
  transform: perspective(var(--perspective)) rotateX(var(--rotateX)) rotateY(var(--rotateY));
  transition: transform 350ms ease;
  width: 180px;
  height: 75px;
  border-radius: 20px;
  left: 29%;
  bottom: 80%;
}

.Embers> :where(h1,
p) {
  background: rgba(221, 221, 221, 0.432);
  margin: 0;
  padding: 0.5rem;
}

.mouse-position-tracker {
  position: absolute;
  inset: 0;
}

.mouse-position-tracker>div {
  position: absolute;
  width: calc(100% / 3);
  height: calc(100% / 3);
  z-index: 2;
}

.Embers:has(.mouse-position-tracker>div:nth-child(1):hover) {
  --rotateX: var(--angle);
  --rotateY: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(2):hover) {
  --rotateX: var(--angle);
}

.Embers:has(.mouse-position-tracker>div:nth-child(3):hover) {
  --rotateX: var(--angle);
  --rotateY: var(--angle);
}

.Embers:has(.mouse-position-tracker>div:nth-child(4):hover) {
  --rotateY: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(6):hover) {
  --rotateY: var(--angle);
}

.Embers:has(.mouse-position-tracker>div:nth-child(7):hover) {
  --rotateX: calc(var(--angle) * -1);
  --rotateY: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(8):hover) {
  --rotateX: calc(var(--angle) * -1);
}

.Embers:has(.mouse-position-tracker>div:nth-child(9):hover) {
  --rotateX: calc(var(--angle) * -1);
  --rotateY: var(--angle);
}


/* 1st, 4th, 7th */

.mouse-position-tracker>div:nth-of-type(3n - 2) {
  left: 0;
}


/* 2nd, 5th, 8th */

.mouse-position-tracker>div:nth-of-type(3n - 1) {
  left: calc(100% / 3);
}


/* 3rd, 6th, 9th */

.mouse-position-tracker>div:nth-of-type(3n) {
  right: 0;
}


/* 1-3 */

.mouse-position-tracker>div:nth-child(n+1):nth-child(-n+3) {
  top: 0;
}


/* 4-6 */

.mouse-position-tracker>div:nth-child(n+4):nth-child(-n+6) {
  top: calc(100% / 3);
}


/* 7-9 */

.mouse-position-tracker>div:nth-child(n+7):nth-child(-n+9) {
  bottom: 0;
}


/* general styling */

 :root {
  --shadow: 0px 1px 2.2px rgba(0, 0, 0, 0.02), 0px 2.5px 5.3px rgba(0, 0, 0, 0.028), 0px 4.6px 10px rgba(0, 0, 0, 0.035), 0px 8.3px 17.9px rgba(0, 0, 0, 0.042), 0px 15.5px 33.4px rgba(0, 0, 0, 0.05), 0px 37px 80px rgba(0, 0, 0, 0.07);
}

.Embers {
  cursor: pointer;
}

.Darkmode-Theme-Card {
  --perspective: 1400px;
  --rotateX: 0;
  --rotateY: 0;
  --angle: 5deg;
  position: absolute;
  display: grid;
  place-content: center;
  text-align: center;
  box-shadow: rgba(0, 0, 0, 0.25) -20px 20px 20px 0px;
  padding: 2rem;
  aspect-ratio: 1 / 2;
  background-image: url("https://i.postimg.cc/Px4xqk7G/DarkMode.png");
  background-size: cover;
  transform: perspective(var(--perspective)) rotateX(var(--rotateX)) rotateY(var(--rotateY));
  transition: transform 350ms ease;
  width: 180px;
  height: 75px;
  border-radius: 20px;
  left: 10%;
  bottom: 80%;
}

.Darkmode-Theme-Card > :where(h1, p) {
    background: rgba(221, 221, 221, 0.432);
    margin: 0;
    padding: 0.5rem;
  }
  
  .mouse-position-tracker {
    position: absolute;
    inset: 0;
  }
  
  .mouse-position-tracker > div {
    position: absolute;
    width: calc(100% / 3);
    height: calc(100% / 3);
    z-index: 2;
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(1):hover) {
    --rotateX: var(--angle);
    --rotateY: calc(var(--angle) * -1);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(2):hover) {
    --rotateX: var(--angle);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(3):hover) {
    --rotateX: var(--angle);
    --rotateY: var(--angle);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(4):hover) {
    --rotateY: calc(var(--angle) * -1);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(6):hover) {
    --rotateY: var(--angle);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(7):hover) {
    --rotateX: calc(var(--angle) * -1);
    --rotateY: calc(var(--angle) * -1);
  }
  
.Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(8):hover) {
    --rotateX: calc(var(--angle) * -1);
  }
  
 .Darkmode-Theme-Card:has(.mouse-position-tracker > div:nth-child(9):hover) {
    --rotateX: calc(var(--angle) * -1);
    --rotateY: var(--angle);
  }
  
  /* 1st, 4th, 7th */
  .mouse-position-tracker > div:nth-of-type(3n - 2) {
    left: 0;
  }
  /* 2nd, 5th, 8th */
  .mouse-position-tracker > div:nth-of-type(3n - 1) {
    left: calc(100% / 3);
  }
  /* 3rd, 6th, 9th */
  .mouse-position-tracker > div:nth-of-type(3n) {
    right: 0;
  }
  
  /* 1-3 */
  .mouse-position-tracker > div:nth-child(n + 1):nth-child(-n + 3) {
    top: 0;
  }
  
  /* 4-6 */
  .mouse-position-tracker > div:nth-child(n + 4):nth-child(-n + 6) {
    top: calc(100% / 3);
  }
  
  /* 7-9 */
  .mouse-position-tracker > div:nth-child(n + 7):nth-child(-n + 9) {
    bottom: 0;
  }
  
  /* general styling */
  :root {
    --shadow: 0px 1px 2.2px rgba(0, 0, 0, 0.02),
      0px 2.5px 5.3px rgba(0, 0, 0, 0.028), 0px 4.6px 10px rgba(0, 0, 0, 0.035),
      0px 8.3px 17.9px rgba(0, 0, 0, 0.042), 0px 15.5px 33.4px rgba(0, 0, 0, 0.05),
      0px 37px 80px rgba(0, 0, 0, 0.07);
  }

  .Darkmode-Theme-Card
  {
    cursor:pointer;
  }

#SettingsBox
{
  position:relative;
  height:850px;
  width:1400px;
  background-color:rgba(0, 0, 0, 0.25);
  border-radius:20px;
  box-shadow: -5px 5px 15px #111a;
  margin:auto;
  top:10%;
}

How to Use GraalVM to Execute JavaScript Code Making REST Calls Using Java?

I’m trying to use GraalVM to execute JavaScript code that makes a REST call using Java. Below is the code I am working with:

JavaScript Code:

import axios from "axios";
const API_URL = "https://jsonplaceholder.typicode.com/posts";
const fetchPosts = async () => {
try {
const response = await axios.get(API_URL);
console.log("Posts:", response.data);
} catch (error) {
console.error("Error fetching posts:", error);
}
};
// Call the function
fetchPosts();

Bundled JavaScript using es bundle
Java Code to Execute the ES Bundled Code:

public static void main( String[] args )
{
String jscode = null;
try {
jscode = new String(Files.readAllBytes(Paths.get("/tmp/main.js")));
} catch (IOException e) {
throw new RuntimeException(e);
}
try (Context context = Context.create()) {
Value value = context.eval("js", jscode);
value.execute();
}
}

pom.xml:

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<graaljs.version>24.1.1</graaljs.version>

<dependency>
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>polyglot</artifactId>
  <version>${graaljs.version}</version>
</dependency>
<dependency>
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>js</artifactId>
  <version>${graaljs.version}</version>
  <type>pom</type>
</dependency>
<dependency> <!-- all tools we include in Oracle GraalVM -->
  <groupId>org.graalvm.polyglot</groupId>
  <artifactId>tools</artifactId>
  <version>${graaljs.version}</version>
  <type>pom</type>
</dependency>


<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>3.8.1</version>
  <scope>test</scope>
</dependency>

When I run the above code, I encounter the following error:

Error fetching posts: AxiosError: There is no suitable adapter to dispatch the request since :
adapter xhr is not supported by the environment
adapter http is not available in the build
adapter fetch is not supported by the environment

Could someone please help me figure out how to properly use GraalVM to execute JavaScript code that makes a REST call in Java?

Thank you in advance!

How can I create hyperlinkOrPicture column types on SharePoint Lists with Microsoft Graph API or Sharepoint API?

Background

I am working on a script in JavaScript that generates new columns for a given Sharepoint List. I have been referencing the Graph API which defines the column types and what should be present in the payload for the POST requests to create new columns. To format the request I have referred to the following: https://learn.microsoft.com/en-us/graph/api/list-post-columns?view=graph-rest-1.0&tabs=http.

The following code from my script that is working for almost all types: (text, dateTime, boolean, choice, currency, etc…)

const graphApiUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/columns`;
const response = await fetch(graphApiUrl, {
    method: "POST",
    headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
    },
    body: JSON.stringify(graphPayload),
});

if (!response.ok) {
    const errorDetails = await response.text();
    logError(`Failed to create column "${field.name}": ${response.statusText}nDetails: ${errorDetails}`);
    return; 
}

const responseData = await response.json();

Unfortunately, I am having an issue with the hyperlinkOrPicture columns… For instance the following combinations of payloads do not work:

// payload for hyperlink column
{ 
   name: 'URL', 
   hyperlinkOrPicture: { isPicture: false } 
}
// payload for picture column 
{
  name: 'Files (Image Files Only)',
  hyperlinkOrPicture: { isPicture: true }
}

The following error occurs:

ERROR: Failed to create column "URL": Bad Request
Details: {"error":{"code":"invalidRequest","message":"Invalid request","innerError":{"date":"2025-01-03T21:32:54","request-id":"ad66da6b-c273-409a-801c-aabe918c80e2","client-request-id":"ad66da6b-c273-409a-801c-aabe918c80e2"}}}

# similar for the second column

The above formatting comes from the documentation:

Graph API hyperlinkOrPicture JSON

Research and Attempt at Solution

Bad Graph API Documentation

Before resorting to making a post on here, I did my best to research as much as possible: both from other posts, and Microsoft’s API documentation. I knew there was a possibility that the API documentation was missing something because the Graph documentation in particular for Lists related requests is very minimal in detail, and tends to just include examples without a thorough breakdown of all the fields that are necessary in the body of the requests. I noticed this when working on the second part of my script which was to insert items into the columns I generated.

Example: Inserting a new Item to a “choice” column type with multipleSelects enabled.

If we look at the documentation it is very minimal and does not provide any example for all possible fields: https://learn.microsoft.com/en-us/graph/api/listitem-create?view=graph-rest-1.0&tabs=http

I had to resort to another post that mentioned how to have this done.

Answer to choice column with multiple choices enabled

Thus, I was hoping that something like this was the case for the hyperlinkOrPicture columns – which in the Sharepoint API are referred to as different types: https://learn.microsoft.com/en-us/previous-versions/office/sharepoint-csom/ee540543(v=office.15). It states that there is a ‘URL’ Field, with a value of 11, and a ‘File’ field with a value of 18. Clearly, there is a disconnect here and cause of confusion.

Using Sharepoint API Instead

After not finding anything on the Graph API documentation as to why hyperlinkOrPicture column type happens to be the only column type that is not being created properly, even though I am following the formatting, I decided to try the Sharepoint API. However, I have been having a difficult time setting that up and having an issue with the token that I am using. Even though I have Sites.FullControl.All Application Access, and have followed the instructions in this post from MicroSoft to setup app-only token access: https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread, by including a certificate to my registered app on azure, I am still getting an error that says the following:

ERROR: Failed to create SharePoint column "URL": Unauthorized
Unsupported app only token.

I am not sure why this is only an issue with SharePoint API when Graph API is working just fine with similar permissions.

I am using the following payload according to SharePoint API documentation to create the new column:

const isPicture = field.type === 'multipleAttachments';
const sharePointPayload = {
    __metadata: { type: "SP.Field" },
    Title: columnName,
    FieldTypeKind: 11,
    Required: false,
    EnforceUniqueValues: false,
    UrlFormat: isPicture ? 1 : 0, // 0 for Hyperlink, 1 for Picture
    Description: columnPayload.description,
};

Request is below…

const sharePointApiUrl = `${SITE_URL}/_api/web/lists(guid'${listId}')/fields`;

try {
    const response = await fetch(sharePointApiUrl, {
        method: "POST",
        headers: {
            Authorization: `Bearer ${sharePointAccessToken}`,
            Accept: "application/json;odata=verbose",
            "Content-Type": "application/json;odata=verbose",
        },
        body: JSON.stringify(sharePointPayload),
    });

    if (!response.ok) {
        const errorDetails = await response.text();
        logError(
            `Failed to create SharePoint column "${columnName}": ${response.statusText}n${errorDetails}`
        );
    }

    log(`SharePoint column "${columnName}" created successfully.`);

} catch (error) {
    logError(`Error creating SharePoint column "${columnName}": ${error.message}`);
}

I am not completely certain if the above is the correct payload for creating a hyperlinkOrPicture column type in SharePoint Lists. I would not be able to know since I am getting the previous error I mentioned with regard to the token.

If someone could come up with a solution by using just the Graph API, that would be the best; however, I would also like to know what I may be doing wrong in the setup process to have SharePoint API requests working.

Compare dependencies changes using two lock file

In a project that is broken but no changes in my source code, I suspect something changed in my dependency tree.

I have both lock file, I have tried to do like this:

grep 'version:' yarn.lock > yarn-versions.txt
grep 'version:' yarn-old.lock > yarn-old-versions.txt
diff yarn-versions.txt yarn-old-versions.txt

And this is the result of the diff:

❯ diff yarn-versions.txt yarn-old-versions.txt
156d155
<   version: 0.0.0-use.local
317c316
<   version: 0.6.5
---
>   version: 0.6.2
319c318
<   version: 0.6.5
---
>   version: 0.6.2
321c320
<   version: 0.6.5
---
>   version: 0.6.2
323c322
<   version: 0.6.5
---
>   version: 0.6.2
325c324
<   version: 0.6.5
---
>   version: 0.6.2
327c326
<   version: 0.6.5
---
>   version: 0.6.2
329c328
<   version: 0.6.5
---
>   version: 0.6.2
331c330
<   version: 0.6.5
---
>   version: 0.6.2
843d841
<   version: 9.1.0
1079d1076
<   version: 6.4.2
1181c1178
<   version: 2.22.17
---
>   version: 2.22.12
1673d1669
<   version: 1.1.1
1676d1671
<   version: 4.0.2
1854d1848
<   version: 1.8.2
1970d1963
<   version: 0.2.10

Not very easy to read, I must be not the first one to have this need.

I use yarn 4.3.1, how can I know all dependencies that have been modified/added/deleted?

Comapre dependencies changes using two lock file

In a project that is broken but no changes in my source code, I suspect something changed in my dependency tree.

I have both lock file, I have tried to do like this:

grep 'version:' yarn.lock > yarn-versions.txt
grep 'version:' yarn-old.lock > yarn-old-versions.txt
diff yarn-versions.txt yarn-old-versions.txt

And this is the result of the diff:

❯ diff yarn-versions.txt yarn-old-versions.txt
156d155
<   version: 0.0.0-use.local
317c316
<   version: 0.6.5
---
>   version: 0.6.2
319c318
<   version: 0.6.5
---
>   version: 0.6.2
321c320
<   version: 0.6.5
---
>   version: 0.6.2
323c322
<   version: 0.6.5
---
>   version: 0.6.2
325c324
<   version: 0.6.5
---
>   version: 0.6.2
327c326
<   version: 0.6.5
---
>   version: 0.6.2
329c328
<   version: 0.6.5
---
>   version: 0.6.2
331c330
<   version: 0.6.5
---
>   version: 0.6.2
843d841
<   version: 9.1.0
1079d1076
<   version: 6.4.2
1181c1178
<   version: 2.22.17
---
>   version: 2.22.12
1673d1669
<   version: 1.1.1
1676d1671
<   version: 4.0.2
1854d1848
<   version: 1.8.2
1970d1963
<   version: 0.2.10

Not very easy to read, I must be not the first one to have this need.

I use yarn 4.3.1, how can I know all dependencies that have been modified/added/deleted?