Skip to content

Doc Browser Customisation Recipes

Jakub Hampl edited this page Aug 16, 2016 · 5 revisions

How do I change the colours of the docs?

Go to docs/styles.scss and add variable declarations with appropriate values. You can check this page for all the possible variables. The variable declarations should go above the @import "praxis.scss"; line. For example:

$navbar-default-bg: #076cca;
$navbar-default-gradient-start: #076cca;
$navbar-default-gradient-end: #065bac;
$navbar-default-color: #fff;
$navbar-default-link-color: #fff;
$navbar-default-link-hover-color: darken($navbar-default-link-color, 10%);
$navbar-height: 45px;

@import "praxis.scss";

How do I change the label in the version selector?

Make your app.js look like this:

angular.module('DocBrowser', ['PraxisDocBrowser'])
.config(function(ConfigurationProvider) {
  ConfigurationProvider.versionLabel = 'Rad Version';
});

The ConfigurationProvider enables you to set the following options:

Name Default Notes
title API Browser This changes what is displayed in the <title> element, as well as in the navbar.
versionLabel API Version Displayed in the version selector button.
expandChildren true If true, the child resources will be hidden in the sidebar unless they or their parent or siblings are selected.

How do I customise the top navigation?

Create a file named docs/views/navbar.html with content of this file. You can now modify this file to suit your needs.

How do I customise the home page?

Create a file named docs/views/home.html with content of this file. You can now modify this file to suit your needs.

In general you can override any template that ships with the doc browser by using a file with the same path in your docs/views directory. You can browse the available templates here: https://github.com/rightscale/praxis/blob/master/lib/api_browser/app/views/. Remember that this may break when updating you major version (but not patch release).

How do I add Google Analytics tracking to my app?

Since the docs are a singe page app, you will need to add the Angulartics module. To do that, create docs/bower.json with the following content:

{
  "dependencies": {
     "angulartics-google-analytics": "^0.2.1"
  }
}

Praxis will automatically download and link this package into the docs page. Then in docs/app.js you will need to make it read:

angular.module('DocBrowser', ['PraxisDocBrowser', 'angulartics', 'angulartics.google.analytics'])
  .config(function() {
    // paste the google analytics snippet here (without the <script> tag)
  });

Check the Angulartics readme for more information.

How do I change the displayed name of a resource?

Praxis - by default - use the resource class name as the resource displayed name in the generated documentation. You can give a different value for the displayed name using the display_name:

# design/v1/resources/a_resource.rb
module V1
  module Resources
    class AResource
      include Praxis::ResourceDefinition

      display_name 'A human readable resource description'
      ...
    end
  end
end

How do I add new pages?

Make your app.js look like this:

angular.module('DocBrowser', ['PraxisDocBrowser'])
.config(function($stateProvider) {
  $stateProvider
    .state('root.mypage', {
      url: '/my-page',
      templateUrl: 'views/my_page.html'
    })
});

This will render the template you put into views/my_page.html at /#/my-page inside the layout. If you wish not to use the layout, simply omit the root. part in the state declaration. See ui-router for more information.

Can I have "real" URLs that are easy to index?

First, you will need to set the documentation_url top-level API directive to the location you will host your documentation from. This is required so we can generate all the links properly.

Next add this to your docs/app.js:

angular.module('DocBrowser', ['PraxisDocBrowser'])
.config(function($locationProvider) {
  $locationProvider.html5mode(true);
});

Now all the links inside the app will be "proper" links (/1.0/controller/V1-ApiResources-MyResource instead of /index.html#/1.0/controller/V1-ApiResources-MyResource). Old style links should still work and automatically redirect the user to the new url.

Finally you will need to configure your server for Single Page App mode - all requests that don't point to a resource found on disk should serve the index.html page instead of a 404 response. For an example with an S3/CloudFront stack see here.

How do I customise documentation for (custom) types?

Most of the actual documentation content is documentation of various types - the request params type, the request body type, the response headers type, etc.

Each type goes through a template resolver function that decides which view will end up rendering the type. You can add your own resolver function that can return an appropriate template for your type.

For this example, assume that we have defined a custom Set type. In docs/app.js we do:

angular.module('DocBrowser', ['PraxisDocBrowser'])
.config(function(templateForProvider) {
  // this is a dependency injected function
  templateForProvider.register(function($type, $requestedTemplate) { 
    if ($type === 'Set') {
      if ($requestedTemplate === 'standalone') {
        return 'views/types/standalone/set.html';
      }
  });
});

Here we register a new resolver function that is dependency injected. There are several special variables you can inject: $type is the name of the type, $family is the name of type family this type belongs to (type families provide a generic way to render similar types), $typeDefinition is an object containing everything we know about the type and finally $requestedTemplate is one of standalone, embedded, label or main.

template illustration

Embedded templates are used for displaying a type as part of an attribute row of a parent type. They are rendered in a three column table and therefore they should be one or more <tr>s. Label templates display just the name of a type within that embedded row - which is usually a link or can conceivably add a popover explaining something about your type. Standalone templates exist to render the full representation of its type. They are typically used in custom payload types that do not fit the table model, and can take the full width of the page. Main templates are a similar to standalone templates in which they display the representation of a type. However, the main difference is that they will always take over the full with and height of the right pane (as opposed to be just one part of a larger page).

The resolver function must return one of these possible values:

  • a string or a promise of a string: this will be considered a url of a template which will be either requested over http or loaded from the local template cache.

  • a link function or a promise of a link function: this will be linked at the appropriate place. Use this if you have a very small template or you want to make some dynamic adjustments to the template. You can get a link function like this:

    $templateForProvider.register(function($compile) {
      return $compile('<div>My template</div>');
    });
  • undefined: means that this resolver doesn't know how to handle the type/template combination. This will then invoke the next resolver in the queue. The built-in resolvers are equipped to handle any type (albeit not so well), so they will eventually pick this up.

How do I upgrade Praxis while keeping my customisations?

Remember that until Praxis reaches 1.0, the templates are subject to change between each minor version. If you experience broken layout, check your customised templates to the ones in the repository and make sure that your modifications are 'compatible' to the original templates.

Can I have search?

Sure. Checkout this Praxis plugin: https://github.com/rightscale/praxis-docs-search

How do I add code examples to my docs?

There is an API that allows you to register code examples:

angular.module('PraxisDocBrowser').config(function(ExamplesProvider) {
  ExamplesProvider.register('some-id', 'Label', function($compile, $context) {
    "ngInject";
     return $compile("<h1>Example language</h1><pre highlight="markdown">Hello world!</pre>");
  });
});

It is entirely up to you what you do in the callback to ExamplesProvider.register as long as you return a linking function (the result of calling $compile). You can generate examples programatically or fetch examples from a file where you define them manually or perhaps a mixture of both.

The $context injectable variable is an object that contains the following keys:

Key Description
resource An object containing keys from the docs json file about the resource being rendered.
action An object containing keys from the docs json file about the action being rendered.
version A string with the API version being shown.

You can use these to work out what code will be necessary to render the example. You can check out this file for an example.