Project

General

Profile

Download (3.29 KB) Statistics
| Branch: | Tag: | Revision:
[[slot-and-fill]]
# Slot And Fill
:toc: right
:toclevels: 5

Slot & Fill allows plugins to extend foreman core functionality in the UI.

## Current Slots List

You can find current slots by search which React component use the `<Slot>` component.
You can find .erb pages that use `<Slot>` component by searching for `slot` helper.


## Components

### Slot

`<Slot>` is an opinionated extension point which responsible of rendering its fills
a Slot can support multiple fills, rendering by weight order by the `multi` prop
if there is no such prop, it will render the max weighted fill.

### Fill

a fill is the filled object of a slot

#### Component fill

a fill that contains a child component, which rendered by a dedicated slot

_core_

```js
<Slot id="slot-id">
a default child // can be empty
</Slot>
```

_plugin A_

```js
<Fill slotId="slot-id" id="some-id" weight={100}>
<div> some text </div>
</Fill>
```

_plugin B_

```js
<Fill slotId="slot-id" id="some-id" weight={200}>
<div> some text </div>
</Fill>
```

Plugin B has a fill with a higher weight, therefore it will be rendered in a dedicated slot.

#### Component fill - remdering multiple fills

If a slot has a `multi` prop, and it has multiple fills, it will render these fills by weight order

_core_

```js
<Slot multi id="slot-id" />
```

_plugin A_

```js
<Fill slotId="slot-id" id="some-id" weight={100}>
<div> some text </div>
</Fill>
```

_plugin B_

```js
<Fill slotId="slot-id" id="some-id" weight={200}>
<div> some text </div>
</Fill>
```

Plugin B's fill will be render first

#### Props fill

a fill that contains an `overrideProps` object
those props are given to the slot's children

_core_

```js
const TextWrapper = ({ text }) => <div>{text}</div>;

<Slot id="slot-id">
<TextWrapper text="some default text" />
</Slot>;
```

_plugin A_

```js
<Fill
slotId="slot-id"
id="some-id"
weight={200}
overrideProps={{ text: '[Plugin A] this text given by a prop' }}
/>
```

_plugin B_

```js
<Fill
slotId="slot-id"
id="some-id"
weight={100}
overrideProps={{ text: '[Plugin B] this text given by a prop' }}
/>
```

In this case, the slot doesn't have `multi` prop, therefore it will take the max weight which is Plugin A's fill.

#### Global fill

This fill is available on each and every core page
A plugin should use global fills when it doesn't have access to that area (i.e adding a component in the about page)
If a plugin wants to extend foreman's layout, or whether it has a partial in a core page via facets, a regular fill is enough.

create a `fills_index.js` file under webpack directory:

```js
import React from 'react';
import SomeComponent from './components/SomeComponent';
import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';

// if some of the components are connected to redux, registering a reducer is required
registerReducer('[plugin]-extends', extendReducer);

addGlobalFill('slotId', 'fillId', <SomeComponent key="some-key" />, 300);
// instead of a component, you can also override props
addGlobalFill(
'slotId',
'fillId',
{ someProp: 'this is an override prop' },
300
);
```

Register `fills` global file in `plugin.rb` file:

```ruby
Foreman::Plugin.register :<plugin> do
# content
register_global_file 'fills'
end
```

Finally, add a slot in foreman core:

```ruby
<%= slot('slotId', true) %>
```
(19-19/21)