Commit b0005ed0 authored by Vladimir Erokhov's avatar Vladimir Erokhov

Merged develop into feature/remove-unused-entities

parents 73b05690 3785365b
Pipeline #4461 passed with stage
in 2 minutes and 2 seconds
# Authentification
- [LDAP](#ldap)
To do
- [SAML2](#saml2)
- [Paramétrage ldP](#paramétrage-idp)
- [Création du paramètrage côté Canopsis](#création-du-paramétrage-côté-canopsis)
- [Intégration des paramètres en base](#intégration-des-paramètres-en-base)
- [Activation de l'authentification SAML2](#activation-de-lauthentification-saml2)
- [Test et logs](#tests-et-log)
- [troubleshooting](#troubleshooting)
- [Troubleshooting](#troubleshooting)
## LDAP
!!! attention
Les fonctionnalités liées à LDAP sont en cours de développement. Toutes les fonctionnalités d'LDAP ne sont pas encore implémentées.
L'authentification LDAP est actuellement fonctionnelle et est basée sur [python-ldap](https://python-ldap.readthedocs.io) qui utilise la *libldap* du projet [OpenLDAP](http://www.openldap.org/).
Canopsis utilise la version 3 du protocole LDAP.
Sa configuration par l'interface web n'est pas prise en charge pour le moment.
Les fonctionnalités actuellement implémentées permettent l'authentification des utilisateurs sur n'importe quel annuaire LDAP, tant que celui-ci respecte la [RFC4510](https://tools.ietf.org/html/rfc4510) et ses déclinaisons.
## SAML2
......
# connector-centreon-engine : module (Event Broker) Centreon pour Canopsis
!!! note
Ce module est maintenant disponible dans l'édition open-source de Canopsis.
## Description
Ce dépôt contient un module Broker Centreon pour l'envoi d'évènements à Canopsis. Il est écrit en C++, et des modules pré-compilés sont disponibles pour certains environnements.
Le connecteur `connector-centreon-engine` est un module Broker permettant l'envoi d'évènements de Centreon vers Canopsis. Il est écrit en C++, et des modules pré-compilés sont disponibles pour certains environnements. Ce module est open-source et disponible sous la licence Apache 2.0.
Ce module vient s'ajouter dans une instance Centreon existante, et doit ensuite être configuré depuis l'interface web de Centreon afin de rediriger le trafic vers Canopsis.
**Pré-requis réseau :** la transmission de flux réseau doit être permise entre Centreon et Canopsis (port 5672 par défaut).
!!! attention
**Pré-requis réseau :** la transmission de flux réseau doit être permise entre Centreon et l'instance RabbitMQ de Canopsis (port TCP `5672` par défaut).
## Installation
!!! note
Toutes les manipulations suivantes doivent être réalisées sur le nœud Centreon que vous souhaitez relier à Canopsis.
## Installation d'un module pré-compilé
### Récupération du connecteur
### Récupération du module
Vous devez récupérer la dernière version du connecteur, disponible à l'adresse suivante : https://git.canopsis.net/canopsis-connectors/connector-centreon-engine.
Clôner le dépôt Git contenant le module (**note :** activer votre proxy HTTP si nécessaire) :
```shell
# Installation de Git sur Debian / Ubuntu
$ sudo apt-get install git-core
# Installation de Git sur Red Hat / CentOS
$ sudo yum install git-core
Vous pouvez pour cela cloner le dépôt Git, ou lancer la commande suivante pour récupérer une archive :
# Clône du dépôt
$ git clone https://VOTRE-UTILISATEUR-GITLAB-ICI@git.canopsis.net/canopsis-connectors/connector-centreon-engine.git
$ cd connector-centreon-engine
```sh
wget https://git.canopsis.net/canopsis-connectors/connector-centreon-engine/-/archive/master/connector-centreon-engine-master.tar.bz2 && tar xjf connector-centreon-engine-master.tar.bz2
```
### Installation du module
Le reste de cette procédure part du principe que vous disposez de ce contenu dans un répertoire `connector-centreon-engine*/`.
Il faut ensuite installer deux composants : le module `.so` et l'extension web.
### Installation du module `.so`
Des modules pré-compilés sont disponibles dans le répertoire `precompiled/` de ce dépôt Git.
Il faut, pour cela, connaître votre environnement (CentOS 6, CentOS 7…) et votre version du Centreon Broker sur le système cible :
```shell
$ cat /etc/centos-release
```sh
cat /etc/centos-release
CentOS Linux release 7.4.1708 (Core)
$ cbd -v
cbd -v
[1513786864] info: Centreon Broker 3.0.11
```
Dans cet exemple, on est sur une CentOS 7 avec un Centreon Broker (CBD) 3.0.11. Le module qui nous intéresse est donc `precompiled/Centos7/85-amqp-cbd-3.0.11.so`.
Il faut ensuite l'envoyer dans le répertoire d'installation des modules Centreon (attention : le nom `85-amqp.so` est attendu en destination) :
```shell
```sh
# À adapter en fonction du système cible !
$ sudo cp precompiled/Centos7/85-amqp-cbd-3.0.11.so /usr/share/centreon/lib/centreon-broker/85-amqp.so
sudo cp precompiled/Centos7/85-amqp-cbd-[VOTRE-VERSION-CBD-ICI].so /usr/share/centreon/lib/centreon-broker/85-amqp.so
```
### Installation de l'extension web
Il faut ensuite ajouter l'extension `centreon-extension/connector-centreon-canopsis` présente dans ce dépôt Git dans l'installation Centreon, afin de pouvoir finaliser l'installation du module.
Il faut ensuite ajouter l'extension `centreon-extension/connector-centreon-canopsis` sur le nœud Centreon, afin de pouvoir finaliser l'installation du module.
```shell
$ sudo cp -r centreon-extension/connector-centreon-canopsis/ /usr/share/centreon/www/modules/
$ sudo chown -R apache:apache /usr/share/centreon/www/modules/connector-centreon-canopsis/
```sh
sudo cp -r centreon-extension/connector-centreon-canopsis/ /usr/share/centreon/www/modules/
sudo chown -R apache:apache /usr/share/centreon/www/modules/connector-centreon-canopsis
```
On peut alors installer le module depuis les menus suivants de l'interface web Centreon (Administration > Extensions > Modules > connector-centreon-canopsis et cliquer sur le bouton Action, sur la droite du tableau) :
Il faut ensuite installer ce module depuis les menus suivants de l'interface web Centreon (Administration > Extensions > Modules > connector-centreon-canopsis et cliquer sur le bouton Action, sur la droite du tableau) :
![Installation du module depuis l'interface web : étape 1](img/webextension_install.png)
......@@ -61,12 +71,12 @@ Puis, valider l'installation de ce module en cliquant sur « Install Module » 
![Installation du module depuis l'interface web : étape 2](img/webextension_install2.png)
Le module est maintenant installé, mais vous devez obligatoirement le configurer.
## Configuration du module
### Configuration
**Attention :** la transmission de flux réseau entre Centreon et Canopsis doit être permise sur vos équipements réseau (port 5672 par défaut, à ajuster en fonction de votre configuration Canopsis/Centreon).
Aller dans Configuration > Pollers > Broker Configuration > central-broker-master.
![Configuration du module AMQP Canopsis : étape 1](img/module_parameters.png)
......@@ -75,20 +85,25 @@ Puis, dans la nouvelle page qui apparaît, aller dans l'onglet Output, choisir l
![Configuration du module AMQP Canopsis : étape 2](img/module_parameters2.png)
Des options de configuration « Canopsis AMQP bus » apparaissent alors en bas de page. Il faut alors renseigner les informations de connexion à l'instance AMQP Canopsis voulue (adresse, port, identifiants, nom de l'Exchange et du Virtual Host...). Valider ces changements avec le bouton « Save ».
Des options de configuration « Canopsis AMQP bus » apparaissent alors en bas de page. Il faut alors renseigner les informations de connexion à l'instance RabbitMQ de Canopsis (adresse, port, identifiants, nom de l'Exchange et du Virtual Host...). Valider ces changements avec le bouton « Save ».
![Configuration du module AMQP Canopsis : étape 3](img/module_parameters3.png)
### Redémarrage
### Redémarrage obligatoire pour charger la configuration
!!! attention
**Attention :** les redémarrages suivants occasionnent une interruption de service le temps du redémarrage du Broker et des Engines Centron.
On redémarre ensuite le service pour s'assurer du bon chargement de la nouvelle configuration.
**Attention :** les redémarrages suivants occasionnent une interruption de service le temps du redémarrage du Broker et des Engines Centron.
Cette étape est **OBLIGATOIRE**, votre connecteur Centreon ne fonctionnera **PAS** dans Canopsis tant que vous n'effectuerez pas cette procédure de redémarrage.
On redémarre ensuite le service pour s'assurer du bon chargement de la nouvelle configuration. Pour cela, aller dans Configuration > Pollers > cocher les éléments concernés > cliquer sur « Export configuration ».
Pour cela, aller dans Configuration > Pollers > cocher les éléments concernés > cliquer sur « Export configuration ».
![Redémarrage du service : étape 1](img/module_restart1.png)
Sur la nouvelle page qui s'affiche, il faut ensuite cocher les cases « Move Export Files » et « Restart Monitoring Engine », puis choisir la méthode « Restart » dans le menu déroulant, et enfin cliquer sur le bouton « Export ».
![Redémarrage du service : étape 2](img/module_restart1.png)
![Redémarrage du service : étape 2](img/module_restart2.png)
**ATTENTION :** Il faut bien faire un `restart` et non pas un simple `reload` ! Sans quoi vous risquez des problèmes de cohérence sur les évènements échangés avec Canopsis.
......@@ -14,7 +14,8 @@
### Guide exploitant
1. [Paramètres du widget](#parametres-du-widget)
1. [Aide sur les variables](#aide-variables)
2. [Paramètres du widget](#parametres-du-widget)
## Guide utilisateur
......@@ -72,7 +73,7 @@ Le filtre par période permet de filtre les alarmes en ne conservant que les ala
Ce filtre est disponible en cliquant sur l'icone ![Filtre par période](./img/period-filter.png "Filtre par période") présente à droite du sélecteur de filtre. Une fenêtre apparaît.
![Modal filtre par période](./img/modal-filtre-periode.png "Modal filtre par période")
![modale filtre par période](./img/modal-filtre-periode.png "modale filtre par période")
Il suffit alors de sélectionner la période souhaitée parmi les périodes prédéfinies, ou d'en créer une personalisé en sélectionnant 'Personnalisé', puis en renseignant les dates de début et de fin.
Cliquez ensuite sur 'Appliquer'.
......@@ -98,6 +99,20 @@ Le choix par défaut est réglable dans les paramètres du bac à alarmes (*Cf:
## Guide exploitant
### Aide - Variables
Durant la configuration de votre widget Bac à alarmes, notamment paramètres "Info popup", et "Fenêtre Plus d'infos", il vous sera possible d'accéder à des variables concernant les alarmes et les entités.
Exemple: Il vous sera possible d'afficher, dans la fenêtre "Plus d'infos", l'état de l'alarme.
Afin de connaitre les variables disponibles, une modale d'aide est disponible.
Pour y accèder, entrez dans le mode d'édition (*Cf: [Vues - Mode d'édition](../../vues#mode-edition)*).
Un bouton d'action supplémentaire "Liste des variables disponibles" apparaît alors pour chaque alarme.
Au clic sur ce bouton, une fenêtre s'ouvre. Celle-ci liste toutes les variables disponibles dans vos différents paramètres. Un bouton, à droite de chacune des variables, vous permet de copier directement dans le Presse-papier le chemin de cette variable.
### Paramètres du widget
1. Taille du widget
......@@ -152,12 +167,12 @@ Ce paramètre permet de définir quels colonnes seront affichées dans le bac à
Afin d'**ajouter une colonne**, cliquez sur le bouton 'Ajouter'.
Une colonne vide est alors ajoutée. Afin de finaliser l'ajout, il est nécessaire de remplir les champs demandés.
Le champ "Label" définit le nom de la colonne, qui sera affiché en haut de tableau. Le champ "Valeur" définit la valeur que doit prendre ce champ. Tous les champs de l'alarme et de l'entité concernée par l'alarme peuvent être utilisés, en préfixant le nom du champ par "alarm" ou "entity".
Le champ "Label" définit le nom de la colonne, qui sera affiché en haut de tableau. Le champ "Valeur" définit la valeur que doit prendre ce champ. Tous les champs de l'alarme et de l'entité concernée par l'alarme peuvent être utilisés.
Exemple : Pour ajouter une colonne ayant pour label "Composant" et pour valeur le nom du composant, renseignez les champs comme suit :
* Label : "Composant"
* Valeur : "alarm.component"
* Valeur : "alarm.v.component"
Pour supprimer une colonne, cliquez dans la liste des colonnes sur la croix rouge présente en haut à droite de la case de la colonne que vous souhaitez effacer.
......@@ -202,8 +217,8 @@ Une case info popup vide apparaît.
Cette case comporte deux champs :
* Colonne : Ce champ permet de définir sur quelle colonne l'info popup sera disponible. Il faut ici entrer la **valeur** de la colonne, et non son nom.
Exemple : pour ajouter une info popup sur la colonne que vous avez nommée "Connecteur", avec comme valeur "v.connector" (*Cf: [Paramètre "Nom des colonnes"](#nom-des-colonnes)*), il faut entrer ici "v.connector" et non "Connecteur".
* Texte : Ce champ, qui a la forme d'un éditeur de texte, permet de définir le contenu de l'info popup. Le langage utilisé ici pour le template de la popup est l'Handlebar. Deux variables sont disponibles : "alarm" et "entity". Exemple : Pour ajouter au template l'état de l'alarme, ajoutez au template `{{ alarm.state.val }}`.
Exemple : pour ajouter une info popup sur la colonne que vous avez nommée "Connecteur", avec comme valeur "alarm.v.connector" (*Cf: [Paramètre "Nom des colonnes"](#nom-des-colonnes)*), il faut entrer ici "alarm.v.connector" et non "Connecteur".
* Texte : Ce champ, qui a la forme d'un éditeur de texte, permet de définir le contenu de l'info popup. Le langage utilisé ici pour le template de la popup est l'Handlebar. Deux variables sont disponibles : "alarm" et "entity". Exemple : Pour ajouter au template l'état de l'alarme, ajoutez au template `{{ alarm.v.state.val }}`.
Vous pouvez ajouter autant d'info popup que vous le souhaitez.
......@@ -219,4 +234,4 @@ Deux variables sont disponibles ici, 'alarm' et 'entity'.
En plus du texte que vous souhaitez afficher, il vous est donc possible d'intégrer des informations de l'alarme ou de l'entité concernée par cette alarme.
Exemple : Pour afficher l'état de l'alarme, ajoutez `{{ alarm.state.val }}`.
Exemple : Pour afficher l'état de l'alarme, ajoutez `{{ alarm.v.state.val }}`.
......@@ -14,7 +14,8 @@
6. [Comportements périodiques](#comportements-periodiques)
### Guide exploitant
1. [Paramètres du widget](#parametres-du-widget)
1. [Aide sur les variables](#aide-variables)
2. [Paramètres du widget](#parametres-du-widget)
## Guide utilisateur
......@@ -132,6 +133,18 @@ Pour ajouter un comportement périodique sur une sélection d'entités, sélecti
## Guide exploitant
### Aide - Variables
Durant la configuration de votre widget Exporateur de contexte, notamment la liste des colonnes, il vous sera possible d'accéder à des variables concernant les entités.
Afin de connaitre les variables disponibles, une modale d'aide est disponible.
Pour y accéder, entrez dans le mode d'édition (*Cf: [Vues - Mode d'édition](../../vues#mode-edition)*).
Un bouton d'action supplémentaire "Liste des variables disponibles" apparaît alors pour chaque entité du tableau.
Au clic sur ce bouton, une fenêtre s'ouvre. Celle-ci liste toutes les variables disponibles dans vos différents paramètres. Un bouton, à droite de chacune des variables, vous permet de copier directement dans le Presse-papier le chemin de cette variable.
### Paramètres du widget
1. Taille du widget
......
{
"plugins": [
"lodash"
],
"presets": [
"@vue/app"
]
}
\ No newline at end of file
}
......@@ -5,3 +5,5 @@ VUE_APP_POPUP_AUTO_CLOSE_DELAY=3000
VUE_APP_PAGINATION_LIMIT=10
VUE_APP_COOKIE_SESSION_KEY=beaker.session.id
BUNDLE_ANALYZER_MODE=disabled # disabled / server / static
......@@ -38,6 +38,7 @@
"vue-i18n": "^7.6.0",
"vue-mq": "^0.2.1",
"vue-quill-editor": "^3.0.6",
"vue-resize-text": "^0.1.0",
"vue-router": "^3.0.1",
"vuedraggable": "^2.17.0",
"vuetify": "^1.3.15",
......@@ -53,6 +54,7 @@
"@vue/test-utils": "^1.0.0-beta.10",
"babel-core": "^7.0.0-0",
"babel-jest": "^22.0.4",
"babel-plugin-lodash": "^3.3.4",
"husky": "^1.3.1",
"jest-localstorage-mock": "^2.2.0",
"lint-staged": "^6.0.0",
......@@ -63,6 +65,7 @@
"sass-loader": "^6.0.6",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.2",
"vue-cli-plugin-webpack-bundle-analyzer": "^1.2.0",
"vue-template-compiler": "^2.5.21"
},
"browserslist": [
......
......@@ -32,7 +32,7 @@
r-rule-form(@input="changeRRule")
v-layout(row)
v-combobox(
label="Reason",
:label="$t('modals.createPbehavior.fields.reason')",
v-model="form.reason",
:items="selectItems.reasons",
:error-messages="errors.collect('reason')",
......@@ -41,13 +41,18 @@
)
v-layout(row)
v-select(
label="Type",
:label="$t('modals.createPbehavior.fields.type')",
v-model="form.type_",
:items="selectItems.types",
:error-messages="errors.collect('type')",
name="type",
v-validate="'required'"
)
v-layout(row)
v-textarea(
:label="$t('modals.createPbehavior.fields.comment')",
v-model="commentMessage",
)
v-layout(row)
v-alert(:value="serverError", type="error")
span {{ serverError }}
......@@ -88,6 +93,7 @@ export default {
data() {
return {
rRuleObject: null,
commentMessage: '',
form: {
name: '',
tstart: new Date(),
......@@ -141,6 +147,13 @@ export default {
data.rrule = this.rRuleObject.toString();
}
if (this.commentMessage !== '') {
data.comments = [{
author: this.currentUser.crecord_name,
message: this.commentMessage,
}];
}
this.$emit('submit', data);
}
},
......
......@@ -172,8 +172,7 @@
<script>
import RRule from 'rrule';
import mapValues from 'lodash/mapValues';
import pickBy from 'lodash/pickBy';
import { mapValues, pickBy } from 'lodash';
import DateTimePicker from '@/components/forms/fields/date-time-picker.vue';
......
......@@ -49,23 +49,14 @@
v-layout(justify-space-between)
span.black--text {{ $t('common.parameters') }}
v-icon settings
v-menu(bottom, offset-y)
v-menu(bottom, offset-y, offset-x)
v-btn.white--text(slot="activator", flat) {{ currentUser._id }}
v-list.pb-0
v-list-tile
v-list-tile-title
v-layout
div {{ $t('user.firstName') }} :
div.px-1(v-if="currentUser.firstname") {{ currentUser.firstname }}
div.px-1.font-italic(v-else) {{ $t('common.undefined') }}
v-divider
v-list-tile
v-list-tile-title
v-layout
div {{ $t('user.lastName') }} :
div.px-1(v-if="currentUser.lastname") {{ currentUser.lastname }}
div.px-1.font-italic(v-else) {{ $t('common.undefined') }}
v-divider
template(v-if="currentUser.firstname && currentUser.lastname")
v-list-tile
v-list-tile-title
p {{ currentUser.firstname }} {{ currentUser.lastname }}
v-divider
v-list-tile
v-list-tile-title
v-layout
......@@ -81,14 +72,14 @@
div.px-1 {{ defaultViewTitle }}
v-flex(v-else)
div.px-1.font-italic {{ $t('common.undefined') }}
v-btn.primary(@click.stop="editDefaultView", small, fab, depressed)
v-btn(@click.stop="editDefaultView", small, fab, icon, depressed)
v-icon edit
v-divider
v-list-tile.error.white--text(@click.prevent="logout")
v-list-tile(@click.prevent="logout")
v-list-tile-title
v-layout(align-center)
div {{ $t('common.logout') }}
v-icon.pl-1.white--text exit_to_app
div.error--text {{ $t('common.logout') }}
v-icon.pl-1(color="error") exit_to_app
template(v-if="isShownGroupsTopBar", slot="extension")
groups-top-bar
</template>
......
......@@ -39,7 +39,7 @@ v-card
</template>
<script>
import pick from 'lodash/pick';
import { pick } from 'lodash';
import { MODALS } from '@/constants';
......
......@@ -72,8 +72,7 @@
<script>
import sha1 from 'sha1';
import omit from 'lodash/omit';
import pick from 'lodash/pick';
import { omit, pick } from 'lodash';
import { MODALS } from '@/constants';
......
......@@ -26,7 +26,7 @@
</template>
<script>
import find from 'lodash/find';
import { find } from 'lodash';
import { MODALS } from '@/constants';
......
......@@ -25,7 +25,7 @@
</template>
<script>
import pick from 'lodash/pick';
import { pick } from 'lodash';
import { MODALS } from '@/constants';
......
......@@ -16,8 +16,7 @@
</template>
<script>
import union from 'lodash/union';
import filter from 'lodash/filter';
import { union, filter } from 'lodash';
import ContextGeneralList from '@/components/other/context/context-general-list.vue';
......
......@@ -25,7 +25,7 @@
</template>
<script>
import omit from 'lodash/omit';
import { omit } from 'lodash';
import { MODALS } from '@/constants';
......
......@@ -33,7 +33,7 @@
</template>
<script>
import cloneDeep from 'lodash/cloneDeep';
import { cloneDeep } from 'lodash';
import { MODALS, EVENT_FILTER_RULE_TYPES, EVENT_FILTER_ENRICHMENT_RULE_AFTER_TYPES } from '@/constants';
import modalInnerMixin from '@/mixins/modal/inner';
......
......@@ -50,8 +50,7 @@
<script>
import Draggable from 'vuedraggable';
import cloneDeep from 'lodash/cloneDeep';
import pick from 'lodash/pick';
import { cloneDeep, pick } from 'lodash';
import { MODALS, EVENT_FILTER_ENRICHMENT_ACTIONS_TYPES } from '@/constants';
......
......@@ -18,7 +18,7 @@
</template>
<script>
import cloneDeep from 'lodash/cloneDeep';
import { cloneDeep } from 'lodash';
import { MODALS } from '@/constants';
......
......@@ -111,6 +111,7 @@ export default {
[MODALS.createWidget]: { maxWidth: 500, lazy: true },
[MODALS.alarmsList]: { fullscreen: true, lazy: true },
[MODALS.createFilter]: { maxWidth: 920, lazy: true },
[MODALS.watcher]: { maxWidth: 920, lazy: true },
},
defaultDialogProps: { maxWidth: 700, lazy: true },
};
......
......@@ -19,7 +19,7 @@
</template>
<script>
import get from 'lodash/get';
import { get } from 'lodash';
import { MODALS } from '@/constants';
......
......@@ -69,8 +69,7 @@
</template>
<script>
import find from 'lodash/find';
import omit from 'lodash/omit';
import { find, omit } from 'lodash';
import { MODALS, USERS_RIGHTS_TYPES, USERS_RIGHTS_MASKS } from '@/constants';
import { generateView, generateViewRow, generateRight, generateRoleRightByChecksum } from '@/helpers/entities';
......@@ -236,10 +235,10 @@ export default {
this.fetchGroupsList(),
]);
this.addSuccessPopup({ text: this.$t('modals.view.success') });
this.addSuccessPopup({ text: this.$t('modals.view.success.delete') });
this.hideModal();
} catch (err) {
this.addErrorPopup({ text: this.$t('modals.view.fail') });
this.addErrorPopup({ text: this.$t('modals.view.fail.delete') });
}
},
},
......
<template lang="pug">
.weather-watcher-entity-expansion-panel
v-expansion-panel
v-expansion-panel-content(hide-actions)
v-layout.pa-2(slot="header", :class="entityClass", justify-space-between)
span.pl-1.white--text.subheading.entity-title {{ entity | get(entityNameField, false, entityNameField) }}
v-layout(justify-end)
div(v-for="action in availableActions", :key="action.name")
v-btn.secondary(
@click.stop="action.action(action.name)",
:disabled="!isActionBtnEnable(action.name)",
small,
fab,
depressed
)
v-icon {{ action.icon }}
v-card
v-expansion-panel(dark)
v-expansion-panel-content(:style="{ backgroundColor: color }")
v-layout(slot="header", justify-space-between, align-center)
v-flex.pa-2(v-for="(icon, index) in mainIcons", :key="index")
v-icon(color="white", small) {{ icon }}
v-flex.pl-1.white--text.subheading.entity-title(
xs12,
)
v-layout(align-center)
div.mr-1.entityName(
v-resize-text="{maxFontSize: '16px'}",
) {{ { entity } | get(entityNameField, false, entityNameField) }}
v-btn.mx-1.white(v-for="icon in extraIcons", :key="icon.icon", :color="icon.color", small, dark, icon)
v-icon(small) {{ icon.icon }}
v-card(color="white black--text")
v-card-text
v-layout(row, align-center)