Jump to content

script filter async updates


Recommended Posts

Hey, 


I'm trying to create a script filter where I can update the options more than once. What I'm trying to achieve is:

 

 

  1. Doing a fetch request to get a list of options
  2. Show the options
  3. Make subsequent fetch requests for each option and as they update reset the options in the dropdown list. 

 

"Why?" Because sometimes I don't care what the subsequent fetch requests return and I just want to interact with the options asap.

"Why don't you just fetch them all at once?" Thats what I'm doing currently but I'm trying to improve the time to interactive. (I don't care about unhandled requests)

Minimal reproducible example: 

const fetchItems = () => {
  // except and actual fetch
  return [
    {id: 0, title: 'Something', arg: ''},
    {id: 1, title: 'Another thing', arg: ''},
  ]
}

const fetchItemData = (id) => {
  // except and actual fetch
  return {id, description: `The status of item ${id}`}
}

const main = () => {
  const items = fetchItems()

  return JSON.stringify({ items })

  if (items) {
    items.forEach((option, index) => {
      const status = fetchItemData(option.id)
      items[index].subtitle = status.description
      JSON.stringify({ items }) // I want to update the items 
    })
  }
}

main()

 

This would be using actual fetches and promise.all in reality but the issue I have is that you can only return once obvs. If there isn't a way to achieve this consider it a feature request to have some kind of setOptions global 🤷

Link to comment

Fetch one result at a time and use the rerun key from the JSON to rerun the code. Keep track of what you have using environment variables, which you can set and read back. There is an example workflow with a counter which you can access from the + in the workflows list.

Link to comment

I couldn't easily find which template you where referring too but I understood what to do now to achieve what I want using the rerun api. 

I created this template file to make it easy for anyone else who stumbles across this using the right keywords haha

  1. Create a script filter with language `/bin/zsh`
  2. Define the script within as follows:
    1. #!/usr/bin/env node
      
      node script.js
  3. In the workflow directory for example: /Users/Yourname/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.A07C7F21-... create your script.js file and put this into it:
    const fs = require('fs')
    
    // A mocked fetch request
    const waitFor = (ms) => new Promise((resolve) => setTimeout(() => resolve("Some cool stuff"), ms))
    
    // Do what you have to do and simply mutate state directly
    const stages = [
        async (state) => {
            state.items = [{ title: "hey", subtitle: "Fetching..." }]
        },
        async (state) => {
            const things = await waitFor(500)
            state.items = state.items.map(i => ({ ...i, subtitle: things }))
        }
    ]
    
    // You shouldn't need to worry about anything under this comment but I'm hungry and this isn't a PR so I've probably missed something...	
    const STATE_FILE_PATH = 'state.json'
    
    const read = async () => {
        if (fs.existsSync(STATE_FILE_PATH)) {
            const data = fs.readFileSync(STATE_FILE_PATH, 'utf8')
            return JSON.parse(data)
        } else {
            const initialState = {
                stage: 0,
                items: [],
            }
            return initialState
        }
    }
    
    const write = async (state) => {
        fs.writeFileSync(STATE_FILE_PATH, JSON.stringify(state))
    }
    
    ~(async () => {
        const state = await read()
    
        await stages[state.stage]?.(state)
    
        const isComplete = state.stage >= stages.length - 1
        if (isComplete) {
            fs.rm(STATE_FILE_PATH, (err) => null)
            state.rerun = undefined
        } else {
            state.rerun = 0.1
            state.stage++
        }
    
        await write(state)
        /** CAN ONLY BE CALLED ONCE PER STAGE - This is the thing that updates alfred options */
        console.log(JSON.stringify(state))
    
    })().catch((err) => console.error(`An error occurred: ${err}`))

     

 

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...