You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@inlong.apache.org by le...@apache.org on 2022/11/24 02:01:48 UTC

[inlong-website] branch master updated: [INLONG-612][Doc] Update Dashboard plugin doc (#615)

This is an automated email from the ASF dual-hosted git repository.

leezng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong-website.git


The following commit(s) were added to refs/heads/master by this push:
     new ce7c97c153 [INLONG-612][Doc] Update Dashboard plugin doc (#615)
ce7c97c153 is described below

commit ce7c97c15385996065ac57fde7d51d1daa2b73d9
Author: Daniel <le...@apache.org>
AuthorDate: Thu Nov 24 10:01:43 2022 +0800

    [INLONG-612][Doc] Update Dashboard plugin doc (#615)
---
 .../how_to_write_plugin_dashboard.md               | 164 +++++++++++----------
 docs/design_and_concept/img/dashboard_plugin.png   | Bin 0 -> 140922 bytes
 .../how_to_write_plugin_dashboard.md               | 146 ++++++++++--------
 .../design_and_concept/img/dashboard_plugin.png    | Bin 0 -> 140922 bytes
 4 files changed, 168 insertions(+), 142 deletions(-)

diff --git a/docs/design_and_concept/how_to_write_plugin_dashboard.md b/docs/design_and_concept/how_to_write_plugin_dashboard.md
index 4f9fb903c4..ae68db52c4 100644
--- a/docs/design_and_concept/how_to_write_plugin_dashboard.md
+++ b/docs/design_and_concept/how_to_write_plugin_dashboard.md
@@ -8,86 +8,92 @@ sidebar_position: 4
 This article is aimed at InLong Dashboard plug-in developers, trying to describe the process of developing a Dashboard plug-in as comprehensively as possible, helping developers quickly add a data storage LoadNode, and making plug-in development easier.
 The InLong Dashboard itself acts as a front-end console, built with the React framework.
 
-## Extend Load Node
-
-In the `inlong-dashboard/src/components/MetaData` directory, create a new `StorageExample.tsx` file, and at the same time export the file in the `index.ts` file in the current directory (refer to the existing LoadNode writing method ), which completes a new sink named `Example`.
-
-````js
-// export in index
-export const Storages: StoragesType[] = [
-  // ... omit existing code
-  {
-    label: 'Example',
-    value: 'Example',
-    ...StorageExample,
-  },
-];
+## Basic
+
+### Design Summary
+
+This is a schematic diagram of the design of the InLong Dashboard plugin. We treat the plugin as a separate level, and each page uses different plugins for consumption. Data and View are abstract classes provided by the system, and plugins are derived classes one by one.
+
+![Dashboard_Plugin](img/dashboard_plugin.png)
+
+### Directory Structure
+
+````sh
+|
+|- defaults: default public plugins provided by the InLong community
+|- extends: The extension plug-in during privatization deployment, as an internal plug-in, will not be released to the community
+|- common: the common design of the plugin, e.g. the design of `BasicInfo`
 ````
 
-Next, we will introduce how to define the internal structure of the LoadNode.
-
-In the definition of LoadNode, we can view the unified specification of our agreement through the type declaration in the `import type { GetStorageFormFieldsType, GetStorageColumnsType } from '@/utils/metaData';` file, here we show a simplest LoadNode definition (emphasis inside the `--Focus--` tag):
-
-````js
-import { getColsFromFields, GetStorageFormFieldsType } from '@/utils/metaData';
-import { ColumnsType } from 'antd/es/table';
-import { excludeObject } from '@/utils';
-
-const getForm: GetStorageFormFieldsType = (
-  type: 'form' | 'col' = 'form',
-  { currentValues, isEdit } = {} as any,
-) => {
-  // -- Focus Start --
-  const fileds = [
-    {
-      name: 'name',
-      type: 'input',
-      label: 'Name',
-      _inTable: true,
-    },
-    {
-      name: 'sex',
-      type: 'radio',
-      label: 'Sex',
-      initialValue: 'female',
-      props: {
-        options: [
-          {
-            label: 'female',
-            value: 'female',
-          },
-          {
-            label: 'male',
-            value: 'male',
-          },
-        ],
-        disabled: isEdit && [110, 130].includes(currentValues?.status),
-      },
-      _inTable: true,
-    },
-    {
-      name: 'age',
-      type: 'inputnumber',
-      label: 'Age',
-      props: {
-        min: 1,
-        max: 200,
-      },
+### Data Class
+
+We provide two basic data classes, and each plugin can only implement one of them to implement the data model. At the same time, in the basic data class, a `@I18n` is provided, which can be used to describe the field.
+
+- DataStatic static data class
+- DataWithBackend communicates with the backend data class
+
+### View Class
+
+On the view, we provide two basic view classes, each plugin can implement one or more of them to implement the view model.
+
+- RenderRow, in which `@FieldDecorator` is provided to describe the row data view
+- RenderList, in which `@ColumnDecorator` is provided to describe the column data view
+
+### Example
+
+Below is a basic example, in the plugin, a class that communicates with backend is implemented, containing 3 fields (username, password, format). Among them, `BasicInfo` comes from their different base type classes.
+
+```ts
+import { DataWithBackend } from '@/metas/DataWithBackend';
+import { RenderRow } from '@/metas/RenderRow';
+import { RenderList } from '@/metas/RenderList';
+import { BasicInfo } from '../common/BasicInfo';
+
+const { I18n } = DataWithBackend;
+const { FieldDecorator } = RenderRow;
+const { ColumnDecorator } = RenderList;
+
+export default class Example extends BasicInfo implements DataWithBackend, RenderRow, RenderList {
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+  })
+  @I18n('meta.Sinks.Username')
+  username: string;
+
+  @FieldDecorator({
+    type: 'password',
+    rules: [{ required: true }],
+  })
+  @I18n('meta.Sinks.Password')
+  password: string;
+
+  @FieldDecorator({
+    type: 'radio',
+    initialValue: 'TextFile',
+    rules: [{ required: true }],
+    props: {
+      options: [
+        {
+          label: 'TextFile',
+          value: 'TextFile',
+        },
+        {
+          label: 'SequenceFile',
+          value: 'SequenceFile',
+        },
+      ],
     },
-    // -- Focus End --
-  ];
-  // The following is a generic return
-  return type === 'col'
-    ? getColsFromFields(fileds)
-    : fileds.map(item => excludeObject(['_inTable'], item));
-};
-// The following is a generic export
-const tableColumns = getForm('col') as ColumnsType;
-
-export const StorageExample = {
-  getForm,
-  tableColumns,
-};
-````
+  })
+  @I18n('meta.Sinks.Example.Format')
+  format: string;
+}
+```
+
+## Extend ExtractNode
+
+In the `inlong-dashboard/src/metas/sources/defaults` directory, create a new `Example.ts` file as a new plugin, and export it in the `index.ts` file in the current directory (refer to Existing writing method), which completes a new ExtractNode named `Example`.
+
+## Extend LoadNode
 
-In the above example, we define a sink of `Example`, which consists of three fields: name, sex, age. The field name corresponds to the name attribute (the API interface field that interacts with the manager), and the type attribute represents the display on the front-end page. The input form usually includes input, inputnumber, radio, select and other forms. More complex display forms or the complete definition of the entire object can be obtained through the ts type description.
\ No newline at end of file
+In the `inlong-dashboard/src/metas/sinks/defaults` directory, create a new `Example.ts` file as a new plugin, and export it in the `index.ts` file in the current directory (refer to The existing writing method), which completes a new LoadNode named `Example`.
diff --git a/docs/design_and_concept/img/dashboard_plugin.png b/docs/design_and_concept/img/dashboard_plugin.png
new file mode 100644
index 0000000000..9a6fac90fc
Binary files /dev/null and b/docs/design_and_concept/img/dashboard_plugin.png differ
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/design_and_concept/how_to_write_plugin_dashboard.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/design_and_concept/how_to_write_plugin_dashboard.md
index f89e5514d3..f09abcf1c0 100644
--- a/i18n/zh-CN/docusaurus-plugin-content-docs/current/design_and_concept/how_to_write_plugin_dashboard.md
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/design_and_concept/how_to_write_plugin_dashboard.md
@@ -5,75 +5,95 @@ sidebar_position: 4
 
 ## 总览
 
-本文面向 InLong Dashboard 插件开发人员,尝试尽可能全面地阐述开发一个 Dashboard 插件所经过的历程,帮助开发者快速新增一个 Load Node,让插件开发变得简单。
+本文面向 InLong Dashboard 插件开发人员,尝试尽可能全面地阐述开发一个 Dashboard 插件所经过的历程,帮助开发者快速新增一个 Plugin,让插件开发变得简单。
 InLong Dashboard 本身作为前端控制台,采用 React 框架构建。
 
-## 扩展 Load Node
+## 插件基础
 
-在 `inlong-dashboard/src/components/MetaData` 目录下,新建一个 `StorageExampleNode.tsx` 文件,同时讲该文件在当前目录的 `index.ts` 文件内部进行导出(可参考已有 LoadNode 的写法),这样便完成了新增一种名为 `ExampleNode` 的 LoadNode,接下来,我们将介绍怎么定义该 LoadNode 的内部结构。
+### 设计概要
 
-在 LoadNode 的定义中,可通过 `import type { GetStorageFormFieldsType, GetStorageColumnsType } from '@/utils/metaData';` 文件中的类型声明查看我们约定的统一规范,这里我们展示了一个最简单的 LoadNode 定义(重点在于`--关注点--`标签内部):
+这是 InLong Dashboard 插件的设计概要图,我们将插件作为一个单独的层级,由各个页面使用不同的插件,进行消费。Data 与 View 是系统提供的抽象类,而插件就是一个个的派生类。
 
-```js
-import { getColsFromFields, GetStorageFormFieldsType } from '@/utils/metaData';
-import { ColumnsType } from 'antd/es/table';
-import { excludeObject } from '@/utils';
+![Dashboard_Plugin](img/dashboard_plugin.png)
 
-const getForm: GetStorageFormFieldsType = (
-  type: 'form' | 'col' = 'form',
-  { currentValues, isEdit } = {} as any,
-) => {
-  // -- 关注点 Start --
-  const fileds = [
-    {
-      name: 'name',
-      type: 'input',
-      label: 'Name',
-      _inTable: true,
-    },
-    {
-      name: 'sex',
-      type: 'radio',
-      label: 'Sex',
-      initialValue: 'female',
-      props: {
-        options: [
-          {
-            label: 'female',
-            value: 'female',
-          },
-          {
-            label: 'male',
-            value: 'male',
-          },
-        ],
-        disabled: isEdit && [110, 130].includes(currentValues?.status),
-      },
-      _inTable: true,
-    },
-    {
-      name: 'age',
-      type: 'inputnumber',
-      label: 'Age',
-      props: {
-        min: 1,
-        max: 200,
-      },
+### 目录结构
+
+```sh
+|
+|- defaults: InLong 社区提供的默认公共插件
+|- extends: 私有化部署时的扩展插件,作为内部插件,不投放到社区
+|- common: 插件的公共设计,例如 `BasicInfo` 的设计
+```
+
+### 插件数据类
+
+我们提供两种基本数据类,每一个插件都只能实现其中的一种,从而实现数据模型。同时,在基本数据类中,均提供一个 `@I18n`,可用于描述字段。
+
+- DataStatic 静态数据类
+- DataWithBackend 与后台通信的数据类
+
+### 插件视图类
+
+在视图上,我们提供两种基本视图类,每一个插件可实现其中的一种或多种,从而实现视图模型。
+
+- RenderRow,在该类中提供 `@FieldDecorator` 用于描述行数据视图
+- RenderList,在该类中提供 `@ColumnDecorator` 用于描述列数据视图
+
+### 基本示例
+
+下面是一个基本示例,在该插件中,实现了与 backend 通信的一个类,包含3个字段(username, password, format)。其中,`BasicInfo` 来源于各自不同的基础类型类。
+
+```ts
+import { DataWithBackend } from '@/metas/DataWithBackend';
+import { RenderRow } from '@/metas/RenderRow';
+import { RenderList } from '@/metas/RenderList';
+import { BasicInfo } from '../common/BasicInfo';
+
+const { I18n } = DataWithBackend;
+const { FieldDecorator } = RenderRow;
+const { ColumnDecorator } = RenderList;
+
+export default class Example extends BasicInfo implements DataWithBackend, RenderRow, RenderList {
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+  })
+  @I18n('meta.Sinks.Username')
+  username: string;
+
+  @FieldDecorator({
+    type: 'password',
+    rules: [{ required: true }],
+  })
+  @I18n('meta.Sinks.Password')
+  password: string;
+
+  @FieldDecorator({
+    type: 'radio',
+    initialValue: 'TextFile',
+    rules: [{ required: true }],
+    props: {
+      options: [
+        {
+          label: 'TextFile',
+          value: 'TextFile',
+        },
+        {
+          label: 'SequenceFile',
+          value: 'SequenceFile',
+        },
+      ],
     },
-    // -- 关注点 End --
-  ];
-  // 下面为通用的 return
-  return type === 'col'
-    ? getColsFromFields(fileds)
-    : fileds.map(item => excludeObject(['_inTable'], item));
-};
-// 下面为通用的 export
-const tableColumns = getForm('col') as ColumnsType;
-
-export const StorageExampleNode = {
-  getForm,
-  tableColumns,
-};
+  })
+  @I18n('meta.Sinks.Example.Format')
+  format: string;
+}
 ```
 
-在上述例子中,我们定义了一个 `ExampleNode` 的 LoadNode,它由 name, sex, age 三个字段构成,字段名对应了 name 属性(与 manager 交互的 API 接口字段),type 属性表示前端页面中展示的输入表单,通常包含 input, inputnumber, radio, select 等多种形式,更多的复杂展示形式或整个对象的完整定义都可通过 ts 类型描述获得。
+## 扩展 ExtractNode
+
+在 `inlong-dashboard/src/metas/sources/defaults` 目录下,新建一个 `Example.ts` 文件,作为我们新建的一个插件,同时在当前目录的 `index.ts` 文件内部进行导出(可参考已有的写法),这样便完成了新增一种名为 `Example` 的 ExtractNode。
+
+## 扩展 LoadNode
+
+在 `inlong-dashboard/src/metas/sinks/defaults` 目录下,新建一个 `Example.ts` 文件,作为我们新建的一个插件,同时在当前目录的 `index.ts` 文件内部进行导出(可参考已有的写法),这样便完成了新增一种名为 `Example` 的 LoadNode。
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/design_and_concept/img/dashboard_plugin.png b/i18n/zh-CN/docusaurus-plugin-content-docs/current/design_and_concept/img/dashboard_plugin.png
new file mode 100644
index 0000000000..9a6fac90fc
Binary files /dev/null and b/i18n/zh-CN/docusaurus-plugin-content-docs/current/design_and_concept/img/dashboard_plugin.png differ