Рутовое приложение
Меню

menu.json

Общее описание

Меню представляет собой массив элементовQNavItem(из библиотеки@diasoft/qpalette-visual). QNavItem - это пункт меню, которые бывают двух типов: Endpoint и Group. По аналогии с файлами и папками: Endpoint (или "файл") представляет собой ссылку на проект, Group - это раскрывающийся пункт меню, содержащий список этих "файлов".

Endpoint

  • caption * - отображаемое имя
  • service * - название сервиса, в котором находится этот веб-компонент
  • component * - название веб-компонента
  • route - маршрут, который нужно будет открыть после загрузки этого пункта меню
  • link - URL-адрес, открывающийся в новой вкладке браузера по клику в меню
  • default - если true, то откроется при старте приложения. Обратите внимание, что невозможно закрыть вкладку с этим флагом
  • icon - иконка для <q-icon>
  • showIconInMenu - отображение иконки у пункта меню (по умолчанию: true)
  • permissions - права доступа к этому пункту меню

Group

  • caption * - отображаемое имя
  • items * - массив пунктов меню
  • description - описание под пунктом меню
  • expanded - если true, то по умолчанию группа будет раскрыта
  • isGroup - опция только для верхнеуровневой группы, позволяющая скрыть (false) заголовок группы в сайдбаре
  • dynamicItemsUrl - URL, по которому будет загружаться список пунктов меню

* - обязательные поля

Создание собственного меню

Доступно использование собственной IDE для создания меню. Для этого необходимо создать TypeScript-файл и импортироватьQNavItemиз@diasoft/qpalette-visual.

import { QNavItem } from '@diasoft/qpalette-visual';
 
const menu: QNavItem[] = {
  // Автодополнение поможет вам собрать собственное меню
};
 
console.log(JSON.stringify(menu, null, 2)); // Отобразит готовый JSON

Динамическое меню

При желании, можно загрузить список пунктов меню с помощью HTTP-запроса. Для этого необходимо установитьdynamicItemsUrl в группе меню.

В случае ошибках запроса или валидации меню, в консоли будут выведены сообщения о конкретных проблемах, а в самой группе – лишь краткое пояснение (для пользователя). Например:

dynamic-menu-error.png

При этом в консоли будут выведены сообщения о конкретных проблемах:

dynamic-menu-console-errors.png

Права доступа к пункту меню

По умолчанию пункты меню доступны всем. Ограничение доступа определяется блокомpermissionsв пункте меню.

При проверке прав доступа к пунктам меню отрабатывает следующая последовательность:

  • Проверяется блок условий "deny": если для пользователя было найдено совпадение по блоку "deny", то доступ запрещен и дальнейшая обработка прекращается.
  • Если совпадений по блоку "deny" нет, то выполняется проверка блока "allow".
  • В каждом блоке могут быть описаны стратегии поиска совпадений по условиям "ИЛИ" / "И". Стратегия поиска может быть представлена массивом или объектом.
  • Блок правил может включать в себя одно или несколько условий доступа к пункту меню

Рассмотрим на примере:

[
  {
    "caption": "Админка",
    "permissions": {
      "allow": {
        "or": [ // внешний блок and/or показывает стратегию поиска правил. or -- совпадение хотя бы по одному, and -- совпадение по всем
          {
            "or": { // внутренний блок and/or влияет на совпадение по значениям блока прав
              "departments": ["Branch01", "HO"], // в данном случае, пользователи, принадлежащие любой из групп блока прав, получат доступ
              "roles": ["admin", "moderator"],
              "userGroups": ["Group01"]
            }
          },
          {
            "or": { // внутренний блок and/or влияет на совпадение по значениям блока прав
              "users": ["nmarkelov"]
            }
          }
        ] // всё вышеописанное правило говорит, что любой пользователь, принадлежащий одному из описанных департаментов ИЛИ одной из ролей ИЛИ одной из групп ИЛИ nmarkelov имеют доступ к этому пункту меню
      },
      "deny": {
        "or": { // в этом случае, если пользователь принадлежит хотя бы одной из групп блока прав, в доступе ему будет отказано
          "departments": ["Branch02", "Branch03"],
          "roles": ["manager", "guest"],
          "userGroups": ["Group04"]
        }
      }
    },
    "items": [
      {
        "caption": "dqqbpmdesignerweb",
        "service": "dqqbpmdesignerservice",
        "component": "dqqbpmdesigner",
        "permissions": {
          "deny": {
            "or": {
              "users": ["ivinogradov"] // доступ к этому пункту будет ограничен только у ivinogradov
            }
          }
        }
      },
      {
        "caption": "dqqbpmcockpitweb",
        "service": "dqqbpmdesignerservice",
        "component": "dqqbpmdesigner",
        "permissions": {
          "allow": {
            "or": {
              "users": ["ivinogradov"] // а этот пункт наоборот увидит только ivingoradov
            }
          }
        }
      }
    ]
  },
  {
    "caption": "Админка",
    "permissions": {
      "allow": {
        "or": [
          {
            "and": { // здесь использована стратегия AND, что означает, что доступ получат только те пользователи, которые находятся в департаменте Branch01 И принадлежат группе Group01
              "departments": ["Branch01"],
              "userGroups": ["Group01"]
            }
          }
        ]
      },
      "deny": {
        "or": { // пользователи, принадлежащие ходя бы одному из представленных департаментов/ролей/групп, не получат доступ к пункту
          "departments": ["Branch02", "Branch03"],
          "roles": ["manager", "guest"],
          "userGroups": ["Group04"]
        }
      }
    },
    "items": [
      {
        "caption": "dqqbpmdesignerweb",
        "service": "dqqbpmdesignerservice",
        "component": "dqqbpmdesigner",
        "permissions": {
          "deny": {
            "or": {
              "users": ["ivinogradov"] // этот пользователь не получит доступ к пункту меню
            }
          }
        }
      }
    ]
  }
]

Разграничение доступа к пунктам меню по модели RBAC или ABAC

💡

Для использования этой возможности необходимо подключить модуль прав.

Если модуль прав подключен, то пункты меню можно разграничивать с помощью поля can:

[
  {
    "caption": "Item 1",
    "items": [],
    "permissions": { "allow": { "or": { "can": ["create", "message"] } } }
  },
  {
    "caption": "Item 2",
    "items": [],
    "permissions": { "allow": { "or": { "can": ["create", ["message", "messageservice"]] } } }
  },
  {
    "caption": "Item 3",
    "items": [],
    "permissions": { "allow": { "or": { "can": ["delete", "message"] } } }
  },
  {
    "caption": "Item 4",
    "items": [],
    "permissions": { "deny": { "or": { "can": ["create", "message"] } } }
  }
]

Блок can имеет следующие правила построения:

  • В случае, если используется режим разграничения RBAC, блок can - это массив, в котором первым элементом является действие, вторым - URL микросервиса.
  • В случае, если используется режим разграничения ABAC, блок can - это массив, в котором первым элементом является действие, вторым - массив вида: [имя объекта, имя сервиса].

Правила применения allow/deny и and/or при этом остаются теми же, что и в стандартном режиме.

Развертывание

Файл меню упаковывается в UI-Микросервис. При старте микросервиса происходит наполнение БД UI микросервиса и заполняются данные в соответствии со структурой меню, описанной в JSON-файле. Для отображения меню в интерфейсе микросервис предоставляет API для получения пунктов меню в соответствии с правами пользователя.

Необходимо поддержать режим разработки, при котором проверка прав не выполняется.

Пример меню

[
  {
    "caption": "Платформа",
    "items": [
      {
        "caption": "Группа",
        "expanded": true,
        "icon": "pi-book",
        "items": [
          {
            "caption": "Пункт 1",
            "service": "my-service",
            "component": "my-component",
            "route": "",
            "icon": "pi-paperclip",
            "default": true
          },
          {
            "caption": "Пункт 2",
            "service": "my-service",
            "component": "my-component",
            "route": "some/route",
            "icon": "pi-home",
            "permissions": {
              "allow": {
                "or": [
                  {
                    "roles": [
                      "manager"
                    ]
                  }
                ]
              }
            }
          }
        ]
      }
    ]
  }
]