SCM 관리자 – 플러그인 개발 소개(3/3): 프런트엔드 및 릴리스

이 시리즈의 첫 번째 부분에서는 플러그인을 사용하여 SCM Manager의 기본 기능을 확장할 수 있는 이유와 방법, 기본 아키텍처의 모양 및 자체 개발 플러그인을 커뮤니티와 공유하는 방법에 대해 설명했습니다. 두 번째 부분에서는 플러그인용 백엔드를 개발했습니다. 이 부분에서는 프런트엔드를 만들고 백엔드에 연결하고 플러그인을 게시하는 방법을 보여줍니다.

프런트 엔드부터 시작하겠습니다.

SCM Manager 프런트엔드는 Typescript를 지원하는 React로 작성되었습니다. 또한 스타일을 지정하기 위해 Bulma와 같은 라이브러리/프레임워크를 사용하고 데이터 동기화를 위해 React Query를 사용합니다. 플러그인의 목표는 SCM 관리자에 대해 전역적으로 사용자 지정 링크를 구성하고 바닥글에 표시하는 것입니다.

글로벌 구성

링크에 대한 전역 구성을 생성하려면 먼저 자체 구성 페이지를 관리자 패널에 추가합니다. 이를 위해 새로운 React 구성 요소를 만듭니다. 와 함께 useState 입력 필드의 데이터를 기록합니다. React Query를 기반으로 하는 사용자 지정 React 후크를 사용하면 서버에서 데이터를 로드하고 요청을 멀리 보낼 수 있습니다.

React Query의 큰 장점은 stale while revalidate– 로딩 스피너 최소화로 이어지는 절차. 이는 새로운 데이터가 도착했을 때만 데이터를 교환하는 프런트엔드 캐시를 통해 실현됩니다. 커스텀 후크는 충전 상태를 관리합니다. 부울 플래그를 사용하여 데이터 로드가 완료되었는지 확인합니다.

오류가 발생하면 UI의 오류 경계에 오류를 표시합니다.

중요한: 처음부터 필요한 구성 요소를 만들 필요가 없습니다. SCM 매니저에서 제공하는 컴포넌트와 api 사용을 권장합니다.

건설

두 부분으로 구성된 구성에 대한 개요를 생성합니다.

  • 모든 사용자 지정 링크가 생성된 테이블.
  • 맞춤 링크를 생성/업데이트하기 위한 작은 양식입니다.

우리 테이블은 1인용 <Table/> SCM Manager UI 구성 요소에서 가져온 구성 요소입니다. 그런 다음 일부 열을 추가하여 데이터와 기능을 표시합니다. 그런 다음 서버에서 오는 사용자 지정 링크의 데이터를 테이블에 직접 입력합니다. 아직 생성된 링크가 없고 테이블이 비어 있는 경우 적절한 정보가 표시됩니다.

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} />
    </>
  );
};

번역 및 스타일링

구성 페이지를 구조적으로 구축한 후에도 여전히 텍스트 번역과 CSS로 마무리 작업이 필요합니다. 번역을 위해 React의 I18Next를 사용하고 언어당 하나의 JSON 파일로 번역을 유지합니다.

CSS는 다양한 접근 방식을 사용하여 스타일을 지정할 수 있습니다. 우리는 Bulma를 CSS 프레임워크로 선호하고 특별한 경우에는 스타일이 지정된 구성 요소를 사용하는 것을 좋아합니다. 우리의 경우 구성 요소는 이미 보기에 좋으며 조화롭게 배치하기만 하면 됩니다. 이를 위해 Bulma의 도우미 클래스를 사용합니다. 이제 구성 페이지가 좋아 보이고 기능적 요구 사항을 충족해야 합니다.

구성 페이지 바인딩

이제 구성 페이지를 만들었으므로 관리 탐색과 통합해야 합니다. 이는 구성 바인더를 사용하여 수행됩니다. ui-components. 이 바인더는 React 구성 요소를 새 구성 항목으로 추가하고(우리의 경우 전역 관리 탐색에) 경로를 바인딩하도록 특별히 설계되었습니다.

예:

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
);

이제 우리는 이미 인터페이스에서 구성 페이지에 액세스하고 여기에서 사용자 지정 링크를 관리할 수 있습니다.

확장점

사용자 지정 링크를 추가한 후 바닥글에도 표시하려고 합니다. 이렇게 하려면 단순히 서버에서 링크를 요청하고 링크 목록을 렌더링하는 사용자 지정 링크 렌더러를 만들어야 합니다. 이 렌더러는 이제 링크에 도달할 수 있도록 바닥글에서 사용해야 합니다. 이 경우 바닥글의 적절한 확장 지점에 대한 확장으로 렌더러를 바인딩해야 합니다. 사용자 정의 링크가 정보 열에 나타나기를 원하므로 확장점을 추가해야 합니다. footer.information 사용.

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>
      ))}
    </>
  );
};

CustomLinkRenderer는 ReactQuery를 사용하여 데이터를 가져와 프런트엔드 캐시에 쓰는 React Hook을 사용합니다.

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
  };
};

비고:

  • 현재 플러그인에 대한 올바른 확장 지점이 없거나 없는 경우 SCM 관리자 팀에 문의하십시오.
  • 확장 포인트는 항상 플러그인의 index.tsx에 포함되어야 합니다.
  • 우리의 예는 아주 간단합니다. 확장 포인트는 또한 바인딩된 모든 확장에 대한 props를 제공하여 확장을 이름 및 우선 순위별로 정렬하거나 조건자 함수를 통해 비활성화할 수 있습니다.

예:

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

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

바닥글에서 사용자 지정 링크를 볼 수 있으며 링크가 변경되는 즉시 바닥글이 업데이트됩니다.

내 플러그인을 어떻게 게시할 수 있습니까?

플러그인의 첫 번째 반복이 준비되었습니다. 예상대로 작동하며 사용할 준비가 되었습니다. 이제 자신을 위해 보관할지 또는 커뮤니티의 다른 구성원에게 도움이 될 수 있다고 생각되면 커뮤니티와 공유할지 여부는 귀하의 결정입니다. 커뮤니티와 공유하려면 GitHub와 같은 공개 인스턴스에 플러그인 코드를 제공한 다음 SCM 관리자 팀에 문의하기만 하면 됩니다. 그런 다음 플러그인을 검토하고 SCM Manager GitHub 조직에 포함합니다. 이 작업이 완료되면 공식 SCM Manager Plugin Center에 게시할 예정입니다.

닫는 단어

SCM Manager용 플러그인 개발에 대한 통찰력을 제공할 수 있기를 바랍니다. 이것은 플러그인이 어떻게 생겼는지 보여주는 아주 간단한 예였습니다. SCM Manager GitHub 조직에서 확인할 수 있는 훨씬 더 크고 복잡한 플러그인이 이미 있습니다.

자신만의 플러그인을 만들 수 있는지 또는 사용 사례를 구현하는 최선의 방법이 아직 확실하지 않은 경우 SCM 관리자 팀에 문의하십시오. 개발자와 UX 전문가가 기꺼이 개발을 지원할 것입니다.

About admin

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다