CI HUBCI HUB SDK
Login Templates

Overview

Login templates are .ect (Embedded CoffeeScript Templates) files rendered server-side by the render() function inside your login handler. They collect user input — server URLs, credentials, organization selections — before authentication proceeds.

Template Chain

Every template extends a two-level chain:

your-template.ect → login-template.ect → base-template.ect
  • base-template.ect — full HTML page: CI HUB header with logo, Bulma CSS, background, container
  • login-template.ect — error notification area (@error), contact info footer (@contact)
  • your template — only the content block (the form)

You write the form. Everything else is inherited.

Minimal Template

<% extend 'login-template.ect' %>

<p>Enter your server URL.</p>
<br>
<form action="<%- @action %>" method="post">
  <div class="field">
    <label class="label">Server URL</label>
    <div class="control">
      <input class="inputfield" type="url" name="serverUrl" value="<%= @serverUrl %>" required>
    </div>
  </div>
  <div class="field is-grouped">
    <div class="control">
      <button class="button is-link" type="submit">Login</button>
    </div>
  </div>
</form>

ECT Syntax

SyntaxPurpose
<% extend 'login-template.ect' %>Inherit from parent template (required first line)
<% content %>Marks where child content is injected (used by parent templates)
<%= @var %>Output escaped variable
<%- @var %>Output unescaped variable (for URLs, HTML)
<% if @var? : %> ... <% end %>Conditional — renders block only if @var exists
<% if @var == "value" : %> ... <% else : %> ... <% end %>Conditional with else
<% for item in @list : %> ... <% end %>Loop over array

Use <%= %> (escaped) for user-supplied values inside attributes. Use <%- %> (unescaped) for URLs and trusted values like @action.

Template Variables

Auto-injected by the template chain

VariableSourceDescription
@logoPassed in render() dataAdapter logo — rendered in the header by base-template.ect
@contactPassed in render() dataSupport contact info — rendered in the footer by login-template.ect
@errorPassed in render() dataError message — shown as a red notification banner by login-template.ect
@titlePassed in render() dataPage heading — rendered above the form box by base-template.ect

Required in your form

VariableDescription
@actionThe POST URL for the form. Always use locals.endpointUrl (with state params appended)

Custom variables

Pass any additional variables your template needs via the render() data object. They become @variableName in the template.

CSS Framework

Templates use Bulma (v0.7.4). Key classes:

ClassElement
.fieldForm field wrapper
.labelField label
.controlInput wrapper
.inputfieldText/password/URL input (CI HUB custom class)
.selectSelect dropdown wrapper
.button.is-linkSubmit button
.notification.is-dangerError message (handled by login-template.ect)
.field.is-groupedGroups buttons horizontally

render() Function

render(templatePath: string, data: Record<string, unknown>): Promise<RenderEnvelope>

Call from your login handler. First argument is the template path without the .ect extension. Place templates next to your index.ts.

return render(path.join(import.meta.dirname, 'select-serverurl'), {
  title: 'Select Portal',
  action: urlObject.toString(),
  serverUrl: defaultUrl,
  logo,
  contact
})

The form POSTs back to action, which re-invokes your login handler with requestData.body populated from the form fields. The name attribute of each <input> becomes a key in requestData.body.

Form Submission Flow


Login Flow | Input Types | Template Examples

On this page