How to override `admin.hbs`

I’m just a caveman.

I want to override app/assets/javascripts/templates/admin.hbs because I want to change the nav menu on the admin page (but if that’s not how to do it, I’m all ears). If this is possible in a theme, I’d be interested, but this is related to a plugin that does a bunch of other stuff, so the plugin solution is what I want. I mostly want to disable links to API.

I figure that I need to:

  1. make a copy of admin.hbs, make my changes, and stick it, uh, somewhere (app/assets/javascripts/templates, perhaps?)
  2. put something in plugin.rb that tells Rails that I want to use my file instead of the stock one.
  3. Keep an eye on updates to admin.hbs in the future so that I don’t break it.
  4. Profit.

Overriding templates is a fairly nuclear solution, and some one-off fiddly javascript or css like

// NB I am pseudocode
$('.api-nav-item').attr('disabled', 'true')
.api-nav-item { display: none; }

would definitely serve you better here if you can get away with it.

If you need to override a whole template, theme component is the simpler way that I know of, with something like

<script type="text/x-handlebars" data-template-name="admin">
  <div>Hello world!</div>
</script>

If your plugin is going to go onto a bunch of instances, or you need to automate the installation more for whatever reason, you can go with my jack-wild solution from mingle, which automatically populates a theme component when the plugin is installed (but note that this is well within the realm of mad science :man_scientist:).

6 Likes

Thanks very much for this. Let me see if I have this straight.

And by “one-off fiddly”, you mean that it wouldn’t survive an upgrade or work across sites because there’s no api-nav-item

image

Do I understand that correctly?

So I can’t hide the API link without overriding the template (which you argue is better in a theme is better than a plugin, but again, the plugin is what’s going to decide whether the API link should be hidden) is a feature request for a enable-api that’s just like the enable_backups?

I’ve already hijacked the /admin/api route, so I think my solution may just be to redirect it somewhere (currently it 404s). EDIT: I did that with custom_admin_check, so that’s why it’s a 404. Hmm.

That’s fantastic, and I do want to automate it. Thanks very much for that.

Ah, I hadn’t really understood what you were up to in the first post, but I think I understand better now.

The admin menu isn’t very open for customization, but there’s often some way around it. I might try something like this for my fiddly one-off javascript solution (this is plugin land):

api.modifyClass('component:nav-item', {
  classNameBindings: ['hidden'],

  @computed('label')
  hidden() {
    return this.label == 'admin.api.title'
  }
})

Note that this works by applying the hidden class to the nav li in question, which has display: none as a style.

4 Likes

Hmm. I tried sticking that in places like assets/javascripts/initializers/lc-site-settings.es6 to no avail. I did manage to foolishly override admin.hbs and use my plugin’s settings to enable/disable stuff in the menu. I do like the idea of not mucking with the template for all the reasons you mention.

In a plugin where do I stick your code?

You’ll want an initializer which imports the pluginApi for use, cerca

// javascripts/initializers/hide-admin-api.js.es6
export default {
  name: 'hide-admin-api',
  initialize: function() {
    withPluginApi('0.8.6', (api) => {
      api.modifyClass(...)
    })
  }
}

I’m also suspicious of the file.es6 extension, as I think the system uses regex matching to look in that folder for things to load, and might enforce a file.js.es6 ending as well.

3 Likes

Update: I’ve managed to get my api-hide.js.es6 file in a place where it is doing something.

// javascripts/initializers/hide-admin-api.js.es6
export default {
  name: 'hide-admin-api',
  initialize: function() {
    withPluginApi('0.8.6', (api) => {
      api.modifyClass('component:nav-item', {
        classNameBindings: ['hidden'],
        @computed('label')
        hidden() {
          return this.label == 'admin.api.title'
        }
      })
    })
  }
}

Results in a blank page. I’ve tried stuff like

hidden() {
    return false
}

and api.modifyClass('component:NOT-nav-item'
but the whole page is still empty.

Thanks again for your patience.

If using a script that applies display: none is an acceptable solution, is there a reason you can’t just use CSS from the start?

.admin-main-nav a[href="/admin/api"] {
    display: none;
}

Mostly because I didn’t know how. But I pasted that in to assets/stylesheets/common/lc-site-settings.scss and lo! it turned it off. And, I swapped in a different path in for that href and it turned off too! I didn’t even need to reload!!! It’s like magic! I’ve done little this exciting since I wrote this:

10 print "Hello, world."
20 goto 10

Brilliant. Thanks very much.

But now, I need to be able to turn off the link optionally when a SiteSetting is on/off.

1 Like