Cloudogu Logo

Hallo, wir sind Cloudogu!

Experten für Software-Lifecycle-Management und Prozess­auto­mati­sierung, Förderer von Open-Source-Soft­ware und Entwickler des Cloudogu EcoSystem.

featured image SCM-Manager – Frontend und Release für mein erstes Plugin
30.11.2021 in Technology

SCM-Manager – Frontend und Release für mein erstes Plugin


Eduard Heimbuch
Eduard Heimbuch

- SCM-Manager Entwickler -


Im ersten Teil dieser Serie haben wir erklärt, warum und wie Plugins verwendet werden können, um die Grundfunktionalität des SCM-Managers zu erweitern, wie die grundlegende Architektur aussieht und wie Sie selbst entwickelte Plugins mit der Community teilen können. Im zweiten Teil haben wir das Backend für ein Plugin entwickelt. In diesem Teil zeigen wir Ihnen, wie Sie das Frontend erstellen, es mit dem Backend verbinden und das Plugin veröffentlichen.

Wir beginnen mit dem Frontend

Das SCM-Manager-Frontend ist in React mit Typescript-Unterstützung geschrieben. Wir verwenden auch Bibliotheken/Frameworks wie Bulma für das Styling und React Query für die Datensynchronisation. Das Ziel für unser Plugin ist es, die benutzerdefinierten Links global für den SCM-Manager zu konfigurieren und sie in der Fußzeile anzuzeigen.

Globale Konfiguration

Um die globale Konfiguration für die Links zu erstellen, fügen wir zunächst eine eigene Konfigurationsseite in den Administrationsbereich ein. Dazu erstellen wir eine neue React-Komponente. Mit useState halten wir die Daten unserer Eingabefelder fest. Mit benutzerdefinierten React-Hooks, die auf React Query basieren, können wir unsere Daten vom Server laden und unsere Anfragen wegschicken.

Ein großer Vorteil von React Query ist die stale while revalidate-Prozedur, die zu einer Minimierung von Loading Spinners führt. Dies wird über Frontend-Caches realisiert, die nur dann Daten austauschen, wenn neue Daten eingetroffen sind. Die benutzerdefinierten Hooks verwalten die Ladezustände für uns. Wir verwenden lediglich ein boolesches Flag, um zu prüfen, ob die Daten fertig geladen sind.

Wenn Fehler auftauchen, zeigen wir diese in unserem Error Boundary in der UI an.

Wichtig: Sie müssen Ihre benötigten Komponenten nicht von Grund auf neu erstellen. Wir empfehlen die Verwendung der vom SCM-Manager bereitgestellten Komponenten und apis.

Aufbau

Wir werden eine Übersicht für unsere Konfiguration erstellen, die aus zwei Teilen besteht:

  • Einer Tabelle mit allen erstellten Custom Links.
  • Einem kleinen Formular zum Erstellen/Aktualisieren von benutzerdefinierten Links.

Unsere Tabelle besteht aus einer <Table/> Komponente, die wir aus den UI-Komponenten des SCM-Managers erhalten. Dann fügen wir einige Spalten hinzu, um unsere Daten und Funktionen anzuzeigen. Direkt in die Tabelle tragen wir dann die Daten unserer Custom Links ein, die vom Server kommen. Wenn noch keine Links angelegt wurden und die Tabelle leer ist, zeigen wir eine entsprechende Information an.

const CustomLinksTable: FC<{ customLinks: CustomLink[] }> = ({ customLinks }) => {
  const [t] = useTranslation("plugins");
  const { deleteLink, error: deleteError } = useDeleteCustomLink();

  return (
    <>
      <Table data={customLinks} emptyMessage={t("scm-custom-links-plugin.form.table.empty")}>
        <TextColumn header={t("scm-custom-links-plugin.form.table.name")} dataKey="name" />
        <TextColumn header={t("scm-custom-links-plugin.form.table.url")} dataKey="url" />
        <Column header={t("")}>
          {(row: any) => (
            <Icon
              name="trash"
              onClick={() => deleteLink((row._links.delete as Link).href)}
              title={t("scm-custom-links-plugin.form.table.deleteLink")}
            />
          )}
        </Column>
      </Table>
      <ErrorNotification error={deleteError} />
    </>
  );
};

Übersetzungen und Styling

Nachdem wir unsere Konfigurationsseite strukturell aufgebaut haben, brauchen wir noch die Übersetzungen unserer Texte und den letzten Schliff mit CSS. Für die Übersetzungen verwenden wir I18Next von React und pflegen unsere Übersetzungen in einer JSON-Datei pro Sprache.

Das CSS kann mit verschiedenen Ansätzen gestylt werden. Wir bevorzugen Bulma als CSS-Framework und für spezielle Fälle verwenden wir gerne gestylte Komponenten. In unserem Fall sehen die Komponenten bereits gut aus und müssen nur noch harmonisch positioniert werden. Hierfür verwenden wir die Hilfsklassen von Bulma. Nun sollte unsere Konfigurationsseite gut aussehen und unsere funktionalen Anforderungen erfüllen.

Binden der Konfigurationsseite

Nachdem wir unsere Konfigurationsseite erstellt haben, müssen wir sie noch in die Verwaltungsnavigation integrieren. Dies geschieht mithilfe des Konfigurationsbinders aus ui-components. Dieser Binder wurde speziell dafür entwickelt React-Komponenten als neue Konfigurationseinträge hinzuzufügen, in unserem Fall in die globale Administrationsnavigation, und auch um die Route zu binden.

Beispiel:

import { ConfigurationBinder as configurationBinder } from "@scm-manager/ui-components";
import GlobalConfig from "./GlobalConfig";

configurationBinder.bindGlobal(
  "/custom-links", // the link where our new config page will be available
  "scm-custom-links-plugin.settings.navLink", // the translation key for the navigation entry which must be translated in the plugins.json files
  "customLinksConfig", // the linkname inside the index. If any user does not have this link (not permitted), this page will not be accessible to them.
  GlobalConfig // our React component we want to render
);

Custom-Links-Konfigurationsseite

Jetzt können wir bereits über die Benutzeroberfläche auf die Konfigurationsseite zugreifen und unsere benutzerdefinierten Links dort verwalten.

Erweiterungspunkte

Nachdem wir einige benutzerdefinierte Links hinzugefügt haben, möchten wir sie auch in der Fußzeile sehen. Dazu müssen wir einen Custom-Links-Renderer erstellen, der sie einfach vom Server anfordert und eine Linkliste rendert. Dieser Renderer muss nun in der Fußzeile verwendet werden, damit unsere Links dort erreicht werden können. Für diesen Fall müssen wir unseren Renderer als Erweiterung gegen den passenden Erweiterungspunkt im Footer binden. Da die benutzerdefinierten Links in der Spalte “Information” angezeigt werden sollen, müssen wir den Erweiterungspunkt footer.information benutzen.

const CustomLinksRenderer: FC<Props> = ({ links }) => {
  const { data, isLoading } = useCustomLinks((links.customLinks as Link).href);

  if (isLoading) {
    return null;
  }

  return (
    <>
      {(data?._embedded?.customLinks as CustomLink[]).map(cl => (
        <li>
          <a href={cl.url} target="_blank">
            {cl.name}
          </a>
        </li>
      ))}
    </>
  );
};

Der CustomLinkRenderer benutzt einen React Hook, welcher die Daten abruft und mithilfe von ReactQuery in unseren Frontend-Cache schreibt.

export const useCustomLinks = (link: string) => {
  const { error, isLoading, data } = useQuery<HalRepresentation, Error>("custom-links", () =>
    apiClient.get(link).then(res => res.json())
  );

  return {
    error,
    isLoading,
    data
  };
};

Anmerkungen:

  • Sollte es derzeit keinen oder nicht den richtigen Erweiterungspunkt für Ihr Plugin geben, kontaktieren Sie bitte das SCM-Manager Team.
  • Erweiterungspunkte sollten immer in der index.tsx Ihres Plugins eingebunden werden.
  • Unser Beispiel ist recht einfach. Erweiterungspunkte können auch Props für alle gebundenen Erweiterungen bereitstellen, die Erweiterungen nach Name und Priorität sortieren oder über eine Prädikatsfunktion deaktiviert werden.

Beispiel:

import { binder } from "@scm-manager/ui-extensions";
import CustomLinksRenderer from "./CustomLinksRenderer";

binder.bind("footer.information", CustomLinksRenderer)

Wir können die benutzerdefinierten Links in unserer Fußzeile sehen und sobald ein Link geändert wird, wird die Fußzeile sofort aktualisiert.

SCM-Manager Fußzeile

Wie kann ich mein Plugin veröffentlichen?

Die erste Iteration des Plugins ist fertig. Es funktioniert wie erwartet und kann verwendet werden. Nun ist es Ihre Entscheidung ob Sie es für sich behalten wollen oder, wenn Sie denken, dass es anderen Mitgliedern der Community helfen könnte, es mit der Community teilen. Um es mit der Community zu teilen müssen Sie lediglich den Code Ihres Plugins auf einer öffentlichen Instanz wie GitHub bereitstellen und anschließend das SCM-Manager-Team kontaktieren. Wir werden dann Ihr Plugin reviewen und es in die SCM-Manager GitHub-Organisation einbinden. Sobald dies geschehen ist, werden wir es im offiziellen SCM-Manager Plugin Center veröffentlichen.

Abschließende Worte

Wir hoffen, wir konnten Ihnen einen Einblick in die Entwicklung von Plugins für den SCM-Manager geben. Dies war ein recht einfaches Beispiel, um Ihnen zu zeigen, wie ein Plugin aussehen kann. Wir haben bereits viel größere und komplexere Plugins, die Sie sich in der SCM-Manager GitHub Organisation ansehen können.

Wenn Sie sich noch nicht sicher sind, ob Sie ein eigenes Plugin erstellen können oder wie Sie Ihren Anwendungsfall am besten realisieren, kontaktieren Sie das SCM-Manager Team. Unsere Entwickler und UX-Spezialisten unterstützen Sie gerne bei der Entwicklung.

SCM-Manager

Der einfachste Weg Ihre Git-, Mercurial- and Subversion-Repositories zu teilen und zu verwalten.

Jetzt kennenlernen
SCM-Manager Logo