Writing Chrome NTP alternative. Can save and read data in chrome.local.storage, but can’t see it in DevTools

I’m writing an alternative for Chrome’s New Tab Page. Data stored in chrome.storage.local is correctly saved and loaded, as confirmed by logging, but it does not appear in the DevTools > Application > chrome.storage.local tab.

The extension’s permissions include “storage”, and data is being stored under individual keys (name, url).

document.addEventListener('DOMContentLoaded', () => {
    // Save data
    document.querySelector('.button-done').addEventListener('click', () => {
        const name = document.getElementById('name-field').value;
        const url = document.getElementById('web-address').value;

        chrome.storage.local.set({ name, url }, () => {
            console.log('Data saved:', { name, url });
        });
    });

    // Load data
    chrome.storage.local.get(["name", "url"], (data) => {
        if (data.name && data.url) {
            document.getElementById('name-field').value = data.name;
            document.getElementById('web-address').value = data.url;
            console.log('Data loaded:', data);
        }
    });
});

Despite successful retrieval and display in the UI, the stored data remains invisible in DevTools. I’ve tried clearing storage, reloading DevTools, and verifying extension context, but the problem persists. This happens both while running the code in Live Preview in VS Code (1.93.1) and when running the extension unpacked in Chrome’s developer mode (128.0.6613.139). Any insights?

handling css colors with combination of codes

I have the following function setCSSColors which assigns background colors to the text displayed in a table like this:

enter image description here

 function setCSSColors(cellsInnerText, row, cellsIndex) {
      let x = cellsInnerText;
      if (x.includes("PET")) {
        row.cells[cellsIndex].className = "petClass";
      } else if (x.includes("VIC")) {
        row.cells[cellsIndex].className = "vicClass";
      } else if (x.includes("NED")) {
        row.cells[cellsIndex].className = "nedClass";
      } else if (x.includes("FAM")) {
        row.cells[cellsIndex].className = "famClass";
      } else if (x.includes("HEX")) {
        row.cells[cellsIndex].className = "hexClass";
      } else if (x.includes("TAMRA")) {
        row.cells[cellsIndex].className = "tamraClass";
      } else if (x.includes("Cy5")) {
        row.cells[cellsIndex].className = "cyfiveClass";
      }

  else if (x.includes("FAM/ZEN/IBFQ")) {
    row.cells[cellsIndex].className = "famComboClass";
  }

The above function is getting called from another function like this:

function colorTableCells(tableObject, pageName) {
  if (pageName === "pageOne") {
    var tables = tableObject;
    for (var j = 0; j < tables.length; j++) {
      var table = tables[j];
      for (var i = 0; i < table.rows.length; i++) {
        if (i != 0) {
          var row = table.rows[i];
          if (row.cells.length > 1) {
            var x = row.cells[1].innerText;
           setCSSColors(x, row, 1);
          }
        }
      }
    }
  } else if (pageName === "pageTwo" || pageName === "pageThree") {
    var table = tableObject;
    for (var i = 0; i < table.rows.length; i++) {
      if (i != 0) {
        var row = table.rows[i];
        if (row.cells.length > 1) {
          let x = row.cells[2].innerText;
          setCSSColors(x, row, 2);
        }
      }
    }
  }
}

Reasoning behind two if statements above:

For pageOne, I am getting the tableObject like this in my pageOne code which used getElementsByName:

var tables = document.getElementsByName("myTableInPageOne");
let pageName = "pageOne";
colorTableCells(tables,pageName)

whereas, in case of other two pages pageTwo and pageThree

I have it like this (using getElementsById) :

var tables = document.getElementsById("myTableInPageTwo");
let pageName = "pageTwo";
colorTableCells(tables,pageName)

Similarly for pageThree.

And here are my CSS colors defined:

famClass {
  background: lightblue;
}
.famComboClass {
    background: #034694;
  }

.petClass {
  background: red;
}

.nedClass {
  background: yellow;
}

.vicClass {
  background: lightgreen;
}

.hexClass {
  background: #40ff00;
}

.tamraClass {
  background: orange;
}

.cyfiveClass {
  background: pink;
}

I’m trying to apply a different color to this combo FAM/ZEN/IBFQ using famComboClass CSS but it’s still adding famClass with light blue color.
Any idea how I can apply a specific color to the above combo? famClass seems to be taking precedence over famClassCombo.

Runtime Error with react-data-table-component in React Application

I encountered a runtime error while trying to integrate react-data-table-component into my React application. The error seems to occur when I attempt to render the data table after fetching data from my API.

Here’s the code I’m using:

import React, { useEffect, useState } from "react";
import DataTable from "react-data-table-component";
import axios from "axios";

const InvitationsDataTable = () => {
  const [tableData, setTableData] = useState([]);

  const columns = [
    { name: "Nomor Undangan", selector: "nomor_undangan", sortable: true },
    { name: "Tanggal", selector: "tanggal", sortable: true },
    { name: "Waktu", selector: "waktu", sortable: true },
    { name: "Tempat", selector: "tempat", sortable: true },
    { name: "Agenda", selector: "agenda", sortable: true },
    { name: "Pemimpin", selector: "leader_name", sortable: true },
    { name: "Peserta", selector: "participants", sortable: true },
    { name: "Dokumen", selector: "documents", sortable: true },
  ];

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get("http://localhost:5000/api/invitations");
        const invitations = response.data.map((invitation) => ({
          ...invitation,
          tanggal: new Date(invitation.tanggal).toLocaleDateString(),
          waktu: `${invitation.waktu_mulai} - ${invitation.waktu_selesai}`,
          participants: JSON.parse(invitation.participants)
            .map((p) => p.name)
            .join(", "),
          documents: JSON.parse(invitation.documents)
            .map((d) => d.file_path)
            .join(", "),
        }));
        setTableData(invitations);
      } catch (error) {
        console.error("Error fetching invitations:", error);
      }
    };

    fetchData();
  }, []);

  return (
    <DataTable
      title="Daftar Undangan"
      columns={columns}
      data={tableData}
      pagination
      keyField="invitation_id"
    />
  );
};

export default InvitationsDataTable;

And this is the error I’m encountering:

Uncaught runtime errors:
ERROR
t is not a function
TypeError: t is not a function
    at http://localhost:3000/static/js/bundle.js:68245:56
    ...

Context:

The error appears when I reload the page, and although it sometimes resolves after a second reload, the issue keeps recurring. My goal is to ensure that the data from the API can be accessed and displayed correctly in the data table.

Any suggestions on how to resolve this issue?

spawnSync returns empty string but command runs well in shell directly?

I am finding a way to run shell command in javascript in a synchronous-like way.
The best I currently found is spawnSync but it returns unexpected empty string while the command is correct in shell.

const foo = spawnSync('git', [
  'log',
  '--diff-filter=A',
  '--format="%cI"',
  '--',
  `path/to/a/file/in/repo`,
])
  .stdout.toString() // -> ''

the command runs well in shell however

$ git log --diff-filter=A --format="%cI" -- "path/to/a/file/in/repo"
2023-12-07T22:11:50+08:00

AWS Amplify: EmptyChallengeResponse Error when confirming sign-in with new password

I’m encountering the following error when trying to confirm a sign-in with a new password in aws-amplify V6:

Error:

EmptyChallengeResponse: challengeResponse is required to confirmSignIn

Here’s the relevant code snippet:

const handleSubmit = async (e) => {
    e.preventDefault();
  
    try {
      if (!requireNewPassword) {
        console.log("[] username", username);
        console.log("[] password", password);
        const signInResponse = await signIn({
          username,
          password,
          options: {
            authFlowType: "ALLOW_USER_PASSWORD_AUTH"
          }
        });
        console.log("[] signInResponse", signInResponse);
  
        if (signInResponse.nextStep.signInStep === "CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED") {
          console.log("CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED");
  
          const newPassword = prompt("Please enter your new password:");
          if (newPassword) {
            const challengeResponse = signInResponse;
            if (challengeResponse) {
              const confirmSignInResponse = await confirmSignIn(
                challengeResponse,
                newPassword,
                "ALLOW_USER_PASSWORD_AUTH"
              );
              console.log("[] user after password change", confirmSignInResponse);
              navigate("/dashboard");
            } else {
              console.error("Challenge response not found.");
            }
          }
  
          setUser(signInResponse);
          setRequireNewPassword(true);
        } else {
          navigate("/dashboard");
        }
      } else {
        const confirmSignInResponse = await confirmSignIn(
          user,
          newPassword,
          "NEW_PASSWORD_REQUIRED"
        );
        console.log("[] user after password change", confirmSignInResponse);
        navigate("/dashboard");
      }
    } catch (error) {
      setError("Invalid username or password");
      console.error("Error:", error);
    }
  };

I am not really sure where the chalange response should be or what is it

How to disable auto-recognition of .js files as TypeScript compilation output in IntelliJ IDEA

I’m using the latest version of IntelliJ IDEA and working on a project that uses both JavaScript and TypeScript. I’m facing an issue where IntelliJ automatically recognizes .js files as compiled output of .ts files when they have the same name.

What is the current method to disable the automatic recognition of .js files as TypeScript compilation output in the latest version of IntelliJ IDEA?

Example:
Let’s say I have the following files in my project:
src/
├── example.ts
└── example.js

When I open example.js, I see a message at the top of the file saying “Excluded from compilation”. This indicates that IntelliJ IDEA is treating this .js file as a compilation output of the .ts file, which is not what I want.

What I want to achieve:
I want IntelliJ IDEA to treat both .ts and .js files as separate, editable source files, without automatically assuming the .js file is a compiled output.

Dispatch Redux action in loader will be cleared by useEffect cleanup function in strict mode

I just migrated from v3 to v6 and started using data loader to fetch data, but ran into a problem because of the React.StrictMode.
This is the simplify route:

// I created my router outside of the component.
const router = createBrowserRouter(
  createRoutesFromElements(
  <Route
    path="/"
    element={<App />}
    // only run loader once before it renders
    shouldRevalidate={() => false}
    loader={({ request, params }: LoaderFunctionArgs) => {
      // ...
      // dispatch action to fetch data
      reduxStore.dispatch(getData(params));
      // ...
    }}
   /> ),
);

function App() {
  const dispatch = useAppDispatch();
  
  // dispatch action to clear data when unmounting
  useEffect(() => () => dispatch(clearData()), []);

  return // UI
}

Above code will work in production environment, but in StrictMode everything I did will be cleared by the clearData().
Any ideas on how to fix it? thanks!

I expected loader run twice in strict mode, but it will only run once.

My textInput keeps refreshing when I type into it

I have a TextInput in my React native project. I use an onCHangeText={(text)=>handleChange(‘postText’, text)} function to update the formData that I had set as a State Object at the beginning of the function. The result I get is whenever I type, the app restarts and refreshes, deleting former content and only writing the latest character to the text field. Worse, it hides the keypad altogether.

Here is my code:

const HomePageBuilder = ({navigation}) =>{
    const [postingMedia, setPostingMedia] = useState(null);
    const [selectedValue, setSelectedValue] = useState(null);
    const [images, setImages] = useState([]);
    const screenWidth = Dimensions.get('window').width;
    const {userId, login, logout, user} = useContext(AppContext);
    const [postData, setPostData] = useState({postMedia : '',
        postText : '', postType : 'General'
    });



    const handleChange = (fieldName, value)=>{
        setFormData(prevState =>({
            ...prevState,
            [fieldName]:value
        }));
    }



    return(<>
        <Header />
        <SafeAreaView style = {HomeStyles.container}>

            <View style = {HomeStyles.bodyMain}>


                        <>
                        <FlatList
                        data = {posts} 
                        renderItem={postBuilder}
                        keyExtractor={(item, index) => index.toString()}

                        style ={{marginBottom: 20, paddingBottom: 20}}

                        ListHeaderComponent={()=>(
                            <View  style = {HomeStyles.postMakerDiv}>
                            <View>
                                <TextInput placeholder="Share some news" style = {HomeStyles.postBoxMain} 
                                ref = {postInputRef}
                                // onChangeText={(text) => handleChange('postText', text)}
                                 value = {postData.postText}
                                onEndEditing={(text) => setPostText(text)}
                                />
                            </View>
                            <View style = {HomeStyles.imageBox}>
        
                            {images.length > 0 && (
                                <>
                                    <Pressable style = {{zIndex: 1}} onPress = {()=>{
                                            setImages([]);
                                        }}>
                                        <Image source = {require("../../views/resources/close-circle.png")}  style = {{width: 25, height: 25, left: '96%', top: 15, zIndex: 1}}/>
        
                                        </Pressable>
                                
                                <ScrollView horizontal style={{ marginTop: 20, height: 320}} contentContainerStyle = {HomeStyles.picturesPreview}>
                                {images.map((imageUri, index) => (
                                    <View key={index} style={{ margin: 5 }}>
                                    <Image
                                        source={{ uri: imageUri }}
                                        style={{ minWidth: screenWidth * 0.9, maxWidth: screenWidth * 0.9, height: 300, borderRadius: 10 }}
                                    />
                                    </View>
                                ))}
                                </ScrollView>
                                </>
                            )}
        
                            </View>
                            <View style = {HomeStyles.imageBox}>
                                {
                                    videoUri ?(
                                        <>
                                        
                                        <Pressable onPress = {()=>{
                                            setVideoUri(null);
                                        }} style = {{width: 30, height: 30, flexDirection: 'row', alignSelf: 'flex-end'}}>
                                            <Image source = {require("../../views/resources/close-circle.png")} style = {{width: 25, height: 25, zIndex: 1, top: 10}}/>
                                        </Pressable>
                                        <TouchableOpacity onPress = {togglePlayback}>
                                            <Video 
                                            source = {{uri: videoUri}}
                                            resizeMode = "cover"
                                            style = {{width: '100%', height: 400, borderWidth: 1, borderRadius: 30}}
                                            ref = {videoRef}
                                            shouldPlay = {isPlaying}
                                            isLooping
                                            />
                                        </TouchableOpacity>
                                        </>
                                    ):(
                                        <>
        
                                        </>
                                    )
                                }
                            </View>
                            <View style = {HomeStyles.postOptions}> 
        
                            <Picker
                                selectedValue={postData.postType}
                                style={{ height: 50, minWidth: 130, borderWidth: 1, borderColor: 'grey' }}
                                onValueChange={(text) => handleChange('postType', text)}
                               
                            >
                                <Picker.Item label="General" value="General" />
                                <Picker.Item label="Business" value="Business" />
                                <Picker.Item label="Politics" value="Politics" />
                                <Picker.Item label="Lifestyle" value="Lifestyle" />
                                <Picker.Item label="Relationship" value="Relationship" />
                                <Picker.Item label="Music" value="Music" />
                                <Picker.Item label="Art" value="Art" />
                                <Picker.Item label="Entertainment" value="Entertainment" />
                            </Picker>
        
        
                                <TouchableOpacity onPress={pickImages}>
                                    {/* Modify this to call the multiple images function later.*/}
                                <Icon name="camera-alt" size={25} color="purple" style = {{top: 10}}/>
                                </TouchableOpacity>
        
        
                                <TouchableOpacity  onPress = {chooseVideo}>
                                <Icon name="videocam" size={25} color="purple" style = {{top: 10}}/>
                                </TouchableOpacity>
        
                                <TouchableOpacity style = {HomeStyles.postBtnMain} onPress = {makePost}>
                                    <Text style = {{color: 'white', fontWeight: 'bold', fontSize: 15}}>
                                        Share
                                    </Text>
                                    {/* <Icon name="campaign" size={25} color="white" style = {{top: -2}}/> */}
        
                                </TouchableOpacity>
                            </View>
                        </View>
                        )}

                        ListEmptyComponent={()=>(
                            <View style = {{justifySelf : 'center', alignSelf : 'center', justifyContent : 'center', alignContent: 'center', width: 300, marginTop: 50}}>

                            <Text  style = {{fontSize: 20, color: 'grey', textAlign: 'center'}}>
                                Seems you are having some internet issues.
                            </Text>
                            <TouchableOpacity onPress = {()=> navigation.navigate("Home")} style = {{backgroundColor: 'purple', justifyContent : 'center', alignContent: 'center',  padding: 10, borderRadius: 10, marginTop: 30}}>
                            <Text style = {{textAlign: 'center', color: 'white'}}>
                                Try again?
                            </Text>
                            </TouchableOpacity>
    
    
                            </View>
                        )}
                        />
                        </>
                    
                

    

              
            </View>
        </SafeAreaView>
    </>
    );


The element causing this is styled with styles.postBoxMain

I have tried Isolating this TextINput by giving it it’s own state separate from the postData object. I have tried using useRef.current.value. I have tried using lodash’s debounce, none of these techniques seem to be working.

I just need the textinput field to act normally and be stored in the postData.postText object. This is not working out. I have even tried onEndEditing. Everything I have done just reflects the same error.

Despite loading core-js & regenerator-runtime I still can’t get async/await to work for my JavaScript with WebPack

An async/await call doesn’t work. I loaded core-js and regenerator-runtime to fix that but it still isn’t working. I’m guessing it’s a matter of the proper components. That’s why I posted my package.json and webpack.config.js files below.

const getPuzzle = async (wordCount) => {
    const response = await fetch(`//puzzle.mead.io/puzzle?wordCount=${wordCount}`, {
        mode: 'no-cors'
    })
    if (response.status === 200) {
        const data = await response.json()
        return data.puzzle
    } else {
        throw new Error('Unable to get puzzle')
    }
}

the error

Uncaught runtime errors:
ERROR
Unable to get puzzle
    at _callee$ (http://localhost:8080/scripts/bundle.js:392:17)
    at tryCatch (http://localhost:8080/scripts/bundle.js:367:1062)
    at Generator.<anonymous> (http://localhost:8080/scripts/bundle.js:367:3008)
    at Generator.next (http://localhost:8080/scripts/bundle.js:367:1699)
    at asyncGeneratorStep (http://localhost:8080/scripts/bundle.js:368:70)
    at _next (http://localhost:8080/scripts/bundle.js:369:163)

package.json:

{
  "name": "boilerplate2",
  "version": "1.0.0",
  "description": "",
  "main": "input.js",
  "scripts": {
    "dev-server": "webpack serve --open --mode development",
    "build": "webpack --mode production",
    "start": "webpack serve --open --mode development"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/cli": "^7.25.6",
    "@babel/preset-env": "^7.25.4",
    "babel-loader": "^9.2.1",
    "core-js": "^3.38.1",
    "live-server": "^1.2.0",
    "regenerator-runtime": "^0.14.1",
    "webpack": "^5.94.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^5.1.0"
  }
}

webpack.config.js:

const path = require('path')

module.exports = {
    entry: ['core-js/stable', 'regenerator-runtime/runtime', './src/index.js'],
    output: {
        path: path.resolve(__dirname, 'public/scripts'),
        filename: 'bundle.js'
    },
    module: {
        rules: [{
            test: /.js$/,
            exclude: /node_modules/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env']
                }
            }
        }]
    },
    devServer: {
        static: {
            directory: path.resolve(__dirname, 'public')
        },
        port: 8080,
        devMiddleware: {
            publicPath: "//localhost:8080/scripts/"
        }
    },
    devtool: 'source-map'
}

Any help is appreciated!

Will stylesheet.onload still fire if the eventlistener was attached after it finished loading?

I am making a component where I only wish to define the component after its CSS file has finished loading. This way I can use wl-button:not(:defined) { animation: loading 1s alternating } in a smaller render blocking stylesheet and it will look clean until the components deferred full CSS and Script files are finished.

However, I am a little paranoid about an edge case where the customElements.define() does not get called due to the timing of when the stylesheet loads. Initially my code was just:

const stylesheet = document.getElementById("stylesheet__wl_button");
stylesheet.addEventListener("load", () => {
    customElements.define('wl-button', WL_Button); // where WL_Button is a class
});

I suppose this is what a sane person would do, but I am not sane, so I figured.. what if the stylesheet has already loaded before the onload event listener is attached? Will it still trigger?

Furthermore, as I expanded the code to check if the stylesheet had already loaded before attaching the event listener, I figured.. what if the stylesheet loads in the awkward tiny gap between the stylesheet.sheet check and the addEventListner() call is finished? This made me write all this logic and I can’t help but wonder if I am completely off my meds right now.

Is there a better way to do this?

const stylesheet = document.getElementById("stylesheet__wl_button");
const def = () => customElements.define('wl-button', WL_Button);

if (!stylesheet) {
    console.warn("Stylesheet missing for '<wl-button>'.");
    def();
}
else if (stylesheet.sheet) {
    // if the style sheet has already loaded, define the component
    def();
}
else {
    // if the style sheet has not loaded, listen to the onload event
    stylesheet.addEventListener("load", def);

    // check if the sheet loaded before the eventlistener was attached
    if (stylesheet.sheet) {
        stylesheet.removeEventListener("load", def);
        
        // check if the sheet actually loaded after the eventlister was attached but before the second stylesheet.sheet call was made to prevent defining twice
        if (!customElements.get("wl-button")) {
            def();
        }
    }
}

Allow dynamic method calls in JS, but no dynamic property access

I’d like to allow dynamic method calls on a JavaScript object, i.e. even if the object does not have the method defined, it should still be invokable (e.g. with a default dummy).

const obj = {a: 5};
obj.dynamicMethodCallWithAnyNameYouWant(); // should work
obj.a; // should work, value is 5
obj.b; // should yield undefined

Now with a JS Proxy, we can do something like this to get in the right direction:

const obj = new Proxy({a: 5}, {
  get(target, prop, receiver) {
    // If the property does not exist, define it as a new function
    if (!(prop in target)) {
      target[prop] = function() {
        console.log(`Method ${prop} has been dynamically created and invoked!`);
      };
    }
    return Reflect.get(target, prop, receiver);
  }
});

obj.dynamicMethodCallWithAnyNameYouWant();
console.log(obj.a); // prints 5
const res = obj.thisShouldYieldUndefinedInsteadOfCreatingAFunction
res(); // this prints "Method thisShouldYieldUndefined ..."

The problem is that we cannot detect whether the property was accessed or called since

[…] JavaScript does not distinguish between attributes and methods. It’s all just properties that are accessed, and their value can be called if it’s a function. ~ this answer

Is there another way to achieve the desired behavior, e.g. with an alternative approach to proxies?