mirror of https://github.com/hashicorp/consul
154 lines
5.9 KiB
Markdown
154 lines
5.9 KiB
Markdown
# Significant patterns
|
|
|
|
## Ember specific
|
|
|
|
The Consul UI tries to follow typical conventional ember but differs
|
|
significantly in several places:
|
|
|
|
### Routing
|
|
|
|
We use a declarative configuration format for our routing rather than Ember's
|
|
DSL. The format is closely modeled on Ember's DSL and if you need to generate
|
|
Ember's DSL from this for some reason you can use one of our Debug Utilities
|
|
to do this.
|
|
|
|
### Routes
|
|
|
|
We use a specific BaseRoute as a parent Route for **all** our Routes. This contains project wide
|
|
functionality for several important additions. If you use the normal `ember
|
|
generate route route-name` generator this inheritance is automatically added
|
|
for you. If you don't use the generator please ensure you use:
|
|
|
|
```js
|
|
import Route from 'consul-ui/routing/route';
|
|
export default class NameOfRoute extends Route {}
|
|
```
|
|
|
|
Query parameters should be added to Routes, not Controllers. If a controller
|
|
has no query parameters configured they are copied over from the Route.
|
|
Preferably we don't use Controllers, but this doesn't mean you shouldn't if
|
|
you need to.
|
|
|
|
### Routlets
|
|
|
|
We use have a concept of 'routlets', the combination of a `<Route />` and
|
|
`<Outlet />` components that we use within our route templates to achieve
|
|
several different pieces of functionality.
|
|
|
|
Every route template should be wrapped in a `<Route @name={{routeName}}>` component and ever
|
|
`{{outlet}}` should be wrapped in `<Outlet @name={{routeName}}>` component.
|
|
The `routeName` variable is made available in every single route template and
|
|
it equal to the routeName of the current template e.g. `dc.services.index`
|
|
|
|
### DataSources
|
|
|
|
In order to support our live updating long-polling blocking queries we use
|
|
'DataSources' which come in two flavours. A service backed
|
|
approach for use within javascript:
|
|
|
|
```js
|
|
class RouteName extends Route {
|
|
@service('datasource/service') data;
|
|
async model(params) {
|
|
return this.data.source(uri => uri`/${params.nspace}/${params.dc}/services`)
|
|
}
|
|
}
|
|
```
|
|
|
|
This method returns an Ember proxy that lets you access the data as if it was
|
|
'just the data', but is also reactive/auto updates when the data in the
|
|
backend updates, for example:
|
|
|
|
```hbs
|
|
|
|
{{@model.Name}}
|
|
|
|
```
|
|
|
|
And a component based approach for use within templates.
|
|
|
|
```hbs
|
|
<DataSource @src={{
|
|
uri '/${nspace}/${dc}/services'
|
|
(hash
|
|
nspace="default"
|
|
dc="dc"
|
|
)
|
|
}}
|
|
@onchange=""
|
|
/>
|
|
```
|
|
|
|
See the relavant component/service documentation for more detail.
|
|
|
|
### Components
|
|
|
|
You could group our components into two different groups:
|
|
|
|
1. UI Components - generic components not necessarily specific to the product.
|
|
2. Consul Components - Components that are specific to Consul/the product.
|
|
These are mostly 'glorified partials'.
|
|
|
|
Mostly the CSS for a component lives in the component folder itself, but if it
|
|
makes sense for it not to live here, thats fine.
|
|
|
|
We currently use a mix of named/block slots and contextual components and its
|
|
fair to say that we use more named/block slots, but both are fine depending on
|
|
your use case.
|
|
|
|
### Significant Addons
|
|
|
|
- `ember-data` - model layer
|
|
- `ember-stargate` - wormhole/portal/put this DOM over there functionality
|
|
- `ember-can` - user abilities and permissions
|
|
- `ember-composable-helpers`, `ember-string-fns`, `ember-truth-helpers` - helpers x lots
|
|
- `ember-changeset` and `ember-changeset-validations` - form validation
|
|
- `ember-cli-flash` - notifications
|
|
|
|
Please see our package.json file dependencies.
|
|
|
|
## Consul specific
|
|
|
|
### Namespace support
|
|
|
|
Whilst Consul namespaces are a OSS feature of Consul, we almost always build
|
|
things 'pretending' that namespaces are always enabled. Then there is code
|
|
within the data layer of the application that removes any namespace related
|
|
query parameters.
|
|
|
|
Namespaces are a little more complex to think about than other things in
|
|
Consul as we have the idea of 'the default' namespace, and then additionally
|
|
an ACL token can have 'a default' namespace (not the same as 'the default'
|
|
namespace) which is a little like a namespace that is assigned to the token,
|
|
or where the token originated from. The Consul backend can then use the tokens
|
|
default/origin/assigned namespace to figure out whether and how to filter any
|
|
results by namespace before sending those results to the UI.
|
|
|
|
When you are requesting data from the API you should always include a
|
|
namespace (if applicable to the API endpoint), but you should never default
|
|
the namespace value to 'the default' namespace - `default`. Conversly, when
|
|
receiving data from an API response, there are some places where we do default
|
|
a namespace to 'the default' namespace `default`. The easiest way to think
|
|
about this is: If its on the way out, don't add a default ever, if its on the
|
|
way in you may need to default any potentially empty Namespace parameters to
|
|
`default` (due to using Consul without namespaces enabled), there is a
|
|
NspaceAbility and/or an `env` feature flag to help you to discover this.
|
|
|
|
We've made various decisions in the UI to make it hard to omit a namespace
|
|
when you shouldn't, for example using our DataSource component requires you to
|
|
include a defined namespace parameter (even if the value for that is `''`),
|
|
and the route parameter `nspace` value will always default to `''`. It also
|
|
reminds you to be continually thinking about namespaces whilst adding new
|
|
features.
|
|
|
|
Lastly, we always refer to namespaces in code as the word `nspace` or
|
|
`nspaces`. Both `ns` and `namespace` have other purposes in Ember and Ember
|
|
Data (in various places one is significant but not the other and vice versa).
|
|
Always using the term `nspace` means we avoid any strange bugs or
|
|
clashes/overwrites with anything in Ember or Ember Data core. The only place
|
|
where we use `ns` or `Namespace` is to construct API requests/responses.
|
|
Sometimes when using this term in CSS or on plain javascript objects, this may
|
|
seem unnecessary but it just helps smooth over writing code around namespaces
|
|
as you don't have the split second decision of whether you write `ns` or
|
|
`namespace` - just use `nspace` and everything will be fine :)
|