Definiowanie niestandardowych aplikacji w Panelu Sterowania Liferay

Techniczny przewodnik obejmujący wszystkie scenariusze dodawania niestandardowych aplikacji do Panelu Sterowania Liferay: niestandardowe kategorie, własne portlety i Client Extensions w customowych kategoriach oraz kategorie root z integracją Objects.

Wprowadzenie

Ten artykuł jest skierowany do programistów, którzy chcą dodać niestandardowe aplikacje do Panelu Sterowania Liferay. Wiedza na ten temat jest obecnie rozproszona po różnych blogach (na różnych stronach internetowych), a niektóre scenariusze nie są w ogóle udokumentowane. Tutaj zbieram wszystkie przypadki związane z definiowaniem niestandardowych aplikacji w Panelu Sterowania w jednym miejscu.

Omówimy cztery scenariusze:

  1. Niestandardowa kategoria w Panelu Sterowania
  2. Portlet w Panelu Sterowania
  3. Client Extension w Panelu Sterowania
  4. Całkowicie niestandardowa kategoria "root" - czyli obok np. domyślnego "Control Panel" (wraz z integracją z konfiguracją obiektów)

Powodem, dla którego zdecydowałem się napisać ten artykuł jest to, że mimo iż dość często używam niestandardowych kategorii, natknąłem się na problem z ostatniego punktu: jak stworzyć niestandardową "root" kategorię z własnymi kategoriami i sprawić, by były widoczne w konfiguracji definicji obiektów. Niestety nie udało mi się znaleźć dokumentacji ani odpowiedzi w Google, więc musiałem zajrzeć do kodu Liferay.

Aby zaoszczędzić Ci czasu postaram się opisać wszystkie scenariusze w tym artykule.

Wymagania wstępne

Ten przewodnik zakłada, że masz doświadczenie z tworzeniem modułów Liferay i podstawową znajomość OSGi. Kod został przetestowany z Liferay 7.4.

1. Niestandardowa kategoria w istniejącej kategorii Panelu Sterowania

Pierwszy scenariusz dotyczy sytuacji, gdy chcesz dodać podkategorię w istniejącej kategorii Panelu Sterowania (np. "Control Panel" lub "Applications").

Aby tego dokonać musisz zaimplementować PanelCategory lub rozszerzyć klasę BasePanelCategory (co jest wygodniejsze i zalecam takie podejście):

@Component(
        property = {
                "panel.category.key=" + PanelCategoryKeys.CONTROL_PANEL,
                "panel.category.order:Integer=100"
        },
        service = PanelCategory.class
)
public class InnRayCustomAppsPanelCategory extends BasePanelCategory {
    @Override
    public String getKey() {
        return PanelCategoryKeys.CONTROL_PANEL + ".innray";
    }

    @Override
    public String getLabel(Locale locale) {
        return "InnRay";
    }

    @Override
    public boolean isShow(PermissionChecker permissionChecker, Group group)
            throws PortalException {
        return super.isShow(permissionChecker, group);
    }
}

Właściwość panel.category.key definiuje kategorię nadrzędną, w której pojawi się ta kategoria. Dla istniejących kategorii Panelu Sterowania możesz użyć kluczy zdefiniowanych w PanelCategoryKeys.class. Na przykład:

  • PanelCategoryKeys.CONTROL_PANEL - bezpośrednio pod Panelem Sterowania
  • PanelCategoryKeys.APPLICATIONS_MENU_APPLICATIONS - pod Aplikacjami

Za pomocą panel.category.order:Integer możesz zdefiniować kolejność kategorii w Panelu Sterowania.

2. Niestandardowa aplikacja w kategorii panelu

Gdy masz już kategorię (istniejącą lub niestandardową), możesz dodać do niej swój niestandardowy Portlet używając interfejsu PanelApp lub klasy BasePanelApp:

@Component(
        property = {
                "panel.app.order:Integer=100",
                "panel.category.key=" + PanelCategoryKeys.CONTROL_PANEL + ".innray"
        },
        service = PanelApp.class
)
public class MyCustomPanelApp extends BasePanelApp {
    @Override
    public String getPortletId() {
        return InnRayPortletKeys.INNRAY_CUSTOM_PORTLET;
    }

    @Override
    public Portlet getPortlet() {
        return _portlet;
    }

    @Reference(
            target = "(javax.portlet.name=" + InnRayPortletKeys.INNRAY_CUSTOM_PORTLET + ")"
    )
    private Portlet _portlet;
}

Właściwość panel.category.key definiuje kategorię, w której pojawi się ta aplikacja. Podobnie jak w przypadku kategorii, możesz również zdefiniować kolejność aplikacji w kategorii za pomocą panel.app.order:Integer.

Po połączeniu naszej niestandardowej kategorii i niestandardowej aplikacji panelowej otrzymujemy nasz wpis zgodnie z oczekiwaniami: Niestandardowy portlet w naszej niestandardowej kategorii panelu sterowania

Upewnij się, że Twój portlet nie jest instanceable. W przeciwnym razie całość może nie zadziałać:

@Component(
    property = {
        "com.liferay.portlet.display-category=category.hidden",
        "com.liferay.portlet.instanceable=false",
        "javax.portlet.display-name=My Custom App",
        "javax.portlet.name=" + InnRayPortletKeys.INNRAY_CUSTOM_PORTLET,
        "javax.portlet.security-role-ref=administrator"
    },
    service = Portlet.class
)
public class MyCustomPortlet extends MVCPortlet {
    // Implementacja portletu
}

3. React Client Extension w Panelu Sterowania

Trzeci przypadek dotyczy sytuacji, gdy chcesz stworzyć Client Extension, który pojawiłby się w panelu sterowania lub lewym panelu bocznym. Jest to możliwe zarówno dla niestandardowych, jak i istniejących kategorii. Kluczem jest odpowiednia konfiguracja client-extension.yaml. W tym przypadku dodam coś pod istniejącą kategorią "Content & Data" (lewy panel boczny). Aby to zrobić, musisz zdefiniować następujące właściwości:

  • panelCategoryKey: kategoria, w której chcemy umieścić nasz niestandardowy client extension
  • panelAppOrder: kolejność, tak samo jak dla niestandardowych aplikacji panelowych
  • instanceable: musi być false
innRayCustomAppAdmin:
  panelCategoryKey: site_administration.content
  panelAppOrder: 660
  instanceable: false
  type: customElement
  name: InnRay Custom App Administration
  portletCategoryName: category.client-extensions
  htmlElementName: innray-custom-app-admin
  friendlyURLMapping: innray-custom-app-admin
  useESM: true
  urls:
    - assets/*.js
  cssURLs:
    - assets/*.css

Efekt: Niestandardowy React Client Extension w Panelu Sterowania

4. Niestandardowa kategoria root

Tworzenie całkowicie niestandardowej kategorii na poziomie root (jak "Applications" czy "Control Panel") jest nieco bardziej złożone i mniej udokumentowane. Przede wszystkim musisz stworzyć "kategorię root", co robi się w ten sam sposób jak dla niestandardowych kategorii, jedyna różnica polega na tym, że musisz podać odpowiednią właściwość panel.category.key:

@Component(
        property = {
                "panel.category.key=" + PanelCategoryKeys.APPLICATIONS_MENU,
                "panel.category.order:Integer=900"
        },
        service = PanelCategory.class
)
public class InnRayRootPanelCategory extends BasePanelCategory {

    @Override
    public String getKey() {
        return PanelCategoryKeys.APPLICATIONS_MENU + ".innray";
    }

    @Override
    public String getLabel(Locale locale) {
        return "InnRay";
    }
}

Musisz upewnić się, że masz co najmniej jedną kategorię z co najmniej jedną niestandardową aplikacją (na przykład jak wyjaśniono w poprzednich sekcjach). W przeciwnym razie kategoria root nie będzie widoczna.

Po wykonaniu tego powinieneś zobaczyć swoją niestandardową kategorię w Panelu Sterowania: Niestandardowa kategoria root w Panelu Sterowania

Integracja kategorii root z obiektami

Jednym z wyzwań związanych z niestandardowymi kategoriami "root" jest sprawienie, by pojawiały się w panelu konfiguracji obiektów (gdy chcesz przypisać obiekt do swojej niestandardowej kategorii) - domyślnie konfiguracja obiektów pokazuje tylko wbudowane kategorie. Utworzenie niestandardowej kategorii "root level" nie sprawi, że pojawi się ona tam automatycznie. Aby Twoja niestandardowa kategoria tam się pojawiła, musisz:

  • Dostarczyć implementację ObjectScopeProvider
  • W metodzie getRootPanelCategoryKeys zwrócić klucz swojej niestandardowej kategorii (poza tymi wbudowanymi)
  • Bazową implementację ObjectScopeProvider można znaleźć w kodzie źródłowym Liferay.

Warto zauważyć, że te konfiguracje mają różne zakresy (scope), np. firmy (company) lub witryny (site). W tym wypadku pokażę przykład dla zakresu firmy (company scope), reszta jest bardzo podobna i jak wspomniałem wcześniej możesz znaleźć domyślną implementację na GitHubie Liferay.

Implementacja powinna wyglądać następująco:

@Component(
        immediate = true,
        property = {
                "object.scope.provider.key=" + ObjectDefinitionConstants.SCOPE_COMPANY,
                "service.ranking:Integer=" + Integer.MAX_VALUE
        },
        service = ObjectScopeProvider.class
)
public class InnRayCompanyInstanceObjectScopeProviderImpl implements ObjectScopeProvider {

    @Reference
    private Language language;

    @Override
    public long getGroupId(HttpServletRequest httpServletRequest) {
        return 0;
    }

    @Override
    public String getKey() {
        return ObjectDefinitionConstants.SCOPE_COMPANY;
    }

    @Override
    public String getLabel(Locale locale) {
        return language.get(locale, "company");
    }

    @Override
    public String[] getRootPanelCategoryKeys() {
        return new String[]{
                PanelCategoryKeys.CONTROL_PANEL, PanelCategoryKeys.COMMERCE,
                PanelCategoryKeys.APPLICATIONS_MENU_APPLICATIONS, PanelCategoryKeys.APPLICATIONS_MENU + ".innray"
        };
    }

    @Override
    public boolean isGroupAware() {
        return false;
    }

    @Override
    public boolean isValidGroupId(long groupId) {
        if (groupId == 0) {
            return true;
        }

        return false;
    }
}

Upewnij się, że zdefiniowałeś service.ranking:Integer, aby domyślna konfiguracja Liferay została nadpisana Twoją.

To wszystko! Twoje niestandardowe konfiguracje w Twojej własnej "kategorii root" powinny pojawić się w konfiguracji obiektów: Niestandardowa kategoria root w konfiguracji Objects

Pytanie które może przyjści na myśl: dlaczego wszystko działa w przypadku niestandardowych kategorii, które tworzymy pod istniejącymi kategoriami root? Otóż dlatego, że z ObjectScopeProviderImpl pobierane są kategorie root, ale następnie kod sam odnajduje podkategorie. Więc jeżeli "root" kategoria jest już zwracana przez ObjectScopeProviderImpl, to nie ma potrzeby dodatkowej konfiguracji.

Podsumowanie

Ten artykuł omówił główne scenariusze dodawania niestandardowych aplikacji do Panelu Sterowania Liferay. Podczas gdy pierwsze trzy scenariusze są stosunkowo proste i już gdzieś wyjaśnione (choć nie w jednym miejscu, o ile mi wiadomo), tworzenie kategorii na poziomie root z integracją z obiektami wymaga dodatkowej konfiguracji.

Kluczowe wnioski:

  • Stwórz komponent OSGi rozszerzający BasePanelCategory dla niestandardowych kategorii i BasePanelApp dla aplikacji
  • Odwołuj się do prawidłowych kluczy kategorii nadrzędnych
  • Client Extensions można zintegrować poprzez konfigurację client-extension.yaml
  • Kategorie root wymagają specjalnej obsługi dla integracji z obiektami

Zainteresowany naszymi usługami? Porozmawiajmy!

Możesz także napisać e-mail lub zadzwonić - czekamy na Ciebie!

contact@innray.com

+48 661 344 000

Skontaktuj się z nami

Pola oznaczone * są wymagane