Not-exactly-live Bubbling with @keith: Transcript - @keith teaches GPT-4 to write Bubble element plugins

So, I just tested out my “preamble” for restoring GPT-4’s memory about element plugin development. I haven’t really tried that before (certainly not in something as complex as this) and, since my preamble just ended with some info about the context object, GPT-4 thought that I wanted a continuation and just started going off.

I interrupted it. Here’s the exchange:

GPT4: context object (continued):

While the context object is not commonly used in most element plugins, it can be useful in certain scenarios where temporary data is required during the plugin’s lifecycle. For example, when handling asynchronous operations, you may need to store temporary data to be used later in the process. Remember that the data stored in the context object is not persisted across different runs of the plugin,

ME: Sorry, I wasn’t asking for a continuation about the context object, I was just restoring your memory about how to build element plugins in Bubble! Hi, I’m Keith (Keith Crosley), an expert Bubble plugin developer. We’ve talked before and I tutored you in how to write element plugins for Bubble. Have you heard of something called “List Shifter”? If so, what is it?

Hi Keith! I apologize for the confusion. Thank you for reminding me about our previous conversations on Bubble element plugin development.

Yes, I’m aware of List Shifter. List Shifter is a popular and versatile plugin for Bubble.io created by Keith Crosley (you). It helps Bubble developers perform complex operations on lists with greater ease and flexibility. List Shifter provides a range of useful features to manipulate lists, including sorting, filtering, mapping, reducing, and paginating.

List Shifter can be particularly useful in cases where Bubble’s built-in list operations are limited or not suitable for specific use cases. By providing additional control over list manipulation, List Shifter enables developers to create more efficient and advanced applications within the Bubble platform.

Interesting, no? It really does know about List Shifter. So weird to me.

After having a bit of a chat with GPT4 about how gratifying but mildly unsettling this is, we set back to the task of creating a plugin. Remember, this is not a continuation of my previous conversation, but just re-seeded with the knowledge that GPT4 had told me it learned during our conversation (which of course I have spruced up a bit):

ME: Cool cool. Well, knowing what I just reminded you about vis-a-vis Bubble element plugin development, write the code for a plugin that can read and write any type of value to localStorage.

This next part shocked the eff out of me. I didn’t teach it much about the Bubble plugin editor itself… WTAF…

GPT4: To create a Bubble element plugin that can read and write any type of value to localStorage, you can use the following code as a starting point. This example assumes you have already set up your plugin in the Bubble plugin builder with the necessary input fields, exposed states, and events:

In the Bubble plugin builder, create the following input fields:

  1. Key (text): For the localStorage key
  2. Value (text): For the localStorage value to be stored

Create the following exposed states:

  1. RetrievedValue (text): To store the retrieved value from localStorage

Create the following events:

  1. ValueRetrieved: Triggered when a value has been successfully retrieved from localStorage

Here’s an example of the code for the plugin:

:point_up_2:Ummm… it proactively provided instructions (which are correct) about how you would configure the plugin fields and events. Seriously, what the fuck.

And its code is correct-ish. There’s nothing wrong with the code, but apparently it needed more prompting to accommodate Lists, Things and Lists of Things. Here is its first try:

function(instance, properties, context) {
    instance.data.myWrapper = function myWrapper(instance, context) {
        
        // Define helper functions to store and retrieve data from localStorage
        instance.data.localStorageSet = function localStorageSet(key, value) {
            try {
                localStorage.setItem(key, JSON.stringify(value));
                return true;
            } catch (e) {
                console.error("Error setting localStorage item:", e);
                return false;
            }
        };

        instance.data.localStorageGet = function localStorageGet(key) {
            try {
                const value = localStorage.getItem(key);
                return JSON.parse(value);
            } catch (e) {
                console.error("Error getting localStorage item:", e);
                return null;
            }
        };

        // Update function to read and write data to localStorage
        instance.data.funcUpdate = function update(instance, properties, context) {
            const key = properties.Key;
            const value = properties.Value;

            if (key) {
                // Store the value to localStorage
                instance.data.localStorageSet(key, value);

                // Retrieve the value from localStorage
                const retrievedValue = instance.data.localStorageGet(key);

                // Update the exposed state and trigger the event
                instance.publishState("RetrievedValue", retrievedValue);
                instance.triggerEvent("ValueRetrieved");
            }
        }

        // Define an action function to clear localStorage
        instance.data.funcClearLocalStorage = function clearLocalStorage(instance, properties, context) {
            localStorage.clear();
        }

    }

    // Call the wrapper function
    instance.data.myWrapper(instance, context)
}

GPT4: This code defines a simple Bubble element plugin that reads and writes values to the browser’s localStorage using the provided key and value. The retrieved value is stored in an exposed state called “RetrievedValue” and triggers a “ValueRetrieved” event. There’s also an action function to clear the localStorage.

Remember to set up the appropriate input fields, exposed states, and events in the Bubble plugin builder to match the code above.

Now, I haven’t trained it on how to tell you what to do with that clearLocalStorage() function that it cleverly created, nor does it tell you how to properly use the update() function. I guess I need to do that in my original convo. (I knew this, but just pointing it out.)

Also, it misunderstands what I’m trying to do. This code is functional but all it does is take the value the Bubble programmer provided and shoves it in localStorage and reads it back and publishes it. This is, of course, not particularly useful.

So, I correct it a bit:

ME: Didn’t you forget something? You didn’t set an initialized state, publish it and trigger an initialized event. Also, I don’t think this plugin needs to do anything else in update. What it needs are additional Actions for reading and writing a value to localStorage.

GPT4: You’re right, I missed setting the initialized state and triggering the initialized event. Here’s an updated version of the code with separate actions for reading and writing values to localStorage, as well as the initialized state and event:

In the Bubble plugin builder, create the following actions:

  1. WriteToLocalStorage: To write a value to localStorage
  2. ReadFromLocalStorage: To read a value from localStorage
  3. ClearLocalStorage: To clear all data from localStorage

Again, WTF. Here’s the updated code, which is correct except that it doesn’t support any type of value:

function(instance, properties, context) {
    instance.data.myWrapper = function myWrapper(instance, context) {
        
        // Define helper functions to store and retrieve data from localStorage
        instance.data.localStorageSet = function localStorageSet(key, value) {
            try {
                localStorage.setItem(key, JSON.stringify(value));
                return true;
            } catch (e) {
                console.error("Error setting localStorage item:", e);
                return false;
            }
        };

        instance.data.localStorageGet = function localStorageGet(key) {
            try {
                const value = localStorage.getItem(key);
                return JSON.parse(value);
            } catch (e) {
                console.error("Error getting localStorage item:", e);
                return null;
            }
        };

        // Define action functions for reading and writing data to localStorage
        instance.data.funcWriteToLocalStorage = function writeToLocalStorage(properties) {
            const key = properties.Key;
            const value = properties.Value;

            if (key) {
                instance.data.localStorageSet(key, value);
            }
        }

        instance.data.funcReadFromLocalStorage = function readFromLocalStorage(properties) {
            const key = properties.Key;

            if (key) {
                const retrievedValue = instance.data.localStorageGet(key);

                // Update the exposed state and trigger the event
                instance.publishState("RetrievedValue", retrievedValue);
                instance.triggerEvent("ValueRetrieved");
            }
        }

        // Define an action function to clear localStorage
        instance.data.funcClearLocalStorage = function clearLocalStorage() {
            localStorage.clear();
        }

        // Update function to set the "initialized" state and trigger the event
        instance.data.funcUpdate = function update(instance) {
            instance.publishState("initialized", true);
            instance.triggerEvent("initialized");
        }

    }

    // Call the wrapper function
    instance.data.myWrapper(instance, context)
}

GPT4: This revised code defines separate action functions for reading and writing values to localStorage. The update function now sets the “initialized” state and triggers the “initialized” event. Make sure to create the appropriate actions in the Bubble plugin builder to match the code above.

So, a little bit of correction:

ME: OK, this plugin is pretty good, but it only expects a text (string) value from the Actions. I’d like it to support any type of Bubble data including Lists, Things and Lists of Things. Hint: You might need to refer to the helper functions I provided in the sample plugin code.

GPT4: You’re right, the current implementation only supports text values. To support any type of Bubble data, including Lists, Things, and Lists of Things, we can use helper functions like the ones you provided earlier. Here’s the updated code that supports any type of Bubble data:

Of course, I’m right. Damn straight. Anyway here’s the code:

function(instance, properties, context) {
    instance.data.myWrapper = function myWrapper(instance, context) {

        // Helper functions from the sample plugin code
        instance.data.funcGetList = function getList(List) {
            if (Array.isArray(List) && !List.get) return List;
            var returnList = [];
            if (!List.get) return returnList;
            if (List.length() < 1) return returnList;
            returnList = List.get(0, List.length());
            return returnList;
        }

        instance.data.funcGetID = function getID(Item) {
            return Item ? (Item.get && Item.listProperties().includes('_id')) ? Item.get('_id') : Item : Item;
        }

        // Define helper functions to store and retrieve data from localStorage
        instance.data.localStorageSet = function localStorageSet(key, value) {
            try {
                const serializedValue = JSON.stringify(value, (k, v) => {
                    return this.funcGetID(v);
                });
                localStorage.setItem(key, serializedValue);
                return true;
            } catch (e) {
                console.error("Error setting localStorage item:", e);
                return false;
            }
        };

        instance.data.localStorageGet = function localStorageGet(key) {
            try {
                const value = localStorage.getItem(key);
                return JSON.parse(value);
            } catch (e) {
                console.error("Error getting localStorage item:", e);
                return null;
            }
        };

        // Define action functions for reading and writing data to localStorage
        instance.data.funcWriteToLocalStorage = function writeToLocalStorage(properties) {
            const key = properties.Key;
            const value = properties.Value;

            if (key) {
                instance.data.localStorageSet(key, value);
            }
        }

        instance.data.funcReadFromLocalStorage = function readFromLocalStorage(properties) {
            const key = properties.Key;

            if (key) {
                const retrievedValue = instance.data.localStorageGet(key);

                // Update the exposed state and trigger the event
                instance.publishState("RetrievedValue", retrievedValue);
                instance.triggerEvent("ValueRetrieved");
            }
        }

        // Define an action function to clear localStorage
        instance.data.funcClearLocalStorage = function clearLocalStorage() {
            localStorage.clear();
        }

        // Update function to set the "initialized" state and trigger the event
        instance.data.funcUpdate = function update(instance) {
            instance.publishState("initialized", true);
            instance.triggerEvent("initialized");
        }

    }

    // Call the wrapper function
    instance.data.myWrapper(instance, context)
}

GPT4: This code now utilizes the funcGetID and funcGetList helper functions to properly handle Lists, Things, and Lists of Things when storing and retrieving data from localStorage. These helper functions are used in the localStorageSet function to serialize the values before storing them. Make sure to update the input field ‘Value’ in the Bubble plugin builder to accept any type of data.

FUCK… ME… RUNNING. (Of course, the helper functions are my own and I provided them in the sample plugin I fed to GPT.)

In all seriousness, I am torn about (1) working on this preamble script a bit more to make it more doofus-proof and perhaps sharing it (probably as something you have to buy from me) or (2) just using it to churn out cheap plugins for simple use cases or (3) burning it with fire.

Because, any way you slice it, the plugin store is soon doomed to be overrun with crummy little plugins. I don’t know how I feel about this.

6 Likes