No internet connection
  1. Home
  2. Script Sharing

Interaction Select From List - Dialog Focus

By Nicolas Aparicio @Nicolas_Aparicio
    2024-10-28 06:30:38.471Z

    bold textHi all,

    I've found a way to Focus the Select From List Interaction Dialog, it works quite well for me so I hope it'll be the same for other users.

    Here are the steps to set it up and use it on your system:

    1 - Create a New "Run AppleScript" Quick Action in Apple's Automator
    2 - Add this code in it:

    tell application "System Events"
    tell application process "osascript"
    set frontmost to true
    end tell
    end tell

    3 - Save it with a name to recall later, say "Dialog Focus" in this case
    4 - Go to System Preferences/Keyboard/Keyboard Shortcuts/Services/General and find "Dialog Focus"
    5 - Double click on the right where it says "none" and add a shortcut that won't create issues with your DAW say for me:
    "ctrl+cmd+alt+shift+f19"
    6 - Add this code to your codes with Select From List Dialogs:

    function dialogFocus() {
        sf.keyboard.press({ keys: "ctrl+cmd+alt+shift+f19" });
    };
    

    and call it before the List codes, say:

    dialogFocus();
    const selectFromList = sf.interaction.selectFromList({
        title: `TITLE`,
        prompt: ``,
        items: ['item 1', 'item 2', 'item 3'],
        allowEmptySelection: false,
        allowMultipleSelections: true,
    }).list
    

    7 - Run it and give it permissions to the necessary apps and you'll be good to go

    Enjoy!!

    • 34 replies

    There are 34 replies. Estimated reading time: 69 minutes

    1. Kitch Membery @Kitch2024-10-29 00:23:50.941Z

      Hi @Nicolas_Aparicio,

      Ah yes, the current implementation under SoundFlow's hood does not focus the dialog window yet. I'll log a report internally but for now, rather than using this workaround try using this script I mocked up.

      function selectFromList(settings) {
          // Get focused app
          const focusedApp = sf.ui.frontmostApp;
      
          const { title,
              prompt,
              items,
              defaultItems,
              allowEmptySelection,
              allowMultipleSelections,
              cancelButton,
              oKButton
          } = settings;
      
          const script = `set options to {"${items.join('", "')}"}
      
          tell application "System Events"
              activate
              set selectedItems to choose from list options ¬
                  with title "${title}" ¬
                  with prompt "${prompt}" ¬
                  OK button name "${oKButton}" ¬
                  default items {"${defaultItems.join('", "')}"} ¬
                  cancel button name "${cancelButton}" ¬
                  empty selection allowed ${JSON.stringify(allowEmptySelection)} ¬
                  multiple selections allowed ${JSON.stringify(allowMultipleSelections)}
          end tell`;
      
          const result = sf.system.execAppleScript({ script }).result;
      
          // Refocus previous app.
          focusedApp.appActivate();
      
          return result;
      }
      
      const selectedItems = selectFromList({
          title: `Title`,
          prompt: `Please select items.`,
          items: ['item 1', 'item 2', 'item 3', 'item 4'],
          defaultItems: ['item 2', 'item 4'],
          allowEmptySelection: true,
          allowMultipleSelections: true,
          cancelButton: "Cancel",
          oKButton: "OK",
      });
      
      log(selectedItems);
      

      It's by no means a perfect solution, but it works without having to leave SoundFlow. It will also refocus the previous app after the selection is made.

      1. NNicolas Aparicio @Nicolas_Aparicio
          2024-10-29 01:47:11.262Z

          OMG @Kitch, you are amazing!
          I'll try this later tonight and let you know how I go. And absolutely, much better to keep it all inside SoundFlow, thanks legend

          1. In reply toKitch:
            NNicolas Aparicio @Nicolas_Aparicio
              2024-11-12 10:44:04.322Z

              Hi @Kitch,

              I've found a way to focus the Interactions (selectFromList, selectFolder, selectFile, etc.) from inside SoundFlow, or well, close enough at least.
              Thanks to the legend @Chad, I've come up with this:

              function interactionFocus() {
                  setTimeout(() => {
                      sf.system.execAppleScript({
                          script: `
                              repeat
              	                tell application "System Events"
              		                tell application process "osascript"
              			               set frontmost to true
              		                end tell
              	                end tell
              	                delay 0.3
                              end repeat
                      `,
                      });
                  }, 200)
              }
              
              interactionFocus();
              sf.interaction.selectFromList({
                  title: `TEST`,
                  prompt: ``,
                  items: ['item 1', 'item 2', 'item 3'],
                  allowEmptySelection: false,
                  allowMultipleSelections: true,
              }).list
              
              

              The 200ms wait from the Timeout is for the selectFromList as it basically comes up in focus with it, and the delay 0.3, is for everything else as the Timeout won't catch them.

              I'm sure it can be done much better but this one works for me everytime!.

              Cheers,
              Nic.

              1. NNicolas Aparicio @Nicolas_Aparicio
                  2024-11-12 10:52:28.119Z

                  Though I find that this code does it for everything regardless and I've noticed the repeat from the one above, can cause issues after the interaction has been closed.

                  function interactionFocus() {
                      setTimeout(() => {
                          sf.system.execAppleScript({
                              script: `
                  	            tell application "System Events"
                  		            tell application process "osascript"
                  			            set frontmost to true
                  		            end tell
                  	            end tell
                          `,
                          });
                      }, 500)
                  };
                  

                  🤙

                  1. Chad Wahlbrink @Chad2024-11-12 19:05:21.790Z

                    Excellent use of setTimeout(), @Nicolas_Aparicio!! 👏👏

                    1. NNicolas Aparicio @Nicolas_Aparicio
                        2024-11-12 20:36:40.323Z

                        Thank you sir!

                        1. Chad Wahlbrink @Chad2024-11-13 18:13:08.402Z

                          @Nicolas_Aparicio,

                          Hard-coding the dialogs using Kitch's approach is still probably more robust than relying on setTimeOut() overall. However, I needed a version of this for a script of mine today, so I did some tweaking to make sure the repeat doesn't go off the rails and it always waits for the window to exist.

                          This will only repeat until a window exists for the interaction. Then I'm using a try/catch/finally to clean up stray apple script processes if the script exits or is cancelled. You could put your whole script in the try block of the try/catch/finally if it made more sense that way!

                          function interactionFocus() {
                              setTimeout(() => {
                                  sf.system.execAppleScript({
                                      script: `
                          	            tell application "System Events"
                                              repeat until (exists window of application process "osascript")
                                                  delay 0.2
                                              end repeat
                          
                                              tell application process "osascript"
                                                  set frontmost to true
                                              end tell
                                          end tell
                                  `,
                                  implementation: "OSAScript", 
                                  });
                              }, 200)
                          };
                          
                          ////////////////////////////////////////////////////
                          
                          try {
                              interactionFocus();
                          
                              // PUT YOUR INTERACTION HERE
                              sf.interaction.selectApplication();
                          
                          } catch (err) {
                              throw err;
                          } finally {
                              // KILL STRAY PROCESSES
                              sf.system.exec({ commandLine: `pkill -9 osascript` })
                          }
                          1. NNicolas Aparicio @Nicolas_Aparicio
                              2024-11-13 20:31:10.297Z

                              Hi @Chad.

                              Absolutely, Kitch's code does a much cleaner, tighter job. I'll eventually set those codes in my scripts when I have extra time to fix them all but yeah, for now I needed a quick/temporary fix as this code would work for all interactions, which are tons 😅

                              Ah right, try catch of course!, and the applescript is much better. I was trying this one but kept getting errors after the interaction window would close:

                                          tell application "System Events"
                                              tell application process "osascript"
                                                  set frontmost to true
                                                      repeat until (exists window of application process "osascript")
                                                         delay 0.2
                                                      end repeat
                                              end tell
                                          end tell
                              

                              Thanks a lot Chad!

                        2. This is very useful - thanks for posting!

                          1. Kitch Membery @Kitch2024-11-12 19:41:34.128Z

                            Thanks for sharing Nick.

                            Did my selectFromList script in the thread above work?

                            As cool as the setTimeout function is, (nice work on that) it would be more robust to create a script similar to the selectFromList function for the other interactions, to avoid timing issues.

                            If the script I shared works for you, let me know, and when I have a chance, I'll make a version that works for the others.

                            Rock on!

                            1. NNicolas Aparicio @Nicolas_Aparicio
                                2024-11-12 20:36:27.083Z

                                Hi @Kitch, ah sorry, I forgot to reply to that.
                                Yeah, that work awesome, quicker and cleaner though I noticed that the code will fail if the "defaultItems" are missing, as it fails to see line 23 "join". Also, it could be nice to default the "ok" and "cancel" buttons to these values if not specified?.
                                I'm just using the timeout atm as it was easier for me to add that line before all my interactions rather that changing them one by one but will use yours eventually. 🤘

                                Thanks legend,
                                Nic.

                                1. Kitch Membery @Kitch2024-11-12 20:54:49.581Z

                                  Solid approach for now... And great feedback on my selectFromList function (Noted!).

                                  It will be great to get these interactions fixed internally at some point, but we'll need to do a bunch of testing once we've got a robust solution. As you can imagine these are used in so many scripts. :-)

                                  Rock on!

                                  1. NNicolas Aparicio @Nicolas_Aparicio
                                      2024-11-12 21:38:28.875Z

                                      Thanks @Kitch, you legend.
                                      And absolutely, if the interactions could have a fix like yours internally, it'll be a game changer!.
                                      I'll keep testing yours on different situations and with different inputs to check it's behavior 🤙.

                                      1. Kitch Membery @Kitch2024-11-12 22:11:50.616Z

                                        Here is an updated version where all the properties can be left undefined. (Adding here for reference)

                                        function selectFromList(settings) {
                                            // Get focused app
                                            const focusedApp = sf.ui.frontmostApp;
                                        
                                            const { title,
                                                prompt,
                                                items,
                                                defaultItems,
                                                allowEmptySelection,
                                                allowMultipleSelections,
                                                cancelButton,
                                                oKButton
                                            } = settings;
                                        
                                            const script = `set options to {"${items !== undefined?items.join('", "'):""}"}
                                        
                                            tell application "System Events"
                                                activate
                                                set selectedItems to choose from list options ¬
                                                    with title "${title !== undefined? title:""}" ¬
                                                    with prompt "${prompt !== undefined? prompt: ""}" ¬
                                                    OK button name "${oKButton ? oKButton : "OK"}" ¬
                                                    default items {"${defaultItems && defaultItems.length > 0 ? defaultItems.join('", "') : []}"} ¬
                                                    cancel button name "${cancelButton ? cancelButton : "Cancel"}" ¬
                                                    empty selection allowed ${allowEmptySelection !== undefined ? JSON.stringify(allowEmptySelection) : true} ¬
                                                    multiple selections allowed ${allowMultipleSelections !== undefined ? JSON.stringify(allowMultipleSelections) : true}
                                            end tell`;
                                        
                                            const result = sf.system.execAppleScript({ script }).result;
                                        
                                            // Refocus previous app.
                                            focusedApp.appActivate();
                                        
                                            return result;
                                        }
                                        
                                        const selectedItems = selectFromList({
                                            title: `Title`,
                                            prompt: `Please select items.`,
                                            items: ['item 1', 'item 2', 'item 3', 'item 4'],
                                            //defaultItems: ["item 2"],
                                            //allowEmptySelection: true,
                                            //allowMultipleSelections: true,
                                            //cancelButton: "Cancel",
                                            //oKButton: "OK",
                                        });
                                        
                                        log(selectedItems);
                                        
                                        1. NNicolas Aparicio @Nicolas_Aparicio
                                            2024-11-13 21:18:09.004Z

                                            Hi @Kitch, this one works as expected and fields can be left undefined! however, it seems to have a 3 second lag before the keyboard or mouse can be used to scroll down though the list is in focus. Also, I've had log() as undefined sometimes with processes like:

                                            let files = sf.file.directoryGetFiles({ path: paths, isRecursive: true }).paths
                                            

                                            or mapping items from a json like:

                                            let fileRead = sf.file.readJson({ path: path }).json
                                            let items = fileRead.map(i => i.name)
                                            

                                            Looks like the "const result" could be the issue?

                                            1. Kitch Membery @Kitch2024-11-13 21:29:50.716Z

                                              Hi @Nicolas_Aparicio,

                                              "this one works as expected and fields can be left undefined!" Great!

                                              I'm not sure I follow the rest of what you're saying in your post. Can you maybe provide a screen recording of what you mean?

                                              1. NNicolas Aparicio @Nicolas_Aparicio
                                                  2024-11-13 22:45:38.033Z

                                                  Hi @Kitch, just sent you an email with the video for this 🤙

                                                  1. Kitch Membery @Kitch2024-11-14 00:58:29.691Z

                                                    Hi Nick,

                                                    I'm not seeing a delay here. Out of interest, how many files and folders are being returned from the sf.file.directoryGetFiles() method?

                                                    I'd say that is where the bottleneck is... Maybe try to filter out items you don't need before pushing them to the selectFromList dialog method or test with a folder that contains fewer items.

                                                    1. NNicolas Aparicio @Nicolas_Aparicio
                                                        2024-11-14 03:59:31.169Z

                                                        Hey Kitch,

                                                        False alarm, I'm a dork and had ".List" at the end of your function so... 😅 my bad, it logs fine.
                                                        The "lag" was happening as the line:

                                                        const result = sf.system.execAppleScript({ script, implementation: 'OSAScript' }).result;
                                                        

                                                        didn't have the "OSAScript" implementation, adding it solved it for me 🤙.
                                                        Loved this code Kitch, amazing work!

                                                        I was thinking, these could be added all into an interactions function? something like:

                                                        function interactions() {
                                                        
                                                            function selectFromList(settings) {
                                                                // Get focused app
                                                                const focusedApp = sf.ui.frontmostApp;
                                                        
                                                                const { title,
                                                                    prompt,
                                                                    items,
                                                                    defaultItems,
                                                                    allowEmptySelection,
                                                                    allowMultipleSelections,
                                                                    cancelButton,
                                                                    oKButton
                                                                } = settings;
                                                        
                                                                const script = `set options to {"${items !== undefined ? items.join('", "') : ""}"}
                                                        
                                                             tell application "System Events"
                                                                activate
                                                                set selectedItems to choose from list options ¬
                                                                    with title "${title !== undefined ? title : ""}" ¬
                                                                    with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                    OK button name "${oKButton ? oKButton : "OK"}" ¬
                                                                    default items {"${defaultItems && defaultItems.length > 0 ? defaultItems.join('", "') : []}"} ¬
                                                                    cancel button name "${cancelButton ? cancelButton : "Cancel"}" ¬
                                                                    empty selection allowed ${allowEmptySelection !== undefined ? JSON.stringify(allowEmptySelection) : true} ¬
                                                                    multiple selections allowed ${allowMultipleSelections !== undefined ? JSON.stringify(allowMultipleSelections) : true}
                                                             end tell`;
                                                        
                                                                const result = sf.system.execAppleScript({ script, implementation: 'OSAScript' }).result;
                                                        
                                                                // Refocus previous app.
                                                                focusedApp.appActivate();
                                                        
                                                                return result;
                                                            }
                                                        
                                                            function selectFolder() {
                                                                //selectFolderInteraction
                                                            }
                                                        
                                                            function selectFile() {
                                                                //selectFileInteraction
                                                            }
                                                        
                                                            //etc, etc
                                                        
                                                            return { selectFromList, selectFolder, selectFile, etc, etc }
                                                        
                                                        }
                                                        
                                                        

                                                        So we can call back the function similar to SF like:

                                                        const test = interactions().selectFromList({
                                                            title: `TEST`,
                                                            prompt: ``,
                                                            items: ['item 1', 'item 2', 'item 3'],
                                                            allowEmptySelection: false,
                                                            allowMultipleSelections: true,
                                                        });
                                                        log(test)
                                                        
                                                        1. NNicolas Aparicio @Nicolas_Aparicio
                                                            2024-11-14 11:11:52.243Z

                                                            @Kitch btw, I thought of saving you some time so I've added all the interaction's applescripts for you.
                                                            I'll keep working on this to try and combine them all into one function and make the code shorter.
                                                            Also started adding the properties for "selectFromList" so ctrl+space gives you the same values as SF does. I'm very new to that area so, not sure if that'll work.

                                                            function interactions() {
                                                            
                                                                function main(script) {
                                                                    // Get focused app
                                                                    const focusedApp = sf.ui.frontmostApp;
                                                            
                                                                    const result = sf.system.execAppleScript({ script, implementation: 'OSAScript' }).result;
                                                            
                                                                    // Refocus previous app.
                                                                    focusedApp.appActivate();
                                                            
                                                                    return result;
                                                                }
                                                            
                                                                function selectApplication(settings) {
                                                            
                                                                    const { title, prompt, } = settings;
                                                            
                                                                    const script = `
                                                                    tell application "System Events"
                                                            	    activate
                                                            	    set theApp to choose application with prompt "${prompt}" with title "${title}"
                                                                    end tell`
                                                            
                                                                    main(script)
                                                                }
                                                            
                                                                function selectApplications(settings) {
                                                            
                                                                    const { title, prompt, } = settings;
                                                            
                                                                    const script = `
                                                                    tell application "System Events"
                                                            	    activate
                                                            	    set theApp to choose application with prompt "${prompt}" with title "${title}" ¬
                                                                    with multiple selections allowed
                                                                    end tell`
                                                            
                                                                    main(script)
                                                                }
                                                            
                                                                function selectFile(settings) {
                                                            
                                                                    const { defaultLocation, prompt, allowedFileTypes, } = settings;
                                                            
                                                                    const script = `
                                                                    tell application "System Events"
                                                                    activate
                                                                    set directory to POSIX path of (choose file of type {"${allowedFileTypes[0]}"} with prompt "${prompt}" default location ("${defaultLocation}"))
                                                                    end tell`
                                                            
                                                                    main(script)
                                                                }
                                                            
                                                                function selectFiles(settings) {
                                                            
                                                                    const { defaultLocation, prompt, allowedFileTypes, } = settings;
                                                            
                                                                    const script = `
                                                                    tell application "System Events"
                                                                    activate
                                                                    set directory to POSIX path of (choose file of type {"${allowedFileTypes[0]}"} with prompt "${prompt}" default location ("${defaultLocation}") ¬
                                                                    with multiple selections allowed)
                                                                    end tell`
                                                            
                                                                    main(script)
                                                                }
                                                            
                                                                function selectFolder(settings) {
                                                            
                                                                    const { defaultLocation, prompt, } = settings;
                                                            
                                                                    const script = `
                                                                    tell application "System Events"
                                                                    activate
                                                                    set directory to POSIX path of (choose folder with prompt "${prompt}" default location ("${defaultLocation}"))
                                                                    end tell`
                                                            
                                                                    main(script)
                                                                }
                                                            
                                                                function selectFolders(settings) {
                                                            
                                                                    const { defaultLocation, prompt, } = settings;
                                                            
                                                                    const script = `
                                                                    tell application "System Events"
                                                                    activate
                                                                    set directory to POSIX path of (choose folder with prompt "${prompt}" default location ("${defaultLocation}") ¬
                                                                    with multiple selections allowed)
                                                                    end tell`
                                                            
                                                                    main(script)
                                                            
                                                                }
                                                            
                                                                /**
                                                                 * @param  {{
                                                                 * title: String,
                                                                 * prompt: String,
                                                                 * items: Array,
                                                                 * defaultItems: Array,
                                                                 * allowEmptySelection: Boolean,
                                                                 * allowMultipleSelections: Boolean,
                                                                 * cancelButton: String,
                                                                 * oKButton: String,
                                                                 * }} settings
                                                                 */
                                                                function selectFromList(settings) {
                                                            
                                                                    const { title,
                                                                        prompt,
                                                                        items,
                                                                        defaultItems,
                                                                        allowEmptySelection,
                                                                        allowMultipleSelections,
                                                                        cancelButton,
                                                                        oKButton
                                                                    } = settings;
                                                            
                                                                    const script = `set options to {"${items !== undefined ? items.join('", "') : ""}"}
                                                            
                                                                 tell application "System Events"
                                                                    activate
                                                                    set selectedItems to choose from list options ¬
                                                                        with title "${title !== undefined ? title : ""}" ¬
                                                                        with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                        OK button name "${oKButton ? oKButton : "OK"}" ¬
                                                                        default items {"${defaultItems && defaultItems.length > 0 ? defaultItems.join('", "') : []}"} ¬
                                                                        cancel button name "${cancelButton ? cancelButton : "Cancel"}" ¬
                                                                        empty selection allowed ${allowEmptySelection !== undefined ? JSON.stringify(allowEmptySelection) : true} ¬
                                                                        multiple selections allowed ${allowMultipleSelections !== undefined ? JSON.stringify(allowMultipleSelections) : true}
                                                                 end tell`;
                                                            
                                                                    main(script)
                                                                }
                                                            
                                                                function selectSaveFileName(settings) {
                                                            
                                                                    const { defaultLocation, prompt, } = settings;
                                                            
                                                                    //missing default name
                                                                    const script = `
                                                                    tell application "System Events"
                                                                    activate
                                                                    set theNewFilePath to choose file name with prompt "${prompt}" default location ("${defaultLocation}")
                                                                    end tell`
                                                            
                                                                    main(script)
                                                                }
                                                            
                                                                return { selectApplication, selectApplications, selectFile, selectFiles, selectFolder, selectFolders, selectFromList, selectSaveFileName }
                                                            
                                                            }
                                                            
                                                            interactions().selectFromList({
                                                                title: 'Test Title',
                                                                prompt: 'Test Prompt',
                                                            });
                                                            
                                                            1. Chad Wahlbrink @Chad2024-11-14 16:02:28.672Z

                                                              Epic work, @Nicolas_Aparicio !

                                                              1. Kitch Membery @Kitch2024-11-14 18:03:20.926Z

                                                                Great stuff @Nicolas_Aparicio. :-)

                                                                1. NNicolas Aparicio @Nicolas_Aparicio
                                                                    2024-11-29 06:25:36.414Z

                                                                    Hi all, I've done my version of this in the meantime if anyone is interested.


                                                                    •All interactions that currently don't come up in focus are added to this script.
                                                                    •Not only they come up in focus but they work almost the same way as the ones in soundFlow. So, you can just replace sf.interaction for interactions() on your current scripts and it'll still work the same "famous last words"
                                                                    (btw never as good as the already implemented interactions but they"ll do the job)
                                                                    • I've added most of the importat stuff except for "onError" and "onCancel" which I'll try to add later on.
                                                                    • control + spacebar also shows you the available options per interaction
                                                                    • Interactions like selectFile, work with undefined settings like: interactions().selectFile()
                                                                    • The interactions will return the same values, so you can still log them and retrieve the same info


                                                                    How to:

                                                                    1 - Add function to a script
                                                                    2 - Replace intended sf.interaction with interactions() and you should be good to go


                                                                    Cheers team,
                                                                    Nic

                                                                    function interactions() {
                                                                    
                                                                        /**
                                                                         * @param {Object} [settings]
                                                                         * @param {any} [settings.title] 
                                                                         * @param {any} [settings.prompt] 
                                                                         */
                                                                        function selectApplication(settings) {
                                                                    
                                                                            if (settings === undefined) {
                                                                                var title = undefined
                                                                                var prompt = undefined
                                                                            } else {
                                                                                var { title, prompt, } = settings;
                                                                            };
                                                                    
                                                                            const script = `
                                                                            tell application "System Events"
                                                                    	    activate
                                                                    	    set theApp to choose application ¬
                                                                            with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                            with title "${title !== undefined ? title : ""}"
                                                                            end tell`
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const appName = appleScript.result
                                                                            const appPath = sf.system.execAppleScript({
                                                                                script: `POSIX path of (path to application "${appName.trim()}")`,
                                                                                implementation: 'OSAScript'
                                                                            }).result.replace('\n', '')
                                                                    
                                                                            const path = appPath
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { path, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        /**
                                                                         * @param {Object} [settings]
                                                                         * @param {any} [settings.title] 
                                                                         * @param {any} [settings.prompt] 
                                                                         */
                                                                        function selectApplications(settings) {
                                                                    
                                                                            if (settings === undefined) {
                                                                                var title = undefined
                                                                                var prompt = undefined
                                                                            } else {
                                                                                var { title, prompt, } = settings;
                                                                            };
                                                                    
                                                                            const script = `
                                                                            tell application "System Events"
                                                                    	    activate
                                                                    	    set theApp to choose application ¬
                                                                            with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                            with title "${title !== undefined ? title : ""}" ¬
                                                                            with multiple selections allowed
                                                                            end tell`
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const appNames = appleScript.result.split(',').map(i => i.trim().replace('\n', ''))
                                                                    
                                                                            const appPaths = []
                                                                            appNames.forEach(app => {
                                                                                let appPath = sf.system.execAppleScript({
                                                                                    script: `POSIX path of (path to application "${app}")`,
                                                                                    implementation: 'OSAScript'
                                                                                }).result.replace('\n', '')
                                                                    
                                                                                appPaths.push(appPath)
                                                                            });
                                                                    
                                                                            const paths = appPaths
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { paths, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        /**
                                                                         * @param {Object} [settings]
                                                                         * @param {any} [settings.defaultLocation] 
                                                                         * @param {any} [settings.prompt] 
                                                                         * @param {any} [settings.allowedFileTypes] 
                                                                         */
                                                                        function selectFile(settings) {
                                                                    
                                                                            if (settings === undefined) {
                                                                                var defaultLocation = undefined
                                                                                var prompt = undefined
                                                                                var allowedFileTypes = undefined
                                                                            } else {
                                                                                var { defaultLocation, prompt, allowedFileTypes, } = settings;
                                                                            };
                                                                    
                                                                            const desktopPath = sf.system.execAppleScript({
                                                                                script: `set theTargetFolder to (path to Desktop Folder) as string`,
                                                                            }).result.split(':').slice(1).join('/')
                                                                    
                                                                            const script = `
                                                                            tell application "System Events"
                                                                            activate
                                                                            set directory to POSIX path of (choose file ¬
                                                                            of type {"${allowedFileTypes !== undefined ? allowedFileTypes[0] : ""}"} ¬
                                                                            with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                            default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath}"))
                                                                            end tell`
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const path = appleScript.result
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { path, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        /**
                                                                         * @param {Object} [settings]
                                                                         * @param {any} [settings.defaultLocation] 
                                                                         * @param {any} [settings.prompt] 
                                                                         * @param {any} [settings.allowedFileTypes] 
                                                                         */
                                                                        function selectFiles(settings) {
                                                                    
                                                                            if (settings === undefined) {
                                                                                var defaultLocation = undefined
                                                                                var prompt = undefined
                                                                                var allowedFileTypes = undefined
                                                                            } else {
                                                                                var { defaultLocation, prompt, allowedFileTypes, } = settings;
                                                                            };
                                                                    
                                                                            const desktopPath = sf.system.execAppleScript({
                                                                                script: `set theTargetFolder to (path to Desktop Folder) as string`,
                                                                            }).result.split(':').slice(1).join('/')
                                                                    
                                                                            const script = `
                                                                            tell application "System Events"
                                                                            activate
                                                                            set directory to POSIX path of (choose file ¬
                                                                            of type {"${allowedFileTypes !== undefined ? allowedFileTypes[0] : ""}"} ¬
                                                                            with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                            default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath}") ¬
                                                                            with multiple selections allowed)
                                                                            end tell`
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const paths = appleScript.standardError.split(`alias `).slice(1).map(i => '/' + i.split('"')[1].split(':').slice(1).join('/'))
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { paths, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        /**
                                                                         * @param {Object} [settings]
                                                                         * @param {any} [settings.defaultLocation] 
                                                                         * @param {any} [settings.prompt] 
                                                                         */
                                                                        function selectFolder(settings) {
                                                                    
                                                                            if (settings === undefined) {
                                                                                var defaultLocation = undefined
                                                                                var prompt = undefined
                                                                            } else {
                                                                                var { defaultLocation, prompt, } = settings;
                                                                            };
                                                                    
                                                                            const desktopPath = sf.system.execAppleScript({
                                                                                script: `set theTargetFolder to (path to Desktop Folder) as string`,
                                                                            }).result.split(':').slice(1).join('/')
                                                                    
                                                                            const script = `
                                                                            tell application "System Events"
                                                                            activate
                                                                            set directory to POSIX path of (choose folder ¬
                                                                            with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                            default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath}"))
                                                                            end tell`
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const path = appleScript.result
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { path, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        /**
                                                                         * @param {Object} [settings]
                                                                         * @param {any} [settings.defaultLocation] 
                                                                         * @param {any} [settings.prompt] 
                                                                         */
                                                                        function selectFolders(settings) {
                                                                    
                                                                            if (settings === undefined) {
                                                                                var defaultLocation = undefined
                                                                                var prompt = undefined
                                                                            } else {
                                                                                var { defaultLocation, prompt, } = settings;
                                                                            };
                                                                    
                                                                            const desktopPath = sf.system.execAppleScript({
                                                                                script: `set theTargetFolder to (path to Desktop Folder) as string`,
                                                                            }).result.split(':').slice(1).join('/')
                                                                    
                                                                            const script = `
                                                                            tell application "System Events"
                                                                            activate
                                                                            set directory to POSIX path of (choose folder ¬
                                                                            with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                            default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath}") ¬
                                                                            with multiple selections allowed)
                                                                            end tell`
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const paths = appleScript.standardError.split(`alias `).slice(1).map(i => '/' + i.split('"')[1].split(':').slice(1, -1).join('/'))
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { paths, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        /**
                                                                         * @param {Object} settings
                                                                         * @param {string} [settings.title] 
                                                                         * @param {string} [settings.prompt] 
                                                                         * @param {array} [settings.items] 
                                                                         * @param {array} [settings.defaultItems] 
                                                                         * @param {Boolean} [settings.allowEmptySelection] 
                                                                         * @param {Boolean} [settings.allowMultipleSelections] 
                                                                         * @param {string} [settings.oKButton] 
                                                                         * @param {string} [settings.cancelButton] 
                                                                         */
                                                                        function selectFromList(settings) {
                                                                    
                                                                            const {
                                                                                title,
                                                                                prompt,
                                                                                items,
                                                                                defaultItems,
                                                                                allowEmptySelection,
                                                                                allowMultipleSelections,
                                                                                cancelButton,
                                                                                oKButton,
                                                                            } = settings;
                                                                    
                                                                            const script = `set options to {"${items !== undefined ? items.join('", "') : ""}"}
                                                                    
                                                                            tell application "System Events"
                                                                            activate
                                                                            set selectedItems to choose from list options ¬
                                                                                with title "${title !== undefined ? title : ""}" ¬
                                                                                with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                                OK button name "${oKButton ? oKButton : "OK"}" ¬
                                                                                default items {"${defaultItems && defaultItems.length > 0 ? defaultItems.join('", "') : []}"} ¬
                                                                                cancel button name "${cancelButton ? cancelButton : "Cancel"}" ¬
                                                                                empty selection allowed ${allowEmptySelection !== undefined ? JSON.stringify(allowEmptySelection) : true} ¬
                                                                                multiple selections allowed ${allowMultipleSelections !== undefined ? JSON.stringify(allowMultipleSelections) : true}
                                                                            end tell`;
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const list = appleScript.result.replace('\n', '').split(',').map(i => i.trim())
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { list, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        /**
                                                                         * @param {Object} [settings]
                                                                         * @param {any} [settings.defaultLocation] 
                                                                         * @param {any} [settings.defaultName] 
                                                                         * @param {any} [settings.prompt] 
                                                                         */
                                                                        function selectSaveFileName(settings) {
                                                                    
                                                                            if (settings === undefined) {
                                                                                var defaultLocation = undefined
                                                                                var defaultName = undefined
                                                                                var prompt = undefined
                                                                            } else {
                                                                                var { defaultLocation, defaultName, prompt } = settings
                                                                            };
                                                                    
                                                                            const desktopPath = sf.system.execAppleScript({
                                                                                script: `set theTargetFolder to (path to Desktop Folder) as string`,
                                                                            }).result.split(':').slice(1).join('/')
                                                                    
                                                                            const script = `
                                                                            tell application "System Events"
                                                                            activate
                                                                            set theNewFilePath to choose file name ¬
                                                                            with prompt "${prompt !== undefined ? prompt : ""}" ¬
                                                                            default name "${defaultName !== undefined ? defaultName : ""}" ¬
                                                                            default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath}")
                                                                            end tell`
                                                                    
                                                                            const appleScript = sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                    
                                                                            const path = appleScript.result.split(':').slice(1).map(i => '/' + i.trim().replace('\n', '')).join('')
                                                                            const success = appleScript.success
                                                                            const error = appleScript.error
                                                                            const userCancelled = appleScript.userCancelled
                                                                    
                                                                            return { path, success, error, userCancelled };
                                                                    
                                                                        }
                                                                    
                                                                        return { selectApplication, selectApplications, selectFile, selectFiles, selectFolder, selectFolders, selectFromList, selectSaveFileName }
                                                                    
                                                                    }
                                                                    
                                                                    1. NNicolas Aparicio @Nicolas_Aparicio
                                                                        2024-12-09 23:29:25.007Z

                                                                        Hi @Kitch, me again 😅, I'm obsessed with this 😆.

                                                                        Here's a refined version of the interactions in focus code after a few weeks of testing. I'm sure it can be written in a much more elegant way but it'll give you a starting point.
                                                                        So far it's returning and behaving as expected on a few different systems but I'm sure there are still a few tweaks to add. Also, my error handling and values return might not be the best so keen to see your approach on it.

                                                                        Hope it helps,
                                                                        Nic.

                                                                        function interactions() {
                                                                        
                                                                            const desktopPath = () => sf.system.exec({ commandLine: `echo ~/Desktop` }).result
                                                                        
                                                                            function runApplescript(script) {
                                                                                return sf.system.execAppleScript({ script, implementation: 'OSAScript' });
                                                                            }
                                                                        
                                                                            function returnPaths(appleScript) {
                                                                                let regex = /alias "(.*?)"/g;
                                                                                let matches;
                                                                                let pathsToFix = [];
                                                                        
                                                                                while ((matches = regex.exec(appleScript.standardError)) !== null) {
                                                                                    pathsToFix.push(matches[1]);
                                                                                }
                                                                        
                                                                                const paths = pathsToFix.map(path => {
                                                                                    return '/Volumes/' +
                                                                                        path.replace(/Macintosh HD:/, '/')
                                                                                            .replace(/:/g, '/')
                                                                                            .replace(/\\:/g, '')
                                                                                            .replace(/ \[.*?\]/g, "");
                                                                                });
                                                                                return paths
                                                                            }
                                                                        
                                                                            function onCancelFunction(settings) {
                                                                                if (settings !== undefined && settings.onCancel !== undefined) {
                                                                                    if (settings.onCancel === "ThrowError") throw 'Error, user cancelled'
                                                                                    if (settings.onCancel === "Abort") throw 0
                                                                                    if (settings.onCancel === "Continue") { }
                                                                                } else {
                                                                                    throw 0
                                                                                }
                                                                            }
                                                                        
                                                                            function onErrorFunction(settings) {
                                                                                if (settings !== undefined && settings.onError !== undefined) {
                                                                                    if (settings.onError === "ThrowError") throw `Interaction Error`
                                                                                    if (settings.onError === "Continue") { }
                                                                                } else {
                                                                                    throw `Unexpected Error`
                                                                                }
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} [settings]
                                                                             * @param {any} [settings.title] 
                                                                             * @param {any} [settings.prompt] 
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectApplication(settings) {
                                                                        
                                                                                if (settings === undefined) {
                                                                                    var title = undefined
                                                                                    var prompt = undefined
                                                                                } else {
                                                                                    var { title, prompt, } = settings;
                                                                                };
                                                                        
                                                                                const script = `
                                                                                        tell application "System Events"
                                                                        	            activate
                                                                        	            set theApp to choose application ¬
                                                                                        with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                        with title "${title !== undefined ? title.replace(/"/g, `“`) : ""}"
                                                                                        end tell`
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const appName = appleScript.result.replace('\n', '')
                                                                                const appPath = sf.system.exec({ commandLine: `mdfind "kMDItemKind == 'Application' && kMDItemFSName == '${appName}.app'"` }).result
                                                                        
                                                                                const path = appPath
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { path, success, error, userCancelled }
                                                                        
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} [settings]
                                                                             * @param {any} [settings.title] 
                                                                             * @param {any} [settings.prompt] 
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectApplications(settings) {
                                                                        
                                                                                if (settings === undefined) {
                                                                                    var title = undefined
                                                                                    var prompt = undefined
                                                                                } else {
                                                                                    var { title, prompt, } = settings;
                                                                                };
                                                                        
                                                                                const script = `
                                                                                        tell application "System Events"
                                                                        	            activate
                                                                        	            set theApp to choose application ¬
                                                                                        with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                        with title "${title !== undefined ? title.replace(/"/g, `“`) : ""}" ¬
                                                                                        with multiple selections allowed
                                                                                        end tell`
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const appNames = appleScript.result.split(',').map(i => i.trim().replace('\n', ''))
                                                                                const appPaths = []
                                                                                appNames.forEach(app => {
                                                                                    let appPath = sf.system.exec({ commandLine: `mdfind "kMDItemKind == 'Application' && kMDItemFSName == '${app}.app'"` })
                                                                                    appPaths.push(appPath)
                                                                                });
                                                                        
                                                                                const paths = appPaths.map(i => i.result)
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { paths, success, error, userCancelled }
                                                                        
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} [settings]
                                                                             * @param {any} [settings.defaultLocation] 
                                                                             * @param {any} [settings.prompt] 
                                                                             * @param {any} [settings.allowedFileTypes] 
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectFile(settings) {
                                                                        
                                                                                if (settings === undefined) {
                                                                                    var defaultLocation = undefined
                                                                                    var prompt = undefined
                                                                                    var allowedFileTypes = undefined
                                                                                } else {
                                                                                    var { defaultLocation, prompt, allowedFileTypes, } = settings;
                                                                                };
                                                                        
                                                                                const script = `
                                                                                        tell application "System Events"
                                                                                        activate
                                                                                        set directory to POSIX path of (choose file ¬
                                                                                        ${allowedFileTypes !== undefined ? `of type {"${allowedFileTypes.join('", "')}"} ¬` : `¬`}
                                                                                        with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                        default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath()}"))
                                                                                        end tell`
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const path = appleScript.result.replace('\n', '')
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { path, success, error, userCancelled }
                                                                        
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} [settings]
                                                                             * @param {any} [settings.defaultLocation] 
                                                                             * @param {any} [settings.prompt] 
                                                                             * @param {any} [settings.allowedFileTypes] 
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectFiles(settings) {
                                                                        
                                                                                if (settings === undefined) {
                                                                                    var defaultLocation = undefined
                                                                                    var prompt = undefined
                                                                                    var allowedFileTypes = undefined
                                                                                } else {
                                                                                    var { defaultLocation, prompt, allowedFileTypes, } = settings;
                                                                                };
                                                                        
                                                                                const script = `
                                                                                        tell application "System Events"
                                                                                        activate
                                                                                        set directory to POSIX path of (choose file ¬
                                                                                        ${allowedFileTypes !== undefined ? `of type {"${allowedFileTypes.join('", "')}"} ¬` : `¬`}
                                                                                        with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                        default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath()}") ¬
                                                                                        with multiple selections allowed)
                                                                                        end tell`
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const paths = returnPaths(appleScript);
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { paths, success, error, userCancelled }
                                                                        
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} [settings]
                                                                             * @param {any} [settings.defaultLocation] 
                                                                             * @param {any} [settings.prompt] 
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectFolder(settings) {
                                                                        
                                                                                if (settings === undefined) {
                                                                                    var defaultLocation = undefined
                                                                                    var prompt = undefined
                                                                                } else {
                                                                                    var { defaultLocation, prompt, } = settings;
                                                                                };
                                                                        
                                                                                const script = `
                                                                                        tell application "System Events"
                                                                                        activate
                                                                                        set directory to POSIX path of (choose folder ¬
                                                                                        with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                        default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath()}"))
                                                                                        end tell`
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const path = String(appleScript.result.replace('\n', ''))
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { path, success, error, userCancelled }
                                                                        
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} [settings]
                                                                             * @param {any} [settings.defaultLocation] 
                                                                             * @param {any} [settings.prompt] 
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectFolders(settings) {
                                                                        
                                                                                if (settings === undefined) {
                                                                                    var defaultLocation = undefined
                                                                                    var prompt = undefined
                                                                                } else {
                                                                                    var { defaultLocation, prompt, } = settings;
                                                                                };
                                                                        
                                                                                const script = `
                                                                                        tell application "System Events"
                                                                                        activate
                                                                                        set directory to POSIX path of (choose folder ¬
                                                                                        with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                        default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath()}") ¬
                                                                                        with multiple selections allowed)
                                                                                        end tell`
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const paths = returnPaths(appleScript);
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { paths, success, error, userCancelled }
                                                                        
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} settings
                                                                             * @param {string} [settings.title] 
                                                                             * @param {string} [settings.prompt] 
                                                                             * @param {array} [settings.items] 
                                                                             * @param {array} [settings.defaultItems] 
                                                                             * @param {Boolean} [settings.allowEmptySelection] 
                                                                             * @param {Boolean} [settings.allowMultipleSelections] 
                                                                             * @param {string} [settings.oKButton] 
                                                                             * @param {string} [settings.cancelButton]
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectFromList(settings) {
                                                                        
                                                                                const {
                                                                                    title,
                                                                                    prompt,
                                                                                    items,
                                                                                    defaultItems,
                                                                                    allowEmptySelection,
                                                                                    allowMultipleSelections,
                                                                                    cancelButton,
                                                                                    oKButton,
                                                                                } = settings;
                                                                        
                                                                                const script = `set options to {"${items !== undefined ? items.join('", "') : ""}"}
                                                                                
                                                                                        tell application "System Events"
                                                                                        activate
                                                                                        set selectedItems to choose from list options ¬
                                                                                            with title "${title !== undefined ? title.replace(/"/g, `“`) : ""}" ¬
                                                                                            with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                            OK button name "${oKButton ? oKButton : "OK"}" ¬
                                                                                            default items {"${defaultItems && defaultItems.length > 0 ? defaultItems.join('", "') : []}"} ¬
                                                                                            cancel button name "${cancelButton ? cancelButton : "Cancel"}" ¬
                                                                                            empty selection allowed ${allowEmptySelection !== undefined ? JSON.stringify(allowEmptySelection) : true} ¬
                                                                                            multiple selections allowed ${allowMultipleSelections !== undefined ? JSON.stringify(allowMultipleSelections) : true}
                                                                                        end tell`;
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const list = appleScript.result.replace('\n', '').split(',').map(i => i.trim())
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { list, success, error, userCancelled };
                                                                        
                                                                            }
                                                                        
                                                                            /**
                                                                             * @param {Object} [settings]
                                                                             * @param {any} [settings.defaultLocation] 
                                                                             * @param {any} [settings.defaultName] 
                                                                             * @param {any} [settings.prompt] 
                                                                             * @param {"Continue"|"ThrowError"} [settings.onError] 
                                                                             * @param {"Abort"|"Continue"|"ThrowError"} [settings.onCancel] 
                                                                             */
                                                                            function selectSaveFileName(settings) {
                                                                        
                                                                                if (settings === undefined) {
                                                                                    var defaultLocation = undefined
                                                                                    var prompt = undefined
                                                                                    var defaultName = undefined
                                                                                } else {
                                                                                    var { defaultLocation, defaultName, prompt } = settings;
                                                                                };
                                                                        
                                                                                const script = `
                                                                                        tell application "System Events"
                                                                                        activate
                                                                                        set theNewFilePath to choose file name ¬
                                                                                        with prompt "${prompt !== undefined ? prompt.replace(/"/g, `“`) : ""}" ¬
                                                                                        default name "${defaultName !== undefined ? defaultName : ""}" ¬
                                                                                        default location ("${defaultLocation !== undefined ? defaultLocation : desktopPath()}")
                                                                                        end tell`
                                                                        
                                                                                const appleScript = runApplescript(script)
                                                                        
                                                                                const path = '/Volumes/' + appleScript.result
                                                                                    .replace(/file /g, "")
                                                                                    .replace(/ \[.*?\]/g, "")
                                                                                    .replace(/:/g, '/')
                                                                                    .replace(/\n/g, '');
                                                                                const success = appleScript.success
                                                                                const error = appleScript.error
                                                                                error !== null ? onErrorFunction(settings) : null
                                                                                const userCancelled = appleScript.standardError.includes("User cancelled") || appleScript.result.replace('\n', '') === "false"
                                                                                userCancelled ? onCancelFunction(settings) : null
                                                                        
                                                                                return { path, success, error, userCancelled }
                                                                        
                                                                            }
                                                                        
                                                                            return { selectApplication, selectApplications, selectFile, selectFiles, selectFolder, selectFolders, selectFromList, selectSaveFileName }
                                                                        
                                                                        }
                                                                        let interaction = interactions();
                                                                        
                                                                        1. Kitch Membery @Kitch2024-12-10 00:10:53.603Z

                                                                          Great stuff Nicolas,

                                                                          I may not have time this week to take a look. But will do so when I get a chance.

                                                                          Side note, please don't spend too much more time on this as this is something that should probably be taken care of in the SoundFlow API. (Your work so far is not in vain though, I'm sure it will come in very handy when implementing the internal fix.)

                                                                          I have it logged internally as SF-340, and you'll get updated once it's been implemented.

                                                                          Rock on!

                                                                          1. NNicolas Aparicio @Nicolas_Aparicio
                                                                              2024-12-10 00:13:32.951Z

                                                                              Thanks @Kitch, no worries at all, it was a good opportunity to learn a bit more 🤙
                                                                              Cheers.

                                                                              1. Kitch Membery @Kitch2024-12-10 00:15:25.454Z

                                                                                Hat's off to you, @Nicolas_Aparicio!

                                                                                You are kicking goals!

                                                                                And your enthusiasm is infectious! :-)

                                                                            • Chad Wahlbrink @Chad2024-12-10 02:05:57.230Z

                                                                              @Nicolas_Aparicio,

                                                                              It's such a great utility script until the SF API is updated. Thanks for sharing!

                                                                              I used your functions with a script I wrote over the weekend, which worked great. The version I copied hadn't added the replace function to the Select File or Select Folder functions – const path = appleScript.result.replace('\n', ''). I used appleScript.result.trim(), which seemed to do a similar job of solving that issue.

                                                                              Great work. I love the practice of working this out. Thanks for sharing.

                                                                              1. NNicolas Aparicio @Nicolas_Aparicio
                                                                                  2024-12-10 02:11:16.012Z

                                                                                  Thanks legend @Chad_Wahlbrink1, yep I changed a few things as some interactions were not returning the right info.
                                                                                  Ah right, useful to know trim() does that, it's an interesting world when looking into the applescript language.
                                                                                  Thanks a lot for the compliments to you and to @Kitch

                                                                                  1. Chad Wahlbrink @Chad2024-12-10 03:47:29.862Z

                                                                                    Yes for sure. AppleScript is a funny little scripting language.

                                                                                    Also, just a small note that my main account is @Chad. 🙏

                                                                                    Keep up the good work, Nicolas

                                                                  • Kitch Membery @Kitch2024-11-13 21:34:31.772Z

                                                                    Hi @Nico_Aparicio

                                                                    If the directoryGetFiles returning undefined and the mapping JSON issues are separate issues, please open a new thread for them.

                                                                    Thanks in advance.

                                                  2. S
                                                    SoundFlow Bot @soundflowbot
                                                      2024-10-29 00:26:13.002Z

                                                      This report was now added to the internal issue tracked by SoundFlow as SF-340

                                                      1. S
                                                        SoundFlow Bot @soundflowbot
                                                          2024-12-12 15:02:15.434Z

                                                          The linked internal issue SF-340 has been marked as Done

                                                          1. S
                                                            SoundFlow Bot @soundflowbot
                                                              2024-12-12 15:02:22.529Z

                                                              Linked issue SF-340 updated: This will be fixed in SF 5.10.0