Finding out order of properties for a given object

A Json web service returns an object like { "id": 12, "name": "xxx", "age": 12 }. How do I find out the order of the property keys or retrieve each property in the shown sequence?

I need to copy the properties into an array in the same order. This is for a generic web service, so I don’t know in advance what the properties will be in the object”.

TypeORM: How to always format database value in where condition for strings

I would like to use a generic method “exist” given by TypeORM to verify if name is already inserted in database.

My probleme is that I can’t know if name have been inserted in Uppercase or Lowercase and so I can face some false validation and end up inserting twice the same name.

I would like TypeORM and PostgreSQL to always put in lower case the database value (here name) while doing the WHERE condition : WHERE “myname” = valueOfDatabase

Why is my element disappearing for no reason?

Tthe plus sign is placed inside .pokemon-list as a ::before, and I need .pokemon-list to have overflow-y: scroll in order to be able to scroll through all the pokemons. However, the + is still getting hidden as if I had set overflow-x: hidden which I didn’t.
Any idea of what’s happening ?

don’t pay attention to the small images not displaying, they are stored locally

const url = "https://pokeapi.co/api/v2/pokemon/";

const sprite3dElement = document.querySelector(".pokemon-3Dmodel img");

const pokemonList = document.querySelector(".pokemon-list");
const shinyButton = document.querySelector(".shiny-button");

const premierPokemon = 1;
const dernierPokemon = 151;
const nbPokemon = dernierPokemon - premierPokemon + 1;

window.addEventListener("load", getPokedata);

function getPokedata() {
  const pokemonData = []; // array to store each Pokemon's data

  for (let i = premierPokemon; i <= dernierPokemon; i++) {
    const finalUrl = url + i;
    fetch(finalUrl)
      .then((response) => response.json())
      .then((data) => {
        pokemonData[i - premierPokemon + 1] = data; // store the data for each Pokemon in the correct order
      })
      .then(() => {
        if (pokemonData.length === nbPokemon + 1) {
          // if we have fetched all the Pokemon data, generate the cards in the correct order
          pokemonData.forEach((data) => {
            generateCard(data);
          });
          betterPokemonCards();
          toggleShiny();
        }
      });
  }
}

function generateCard(data) {
  console.log(data);
  const dex_number = data.id;
  const name = data.name;
  const sprite3D = data.sprites.other["official-artwork"].front_default;
  const sprite3DShiny = data.sprites.other["official-artwork"].front_shiny;
  const sprite2D = data.sprites.versions["generation-viii"].icons.front_default;

  pokemonList.innerHTML += ` <li class="pokemon${
    dex_number == dernierPokemon ? " pokemon-active" : ""
  }" data-sprite3D="${sprite3D}" data-shiny3D="${sprite3DShiny}" data-id="${dex_number}">
  <div>
  <div class="pokemon__sprite">
  <img src="${sprite2D}" alt="sprite">
  </div>
  <p class="pokemon__num">No. <span class="pokemon__num--field">${dex_number}</span></p>
  </div>
  <p class="pokemon__name">${name}</p>
  <div class="pokeball">
  <img src="images/pokeball.png" alt="pokeball">
  </div>
  </li>
  `;
  sprite3dElement.src = sprite3D;
}

function betterPokemonCards() {
  let pokemons = document.querySelectorAll(".pokemon");

  //adds one or two 0 to the dex number if it is less than 10 or 100
  pokemons.forEach((pokemon) => {
    let dex_entry =
      pokemon.firstElementChild.lastElementChild.lastElementChild.innerText;
    if (dex_entry.length == 1) {
      pokemon.firstElementChild.lastElementChild.lastElementChild.innerText =
        "00" + dex_entry;
    } else if (dex_entry.length == 2) {
      pokemon.firstElementChild.lastElementChild.lastElementChild.innerText =
        "0" + dex_entry;
    }
    //adds an event listener to each pokemon so that when you click on it, it adds the class pokemon-active
    pokemon.addEventListener("click", () => {
      sprite3dElement.src = pokemon.getAttribute("data-sprite3D");
      pokemons.forEach((pokemon) => {
        pokemon.classList.remove("pokemon-active");
      });
      pokemon.classList.add("pokemon-active");
    });
  });
}
:root {
  --attachment: fixed;
  --degrees: 115deg;
  --colorStop-1: 50%;
  --colorStop-2: calc(var(--colorStop-1) + 100px);
}
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
img {
  width: 100%;
}
body {
  font-family: "Noto Sans KR", sans-serif;
  background-color: #fff;
  color: #282828;
  background-image: linear-gradient(
      var(--degrees),
      transparent var(--colorStop-1),
      #fe4d3e var(--colorStop-1) var(--colorStop-2),
      #fa7246 var(--colorStop-2)
    ),
    radial-gradient(
      circle at 20% 70%,
      rgb(239 208 234 / 0.9),
      rgb(234 201 242 / 0.6),
      rgb(231 238 197 / 0.6),
      rgb(205 240 219 / 0.6),
      rgb(231 237 245 / 0.6)
    );
  background-attachment: var(--attachment);
  min-height: 100vh;
  overflow: hidden;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-image: linear-gradient(
    115deg,
    rgba(50 0 0 / 0.15) var(--colorStop-1),
    rgb(53 53 53) var(--colorStop-1)
  );
  background-attachment: var(--attachment);
  margin-top: 10px;
}
.header h1 {
  font-size: 2rem;
  padding-left: 1rem;
}
.header p {
  font-size: 1.5rem;
  color: white;
  padding-right: 13%;
}
.pokedex {
  position: relative;
  display: flex;
  justify-content: flex-end;
}
.shiny-button {
  position: absolute;
  left: 20px;
  top: 20px;
  width: 5rem;
  filter: drop-shadow(5px 5px 0 rgba(130, 217, 211, 0.408));
  cursor: pointer;
}
div:has(.pokemon-3Dmodel) {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-inline: auto;
}
.pokemon-3Dmodel {
  filter: drop-shadow(8px 8px 3px #39393951);
}
.pokemon-list {
  width: clamp(360px, 100%, 520px);
  height: calc(100vh - 56px);
  display: flex;
  overflow-y: scroll;
  overflow-x: visible;
  flex-direction: column;
  gap: 15px;
  padding: 20px 10px 20px 0;
  margin-right: 20px;
  border: 3px solid gold;
  position: relative;
}
.pokemon-list::before {
  content: "+";
  position: absolute;
  top: 0;
  left: -1rem;
  font-size: 3rem;
  border: 3px solid blue;
  line-height: 1em;
}
.pokemon {
  display: flex;
  justify-content: space-between;
  align-items: center;
  text-transform: capitalize;
  padding: 0 10px 0 0;
  color: black;
  font-weight: 500;
  font-size: 1.3rem;
  border-radius: 100vw;
  cursor: pointer;
}
.pokemon:hover,
.pokemon-active {
  background-image: linear-gradient(115deg, #f04f17 45%, black 45%);
  color: white;
}
.pokemon-active {
  position: relative;
}
.pokemon-active .pokeball {
  animation: rotate 1600ms infinite linear;
}

@keyframes rotate {
  to {
    rotate: 360deg;
  }
}
.pokemon > div:first-of-type {
  display: flex;
  align-items: center;
}
.pokemon__sprite {
  width: 60px;
  scale: 1.2;
  transform-origin: bottom;
  margin-inline: 10px;
}
.pokemon__num {
  display: flex;
}
.pokemon__num--field {
  margin-left: 0.5rem;
}
.pokeball {
  width: 25px;
  height: 25px;
  display: flex;
}
<main>
  <div class="header">
    <h1>Pokédex</h1>
    <p>By Number</p>
  </div>
  <section class="pokedex">
    <div>
      <div class="pokemon-3Dmodel">
        <img src="">
      </div>
    </div>
    <ul class="pokemon-list">
    </ul>
  </section>
</main>

Download iCal files does not working on mobile Chrome

I have a simple code that generate an ics file and automatically opens calendar app on ios
I tested works well on MacOS desktop and safari on ios mobile phones, however my code does not works for chrome browser on mobile,

  var test =
        "BEGIN:VCALENDARn" +
        "CALSCALE:GREGORIANn" +
        "METHOD:PUBLISHn" +
        "PRODID:-//Test Cal//ENn" +
        "VERSION:2.0n" +
        "BEGIN:VEVENTn" +
        "UID:test-1n" +
        "DTSTART;VALUE=DATE:" +
        convertDate(starting_date_html) +
        "n" +
        "DTEND;VALUE=DATE:" +
        convertDate(ending_date_html) +
        "n" +
        "SUMMARY:" +
        event_title +
        "n" +
        "DESCRIPTION:" +
        event_location +
        "n" +
        "END:VEVENTn" +
        "END:VCALENDAR";
    window.open("data:text/Calendar;charset=utf8," + escape(test)); 

I cannot get my head around on this issue …

I also tried the encodeURIComponent but no luck :/


window.open("data:text/Calendar;charset=utf8," + encodeURIComponent(test)); 

Trying to get a filter button to click on page load

I have a set of filters. I want the first button to be selected and clicked on at the loading of the page, so as to show all projects. Unfortunately I cannot seem to make this happen and I’m stumped.
If someone could help me understand where the problem lies I’d be very grateful.

function getProjects(event) {
    console.log("get projects");
    fetch('http://localhost:5678/api/works') // récuparation des données de l'API
        .then((resp) => resp.json()) // transforme la réponse en JSON
        .then(projects => { // réception de la réponse et exécute le code contenu après réception
            // on récupère toutes les boutons de catégories pour pouvoir filtrer les travaux
            const btnsCategory = document.querySelectorAll('.filter-btn');
            // pour chaque bouton récupéré
            btnsCategory.forEach(btnCategory => {
                // on clique sur une catégorie
                btnCategory.addEventListener('click', event => {
                    // récupération de la catégorie sélectionnée auparavant 
                    // et on lui enlève la classe active pour lui enlever la surbrillance
                    document.querySelector('.filter-btn.active').classList.remove("active");
                    event.target.classList.add("active");
                    // on exécute le code
                    //filterProjects(event, projects); // on affiche les projets correspondant au filtre actif
                    const gallery = document.querySelector('.gallery'); // Sélection de l'élément HTML qui contient les projets
                    gallery.innerHTML = ''; // Vide la galerie afin de pouvoir la remplir avec les éléments filtrés
                    let filterSelected = event.target.dataset.filter;
                    projects.forEach(project => {// on crée une boucle  
                        if (project.categoryId == filterSelected || filterSelected == "all") { // on vérifie si le projet doit être affiché en fonction du filtre choisi
                            const figure = document.createElement('figure'); // on crée un élément figure pour chaque objet
                            const image = document.createElement('img'); // même chose avec img
                            image.setAttribute('src', project.imageUrl); // on attribue l'url de l'image à l'élément img
                            image.setAttribute('alt', project.title); // on donne le titre du projet à l'attribut alt de l'img 
                            const title = document.createElement('figcaption'); // on crée un élément figcaption pour chaque projet
                            title.innerHTML = project.title; // on ajoute le titre du projet à figcaption
                            figure.appendChild(image); // on attache image à figure
                            figure.appendChild(title); // on attache figcaption à figure
                            gallery.appendChild(figure); // on attche figure à la galerie
                        }
                    });
                });
            });
        });
}


async function getCategories() {
    await fetch('http://localhost:5678/api/categories')
        .then(resp => resp.json())
        .then(categories => {
            const filterButtons = document.querySelector('.filter-buttons');
            // Ajoute un bouton de filtre pour chaque catégorie
            categories.forEach(category => {
                const button = document.createElement('button');
                button.classList.add('filter-btn');
                button.dataset.filter = category.id;
                button.textContent = category.name;
                filterButtons.appendChild(button);
            });
            // Ajoute un bouton "Tous" pour afficher tous les projets
            const allButton = document.createElement('button');
            allButton.classList.add('filter-btn');
            allButton.dataset.filter = 'all';
            allButton.id = "allWorks";
            allButton.textContent = 'Tous';
            filterButtons.prepend(allButton);
            allButton.click();
            // Sélectionne tous les boutons de filtre et ajoute un écouteur d'événement sur chacun
            const filterBtns = document.querySelectorAll('.filter-btn');
            filterBtns.forEach(filterBtn => {                
                filterBtn.addEventListener('click', event => {
                    // Enlève la classe "active" du bouton de filtre actif et ajoute-la au bouton sélectionné
                    let elementActive = document.querySelector('.filter-btn.active');
                    if (elementActive != null) {
                        elementActive.classList.remove('active');
                    }
                    event.target.classList.add('active');
                    // Filtre les projets selon la catégorie sélectionnée
                    getProjects(event);
                });
            });
        });

}


document.addEventListener('DOMContentLoaded', async (event) => { // vérifie si la page est chargée
    await getCategories();
    await document.querySelector("#allWorks").click(); 
     


});


I’ve tried to have a list of filters that help the user search through the projects available on the website. Unfortunately while the “Tous” (all) button is indeed selected at page load, it isn’t clicked and the display of all the projects needs to be done manually which isn’t what I want.

Unable to set angle in transform, rotate using an anom.function

I cannot figure out what is wrong with the following code:

 svg.selectAll(".axislabel")
            .data(featureData)
            .join(
                enter => enter.append("text")
                    .attr("x", d => d.label_coord.x)
                    .attr("y", d => d.label_coord.y)
                    .attr("transform", "rotate(" + (d => d.angle)+ ")" )  //ERROR
                    .text(d => d.name)
            );

I’m getting this error:

Error: <text> attribute transform: Expected number, "rotate(d =u003E d.angle)".

If I use .attr("transform", "rotate(90)" ) then it works.

Thank you

I’ve tried various versions of the syntax.

How are dot relative paths and rootDir paths treated differently in my projects jest configuration?

Problem Description

I have a question about the jest.config.ts that I am setting up.
There I use a moduleNameMapper, so that imports a la import ... from "@base/..." also work in the tests. For this I use a function of ts-jest, which returns the corresponding regular expressions from the tsconfig.json.compilerOptions.paths. tsconfig.json is a json file which I am importing with typescript’s resolveJsonModule option. See here for the documentation on moduleNameMapper.

The function from ts-jest returns one of the following two objects to be used as the moduleNameWrapper, depending on other parameters passed. How that works is not relevant for the question, as I am also able to just enter the keys and values directly, not using the ts-jest function.

First Object: { '^@base/(.*)$': './src/$1' }
Second Object: { '^@base/(.*)$': '<rootDir>/src/$1' }
The first does not work (the modules are then not resolved), the second works correctly.

Question

Hence my question: What does . mean as a path for jest? What is the difference with <rootDir>? Why do they both not point to the same directory? My jest config is in the root directory of the project, so I would assume that both . and <rootDir would point to the root directory (the folder where the jest config is located). Also see the documentation for rootDir.

What I’ve tried so far

I tried putting both objects in as moduleNameWrapper in the jest.config, but only the one with rootDir worked. I would have expected ./src/$1 to have worked as well, but it did not.

The rootDir solution is unsatisfying, as producing the object including <rootDir> requires an additional options parameter, which sets a prefix. This prefix is hard coded, and could e.g. result in problems further in this project or when using this project as a foundation for the next.

This is the call to create the moduleNameMapper object via ts-jest:

pathsToModuleNameMapper(compilerOptions.paths, {prefix: "<rootDir>/src/"}),

If the second parameter is omitted, then the dot version is produced, which does not work.

Thanks.

Problem with Formidable Error : Request aborted

I have an application with Node.js, Express.js , MongoDB and Javascript for front-end. I want to create file upload to add image . I use formidable and use AWS like cloud platform to save images too.

The problem is :
In my application , I have a form for add information about a car , for example: mark, model, year, location ,price, Choose image button and Submit button. When I fill the fields with data and choose image , then click on Submit button, in the console it write this:

Error: Request aborted
    at IncomingMessage.<anonymous> (C:Users201217040DocumentsCarRentalnode_modulesformidablelibincoming_form.js:122:19)
    at IncomingMessage.emit (node:events:369:20)
    at IncomingMessage.emit (node:domain:470:12)
    at abortIncoming (node:_http_server:598:9)
    at socketOnClose (node:_http_server:589:3)
    at Socket.emit (node:events:381:22)
    at Socket.emit (node:domain:470:12)
    at TCP.<anonymous> (node:net:666:12)

I put part of app.js :

const express = require('express');
const exphbs = require('express-handlebars');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const passport = require('passport');
const bcrypt = require('bcryptjs');
const formidable = require('formidable');
const socketIO = require('socket.io')

// init app
const app = express();

// setup body parser
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());

// configuration for autthentication
app.use(cookieParser());
app.use(session({
    secret: 'mysecret',
    resave: true,
    saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());

// load helpers
const {requireLogin, ensureGuest} = require('./helpers/authHelper');
const {upload} = require('./helpers/aws');

// load passports
require('./passport/local');
require('./passport/facebook.js');

// receive image
app.post('/uploadImage',requireLogin,upload.any(),(req,res)=>{
    const form = new formidable.IncomingForm();
    form.on('file',(field,file)=>{
        console.log(file);
    });
    form.on('error',(err)=>{
        console.log(err);
    });
    form.on('end',()=>{
        console.log('Image received successfully.');
    });
    form.parse(req);
});

Here is where I add “upload” in aws.js :

const aws = require('aws-sdk');
const multer = require('multer');
const multers3 = require('multer-s3');
const keys = require('../config/keys');

aws.config.update({
    accessKeyId:keys.AWSAccessID,
    secretAccessKey: keys.AWSSecretKey,
    region: 'eu-north-1'
});

const s3 = new aws.S3({});

const upload = multer({
    storage: multers3({
        s3:s3,
        bucket: 'car-rental-application',
        ac1:'public-read',
        metadata:(req,file,cb)=>{
            cb(null,{fieldName:file.fieldname});
        }, 
        key: (req,file,cb)=>{
            cb(null,file.originalname);
        },
        rename: (fieldName,fileName) =>{
            return fileName.replace(/W+/g, '-').toLowerCase();
        }
    })
});
exports.upload = upload;

And here is html form:

<div class="row">
    <div class="col-sm"></div>

    <div class="col-sm-5">
            <form action="/listCar2" method="POST">
            <input type="hidden" name="carID" value="{{car._id}}">
            <div class="form-group">
                <label for="pricePerHour">Price per hour</label>
                <input type="number" name="pricePerHour" id="pricePerhour" class="form-control" required>
            </div>
            <div class="form-group">
                <label for="pricePerWeek">Price per week</label>
                <input type="number" name="pricePerWeek" id="pricePerWeek" class="form-control" required>
            </div>
            <div class="form-group">
                <label for="location">Location</label>
                <input type="text" name="location" id="location" class="form-control" placeholder="street, city, state and zipcode " required>
            </div>
            <div class="form-group">
                <button class="btn btn-info upload-btn" type="button">Choose image</button>
                <input type="file" name="image" id="upload-input" style="display: none;" required>
            </div>
            <div class="form-group">
                <button type="submit" class="btn btn-primary">List a car</button>
            </div>
            </form>
    </div>

    <div class="col-sm"></div>
</div>
<script src="https://code.jquery.com/jquery-3.6.4.js" integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E=" crossorigin="anonymous"></script>
<script>
    // fetch location using javascript
function initMap(){
    var location = document.getElementById('location');
    var Autocomplete = new google.maps.places.Autocomplete(location);
}

// jquery code starts here
$(document).ready(function(){
    $('.upload-btn').on('click',function(){
        $('#upload-input').click();
    });
    $('#upload-input').on('change', function(){
        var uploadInput = $('#upload-input');
        if(uploadInput.val() != ''){
            var formData = new FormData();
            formData.append('image', uploadInput[0].files[0]);
            
            // make ajax request to send image to database
            $.ajax({
                url: '/uploadImage',
                type: 'POST',
                data: formData,
                processData: false,
                contentType: false,
                success: function() {
                    uploadInput.val('');
                }
            })
         }
    })
})

</script>
<script async
    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCZa44WBMahTn9Zf2z9x6fKiZTMQQh3vbw&libraries=places&callback=initMap"></script>

How can I fix this problem?

Cypress API testing : How to access data generated from it block to another it block

How can I access the token generated from 1st it block to 2nd it block.

here is the code:

1st it block

      it('Login using new user', () => {
        cy.api({
          method: "POST",
          url:    "https://api-stg.sample.com/v1/user/login",
          body: 
          {
          "mobile_number": "+9912345678"
          "password": "p@ssword"  
          }

        })
          .then((response) => {
            expect(response.status).to.eq(200)
        })
          .then((response) => {
            const bearer_token = response.body.data.user.access_token.token // 
*in here where I get and put the token in var bearer_token*

            cy.log("Bearer token: " + token )
        })
      })

2nd it block

     it('Create New Mobile', () => {
        cy.api({
          method: "POST",
          url:    "https://api-stg.sample.com/v1/user/add_new_mobile_numbers",
          headers: {
            'Authorization': 'Bearer ' + token // *in here where I put the token*
          },
          body: 
          {
            "mobile_prefix": "+991",
            "mobile_number": "9912345679"
          }
})

I login from 1st block, then i need to use the token to add new mobile num in 2nd block.
in cypress dashboard it returns an error:
token is not defined

await this.showPopup(”); don’t show the Popup

I wanted to show the CreateOrderPopup in Odoo15 BUT it’s not showing and there is no error message.
I created 2 logs : ffffffff and QQQQQ
the fffffffff is shown in the logs but the QQQQQ which is after calling ” await this.showPopup(‘CreateOrderPopup’); ” it’s not being shown.

I have this in the JS file :

odoo.define("point_of_sale.CreateOrderButton", function (require) {
    "use strict";

    const PosComponent = require("point_of_sale.PosComponent");
    const ProductScreen = require("point_of_sale.ProductScreen");
    const Registries = require("point_of_sale.Registries");
   
    class CreateOrderButton extends PosComponent {
        async onClick() {
            console.log("ffffffffffffffffffff");
           await this.showPopup('CreateOrderPopup');
            console.log('QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ');
        };
        
    }
    CreateOrderButton.template = "CreateOrderButton";
    
    ProductScreen.addControlButton({
        
        component: CreateOrderButton,
        condition: function () {
            return (
                this.env.pos.config.iface_create_sale_order &&
                this.env.pos.get_order().get_client() &&
                this.env.pos.get_order().get_orderlines().length !== 0
                
            );
        },
    });

    Registries.Component.add(CreateOrderButton);
});

But the CreateOrderPopup is not showing when I click on the button. Also the QQQQ logs don’t get shown

For the CreateOrderPopUp i have :

odoo.define("point_of_sale.CreateOrderPopup", function (require) {
    "use strict";

    const AbstractAwaitablePopup = require("point_of_sale.AbstractAwaitablePopup");
    const Registries = require("point_of_sale.Registries");
    const framework = require("web.framework");

    class CreateOrderPopup extends AbstractAwaitablePopup {
        setup() {
            super.setup();
            this.createOrderClicked = false;
        }

        async createDraftSaleOrder() {
            await this._createSaleOrder("draft");
        }

        async createConfirmedSaleOrder() {
            await this._createSaleOrder("confirmed");
        }

        async createDeliveredSaleOrder() {
            await this._createSaleOrder("delivered");
        }

        async createInvoicedSaleOrder() {
            await this._createSaleOrder("invoiced");
        }

        async _createSaleOrder(order_state) {
            var current_order = this.env.pos.get_order();

            framework.blockUI();

            await this.rpc({
                model: "sale.order",
                method: "create_order_from_pos",
                args: [current_order.export_as_JSON(), order_state],
            })
                .catch(function (error) {
                    throw error;
                })
                .finally(function () {
                    framework.unblockUI();
                });

            // Delete current order
            this.env.pos.removeOrder(current_order);
            this.env.pos.add_new_order();

            // Close popup
            return await super.confirm();
        }
    }

    CreateOrderPopup.template = "CreateOrderPopup";
    Registries.Component.add(CreateOrderPopup);

    return CreateOrderPopup;
});

both templates are created and they are all called like this in the manifest file :

  "assets": {
        "point_of_sale.assets": [
            "pos_order_to_sale_order/static/src/css/pos.css",
            "pos_order_to_sale_order/static/src/js/CreateOrderPopup.js",
            "pos_order_to_sale_order/static/src/js/CreateOrderButton.js",
        ],
        'web.assets_qweb': [
            "pos_order_to_sale_order/static/src/xml/CreateOrderPopup.xml",
            "pos_order_to_sale_order/static/src/xml/CreateOrderButton.xml",

        ],

Why does the PopUp stops the QQQQ log from showing in the logs and itself in the POS

Install npm project A which has dependency to project B in project B but use current project B’s index.js file instead of original project B’s version

I have such case:

  1. I created npm project A which has peer dependency to project B
{
  "name": "project-A",
  "peerDependencies": {
    "project-B": "*"
  }
}
  1. I want to test project A inside project B without the need of installing specific version of project B inside project A
  2. I want to install project A inside project B and resolve project A’s dependency to project B’s index.js file which exports all the needed modules.

Is it achievable?

Currently I need to release project A with dependency to specific version of project B and install it like so in project B to test it. Obviously, if there are some changes in project B, project A becomes incompatible.

{
  "name": "project-A",
  "dependencies": {
    "project-B": "1.0.0"
  }
}

Tooltips overlap in vueform slider

I’m using this slider (https://github.com/vueform/slider#multiple-slider) in one of my form field and for some reasons, both the tooltips are stuck at one place.

Template Code of the slider component:

<template>
  <div class="input-container">
    <label class="input-label">{{ label }}</label>
    <div class="input-field">
      <Slider 
        v-model="value"
        :min="0"
        :max="4500"
        :showTooltip="always"
        :format="formatTooltip"
        class="slider-red"
        />
    </div>
  </div>
</template>

Script:

<script>

import Slider from '@vueform/slider'
import '@vueform/slider/themes/default.css';

export default {
  name: 'RangeSlider',
  components: {
    Slider,
  },
  props: {
    label: String,
  },
  data() {
    return {
      value: [0, 4500],
    }
  },
  watch: {
    activeButton(newValue) {
      this.activeButtonValue = newValue
    },
  },
  methods: {
    formatTooltip(val) {
      return `$${val}`
    },
  },
}
</script>

<style scoped>
.input-label {
  position: absolute;
  top: -10px;
  left: 10px;
  color: #d7c8f1;
  padding: 0 5px;
  text-decoration-color: white;
}

.input-field {
  padding-top: 20px;
  padding-bottom: 20px;
  border: 1px solid var(--secondary-color);
  color: white;
  cursor: pointer;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}

.space-right {
  margin-right: 16px;
}

.active {
  border: 1px solid var(--secondary-color);
  padding: 4px !important;
  border-radius: 12px !important;
  color: #101828 !important;
  background-color: #f9fafb;
}

.button {
  border: none;
  color: var(--primary-color);
  font-weight: 500;
  font: inherit;
  cursor: pointer;
  padding: 0px;
  border-radius: 8px;
}
.content-button {
  padding-left: 12px;
  padding-right: 12px;
  padding-top: 6px;
  padding-bottom: 6px;
  border-radius: 8px;
  border: 1px solid var(--secondary-color);
}

.slider-red {
  --slider-connect-bg: #EF4444;
  --slider-tooltip-bg: #EF4444;
  --slider-handle-ring-color: #EF444430;
}

</style>


I have tried formatting the width/height of the class, but it doesn’t seem to work.

The problem state:

enter image description here

How to display content for x seconds? [closed]

How do I display the drivers wins/podiums/points depending on what the user chooses below the drivers name after the user guesses?
How can I display the wins/podiums/points so it counts to it?
Then if the user guesses right it will take the user to the next round like my code does and if the user guesses wrong then the game ends that my code does as well.
CodePen: https://codepen.io/BobbyJackson19/pen/qBJbrWP.

// Define F1 driver data
const f1Drivers = [{
    name: 'Lewis Hamilton',
    wins: 103,
    podiums: 192,
    points: 4443.5
  },
  {
    name: 'George Russel',
    wins: 1,
    podiums: 9,
    points: 312
  },
  {
    name: 'Michael Schumacher',
    wins: 91,
    podiums: 155,
    points: 1566
  },
  {
    name: 'Sebastian Vettel',
    wins: 53,
    podiums: 122,
    points: 3098
  },
  {
    name: 'Alain Prost',
    wins: 51,
    podiums: 106,
    points: 798.5
  },
  {
    name: 'Ayrton Senna',
    wins: 41,
    podiums: 80,
    points: 614
  },
  {
    name: 'Nigel Mansell',
    wins: 31,
    podiums: 59,
    points: 482
  },
  {
    name: 'Jim Clark',
    wins: 25,
    podiums: 32,
    points: 274.5
  },
  {
    name: 'Juan Manuel Fangio',
    wins: 24,
    podiums: 35,
    points: 277.64
  },
  {
    name: 'Niki Lauda',
    wins: 25,
    podiums: 54,
    points: 420.5
  },
  {
    name: 'Jack Brabham',
    wins: 14,
    podiums: 31,
    points: 261
  },
  {
    name: 'Fernando Alonso',
    wins: 32,
    podiums: 101,
    points: 2106
  },
  {
    name: 'Max Verstappen',
    wins: 37,
    podiums: 80,
    points: 2080.5
  },
  {
    name: 'Nico Rosberg',
    wins: 23,
    podiums: 57,
    points: 1594.5
  },
  {
    name: 'Kimi Raikkonen',
    wins: 21,
    podiums: 103,
    points: 1873
  },
  {
    name: 'Mika Hakkinen',
    wins: 20,
    podiums: 51,
    points: 420
  },
  {
    name: 'Jenson Button',
    wins: 15,
    podiums: 50,
    points: 1235
  },
  {
    name: 'Jackie Stewart',
    wins: 27,
    podiums: 43,
    points: 359
  },
  {
    name: 'Damon Hill',
    wins: 22,
    podiums: 42,
    points: 360
  },
  {
    name: 'Felipe Massa',
    wins: 11,
    podiums: 41,
    points: 1167
  },
  {
    name: 'Valtteri Bottas',
    wins: 10,
    podiums: 67,
    points: 1791
  },
  {
    name: 'Mark Webber',
    wins: 9,
    podiums: 50,
    points: 1235
  },
  {
    name: 'Daniel Ricciardo',
    wins: 8,
    podiums: 32,
    points: 1311
  },
  {
    name: 'Charles Leclerc',
    wins: 5,
    podiums: 24,
    points: 874
  },
  {
    name: 'Sergio Perez',
    wins: 5,
    podiums: 28,
    points: 1255
  },
];

// Get HTML elements
const difficultySelect = document.getElementById('difficulty-select');
const startGameButton = document.querySelector('button');
const gameContainer = document.getElementById('game-container');
const higherButton = document.getElementById('higher-button');
const lowerButton = document.getElementById('lower-button');
const resultContainer = document.getElementById('result-container');
const playAgainButton = document.getElementById('play-again-button');
const frontImage = document.getElementById('bikar');
const easy = document.getElementById('easy_level');
const normal = document.getElementById('normal_level');
const hard = document.getElementById('hard_level');
const diff = document.getElementById('diff-text');



let currentDriverIndex;
let previousDriverIndex;
let currentDifficulty;
let score;


// Add event listener to the "Start Game" button
startGameButton.addEventListener('click', startGame);

function startGame() {
  startGameButton.style.display = 'none'
  frontImage.style.display = 'none';
  easy.style.display = 'none';
  normal.style.display = 'none';
  hard.style.display = 'none';
  difficultySelect.style.display = 'none'
  diff.style.display = 'none'


  currentDifficulty = difficultySelect.value;

  // Show the type of data to be guessed by the user
  const dataTypeElement = document.getElementById('data-type');
  if (currentDifficulty === 'easy') {
    dataTypeElement.textContent = 'Guess the driver with more wins';
  } else if (currentDifficulty === 'normal') {
    dataTypeElement.textContent = 'Guess the driver with more podiums';
  } else if (currentDifficulty === 'hard') {
    dataTypeElement.textContent = 'Guess the driver with more points';
  }

  higherButton.addEventListener('click', onHigherButtonClicked);
  lowerButton.addEventListener('click', onLowerButtonClicked);

  score = 0;

  // Hide the result container and play again button
  resultContainer.textContent = '';
  playAgainButton.style.display = 'none';

  // Show the first driver
  currentDriverIndex = previousDriverIndex = null;
  showNextDriver();
}


function onHigherButtonClicked() {
  checkAnswer('higher');
}

function onLowerButtonClicked() {
  checkAnswer('lower');
}

let lastDriverIndex;

function showNextDriver() {
  // Clear the previous driver's data
  gameContainer.innerHTML = '';

  // Pick two random drivers from the list
  if (currentDriverIndex === null) {
    currentDriverIndex = getRandomDriverIndex();
  }

  if (previousDriverIndex === null) {
    previousDriverIndex = getRandomDriverIndex(currentDriverIndex);
  }

  // Create and append elements to display the two drivers and their data
  const currentDriverElement = document.createElement('div');
  const previousDriverElement = document.createElement('div');
  const currentDriverDataElement = document.createElement('ul');
  const previousDriverDataElement = document.createElement('ul');
  const vsElement = document.createElement('div');

  currentDriverElement.classList.add('driver');
  previousDriverElement.classList.add('driver');
  vsElement.textContent = "Vs";

  currentDriverElement.innerHTML = `
            <h2>${f1Drivers[currentDriverIndex].name}</h2>
            <img src="driver-images/${f1Drivers[currentDriverIndex].name.toLowerCase().replace(' ', '-')}.png">
          `;
  previousDriverElement.innerHTML = `
            <h2>${f1Drivers[previousDriverIndex].name}</h2>
            <img src="driver-images/${f1Drivers[previousDriverIndex].name.toLowerCase().replace(' ', '-')}.png">
          `;

  currentDriverElement.appendChild(currentDriverDataElement);
  previousDriverElement.appendChild(previousDriverDataElement);
  gameContainer.appendChild(currentDriverElement);
  gameContainer.appendChild(vsElement);
  gameContainer.appendChild(previousDriverElement);

  // Show the "Higher or Lower" buttons
  const buttonContainer = document.getElementById('button-container');
  buttonContainer.style.display = 'block';
}

function getRandomDriverIndex(excludeIndex) {
  let index;
  do {
    index = Math.floor(Math.random() * f1Drivers.length);
  } while (index === excludeIndex);
  return index;
}


function checkAnswer(guess) {;
  const previousDriver = f1Drivers[previousDriverIndex];
  const currentDriver = f1Drivers[currentDriverIndex];
  let previousData, currentData;
  if (currentDifficulty === 'easy') {
    previousData = previousDriver.wins;
    currentData = currentDriver.wins;
  } else if (currentDifficulty === 'normal') {
    previousData = previousDriver.podiums;
    currentData = currentDriver.podiums;
  } else if (currentDifficulty === 'hard') {
    previousData = previousDriver.points;
    currentData = currentDriver.points;
  }

  const answerIsCorrect =
    (guess === 'higher' && currentData <= previousData) ||
    (guess === 'lower' && currentData >= previousData);


  if (answerIsCorrect) {
    score++;
    currentDriverIndex = previousDriverIndex;
    previousDriverIndex = null;
    showNextDriver();
  } else {
    endGame();
  }
}


function endGame() {
  // Remove event listeners from the buttons
  higherButton.removeEventListener('click', onHigherButtonClicked);
  lowerButton.removeEventListener('click', onLowerButtonClicked);

  let message = "";
  if (score <= 1) {
    const messages = [
      "You may need to get a new pit crew - they're clearly not feeding you the right information!",
      "That answer is a bit like a car stuck in the gravel trap - not quite what we were hoping for!",
      "Looks like you need to spend less time watching the races and more time studying the history books!",
      "Looks like you need some more practice laps before you get the hang of this."
    ];
    const randomIndex = Math.floor(Math.random() * messages.length);
    message = `${messages[randomIndex]} ${message}`;
  } else if (score <= 4) {
    const messages = [
      "Let's just say, if you were driving in the F1, you'd be lapped by now.",
      "Very Bad - You might want to stick to bumper cars!",
      "Don't worry, even the best drivers have their off days. Maybe you'll do better next time.",
      "Well, that answer was definitely not pole position material."
    ];
    const randomIndex = Math.floor(Math.random() * messages.length);
    message = `${messages[randomIndex]} ${message}`;
  } else if (score <= 10) {
    const messages = [
      "You're like a midfield driver - solid, but not quite podium material.",
      "You're doing okay, but maybe you should watch a few more races before playing again.",
      "You're not exactly setting the track on fire, but you're not stalling out either.",
      "Not bad, not bad at all! You're definitely on the right track to becoming an F1 expert."
    ];
    const randomIndex = Math.floor(Math.random() * messages.length);
    message = `${messages[randomIndex]} ${message}`;
  } else {
    const messages = [
      "I think we need to do a doping test on you because that score is unreal!",
      "Congratulations! You just set a new lap record for F1 trivia. Absolutely amazing!",
      "Wow, you're like the Lewis Hamilton of F1 trivia! Impressive!",
      "Hold on, let me check if you're not secretly connected to the FIA. Your knowledge is on another level!"
    ];
    const randomIndex = Math.floor(Math.random() * messages.length);
    message = `${messages[randomIndex]} ${message}`;
  }

  // Display the user's score and message
  resultContainer.textContent = `Game over! You got ${score} correct. ${message}`;
  playAgainButton.style.display = 'block';
  playAgainButton.addEventListener('click', startGame);
}
.home {
  color: black;
  /* Change the color to black */
  text-decoration: none;
  /* Remove the underline */
}

body {
  background-color: #adadad;
}

#difficulty-select {
  width: 120px;
  height: 30px;
  border: 1px solid #999;
  font-size: 18px;
  color: #1c87c9;
  background-color: #eee;
  border-radius: 5px;
  box-shadow: 4px 4px #ccc;
}

title {
  text-align: center;
}

.info {
  display: none;
  text-align: center;
  top: 5;
}

.icon:hover~.info {
  display: block;
}

#info-hover {
  width: 4%;
  position: absolute;
  top: 4;
  right: 1;
}


/* Style the header */

header {
  background-color: #fff;
  color: rgb(0, 0, 0);
  padding: 10px;
  display: flex;
  justify-content: space-between;
}


/* Style the game container */

#game-container {
  margin: 20px;
  font-size: 24px;
  text-align: center;
}


/* Style the button container */

#button-container {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}


/* Style the result container */

#result-container {
  font-size: 24px;
  text-align: center;
}

#start-game-button {
  margin: 0;
  position: absolute;
  top: 15%;
  left: 50%;
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}


/* Style the footer */

footer {
  background-color: #333;
  color: white;
  padding: 10px;
  text-align: center;
  position: fixed;
  bottom: 0;
  width: 100%;
}


/* Style the "Higher" and "Lower" buttons */

button {
  font-size: 24px;
  margin: 0 10px;
  padding: 10px 20px;
  border-radius: 5px;
  background-color: #005eff;
  color: white;
  cursor: pointer;
}


/*
        #button-container {
            margin: 0;
            position: absolute;
            top: 70%;
            left: 75%;
            -ms-transform: translate(-50%, -50%);
            transform: translate(-50%, -50%);
        }*/

#play-again-button {
  margin: 0;
  position: absolute;
  top: 90%;
  left: 50%;
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

#resault-container {
  margin: 0;
  position: absolute;
  top: 50%;
  left: 50%;
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}


/* Style the selected difficulty option */

#difficulty option:checked {
  background-color: #4CAF50;
  color: white;
}

.home {
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
}

.title {
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
  font-size: 4em;
}

#easy_level {
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
  font-size: 3em;
}

#normal_level {
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
  font-size: 3em;
}

#hard_level {
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
  font-size: 3em;
}

#data-type {
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
}

#bikar {
  display: block;
  margin-left: auto;
  margin-right: auto;
  width: 40%;
}

#higher-button {
  background-color: #4CAF50;
  margin: 0;
  position: absolute;
  top: 80%;
  left: 75%;
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

#lower-button {
  background-color: #ff0000;
  margin: 0;
  position: absolute;
  top: 87%;
  left: 75%;
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

#game-container {
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
}

header {
  width: 100%;
  padding: 0;
}

.contact {
  display: flex;
  justify-content: center;
  background-color: #262626;
  padding: 10px 0;
  position: fixed;
  bottom: 0;
  width: 100%;
}

#contact {
  color: #fff;
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
}

#privacy {
  color: #fff;
  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
}
<header>
  <h1 class="title">Higher or Lower F1 Game</h1>

  <button id="start-game-button">Start Game</button>
</header>
<label id="diff-text" for="difficulty-select" style="text-align: center;  font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif; font-size: 3em;">Choose difficulty level:</label>
<select id="difficulty-select">
  <option value="easy">Easy</option>
  <option value="normal">Normal</option>
  <option value="hard">Hard</option>
</select>
<div class="icon"><img id="info-hover" src="info.png"></div>
<div class="info" style="font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif; font-size: 3em;">Guess if the driver below has more wins/podiums/points</div>
<h2 id="easy_level" style="text-align:center">Easy: Higher or Lower Wins</h2>
<h2 id="normal_level" style="text-align:center">Normal: Higher or Lower Podiums</h2>
<h2 id="hard_level" style="text-align:center">Hard: Higher or Lower Points</h2>
<img id="bikar" src="bikar.png">
<main>
  <div id="data-type" style="text-align:center; font-size: 3em;"></div>
  <div id="game-container" style="font-size: 4em; display: flex; justify-content: center; align-items: center; ">

    <!-- Display F1 driver data here -->
  </div>
  <div id="button-container" style="display: none;">
    <button id="higher-button">Higher</button>
    <button id="lower-button">Lower</button>
  </div>
  <div id="result-container" style="font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;  position: relative; top: 150px; ">
    <!-- Display game result here -->
  </div>
  <button id="play-again-button" style="display:none">Play Again</button>
</main>
<!--<footer>
          <p>Created by Kristjan Jakob</p>
        </footer>-->

instead of triggering a download, I am getting gibberish text in response

I want to download the zip file without loading it into the browser. However, when I hit the endpoint, instead of triggering a download, I am getting gibberish text in response.

This is my API endpoint.

[HttpGet("downloadfile")]
public async Task<IActionResult> Downloadfile(string userId, CancellationToken ct)
    {
        string docId = $"tinyurl:{userId}";
        DocumentResponse response1 = await blobManager.GetCustomUrlByUserId(docId, ct);
        TinyUrl tinyUrl = JsonConvert.DeserializeObject<TinyUrl>(response1.Content);

      
        var response = await wc.GetAsync(tinyUrl.ActualUrl, HttpCompletionOption.ResponseHeadersRead, ct);

        if (!response.IsSuccessStatusCode)
        {
            return NotFound();
        }
        var contentStream = await response.Content.ReadAsStreamAsync();
        var fileName = "file.zip";
        return new FileStreamResult(contentStream, "application/octet-stream")
        {
            FileDownloadName = fileName
        };
    }

This is my react code


    export const DownloadZip = async (uri) => {
      const method = 'GET';
      const headers = await auth.getTokenHeader(true);
      headers.append('Accept', 'application/octet-stream');
      return retryFetch(uri, { method, headers });
};