How to use api.addHeaderPanel?

AI-generated summary

The discussion is about using the api.addHeaderPanel function in Discourse. kara-todd is trying to add an interactive nav icon to the top menu bar and is having trouble setting the header widget state to show the custom panel.

kara-todd initially worked around the issue by introducing a service, but found it limited. gdpelican, the creator of the api.addHeaderPanel function, suggested using api.attachWidgetAction to toggle the panel state and api.decorateWidget to trigger the action.

gdpelican also suggested using Ember.evented to emit events that the header can listen to, as the panel cannot be nested in the header. The discussion is ongoing, and gdpelican is interested in finding a natural solution for the addHeaderPanel function.

I’ve been trying to add an interactive nav icon to our top menu bar.

So far I have:

  1. created a widget
  2. found the addHeaderPanel and called api.addHeaderPanel('custom-menu-button', 'customMenu')

However, this is where I get stuck… it looks like (according to the code) the panel will only show if the header widget state has {customMenu: true} in it… and for the life of me I cannot figure out how to set/override the state…

This panel will ultimately need to toggle it’s own state property (open/closed) to change the icon state, and also to send an action out to render a component with the menu. (unfortunately, it’s full-screen so I can’t nest it in the header Panel)

I had this working with a component pretty quickly, but the new virtual DOM is taking some adjustment mentally. :slight_smile:

This is a good question. I see that api was added by @gdpelican – how are you supposed to wire up the state in this case?

I managed to work around this now by just introducing a service and by-passing the state management entirely, but I think it would still be good to get some clarifications around how this should properly work. :slight_smile:

The service implementation I have is a bit limited since it can’t really loop back in and update the widget state effectively.

I was doing it through an attachWidgetAction call to the header.

api.attachWidgetAction('header', 'toggleMyPanel', function() {
  this.state.myPanelVisible = !this.state.myPanelVisible
})

You can then trigger that action by bubbling up an action from within the header. In my case I added a header icon that I could click to toggle:

api.decorateWidget('header-icons:before', function(h) {
  h.attach('header-dropdown', { action: 'toggleMyPanel' })
})

EDIT:

Sorry, I just read this bit. I think the whole point of widget state is that it’s self-contained and doesn’t leak out into other parts of the app, so not sure I have a solid recommendation here. Have you looked into using Ember.evented, to emit events that the header can listen to, perhaps?

// reopening the header widget...
this.appEvents = this.container.lookup('app-events:main')
this.appEvents.on('toggleCustomHeader', () => { this.state.customMenu = !this.state.customMenu })
// MEANWHILE, elsewhere:
this.appEvents = this.container.lookup('app-events:main')
this.appEvents.trigger('toggleCustomHeader')

The keyboard shortcuts code looks like a decent example of this.

I’d be curious to hear what your solution ends up being, maybe it’s something that the addHeaderPanel function should support naturally.