# Development This is part of the developer [getting started guide](./README.md). ## API See [APIs](../../../README.md#apis). The older Norman API is served on `/v3`. The newer Steve API (see [here](https://github.com/rancher/api-spec/blob/master/specification.md) for spec) is served on `/v1` . In both cases the schemas returned dictate - Which resources are shown - What operations (create, update, delete, etc) can be made against resource/s - What actions (archive, change password, etc) can be made against resource/s In addition the resources themselves can dictate - What actions can be made against the collection The above, plus other factors, will effect what is shown by the UI - Resources in the cluster explorer - Edit resource buttons - Delete resource - etc There are other factors that assist in this, namely values from the `type-map`. More details can be found throughout this document. > When catching exceptions thrown by anything that contacts the API use `utils/error exceptionToErrorsArray` to correctly parse the response into a commonly accepted array of errors > If you need to add an endpoint to an unauthenticated route for loading from the store before login, you will need to add it [here](https://github.com/rancher/rancher/blob/cb7de4e6c3d7e783828dc662b1142c1f9ae5edbe/pkg/multiclustermanager/routes.go#L69). ## Store State is cached locally via [Vuex](https://vuex.vuejs.org/). See the Model section for retrieving information from the store. See [README#vuex-stores](../../../README.md#what-is-it) for the basics. The most important concepts are described first i.e. the three store parts `management`, `cluster` and `rancher`. These sections contain schema information for each supported type and, per type, the resource instance and list data. Store objects are accessed in different ways, below are common ways they are referenced by models and components |Location|type|object|example| |----|----|----|----| | `/model/` | Dispatching Actions | `this.$dispatch` | `this.$dispatch('cluster/find', { type: WORKLOAD_TYPES.JOB, id: relationship.toId }, { root: true })` | `/model/` | Access getters (store type) | `this.$getters` | `this.$getters['schemaFor'](this.type)` | `/model/` | Access getters (all) | `this.$rootGetters` | `this.$rootGetters['productId']` | component | Dispatching Actions | `this.$store.dispatch` | ``this.$store.dispatch(`${ inStore }/find`, { type: row.type, id: row.id })`` | component | Access getters | `this.$store.getters` | `this.$store.getters['rancher/byId'](NORMAN.PRINCIPAL, this.value)` > Prefixing a property in a model with `$`, as per `model` rows above, results in calling properties on the store object directly. For further details on resources, proxy's and types see further below in this doc. > Troubleshooting: Fetching the name of a resource type > > Good - Trims the text and respects `.` in path to type's string - `store.getters['type-map/labelFor']({ id: NORMAN.SPOOFED.GROUP_PRINCIPAL }, 2)` > > Bad - Does not trim text, issues when resource type contains "`.`" - ``store.getters['i18n/t'](`typeLabel.${ NORMAN.SPOOFED.GROUP_PRINCIPAL }`, { count: 2 })`` ## Resources A resource is an instance of a schema e.g. the `admin` user is an instance of type `management.cattle.io.user` from the `Steve` API. ### Schemas Schemas are provided in bulk via the APIs and cached locally in the relevant store (`management`, `rancher`, etc). A schema can be fetched synchronously via store getter ``` import { POD } from '@/config/types'; this.$store.getters['cluster/schemaFor'](POD)` ``` > Troubleshooting: Cannot find new schema > > Ensure that your schema text in `/config/types.js` is singular, not plural As mentioned before a schema dictates the functionality available to that type and what is shown for the type in the UI. ### Virtual and Spoofed Resource Types The side nav is populated by resource types that have been applied to the current product. Virtual Types are a way to add additional menu items. These are purely for adding navigation and do not support tables or details views. Examples of virtual types can be found by searching for `virtualType`. For instance the `Users & Authentication` product has a virtual type of 'config' to show the `Auth Providers` page. Spoofed Types, like virtual types, add menu items but also define a spoofed schema and a `getInstances` function. The latter provides a list of objects of the spoofed type. This allows the app to then make use of the generic list, detail, edit, etc pages used for standard types. > Any resources returned by `getInstances` should have a `kind` matching required type. This results in the tables showing the correct actions, handling create/edit, etc. ### Model Architecture The ES6 class models in the `models` directory are used to represent Kubernetes resources. The class applies properties and methods to the resource, which defines how the resource can function in the UI and what other components can do with it. Different APIs return models in different structures, but the implementation of the models allows some common functionality to be available for any of them, such as `someModel.name`, `someModel.description`, `setLabels` or `setAnnotations`. Much of the reused functionality for each model is taken from the Steve plugin. The class-based models use functionality from `plugins/steve/resource-class.js`. The `Resource` class in `plugins/steve/resource-class.js` should not have any fields defined that conflict with any key ever returned by the APIs (e.g. name, description, state, etc used to be a problem). The `SteveModel` (`plugins/steve/steve-class.js`) and `NormanModel` (`plugins/steve/norman-class.js`) know how to handle those keys separately now, so the computed name/description/etc is only in the Steve implementation. It is no longer needed to use names like `_name` to avoid naming conflicts. ### Extending Models The `Resource` class in `plugins/steve/resource-class.js` is the base class for everything and should not be directly extended. (There is a proxy-based counterpart of `Resource` which is the default export from `plugins/steve/resource-instance.js` as well.) If a model needs to extend the basic functionality of a resource, it should extend one of these three models: - `NormanModel`: For a Rancher management type being loaded via the Norman API (/v3, the Rancher store). These have names, descriptions and labels at the root of the object. - `HybridModel`: This model is used for old Rancher types, such as a Project (mostly in management.cattle.io), that are loaded with the Steve API (/v1, the cluster/management stores). These have the name and description at the root, but labels under metadata. - `SteveModel`: Use this model for normal Kubernetes types such as workloads and secrets. The name, description and labels are under metadata. The Norman and Hybrid models extend the basic Resource class. The Hybrid model is extended by the Steve model. ### Create and Fetch Resource/s Most of the options to create and fetch resources can be achieved via dispatching actions defined in `/plugins/steve/actions.js` | Action| Example Command | Description | |--------|-------|-----| | Create | `$store.$dispatch('/create', )`| Creates a new Proxy object of the required type (`type` property must be included in the new object) | | Clone | `$store.$dispatch('/clone', { resource: })` | Performs a deep clone and creates a proxy from it | | Fetch all of a resource type | `$store.dispatch('/findAll', { type: })` | Fetches all resources of the given type. Also, when applicable, will register the type for automatic updates. If the type has already been fetched return the local cached list instead | | Fetch a resource by ID | `$store.dispatch('/find', { type: , id: })` | Finds the resource matching the ID. If the type has already been fetched return the local cached instance. | | Fetch resources by label | `$store.dispatch('/findMatching', { type: , selector: